深入源码分析 kotlin的CoroutineExceptionHandler机制

启动一个协程,然后内部启动子协程,那么最内层如果发生异常,是怎么传递异常的?

   val rootExceptionHandler = CoroutineExceptionHandler { _, throwable -> println("调用【根】协程异常处理器:${throwable.message}") }
        val parentExceptionHandler = CoroutineExceptionHandler { _, throwable -> println("调用【父】协程异常处理器:${throwable.message}") }
        val selfExceptionHandler = CoroutineExceptionHandler { _, throwable -> println("调用【自身】协程异常处理器:${throwable.message}") }
        val childExceptionHandler = CoroutineExceptionHandler { _, throwable -> println("调用【子】协程异常处理器:${throwable.message}") }

        //即child无效,有self用self,没有self用parent,没有parent用root,同时设置self、parent、root用最近的self
        CoroutineScope(Job()).launch(rootExceptionHandler) {
            launch(SupervisorJob()+parentExceptionHandler) {
                launch(SupervisorJob()+selfExceptionHandler) {
                    launch(childExceptionHandler) {
                        throw Exception("子协程使用的是SupervisorJob")
                    }
                }
            }
        }

反编译源码可得以下代码,看一下是怎么传递的

     int $i$f$CoroutineExceptionHandler = false;
      CoroutineExceptionHandler.Key var3 = CoroutineExceptionHandler.Key;
      CoroutineExceptionHandler rootExceptionHandler = (CoroutineExceptionHandler)(new MainActivity$testException$$inlined$CoroutineExceptionHandler$1(var3));
      int $i$f$CoroutineExceptionHandler = false;
      CoroutineExceptionHandler.Key var4 = CoroutineExceptionHandler.Key;
      final CoroutineExceptionHandler parentExceptionHandler = (CoroutineExceptionHandler)(new MainActivity$testException$$inlined$CoroutineExceptionHandler$2(var4));
      int $i$f$CoroutineExceptionHandler = false;
      CoroutineExceptionHandler.Key var5 = CoroutineExceptionHandler.Key;
      final CoroutineExceptionHandler selfExceptionHandler = (CoroutineExceptionHandler)(new MainActivity$testException$$inlined$CoroutineExceptionHandler$3(var5));
      int $i$f$CoroutineExceptionHandler = false;
      CoroutineExceptionHandler.Key var6 = CoroutineExceptionHandler.Key;
      final CoroutineExceptionHandler childExceptionHandler = (CoroutineExceptionHandler)(new MainActivity$testException$$inlined$CoroutineExceptionHandler$4(var6));
      BuildersKt.launch$default(CoroutineScopeKt.CoroutineScope((CoroutineContext)JobKt.Job$default((Job)null, 1, (Object)null)), (CoroutineContext)rootExceptionHandler, (CoroutineStart)null, (Function2)(new Function2((Continuation)null) {
         int label;
         // $FF: synthetic field
         private Object L$0;

         public final Object invokeSuspend(Object var1) {
            Object var3 = IntrinsicsKt.getCOROUTINE_SUSPENDED();
            switch (this.label) {
               case 0:
                  ResultKt.throwOnFailure(var1);
                  CoroutineScope $this$launch = (CoroutineScope)this.L$0;
                  BuildersKt.launch$default($this$launch, SupervisorKt.SupervisorJob$default((Job)null, 1, (Object)null).plus((CoroutineContext)parentExceptionHandler), (CoroutineStart)null, (Function2)(new Function2((Continuation)null) {
                     int label;
                     // $FF: synthetic field
                     private Object L$0;

                     public final Object invokeSuspend(Object var1) {
                        Object var3 = IntrinsicsKt.getCOROUTINE_SUSPENDED();
                        switch (this.label) {
                           case 0:
                              ResultKt.throwOnFailure(var1);
                              CoroutineScope $this$launch = (CoroutineScope)this.L$0;
                              BuildersKt.launch$default($this$launch, SupervisorKt.SupervisorJob$default((Job)null, 1, (Object)null).plus((CoroutineContext)selfExceptionHandler), (CoroutineStart)null, (Function2)(new Function2((Continuation)null) {
                                 int label;
                                 // $FF: synthetic field
                                 private Object L$0;

                                 public final Object invokeSuspend(Object var1) {
                                    Object var3 = IntrinsicsKt.getCOROUTINE_SUSPENDED();
                                    switch (this.label) {
                                       case 0:
                                          ResultKt.throwOnFailure(var1);
                                          CoroutineScope $this$launch = (CoroutineScope)this.L$0;
                                          BuildersKt.launch$default($this$launch, (CoroutineContext)childExceptionHandler, (CoroutineStart)null, (Function2)(new Function2((Continuation)null) {
                                             int label;

                                             public final Object invokeSuspend(Object var1) {
                                                Object var2 = IntrinsicsKt.getCOROUTINE_SUSPENDED();
                                                switch (this.label) {
                                                   case 0:
                                                      ResultKt.throwOnFailure(var1);
                                                      throw new Exception("子协程使用的是SupervisorJob");
                                                   default:
                                                      throw new IllegalStateException("call to 'resume' before 'invoke' with coroutine");
                                                }
                                             }

                                             public final Continuation create(Object value, Continuation $completion) {
                                                return (Continuation)(new ($completion));
                                             }

                                             public final Object invoke(CoroutineScope p1, Continuation p2) {
                                                return (()this.create(p1, p2)).invokeSuspend(Unit.INSTANCE);
                                             }

                                             // $FF: synthetic method
                                             // $FF: bridge method
                                             public Object invoke(Object p1, Object p2) {
                                                return this.invoke((CoroutineScope)p1, (Continuation)p2);
                                             }
                                          }), 2, (Object)null);
                                          return Unit.INSTANCE;
                                       default:
                                          throw new IllegalStateException("call to 'resume' before 'invoke' with coroutine");
                                    }
                                 }

                                 public final Continuation create(Object value, Continuation $completion) {
                                    Function2 var3 = new ($completion);
                                    var3.L$0 = value;
                                    return (Continuation)var3;
                                 }

                                 public final Object invoke(CoroutineScope p1, Continuation p2) {
                                    return (()this.create(p1, p2)).invokeSuspend(Unit.INSTANCE);
                                 }

                                 // $FF: synthetic method
                                 // $FF: bridge method
                                 public Object invoke(Object p1, Object p2) {
                                    return this.invoke((CoroutineScope)p1, (Continuation)p2);
                                 }
                              }), 2, (Object)null);
                              return Unit.INSTANCE;
                           default:
                              throw new IllegalStateException("call to 'resume' before 'invoke' with coroutine");
                        }
                     }

                     public final Continuation create(Object value, Continuation $completion) {
                        Function2 var3 = new ($completion);
                        var3.L$0 = value;
                        return (Continuation)var3;
                     }

                     public final Object invoke(CoroutineScope p1, Continuation p2) {
                        return (()this.create(p1, p2)).invokeSuspend(Unit.INSTANCE);
                     }

                     // $FF: synthetic method
                     // $FF: bridge method
                     public Object invoke(Object p1, Object p2) {
                        return this.invoke((CoroutineScope)p1, (Continuation)p2);
                     }
                  }), 2, (Object)null);
                  return Unit.INSTANCE;
               default:
                  throw new IllegalStateException("call to 'resume' before 'invoke' with coroutine");
            }
         }

         public final Continuation create(Object value, Continuation $completion) {
            Function2 var3 = new ($completion);
            var3.L$0 = value;
            return (Continuation)var3;
         }

         public final Object invoke(CoroutineScope p1, Continuation p2) {
            return (()this.create(p1, p2)).invokeSuspend(Unit.INSTANCE);
         }

         // $FF: synthetic method
         // $FF: bridge method
         public Object invoke(Object p1, Object p2) {
            return this.invoke((CoroutineScope)p1, (Continuation)p2);
         }
      }), 2, (Object)null);

