分屏启动

62 阅读3分钟
---- launcher端 ----
07-30 16:17:27.140  1333  1333 D xmsysui : startTasks
07-30 16:17:27.140  1333  1333 D xmsysui : java.lang.Exception
07-30 16:17:27.140  1333  1333 D xmsysui : 	at com.android.quickstep.SystemUiProxy.startTasks(SystemUiProxy.java:1012)
07-30 16:17:27.140  1333  1333 D xmsysui : 	at com.android.quickstep.util.SplitSelectStateController.launchTasks(SplitSelectStateController.java:462)
07-30 16:17:27.140  1333  1333 D xmsysui : 	at com.android.quickstep.util.SplitSelectStateController.launchSplitTasks(SplitSelectStateController.java:351)
07-30 16:17:27.140  1333  1333 D xmsysui : 	at com.android.quickstep.util.SplitSelectStateController.launchSplitTasks(SplitSelectStateController.java:371)
07-30 16:17:27.140  1333  1333 D xmsysui : 	at com.android.quickstep.views.RecentsView.lambda$confirmSplitSelect$45(RecentsView.java:5348)
07-30 16:17:27.140  1333  1333 D xmsysui : 	at com.android.quickstep.views.RecentsView.$r8$lambda$Z4VyoYJdEinFf5QssVYcQ-J5348(RecentsView.java:0)
07-30 16:17:27.140  1333  1333 D xmsysui : 	at com.android.quickstep.views.RecentsView$$ExternalSyntheticLambda8.accept(R8$$SyntheticClass:0)
07-30 16:17:27.140  1333  1333 D xmsysui : 	at com.android.launcher3.anim.AnimatorListeners$EndStateCallbackWrapper.onAnimationEnd(AnimatorListeners.java:80)
07-30 16:17:27.140  1333  1333 D xmsysui : 	at android.animation.Animator$AnimatorListener.onAnimationEnd(Animator.java:755)
07-30 16:17:27.140  1333  1333 D xmsysui : 	at android.animation.Animator$AnimatorCaller$$ExternalSyntheticLambda1.call(D8$$SyntheticClass:0)
07-30 16:17:27.140  1333  1333 D xmsysui : 	at android.animation.Animator.callOnList(Animator.java:713)
07-30 16:17:27.140  1333  1333 D xmsysui : 	at android.animation.Animator.notifyListeners(Animator.java:634)
07-30 16:17:27.140  1333  1333 D xmsysui : 	at android.animation.Animator.notifyEndListeners(Animator.java:659)
07-30 16:17:27.140  1333  1333 D xmsysui : 	at android.animation.Animator.completeEndAnimation(Animator.java:679)
07-30 16:17:27.140  1333  1333 D xmsysui : 	at android.animation.ValueAnimator.completeEndAnimation(ValueAnimator.java:1321)
07-30 16:17:27.140  1333  1333 D xmsysui : 	at android.animation.Animator.notifyEndListenersFromEndAnimation(Animator.java:668)
07-30 16:17:27.140  1333  1333 D xmsysui : 	at android.animation.ValueAnimator.endAnimation(ValueAnimator.java:1312)
07-30 16:17:27.140  1333  1333 D xmsysui : 	at android.animation.ValueAnimator.doAnimationFrame(ValueAnimator.java:1577)
07-30 16:17:27.140  1333  1333 D xmsysui : 	at android.animation.ValueAnimator.pulseAnimationFrame(ValueAnimator.java:1593)
07-30 16:17:27.140  1333  1333 D xmsysui : 	at android.animation.AnimatorSet.pulseFrame(AnimatorSet.java:1314)
07-30 16:17:27.140  1333  1333 D xmsysui : 	at android.animation.AnimatorSet.handleAnimationEvents(AnimatorSet.java:1297)
07-30 16:17:27.140  1333  1333 D xmsysui : 	at android.animation.AnimatorSet.doAnimationFrame(AnimatorSet.java:1197)
07-30 16:17:27.140  1333  1333 D xmsysui : 	at android.animation.AnimationHandler.doAnimationFrame(AnimationHandler.java:396)
07-30 16:17:27.140  1333  1333 D xmsysui : 	at android.animation.AnimationHandler.-$$Nest$mdoAnimationFrame(Unknown Source:0)
07-30 16:17:27.140  1333  1333 D xmsysui : 	at android.animation.AnimationHandler$1.doFrame(AnimationHandler.java:106)
07-30 16:17:27.140  1333  1333 D xmsysui : 	at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1564)
07-30 16:17:27.140  1333  1333 D xmsysui : 	at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1575)
07-30 16:17:27.140  1333  1333 D xmsysui : 	at android.view.Choreographer.doCallbacks(Choreographer.java:1175)
07-30 16:17:27.140  1333  1333 D xmsysui : 	at android.view.Choreographer.doFrame(Choreographer.java:1100)
07-30 16:17:27.140  1333  1333 D xmsysui : 	at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1549)
07-30 16:17:27.140  1333  1333 D xmsysui : 	at android.os.Handler.handleCallback(Handler.java:991)
07-30 16:17:27.140  1333  1333 D xmsysui : 	at android.os.Handler.dispatchMessage(Handler.java:102)
07-30 16:17:27.140  1333  1333 D xmsysui : 	at android.os.Looper.loopOnce(Looper.java:232)
07-30 16:17:27.140  1333  1333 D xmsysui : 	at android.os.Looper.loop(Looper.java:317)
07-30 16:17:27.140  1333  1333 D xmsysui : 	at android.app.ActivityThread.main(ActivityThread.java:8934)
07-30 16:17:27.140  1333  1333 D xmsysui : 	at java.lang.reflect.Method.invoke(Native Method)
07-30 16:17:27.140  1333  1333 D xmsysui : 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:591)
07-30 16:17:27.140  1333  1333 D xmsysui : 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:911)


