Android O - java.lang.RuntimeException: An error occurred while executing doInBackground()

最近任务列表中多了一个bug,让在这个sprint中解决掉,bug的堆栈信息如下:

Fatal Exception: java.lang.RuntimeException: An error occurred while executing doInBackground()
       at android.os.AsyncTask$3.done(AsyncTask.java:353)
       at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:383)
       at java.util.concurrent.FutureTask.setException(FutureTask.java:252)
       at java.util.concurrent.FutureTask.run(FutureTask.java:271)
       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
       at java.lang.Thread.run(Thread.java:764)
Caused by java.lang.SecurityException: Caller no longer running, last stopped +25s437ms because: timed out while starting
       at android.os.Parcel.readException(Parcel.java:1942)
       at android.os.Parcel.readException(Parcel.java:1888)
       at android.app.job.IJobCallback$Stub$Proxy.dequeueWork(IJobCallback.java:191)
       at android.app.job.JobParameters.dequeueWork(JobParameters.java:196)
       at android.support.v4.app.JobIntentService$JobServiceEngineImpl.dequeueWork(JobIntentService.java:309)
       at android.support.v4.app.JobIntentService.dequeueWork(JobIntentService.java:627)
       at android.support.v4.app.JobIntentService$CommandProcessor.doInBackground(JobIntentService.java:384)
       at android.support.v4.app.JobIntentService$CommandProcessor.doInBackground(JobIntentService.java:377)
       at android.os.AsyncTask$2.call(AsyncTask.java:333)
       at java.util.concurrent.FutureTask.run(FutureTask.java:266)
       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
       at java.lang.Thread.run(Thread.java:764)
  • 由上面的bug信息可知是调用了系统JobIntentService中的AsyncTask中的doInBackground所致, 而doInBackground又调用了dequeueWork,下面是源码部分(androidx 1.1.0的源码):

    final class CommandProcessor extends AsyncTask {
        @Override
        protected Void doInBackground(Void... params) {
            GenericWorkItem work;
    
            if (DEBUG) Log.d(TAG, "Starting to dequeue work...");
    
            while ((work = dequeueWork()) != null) {
                if (DEBUG) Log.d(TAG, "Processing next work: " + work);
                onHandleWork(work.getIntent());
                if (DEBUG) Log.d(TAG, "Completing work: " + work);
                work.complete();
            }
    
            if (DEBUG) Log.d(TAG, "Done processing work!");
    
            return null;
        }
    
  • dequeueWork()的源码如下, 我们关注mJobImpl != null的部分, 又会进入mJobImpl.dequeueWork()的部分:

    
        GenericWorkItem dequeueWork() {
            if (mJobImpl != null) {
                return mJobImpl.dequeueWork();
            } else {
                synchronized (mCompatQueue) {
                    if (mCompatQueue.size() > 0) {
                        return mCompatQueue.remove(0);
                    } else {
                        return null;
                    }
                }
            }
        }
    
  • mJobImpl其实是一个CompatJobEngine类型,源码以及是实现类JobServiceEngineImpl如下:

    	interface CompatJobEngine {
       		 IBinder compatGetBinder();
        	GenericWorkItem dequeueWork();
        }
    
    	@RequiresApi(26)
    	 static final class JobServiceEngineImpl extends JobServiceEngine
            implements JobIntentService.CompatJobEngine {
    	 @Override
            public JobIntentService.GenericWorkItem dequeueWork() {
                JobWorkItem work;
                synchronized (mLock) {
                    if (mParams == null) {
                        return null;
                    }
                    work = mParams.dequeueWork();
                }
                if (work != null) {
                    work.getIntent().setExtrasClassLoader(mService.getClassLoader());
                    return new WrapperWorkItem(work);
                } else {
                    return null;
                }
            }
        }
    
  • 从文章开头的bug信息中看到,接着又进入到了mParams.dequeueWork();中,然后就进入到了Binder机制中,源码如下,由此可以断定是在这里出了问题,抛出了异常,但是因为这里属于源码部分,不应该属于我们的职责范围。

    	public @Nullable JobWorkItem dequeueWork() {
        try {
            return getCallback().dequeueWork(getJobId());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }
    		/** @hide */
        @UnsupportedAppUsage
        public IJobCallback getCallback() {
            return IJobCallback.Stub.asInterface(callback);
        }
    
  • 经过查询源码,发现问题出现在framework层,而且网上早已有这个问题的issue:
    https://github.com/evernote/android-job/issues/255
    https://issuetracker.google.com/issues/63622293

  • 网上遇到这类问题的人很多很多,但是到目前为止,我查看了最新的google的androidx库("androidx.core:core-ktx:1.2.0-rc01"),依旧是没有解决这个问题。

  • 其实查看源码后发现解决这个问题的方法也比较简单,就是我们可以新建一个androidx.core.app的包,在其中新建一个类SafeJobIntentService继承JobIntentService, 之所以这么做是因为dequeueWork()方法的权限不是public,我们得写在同一个包中才能重写它的方法,进行bug的修复。

    @RestrictTo({Scope.LIBRARY})
    public abstract class SafeJobIntentService extends JobIntentService {
        public SafeJobIntentService() {
        }
    
        GenericWorkItem dequeueWork() {
            try {
                return super.dequeueWork();//1 这里我们对此方法进行了try/catch操作
            } catch (SecurityException var2) {
                var2.printStackTrace();
                return null;
            }
        }
    
        public void onCreate() {
            super.onCreate();
            if (VERSION.SDK_INT >= 26) {
                this.mJobImpl = new SafeJobServiceEngineImpl(this);
            } else {
                this.mJobImpl = null;
            }
        }
    }
    
    @RequiresApi(26)
    public class SafeJobServiceEngineImpl extends JobServiceEngine implements CompatJobEngine {
        static final String TAG = "JobServiceEngineImpl";
        static final boolean DEBUG = false;
        final JobIntentService mService;
        final Object mLock = new Object();
        JobParameters mParams;
    
        SafeJobServiceEngineImpl(JobIntentService service) {
            super(service);
            this.mService = service;
        }
    
        public IBinder compatGetBinder() {
            return this.getBinder();
        }
    
        public boolean onStartJob(JobParameters params) {
            this.mParams = params;
            this.mService.ensureProcessorRunningLocked(false);
            return true;
        }
    
        public boolean onStopJob(JobParameters params) {
            boolean result = this.mService.doStopCurrentWork();
            synchronized(this.mLock) {
                this.mParams = null;
                return result;
            }
        }
    
        public GenericWorkItem dequeueWork() {
            JobWorkItem work = null;
            synchronized(this.mLock) {
                if (this.mParams == null) {
                    return null;
                }
    
                try {
                    work = this.mParams.dequeueWork();
                } catch (SecurityException var5) {
                    var5.printStackTrace();
                }
            }
    
            if (work != null) {
                work.getIntent().setExtrasClassLoader(this.mService.getClassLoader());
                return new SafeJobServiceEngineImpl.WrapperWorkItem(work);
            } else {
                return null;
            }
        }
    
        final class WrapperWorkItem implements GenericWorkItem {
            final JobWorkItem mJobWork;
    
            WrapperWorkItem(JobWorkItem jobWork) {
                this.mJobWork = jobWork;
            }
    
            public Intent getIntent() {
                return this.mJobWork.getIntent();
            }
    
            public void complete() {
                synchronized(SafeJobServiceEngineImpl.this.mLock) {
                    if (SafeJobServiceEngineImpl.this.mParams != null) {
                        try {
                            SafeJobServiceEngineImpl.this.mParams.completeWork(this.mJobWork);
                        } catch (SecurityException  | IllegalArgumentException var4) {
                        // 2 这里我们也对completeWork进行了try/catch操作
                            var4.printStackTrace();
                        }
                    }
                }
            }
        }
    }
    
  • 上面的代码是在源码的基础上仅仅在12处做了Exception的处理,其余的地方没有变化,可以对比源码查看比较。

  • 如果你的项目中有的三方库中已经引入了这个SafeJobIntentService类,但是因为你使用不了它们的这个类,而你再引用比如implementation 'com.evernote:android-job:1.4.2'库的话,就会出现duplicate class found in the module, 如果出现这种问题,我们可以通过重新命名类的方式,按照上面的代码来做处理就好了。

  • 希望Google在未来的库中加入这个问题的解决办法。

JSON三种数据解析方法

你可能感兴趣的:(源码分析,ERROR)