一、创建带job的context过程

1、最外层是

BuildersKt.launch$default(CoroutineScopeKt.CoroutineScope((CoroutineContext)JobKt.Job$default((Job)null, 1, (Object)null)), (CoroutineContext)rootExceptionHandler, (CoroutineStart)null, (Function2)(new Function2((Continuation)null) {

}

2、CoroutineScopeKt.CoroutineScope 创建一个带job的作用域,源码如下,如果传递的context有job就使用,如果没有,则给这个context加一个Job()

public fun CoroutineScope(context: CoroutineContext): CoroutineScope =
    ContextScope(if (context[Job] != null) context else context + Job())

这里是传了一个创建新的job进去 JobKt.Job$default((Job)null, 1, (Object)null)

public static CompletableJob Job$default(Job var0, int var1, Object var2) {
   return JobKt__JobKt.Job$default(var0, var1, var2);
}

JobKt__JobKt.Job$default方法如下,传了参数 (null, 1,null)

public static CompletableJob Job$default(Job var0, int var1, Object var2) {
   if ((var1 & 1) != 0) {
      var0 = null;
   }

   return JobKt.Job(var0);
}

JobKt.Job方法如下,创建一个jobImpl实例,参数从上面可知是null,  也就是parent: Job? = null

public fun Job(parent: Job? = null): CompletableJob = JobImpl(parent)

我们来看一下JobImpl的实现,

internal open class JobImpl(parent: Job?) : JobSupport(true), CompletableJob {
    init { initParentJob(parent) }
    override val onCancelComplete get() = true
    /*
     * Check whether parent is able to handle exceptions as well.
     * With this check, an exception in that pattern will be handled once:
     * ```
     * launch {
     *     val child = Job(coroutineContext[Job])
     *     launch(child) { throw ... }
     * }
     * ```
     */
    override val handlesException: Boolean = handlesException()
    override fun complete() = makeCompleting(Unit)
    override fun completeExceptionally(exception: Throwable): Boolean =
        makeCompleting(CompletedExceptionally(exception))

    @JsName("handlesExceptionF")
    private fun handlesException(): Boolean {
        var parentJob = (parentHandle as? ChildHandleNode)?.job ?: return false
        while (true) {
            if (parentJob.handlesException) return true
            parentJob = (parentJob.parentHandle as? ChildHandleNode)?.job ?: return false
        }
    }
}

有个关键方法handlesException(): Boolean 表示是否处理异常的判断,这里代码逻辑就是把

parentHandle转成ChildHandleNode,取出job。

1、如果job为空,则返回false,不处理

2、如果递归向上查找job,找出job不为空,且handlesException消费了异常,则直接返回true

ChildHandleNode是什么玩意?看看,就是子job,保存了parent父节点的job

internal class ChildHandleNode(
    @JvmField val childJob: ChildJob
) : JobCancellingNode(), ChildHandle {
    override val parent: Job get() = job
    override fun invoke(cause: Throwable?) = childJob.parentCancelled(job)
    override fun childCancelled(cause: Throwable): Boolean = job.childCancelled(cause)
}

另外我们看看JobImpl的父类JobSupport,这个是Job的关键实现,大部分实现都在这个类,实现对job状态的管理。

JobSupport constructor(active: Boolean) : Job, ChildJob, ParentJob {

继承了job,是有job的生命周期方法,也是个CoroutineContext.Element,可以累加到context里

public interface Job : CoroutineContext.Element 

继承了ChildJob,多了方法,父亲取消的调用方法

public interface ChildJob : Job {
    /**
     * Parent is cancelling its child by invoking this method.
     * Child finds the cancellation cause using [ParentJob.getChildJobCancellationCause].
     * This method does nothing is the child is already being cancelled.
     *
     * @suppress **This is unstable API and it is subject to change.**
     */
    @InternalCoroutinesApi
    public fun parentCancelled(parentJob: ParentJob)
}

继承了ParentJob,getChildJobCancellationCause获取子job取消的异常。

public interface ParentJob : Job {
    /**
     * Child job is using this method to learn its cancellation cause when the parent cancels it with [ChildJob.parentCancelled].
     * This method is invoked only if the child was not already being cancelled.
     *
     * Note that [CancellationException] is the method's return type: if child is cancelled by its parent,
     * then the original exception is **already** handled by either the parent or the original source of failure.
     *
     * @suppress **This is unstable API and it is subject to change.**
     */
    @InternalCoroutinesApi
    public fun getChildJobCancellationCause(): CancellationException
}

二、执行协程时的异常分发过程

可以看我之前写的一个协程的启动源码过程 kotlin启动协程源码分析_kotlin 协程源码-CSDN博客

2.1   关键分发协程执行方法 DispatchedTask的run方法

分析代码可知,如果没有被cancel并且context的job也是active状态,其实也是协程的continuation的实现resumeWith方法,会真正执行

continuation.resumeWith(Result.constructor-impl(this.getSuccessfulResult$kotlinx_coroutines_core(state)));

2.2 然后执行的真正的resumeWith方法

取出代理的continuation去执行恢复执行,最后是执行基类的 BaseContinuationImpl.resumeWith

 public final void resumeWith(@NotNull Object result) {
      Object current = null;
      current = this;
      Object param = null;
      param = result;
 
      while(true) {
         DebugProbesKt.probeCoroutineResumed((Continuation)current);
         BaseContinuationImpl $this$resumeWith_u24lambda_u240 = (BaseContinuationImpl)current;
         int var6 = false;
         Continuation var10000 = $this$resumeWith_u24lambda_u240.completion;
         Intrinsics.checkNotNull(var10000);
         Continuation completion = var10000;
 
         Object outcome;
         Result.Companion var12;
         try {
            outcome = $this$resumeWith_u24lambda_u240.invokeSuspend(param);
            if (outcome == IntrinsicsKt.getCOROUTINE_SUSPENDED()) {
               return;
            }
 
            var12 = Result.Companion;
            outcome = Result.constructor-impl(outcome);
         } catch (Throwable var11) {
            var12 = Result.Companion;
            outcome = Result.constructor-impl(ResultKt.createFailure(var11));
         }
 
         $this$resumeWith_u24lambda_u240.releaseIntercepted();
         if (!(completion instanceof BaseContinuationImpl)) {
            completion.resumeWith(outcome);
            return;
         }
 
         current = completion;
         param = outcome;
      }
   }

可以看到如果协程执行方法invokeSuspend如果发生了异常,则会catch住,分发一个异常返回

  outcome = Result.constructor-impl(ResultKt.createFailure(var11));

     if (!(completion instanceof BaseContinuationImpl)) {
            completion.resumeWith(outcome);
            return;
         }

这个completion是谁呢?是在哪里传递进来的???????

从我这之前的文章可以知道   kotlin启动协程源码分析_kotlin 协程源码-CSDN博客

在这协程启动的时候

BuildersKt__Builders_commonKt.launch这个方法

  @NotNull
   public static final Job launch(@NotNull CoroutineScope $this$launch, @NotNull CoroutineContext context, @NotNull CoroutineStart start, @NotNull Function2 block) {
      CoroutineContext newContext = CoroutineContextKt.newCoroutineContext($this$launch, context);
      StandaloneCoroutine coroutine = start.isLazy() ? (StandaloneCoroutine)(new LazyStandaloneCoroutine(newContext, block)) : new StandaloneCoroutine(newContext, true);
      coroutine.start(start, coroutine, block);
      return (Job)coroutine;
   }

这里一般分支是执行 StandaloneCoroutine,函数关键,把context和父context叠加

public final override val context: CoroutineContext = parentContext + this

调用start方法实现
public final void start(@NotNull CoroutineStart start, Object receiver, @NotNull Function2 block) {
   start.invoke(block, receiver, (Continuation)this);
}

继续深入CoroutineStart.invoke方法可以知道是这个completion就是新创建的StandaloneCoroutine

   @InternalCoroutinesApi
   public final void invoke(@NotNull Function1 block, @NotNull Continuation completion) {
      switch (CoroutineStart.WhenMappings.$EnumSwitchMapping$0[this.ordinal()]) {
         case 1:
            CancellableKt.startCoroutineCancellable(block, completion);
            break;
         case 2:
            ContinuationKt.startCoroutine(block, completion);
            break;
         case 3:
            UndispatchedKt.startCoroutineUndispatched(block, completion);
         case 4:
            break;
         default:
            throw new NoWhenBranchMatchedException();
      }

   }

这里内部是执行分支1,CancellableKt.startCoroutineCancellable,其实内部就是把compleition传进去创建拦截分发器包住嵌套的function,最终把completion传到最底层的Continuation作为参数创建协程continuation

我们来看看这个StandaloneCoroutine也是一个Continuation实现类,看一下他的类继承关系

private open class StandaloneCoroutine(
    parentContext: CoroutineContext,
    active: Boolean
) : AbstractCoroutine(parentContext, initParentJob = true, active = active) {
    override fun handleJobException(exception: Throwable): Boolean {
        handleCoroutineException(context, exception)
        return true
    }
}

继承了AbstractCoroutine抽象类,resumWith方法实现,先调用JobSupport的一个方法makeCompletingOnce,把job的状态标记结束,并处理异常

  public final override fun resumeWith(result: Result) {
        val state = makeCompletingOnce(result.toState())
        if (state === COMPLETING_WAITING_CHILDREN) return
        afterResume(state)
    }

    protected open fun afterResume(state: Any?): Unit = afterCompletion(state)

    internal final override fun handleOnCompletionException(exception: Throwable) {
        handleCoroutineException(context, exception)
    }

把结果转成state进行处理,这里是Result是失败的,那就是个CompletedExceptionally,包住了异常onFailure = { CompletedExceptionally(it) }

internal fun  Result.toState(
    onCancellation: ((cause: Throwable) -> Unit)? = null
): Any? = fold(
    onSuccess = { if (onCancellation != null) CompletedWithCancellation(it, onCancellation) else it },
    onFailure = { CompletedExceptionally(it) }
)

调用jobSupport的内联方法,makeCompletingOnce(proposedUpdate: Any?),参数proposedUpdate上面封装好的CompletedExceptionally

   @Nullable
   public final Object makeCompletingOnce$kotlinx_coroutines_core(@Nullable Object proposedUpdate) {
      JobSupport this_$iv = this;
      int $i$f$loopOnState = false;

      Object finalState;
      do {
         Object state = this_$iv.getState$kotlinx_coroutines_core();
         int var5 = false;
         finalState = this.tryMakeCompleting(state, proposedUpdate);
         if (finalState == JobSupportKt.access$getCOMPLETING_ALREADY$p()) {
            throw new IllegalStateException("Job " + this + " is already complete or completing, but is being completed with " + proposedUpdate, this.getExceptionOrNull(proposedUpdate));
         }
      } while(finalState == JobSupportKt.access$getCOMPLETING_RETRY$p());

      return finalState;
   }

再执行下面的方法tryMakeCompleting,这里判断可知执行的是分支

 this.tryMakeCompletingSlowPath((Incomplete)state, proposedUpdate);
  private final Object tryMakeCompleting(Object state, Object proposedUpdate) {
      if (!(state instanceof Incomplete)) {
         return JobSupportKt.access$getCOMPLETING_ALREADY$p();
      } else if ((state instanceof Empty || state instanceof JobNode) && !(state instanceof ChildHandleNode) && !(proposedUpdate instanceof CompletedExceptionally)) {
         return this.tryFinalizeSimpleState((Incomplete)state, proposedUpdate) ? proposedUpdate : JobSupportKt.access$getCOMPLETING_RETRY$p();
      } else {
         return this.tryMakeCompletingSlowPath((Incomplete)state, proposedUpdate);
      }
   }

我们看看这个方法tryMakeCompletingSlowPath内部实现

 private fun tryMakeCompletingSlowPath(state: Incomplete, proposedUpdate: Any?): Any? {
        // get state's list or else promote to list to correctly operate on child lists
        val list = getOrPromoteCancellingList(state) ?: return COMPLETING_RETRY
        // promote to Finishing state if we are not in it yet
        // This promotion has to be atomic w.r.t to state change, so that a coroutine that is not active yet
        // atomically transition to finishing & completing state
        val finishing = state as? Finishing ?: Finishing(list, false, null)
        // must synchronize updates to finishing state
        var notifyRootCause: Throwable? = null
        synchronized(finishing) {
            // check if this state is already completing
            if (finishing.isCompleting) return COMPLETING_ALREADY
            // mark as completing
            finishing.isCompleting = true
            // if we need to promote to finishing then atomically do it here.
            // We do it as early is possible while still holding the lock. This ensures that we cancelImpl asap
            // (if somebody else is faster) and we synchronize all the threads on this finishing lock asap.
            if (finishing !== state) {
                if (!_state.compareAndSet(state, finishing)) return COMPLETING_RETRY
            }
            // ## IMPORTANT INVARIANT: Only one thread (that had set isCompleting) can go past this point
            assert { !finishing.isSealed } // cannot be sealed
            // add new proposed exception to the finishing state
            val wasCancelling = finishing.isCancelling
            (proposedUpdate as? CompletedExceptionally)?.let { finishing.addExceptionLocked(it.cause) }
            // If it just becomes cancelling --> must process cancelling notifications
            notifyRootCause = finishing.rootCause.takeIf { !wasCancelling }
        }
        // process cancelling notification here -- it cancels all the children _before_ we start to to wait them (sic!!!)
        notifyRootCause?.let { notifyCancelling(list, it) }
        // now wait for children
        val child = firstChild(state)
        if (child != null && tryWaitForChild(finishing, child, proposedUpdate))
            return COMPLETING_WAITING_CHILDREN
        // otherwise -- we have not children left (all were already cancelled?)
        return finalizeFinishingState(finishing, proposedUpdate)
    }

修改job状态为isCompleting = true,通知取消,这里处理job的子job的取消逻辑,通知相关的子节点取消执行。

notifyRootCause?.let { notifyCancelling(list, it) }
  private fun notifyCancelling(list: NodeList, cause: Throwable) {
        // first cancel our own children
        onCancelling(cause)
        notifyHandlers(list, cause)
        // then cancel parent
        cancelParent(cause) // tentative cancellation -- does not matter if there is no parent
    }

通知handler,也就是各个节点取消异常。

  private inline fun  notifyHandlers(list: NodeList, cause: Throwable?) {
        var exception: Throwable? = null
        list.forEach { node ->
            try {
                node.invoke(cause)
            } catch (ex: Throwable) {
                exception?.apply { addSuppressedThrowable(ex) } ?: run {
                    exception =  CompletionHandlerException("Exception in completion handler $node for $this", ex)
                }
            }
        }
        exception?.let { handleOnCompletionException(it) }
    }

在等待所有子节点取消完成后,我们再看tryMakeCompletingSlowPath里面的的最后一个方法调用

  val child = firstChild(state)
        if (child != null && tryWaitForChild(finishing, child, proposedUpdate))
            return COMPLETING_WAITING_CHILDREN
        // otherwise -- we have not children left (all were already cancelled?)
        return finalizeFinishingState(finishing, proposedUpdate)
 private fun finalizeFinishingState(state: Finishing, proposedUpdate: Any?): Any? {
        /*
         * Note: proposed state can be Incomplete, e.g.
         * async {
         *     something.invokeOnCompletion {} // <- returns handle which implements Incomplete under the hood
         * }
         */
        assert { this.state === state } // consistency check -- it cannot change
        assert { !state.isSealed } // consistency check -- cannot be sealed yet
        assert { state.isCompleting } // consistency check -- must be marked as completing
        val proposedException = (proposedUpdate as? CompletedExceptionally)?.cause
        // Create the final exception and seal the state so that no more exceptions can be added
        val wasCancelling: Boolean
        val finalException = synchronized(state) {
            wasCancelling = state.isCancelling
            val exceptions = state.sealLocked(proposedException)
            val finalCause = getFinalRootCause(state, exceptions)
            if (finalCause != null) addSuppressedExceptions(finalCause, exceptions)
            finalCause
        }
        // Create the final state object
        val finalState = when {
            // was not cancelled (no exception) -> use proposed update value
            finalException == null -> proposedUpdate
            // small optimization when we can used proposeUpdate object as is on cancellation
            finalException === proposedException -> proposedUpdate
            // cancelled job final state
            else -> CompletedExceptionally(finalException)
        }
        // Now handle the final exception
        if (finalException != null) {
            val handled = cancelParent(finalException) || handleJobException(finalException)
            if (handled) (finalState as CompletedExceptionally).makeHandled()
        }
        // Process state updates for the final state before the state of the Job is actually set to the final state
        // to avoid races where outside observer may see the job in the final state, yet exception is not handled yet.
        if (!wasCancelling) onCancelling(finalException)
        onCompletionInternal(finalState)
        // Then CAS to completed state -> it must succeed
        val casSuccess = _state.compareAndSet(state, finalState.boxIncomplete())
        assert { casSuccess }
        // And process all post-completion actions
        completeStateFinalization(state, finalState)
        return finalState
    }

关键方法

if (finalException != null) {
    val handled = cancelParent(finalException) || handleJobException(finalException)
    if (handled) (finalState as CompletedExceptionally).makeHandled()
}

这里会先调用取消父亲的cancelParent,如果父亲处理了,则不会用当前context处理 handleJobException了

    private fun cancelParent(cause: Throwable): Boolean {
        // Is scoped coroutine -- don't propagate, will be rethrown
        if (isScopedCoroutine) return true

        /* CancellationException is considered "normal" and parent usually is not cancelled when child produces it.
         * This allow parent to cancel its children (normally) without being cancelled itself, unless
         * child crashes and produce some other exception during its completion.
         */
        val isCancellation = cause is CancellationException
        val parent = parentHandle
        // No parent -- ignore CE, report other exceptions.
        if (parent === null || parent === NonDisposableHandle) {
            return isCancellation
        }

        // Notify parent but don't forget to check cancellation
        return parent.childCancelled(cause) || isCancellation
    }
我们来看看parent.childCancelled(cause)实现

internal class ChildHandleNode(
    @JvmField val childJob: ChildJob
) : JobCancellingNode(), ChildHandle {
    override val parent: Job get() = job
    override fun invoke(cause: Throwable?) = childJob.parentCancelled(job)
    override fun childCancelled(cause: Throwable): Boolean = job.childCancelled(cause)
}

对应job实现

   public open fun childCancelled(cause: Throwable): Boolean {
        if (cause is CancellationException) return true
        return cancelImpl(cause) && handlesException
    }
return cancelImpl(cause) && handlesException,这里调用到cancelImpl
 internal fun cancelImpl(cause: Any?): Boolean {
        var finalState: Any? = COMPLETING_ALREADY
        if (onCancelComplete) {
            // make sure it is completing, if cancelMakeCompleting returns state it means it had make it
            // completing and had recorded exception
            finalState = cancelMakeCompleting(cause)
            if (finalState === COMPLETING_WAITING_CHILDREN) return true
        }
        if (finalState === COMPLETING_ALREADY) {
            finalState = makeCancelling(cause)
        }
        return when {
            finalState === COMPLETING_ALREADY -> true
            finalState === COMPLETING_WAITING_CHILDREN -> true
            finalState === TOO_LATE_TO_CANCEL -> false
            else -> {
                afterCompletion(finalState)
                true
            }
        }
    }

又调到相同的方法 cancelMakeCompleting(cause),层层往上传递。

这个调用逻辑可以知道,有点像java的双亲类加载机制,先询问父亲,一直到最顶部处理。如果最顶部没有处理器,则顶部context 也就是StandaloneCoroutine处理handleJobException。

class StandaloneCoroutine extends AbstractCoroutine {
   public StandaloneCoroutine(@NotNull CoroutineContext parentContext, boolean active) {
      super(parentContext, true, active);
   }

   protected boolean handleJobException(@NotNull Throwable exception) {
      CoroutineExceptionHandlerKt.handleCoroutineException(this.getContext(), exception);
      return true;
   }
}

这里会有点坑,子协程如果设置了捕获器,会无效,源码分析显示,只会调用到顶部context处理。如果不想只让顶部context处理,只让当前处理,则需要另外一个名字叫监督者,SupervisorJob,重写子chileCancelled方法实现,返回了false

看看一下源码

private class SupervisorJobImpl(parent: Job?) : JobImpl(parent) {
    override fun childCancelled(cause: Throwable): Boolean = false
}

结合之前的代码

if (finalException != null) {

val handled = cancelParent(finalException) || handleJobException(finalException)

if (handled) (finalState as CompletedExceptionally).makeHandled()

}


    private fun cancelParent(cause: Throwable): Boolean {
         .......

        // Notify parent but don't forget to check cancellation
        return parent.childCancelled(cause) || isCancellation
    }

结合分析可知SupervisorJob就是让这里的cancelParent直接写死返回了false,那么cancelParent(finalException)就是false,就会执行到或语句后面的||handleJobException(finalException),也就是当前context的捕获器进行处理了

最后我们来看看handleCoroutineException是如何抛出异常的

public fun handleCoroutineException(context: CoroutineContext, exception: Throwable) {
    // Invoke an exception handler from the context if present
    try {
        context[CoroutineExceptionHandler]?.let {
            it.handleException(context, exception)
            return
        }
    } catch (t: Throwable) {
        handleUncaughtCoroutineException(context, handlerException(exception, t))
        return
    }
    // If a handler is not present in the context or an exception was thrown, fallback to the global handler
    handleUncaughtCoroutineException(context, exception)
}

如果有捕获器,则 it.handleException(context, exception) return 

如果没有捕获器,则会执行到 

handleUncaughtCoroutineException(context, exception)
internal fun handleUncaughtCoroutineException(context: CoroutineContext, exception: Throwable) {
    // use additional extension handlers
    for (handler in platformExceptionHandlers) {
        try {
            handler.handleException(context, exception)
        } catch (_: ExceptionSuccessfullyProcessed) {
            return
        } catch (t: Throwable) {
            propagateExceptionFinalResort(handlerException(exception, t))
        }
    }

    try {
        exception.addSuppressed(DiagnosticCoroutineContextException(context))
    } catch (e: Throwable) {
        // addSuppressed is never user-defined and cannot normally throw with the only exception being OOM
        // we do ignore that just in case to definitely deliver the exception
    }
    propagateExceptionFinalResort(exception)
}

最终交给当前线程的捕获器去处理,如果没有设置,其实也就是崩溃crash就发生了

internal actual fun propagateExceptionFinalResort(exception: Throwable) {
    // use the thread's handler
    val currentThread = Thread.currentThread()
    currentThread.uncaughtExceptionHandler.uncaughtException(currentThread, exception)
}

你可能感兴趣的:(kotlin,android)