Detailed source code analysis of TaskView of android framework car desktop CarLauncher

1. Build the relevant TaskView and load it into the corresponding ViewGroup

Free video tutorial explanation at station b:
https://www.bilibili.com/video/BV1wj411o7A9/
insert image description here

//packages/apps/Car/Launcher/src/com/android/car/carlauncher/CarLauncher.java
void onCreate() {
    
    
//ignore
 setContentView(R.layout.car_launcher);
            // We don't want to show Map card unnecessarily for the headless user 0.
            if (!UserHelperLite.isHeadlessSystemUser(getUserId())) {
    
    
                ViewGroup mapsCard = findViewById(R.id.maps_card);
                if (mapsCard != null) {
    
    
                //这里获取了mapsCard后,接下来就是构造出对应的TaskView
                    setUpTaskView(mapsCard);
                }
            }
            //ignore
            }
            //进行TaskView相关的设置
  private void setUpTaskView(ViewGroup parent) {
    
    
        //把TaskViewManager进行构造
        mTaskViewManager = new TaskViewManager(this,
                new HandlerExecutor(getMainThreadHandler()), mCarActivityManagerRef);
                //创建对应的TaskView
        mTaskViewManager.createTaskView(taskView -> {
    
    
            taskView.setListener(getMainExecutor(), mTaskViewListener);
            //把TaskView添加到了mapsCard
            parent.addView(taskView);
            mTaskView = taskView;
        });
    }
    //packages/apps/Car/Launcher/src/com/android/car/carlauncher/TaskViewManager.java
        public TaskViewManager(@UiContext Context context, HandlerExecutor handlerExecutor,
            AtomicReference<CarActivityManager> carActivityManagerRef) {
    
    
        mContext = context;
        mExecutor = handlerExecutor;
        //构造对应的ShellTaskOrganizer
        mTaskOrganizer = new ShellTaskOrganizer(mExecutor, mContext);
     
        //把TaskOrganizer进行对应的注册
        initTaskOrganizer(carActivityManagerRef, transactionPool);
    }
    //构造出TaskView
   void createTaskView(Consumer<TaskView> onCreate) {
    
    
        CarTaskView taskView = new CarTaskView(mContext, mTaskOrganizer, mSyncQueue);
        mExecutor.execute(() -> {
    
    
            onCreate.accept(taskView);
        });
    }

Summary:
1. Build the corresponding TaskViewManager, mainly to register and initialize TaskOrganizer
2. Create the related TaskView, namely SurfaceView, and place it in the ViewGroup of CarLauncher

The timing diagram is as follows:
insert image description here

2. The startup of related activities

Start the Activity related stack

07-26 17:25:48.075  1584  1584 I lsm3333 : TaskView startActivity
07-26 17:25:48.075  1584  1584 I lsm3333 : java.lang.Exception
07-26 17:25:48.075  1584  1584 I lsm3333 : 	at com.android.wm.shell.TaskView.startActivity(TaskView.java:179)
07-26 17:25:48.075  1584  1584 I lsm3333 : 	at com.android.car.carlauncher.CarLauncher.startMapsInTaskView(CarLauncher.java:373)
07-26 17:25:48.075  1584  1584 I lsm3333 : 	at com.android.car.carlauncher.CarLauncher.-$$Nest$mstartMapsInTaskView(Unknown Source:0)
07-26 17:25:48.075  1584  1584 I lsm3333 : 	at com.android.car.carlauncher.CarLauncher$1.onInitialized(CarLauncher.java:108)
07-26 17:25:48.075  1584  1584 I lsm3333 : 	at com.android.wm.shell.TaskView.lambda$surfaceCreated$11$com-android-wm-shell-TaskView(TaskView.java:416)
07-26 17:25:48.075  1584  1584 I lsm3333 : 	at com.android.wm.shell.TaskView$$ExternalSyntheticLambda11.run(Unknown Source:2)
07-26 17:25:48.075  1584  1584 I lsm3333 : 	at android.os.Handler.handleCallback(Handler.java:942)
07-26 17:25:48.075  1584  1584 I lsm3333 : 	at android.os.Handler.dispatchMessage(Handler.java:99)
07-26 17:25:48.075  1584  1584 I lsm3333 : 	at android.os.Looper.loopOnce(Looper.java:201)
07-26 17:25:48.075  1584  1584 I lsm3333 : 	at android.os.Looper.loop(Looper.java:288)
07-26 17:25:48.075  1584  1584 I lsm3333 : 	at android.app.ActivityThread.main(ActivityThread.java:7898)
07-26 17:25:48.075  1584  1584 I lsm3333 : 	at java.lang.reflect.Method.invoke(Native Method)
07-26 17:25:48.075  1584  1584 I lsm3333 : 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
07-26 17:25:48.075  1584  1584 I lsm3333 : 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)