---- systemui端 ------
07-30 16:17:27.142   977  1522 D xmsysui : startTasks 1251
07-30 16:17:27.142   977  1522 D xmsysui : java.lang.Exception
07-30 16:17:27.142   977  1522 D xmsysui : 	at com.android.wm.shell.splitscreen.SplitScreenController$ISplitScreenImpl.startTasks(SplitScreenController.java:1251)
07-30 16:17:27.142   977  1522 D xmsysui : 	at com.android.wm.shell.splitscreen.ISplitScreen$Stub.onTransact(ISplitScreen.java:235)
07-30 16:17:27.142   977  1522 D xmsysui : 	at android.os.Binder.execTransactInternal(Binder.java:1411)
07-30 16:17:27.142   977  1522 D xmsysui : 	at android.os.Binder.execTransact(Binder.java:1350)

这里面涉及launcher3和systemui两个进程。

launcher3端流程

public void startTasks(int taskId1, Bundle options1, int taskId2, Bundle options2,
        @StagePosition int splitPosition, @PersistentSnapPosition int snapPosition,
        RemoteTransition remoteTransition, InstanceId instanceId) {
    if (mSystemUiProxy != null) {
        try {
            //调用aidl方法
            mSplitScreen.startTasks(taskId1, options1, taskId2, options2, splitPosition,
                    snapPosition, remoteTransition, instanceId);
        } catch (RemoteException e) {
            Log.w(TAG, splitFailureMessage("startTasks", "RemoteException"), e);
        }
    }
}

调用mSplitScreen的aidl方法,这个binder对象是哪里赋值的?源码查找发现是在launcher3里面packages/apps/Launcher3/quickstep/src/com/android/quickstep/TouchInteractionService.java中赋值的。

@BinderThread
public void onInitialize(Bundle bundle) {
    ISystemUiProxy proxy = ISystemUiProxy.Stub.asInterface(
            bundle.getBinder(ISystemUiProxy.DESCRIPTOR));
            // 这个看上去像是app右上角的数量角标
    IBubbles bubbles = IBubbles.Stub.asInterface(bundle.getBinder(IBubbles.DESCRIPTOR));
    // 这个就是分屏的binder
    ISplitScreen splitscreen = ISplitScreen.Stub.asInterface(bundle.getBinder(
            ISplitScreen.DESCRIPTOR));
    
    MAIN_EXECUTOR.execute(() -> executeForTouchInteractionService(tis -> {
    // 赋值给SystemUiProxy
        SystemUiProxy.INSTANCE.get(tis).setProxy(proxy, pip,
                bubbles, splitscreen, onehanded, shellTransitions, startingWindow,
                recentTasks, launcherUnlockAnimationController, backAnimation, desktopMode,
                unfoldTransition, dragAndDrop);
        tis.initInputMonitor("TISBinder#onInitialize()");
        tis.preloadOverview(true /* fromInit */);
    }));
    sIsInitialized = true;
}

那onInitialize是哪里调用的? 是在systemui里面绑定这个service并传递binder对象给launcher,launcher后面就可以跨进程通信了。

systemui端流程

packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
private void maybeBindService() {
    try {
        // 绑定service mQuickStepIntent = new Intent("android.intent.action.QUICKSTEP_SERVICE")
        mBound = mContext.bindServiceAsUser(mQuickStepIntent,
                mOverviewServiceConnection,
                Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
                currentUser);
    } catch (SecurityException e) {
        Log.e(TAG_OPS, "Unable to bind because of security error", e);
    }
    if (mBound) {
        mIsPrevServiceCleanedUp = false;
        // Ensure that connection has been established even if it thinks it is bound
        mHandler.postDelayed(mDeferredConnectionCallback, DEFERRED_CALLBACK_MILLIS);
    } else {
        // Retry after exponential backoff timeout
        retryConnectionWithBackoff();
    }
}

绑定的service的action是"android.intent.action.QUICKSTEP_SERVICE",源码查找一下是在launcher3里面manifest

packages/apps/Launcher3/quickstep/AndroidManifest.xml
<service android:name="com.android.quickstep.TouchInteractionService"
     android:permission="android.permission.STATUS_BAR_SERVICE"
     android:directBootAware="true"
     android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.QUICKSTEP_SERVICE"/>
    </intent-filter>
</service>

bindServiceAsUser传的connection对象

private final ServiceConnection mOverviewServiceConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        
        mCurrentBoundedUserId = mUserTracker.getUserId();
        mOverviewProxy = IOverviewProxy.Stub.asInterface(service);
        // new了一个bundle对象,用于添加binder对象返回给launcher端的service
        Bundle params = new Bundle();
        addInterface(mSysUiProxy, params);
        addInterface(mSysuiUnlockAnimationController, params);
        addInterface(mUnfoldTransitionProgressForwarder.orElse(null), params);
        // Add all the interfaces exposed by the shell
        // 这里面添加ISplitScreen.Stub对象
        mShellInterface.createExternalInterfaces(params);

        try {
            // 调用launcher端service的onInitialize,解了上面的疑问
            mOverviewProxy.onInitialize(params);
        } catch (RemoteException e) {
            mCurrentBoundedUserId = -1;
            Log.e(TAG_OPS, "Failed to call onInitialize()", e);
        }
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
        Log.w(TAG_OPS, "Service disconnected");
        // Do nothing
        mCurrentBoundedUserId = -1;
    }
};

连接到launcher端的service后,调用service的onInitialize方法,并传了很多的binder对象过去,用于后面的跨进程通信,这里面就包含了ISplitScreen对象