The main code flow steps are as follows:
TaskView.onInitialized -->CarLauncher.startMapsInTaskView -->
TaskView.startActivity -->TaskView.prepareActivityOptions -->PendingIntent.send
The related sequence diagram is as follows:
insert image description here

3. After the Task starts, perform the related surface remounting operation

After the Task is started, the related onTaskAppeared callback:
related stack:

07-26 17:33:03.205  2931  2931 I lsm3333 : onTaskAppeared taskInfo = TaskInfo{
    
    userId=10 taskId=1000013 displayId=0 isRunning=true baseIntent=Intent {
    
     act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.android.car.mapsplaceholder/.MapsPlaceholderActivity } baseActivity=ComponentInfo{
    
    com.android.car.mapsplaceholder/com.android.car.mapsplaceholder.MapsPlaceholderActivity} topActivity=ComponentInfo{
    
    com.android.car.mapsplaceholder/com.android.car.mapsplaceholder.MapsPlaceholderActivity} origActivity=null realActivity=ComponentInfo{
    
    com.android.car.mapsplaceholder/com.android.car.mapsplaceholder.MapsPlaceholderActivity} numActivities=1 lastActiveTime=462943 supportsSplitScreenMultiWindow=false supportsMultiWindow=true resizeMode=2 isResizeable=true minWidth=-1 minHeight=-1 defaultMinSize=220 token=WCT{
    
    android.window.IWindowContainerToken$Stub$Proxy@8b9b010} topActivityType=1 pictureInPictureParams=null shouldDockBigOverlays=false launchIntoPipHostTaskId=0 displayCutoutSafeInsets=null topActivityInfo=ActivityInfo{
    
    7150709 com.android.car.mapsplaceholder.MapsPlaceholderActivity} launchCookies=[android.os.Binder@a4aa911] positionInParent=Point(303, 57) parentTaskId=-1 isFocused=true isVisible=false isSleeping=false topActivityInSizeCompat=false topActivityEligibleForLetterboxEducation= false locusId=null displayAreaFeatureId=1 cameraCompatControlState=hidden}
07-26 17:33:03.205  2931  2931 I lsm3333 : java.lang.Exception
07-26 17:33:03.205  2931  2931 I lsm3333 : 	at com.android.wm.shell.TaskView.onTaskAppeared(TaskView.java:313)
07-26 17:33:03.205  2931  2931 I lsm3333 : 	at com.android.car.carlauncher.CarTaskView.onTaskAppeared(CarTaskView.java:46)
07-26 17:33:03.205  2931  2931 I lsm3333 : 	at com.android.wm.shell.ShellTaskOrganizer.onTaskAppeared(ShellTaskOrganizer.java:440)
07-26 17:33:03.205  2931  2931 I lsm3333 : 	at com.android.wm.shell.ShellTaskOrganizer.onTaskAppeared(ShellTaskOrganizer.java:429)
07-26 17:33:03.205  2931  2931 I lsm3333 : 	at android.window.TaskOrganizer$1.lambda$onTaskAppeared$4$android-window-TaskOrganizer$1(TaskOrganizer.java:306)
07-26 17:33:03.205  2931  2931 I lsm3333 : 	at android.window.TaskOrganizer$1$$ExternalSyntheticLambda6.run(Unknown Source:6)
07-26 17:33:03.205  2931  2931 I lsm3333 : 	at android.os.Handler.handleCallback(Handler.java:942)
07-26 17:33:03.205  2931  2931 I lsm3333 : 	at android.os.Handler.dispatchMessage(Handler.java:99)
07-26 17:33:03.205  2931  2931 I lsm3333 : 	at android.os.Looper.loopOnce(Looper.java:201)
07-26 17:33:03.205  2931  2931 I lsm3333 : 	at android.os.Looper.loop(Looper.java:288)
07-26 17:33:03.205  2931  2931 I lsm3333 : 	at android.app.ActivityThread.main(ActivityThread.java:7898)
07-26 17:33:03.205  2931  2931 I lsm3333 : 	at java.lang.reflect.Method.invoke(Native Method)
07-26 17:33:03.205  2931  2931 I lsm3333 : 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
07-26 17:33:03.205  2931  2931 I lsm3333 : 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)


Execution of relevant business codes:


 @Override
    public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo,
            SurfaceControl leash) {
    
    

        if (mSurfaceCreated) {
    
    
            // Surface is ready, so just reparent the task to this surface control
            //核心的关键方法,对task的surface进行从新reparent到surfaceview的surafce下,这样实现了activity之间的内嵌
            mTransaction.reparent(mTaskLeash, getSurfaceControl())
                    .show(mTaskLeash)
                    .apply();
        } else {
    
    
         
        }
       //这里会再次进行相关的位置变化通知,该方法会触发重新对task的bounds进行更新
        onLocationChanged();
        if (taskInfo.taskDescription != null) {
    
    
            int backgroundColor = taskInfo.taskDescription.getBackgroundColor();
            mSyncQueue.runInSync((t) -> {
    
    
                setResizeBackgroundColor(t, backgroundColor);
            });
        }

        if (mListener != null) {
    
    
            final int taskId = taskInfo.taskId;
            final ComponentName baseActivity = taskInfo.baseActivity;
            mListenerExecutor.execute(() -> {
    
    
            //回调对应的CarLauncher的onTaskCreated方法
                mListener.onTaskCreated(taskId, baseActivity);
            });
        }
    }

4. Detailed analysis of the notification process of the Task startup process

1. First of all, to monitor the display of the Task, you must register the relevant monitoring method
to construct the relevant ShellTaskOrganizer

//省略相关方法
public TaskViewManager(@UiContext Context context, HandlerExecutor handlerExecutor,
            AtomicReference<CarActivityManager> carActivityManagerRef) {
    
    
      //构造对应的TaskOrganizer
        mTaskOrganizer = new ShellTaskOrganizer(mExecutor, mContext);
      
        initTaskOrganizer(carActivityManagerRef, transactionPool);
    }
    
       private void initTaskOrganizer(AtomicReference<CarActivityManager> carActivityManagerRef,
            TransactionPool transactionPool) {
    
    
				//这个方法关键注册到systemserver端,建立联系
        List<TaskAppearedInfo> taskAppearedInfos = mTaskOrganizer.registerOrganizer();
    }
 public List<TaskAppearedInfo> registerOrganizer() {
    
    
        try {
    
    
        //这里就是正式的跨进程,把mInterface传递给systemserver方便回调
            return mTaskOrganizerController.registerTaskOrganizer(mInterface).getList();
        } catch (RemoteException e) {
    
    
            throw e.rethrowFromSystemServer();
        }
    }

Summary: The most important steps above are to establish a connection with the systemserver, and pass the relevant callback mInterface to the systemserver, so that the systemserver can notify the client through mInterface when the Task changes.

2. How to accurately notify TaskView after monitoring

The first step above has realized that CarLauncher can monitor Task-related behaviors. Note that this must be all Task behaviors, but TaskView itself only cares about Map-related Tasks, so how to accurately notify here?

Here you can look through a stack:

07-26 17:33:03.205  2931  2931 I lsm3333 : 	at com.android.car.carlauncher.CarTaskView.onTaskAppeared(CarTaskView.java:46)
07-26 17:33:03.205  2931  2931 I lsm3333 : 	at com.android.wm.shell.ShellTaskOrganizer.onTaskAppeared(ShellTaskOrganizer.java:440)
07-26 17:33:03.205  2931  2931 I lsm3333 : 	at com.android.wm.shell.ShellTaskOrganizer.onTaskAppeared(ShellTaskOrganizer.java:429)
07-26 17:33:03.205  2931  2931 I lsm3333 : 	at android.window.TaskOrganizer$1.lambda$onTaskAppeared$4$android-window-TaskOrganizer$1(TaskOrganizer.java:306)

It can be clearly seen that the system server cross-process calls back to onTaskAppeared of ShellTaskOrganizer. In this method, it accurately matches the task changes that TaskView cares about, and then notifies


    private void onTaskAppeared(TaskAppearedInfo info) {
    
    
        final int taskId = info.getTaskInfo().taskId;
        mTasks.put(taskId, info);
        //这里进行对应的TaskListener获取,这里就是TaskView的listener获取,本身TaskView是有实现 ShellTaskOrganizer.TaskListener接口的
        final TaskListener listener =
                getTaskListener(info.getTaskInfo(), true /*removeLaunchCookieIfNeeded*/);
                
     //获取了TaskView的Listener后就可以进行通知了,从而他知道TaskView的onTaskAppeared
        if (listener != null) {
    
    
            listener.onTaskAppeared(info.getTaskInfo(), info.getLeash());
        }
       
    }

The next step is to focus on analyzing this getTaskListener, how to accurately know that the Task information of the current notification is the Task information corresponding to the TaskView


private TaskListener getTaskListener(RunningTaskInfo runningTaskInfo,
            boolean removeLaunchCookieIfNeeded) {
    
    
				//这里的launchCookies属于系统端回调带的
        final ArrayList<IBinder> launchCookies = runningTaskInfo.launchCookies;
       
        for (int i = launchCookies.size() - 1; i >= 0; --i) {
    
    
            final IBinder cookie = launchCookies.get(i);
            //拿系统端的回调的cookie与本地进行匹配,配上了就进行获取了相关的listener
            listener = mLaunchCookieToListener.get(cookie);

            if (removeLaunchCookieIfNeeded) {
    
    
                // Remove the cookie and add the listener.
                mLaunchCookieToListener.remove(cookie);
                mTaskListeners.put(taskId, listener);
          
            }
            return listener;
        }

        return mTaskListeners.get(taskListenerType);
    }

It can be seen from the above that the core is that the server will have the corresponding cookie in TaskInfo, and then there will be a corresponding cookie set map locally, so that accurate matching can be achieved.
So where does this cookie come from? Haha, in fact, this cookie comes from the client, and it is constructed and set when the activity is started.

 public void startActivity(@NonNull PendingIntent pendingIntent, @Nullable Intent fillInIntent,
            @NonNull ActivityOptions options, @Nullable Rect launchBounds) {
    
    
        //在这prepareActivityOptions进行了相关参数的设置
        prepareActivityOptions(options, launchBounds);
   //省略
    }

Let's take a look at the prepareActivityOptions method:

 private void prepareActivityOptions(ActivityOptions options, Rect launchBounds) {
    
    
       //构造出了这个cookie,其实就是binder对象
        final Binder launchCookie = new Binder();
        mShellExecutor.execute(() -> {
    
    
        //这里把这个cookie进行相关的存放到map
            mTaskOrganizer.setPendingLaunchCookieListener(launchCookie, this);
        });
        options.setLaunchBounds(launchBounds);
        //把cookie设置进了option,可以传递到systemserver端
        options.setLaunchCookie(launchCookie);
        options.setLaunchWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
        options.setRemoveWithTaskOrganizer(true);
    }
   public void setPendingLaunchCookieListener(IBinder cookie, TaskListener listener) {
    
    
        synchronized (mLock) {
    
    
        //把这里的cookie放到了mLaunchCookieToListener的集合中
            mLaunchCookieToListener.put(cookie, listener);
        }
    }

Through this cookie, you can accurately match the TaskInfo called back by the system to the corresponding TaskView

Guess you like

Origin blog.csdn.net/learnframework/article/details/131944173