Andorid N最近のタスクマネージャプロセスの詳細(一)

20364 ワード

前言
誰もがタスクマネージャを使ったことがあると信じています.携帯電話の起動方法によって異なる可能性があります.仮想ボタンや実体ボタンがある場合は、Menuボタンを短く押すか長く押すことでトリガーされる可能性があります.もしこれらがなければ、指紋ボタンが1つしかない場合は、長すぎるボタンでトリガーされる可能性があります.この機能はよく使われています.彼は私たちを早く前のタスクスタックに戻すことができます.はい、くだらないことはあまり言わないで、直接コードを分析します.私たちは5つの部分に分けて説明します.それぞれ:
  • 最近のタスクマネージャのトリガ
  • Taskの取得
  • サムネイルの取得
  • Taskの除去
  • その他
  • 1.最近のタスクマネージャのトリガー
    ファイル:PhoneStatusBar.java
        private View.OnClickListener mRecentsClickListener = new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                awakenDreams();
                //  1.1
                toggleRecentApps();
            }
        };

    1.1 toggleRecentApps
    ファイル:BaseStatusBar.java
        @Override
        public void toggleRecentApps() {
        //  1.1.1
            toggleRecents();
        }

    1.1.1 toggleRecents
    ファイル:BaseStatusBar.java
        protected void toggleRecents() {
            if (mRecents != null) {
                //  1.2
                mRecents.toggleRecents(mDisplay);
            }
        }

    1.2 toggleRecents
    ファイル:Recents.java
        @Override
        public void toggleRecents(Display display) {
    
            ......
    
            int currentUser = sSystemServicesProxy.getCurrentUser();
            if (sSystemServicesProxy.isSystemUser(currentUser)) {
                //  1.2.1
                mImpl.toggleRecents(growTarget);
            } else {
                ......
            }
        }

    このメソッドの名前からも分かるようにRecents activityを起動するには、主にRecentsImplのtoggleRecentsメソッドを通じて、引き続き下を見ていきます
    1.2.1 mImpl.toggleRecents
    ファイル:RecentsImpl.java
        public void toggleRecents(int growTarget) {
            // Skip this toggle if we are already waiting to trigger recents via alt-tab
            if (mFastAltTabTrigger.isDozing()) {
                return;
            }
    
            mDraggingInRecents = false;
            mLaunchedWhileDocking = false;
            mTriggeredFromAltTab = false;
    
            try {
                SystemServicesProxy ssp = Recents.getSystemServices();
                MutableBoolean isHomeStackVisible = new MutableBoolean(true);
                long elapsedTime = SystemClock.elapsedRealtime() - mLastToggleTime;
    
                if (ssp.isRecentsActivityVisible(isHomeStackVisible)) {
                    ......
                } else {
                    //         350
                    if (elapsedTime < MIN_TOGGLE_DELAY_MS) {
                        return;
                    }
                    //           
                    ActivityManager.RunningTaskInfo runningTask = ssp.getRunningTask();
                    //  1.2.2
                    startRecentsActivity(runningTask, isHomeStackVisible.value, true /* animate */,
                            growTarget);
    
                    // Only close the other system windows if we are actually showing recents
                    ssp.sendCloseSystemWindows(BaseStatusBar.SYSTEM_DIALOG_REASON_RECENT_APPS);
                    mLastToggleTime = SystemClock.elapsedRealtime();
                }
            } catch (ActivityNotFoundException e) {
                Log.e(TAG, "Failed to launch RecentsActivity", e);
            }
        }

    ここで最も重要なのはstartRecentsActivity、つまりタスクマネージャを起動するActivityです
    1.2.2 startRecentsActivity
    ファイル:RecentsImpl.java
    protected void startRecentsActivity(ActivityManager.RunningTaskInfo runningTask,
                boolean isHomeStackVisible, boolean animate, int growTarget) {
    
            ......
    
            // animate true
            if (!animate) {
                startRecentsActivity(ActivityOptions.makeCustomAnimation(mContext, -1, -1));
                return;
            }
    
            ActivityOptions opts;
            if (isBlacklisted) {
                opts = getUnknownTransitionActivityOptions();
            } else if (useThumbnailTransition) {
                // Try starting with a thumbnail transition
                opts = getThumbnailTransitionActivityOptions(runningTask, mDummyStackView,
                        windowOverrideRect);
            } else {
                //        0 ,hasRecentTasks true
                opts = hasRecentTasks
                    ? getHomeTransitionActivityOptions() //    ,      
                    : getUnknownTransitionActivityOptions();
            }
            //  1.2.3
            startRecentsActivity(opts);
            mLastToggleTime = SystemClock.elapsedRealtime();
        }

    主にRecentsActivityを起動する前の準備をします.
    1.2.3 RecentsActivityの起動開始
    ファイル:RecentsImpl.java
        private void startRecentsActivity(ActivityOptions opts) {
            Intent intent = new Intent();
            intent.setClassName(RECENTS_PACKAGE, RECENTS_ACTIVITY);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                    | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
                    | Intent.FLAG_ACTIVITY_TASK_ON_HOME);
    
            if (opts != null) {
                //    RecentsActivity
                mContext.startActivityAsUser(intent, opts.toBundle(), UserHandle.CURRENT);
            } else {
                mContext.startActivityAsUser(intent, UserHandle.CURRENT);
            }
            EventBus.getDefault().send(new RecentsActivityStartingEvent());
        }

    1.3 RecentsActivity
    まずonCreateファイルを見てみましょう.
     @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            mFinishedOnStartup = false;
            //    Recents              Activity,   finish Acitivity
            //          debug ,push SysUI apk   
            SystemServicesProxy ssp = Recents.getSystemServices();
            if (ssp == null) {
                mFinishedOnStartup = true;
                finish();
                return;
            }
    
            // Register this activity with the event bus
            EventBus.getDefault().register(this, EVENT_BUS_PRIORITY);
    
            //        
            //          PackageManagerd recent list       
            mPackageMonitor = new RecentsPackageMonitor();
            mPackageMonitor.register(this);
    
            // Set the Recents layout
            setContentView(R.layout.recents);
            takeKeyEvents(true); //    Activity        View,         
            mRecentsView = (RecentsView) findViewById(R.id.recents_view);
            mRecentsView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
                    View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
                    View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
            mScrimViews = new SystemBarScrimViews(this);
            getWindow().getAttributes().privateFlags |=
                    WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY;
    
            Configuration appConfiguration = Utilities.getAppConfiguration(this);
            mLastDeviceOrientation = appConfiguration.orientation;
            mLastDisplayDensity = appConfiguration.densityDpi;
            mFocusTimerDuration = getResources().getInteger(R.integer.recents_auto_advance_duration);
            mIterateTrigger = new DozeTrigger(mFocusTimerDuration, new Runnable() {
                @Override
                public void run() {
                    dismissRecentsToFocusedTask(MetricsEvent.OVERVIEW_SELECT_TIMEOUT);
                }
            });
    
            // Set the window background
            getWindow().setBackgroundDrawable(mRecentsView.getBackgroundScrim());
    
            // Create the home intent runnable
            mHomeIntent = new Intent(Intent.ACTION_MAIN, null);
            mHomeIntent.addCategory(Intent.CATEGORY_HOME);
            mHomeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
                    Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
    
            //        ,            
            IntentFilter filter = new IntentFilter();
            filter.addAction(Intent.ACTION_SCREEN_OFF);
            filter.addAction(Intent.ACTION_TIME_CHANGED);
            registerReceiver(mSystemBroadcastReceiver, filter);
    
            getWindow().addPrivateFlags(LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION);
    
            //  1.3.1     stack view
            reloadStackView();
        }

    1.3.1 stack viewの再ロード
    ファイル:RecentsActivity.java
        private void reloadStackView() {
            // If the Recents component has preloaded a load plan, then use that to prevent
            // reconstructing the task stack
            RecentsTaskLoader loader = Recents.getTaskLoader();
            RecentsTaskLoadPlan loadPlan = RecentsImpl.consumeInstanceLoadPlan();
            if (loadPlan == null) {
                loadPlan = loader.createLoadPlan(this);
            }
    
            // Start loading tasks according to the load plan
            RecentsConfiguration config = Recents.getConfiguration();
            RecentsActivityLaunchState launchState = config.getLaunchState();
            if (!loadPlan.hasTasks()) {
                //  2,     
                loader.preloadTasks(loadPlan, launchState.launchedToTaskId,
                        !launchState.launchedFromHome);
            }
    
            RecentsTaskLoadPlan.Options loadOpts = new RecentsTaskLoadPlan.Options();
            loadOpts.runningTaskId = launchState.launchedToTaskId;
            loadOpts.numVisibleTasks = launchState.launchedNumVisibleTasks;
            loadOpts.numVisibleTaskThumbnails = launchState.launchedNumVisibleThumbnails;
            loader.loadTasks(this, loadPlan, loadOpts);
            TaskStack stack = loadPlan.getTaskStack();
            mRecentsView.onReload(mIsVisible, stack.getTaskCount() == 0);
            mRecentsView.updateStack(stack, true /* setStackViewTasks */);
    
            // Update the nav bar scrim, but defer the animation until the enter-window event
            boolean animateNavBarScrim = !launchState.launchedViaDockGesture;
            mScrimViews.updateNavBarScrim(animateNavBarScrim, stack.getTaskCount() > 0, null);
    
            // If this is a new instance relaunched by AM, without going through the normal mechanisms,
            // then we have to manually trigger the enter animation state
            boolean wasLaunchedByAm = !launchState.launchedFromHome &&
                    !launchState.launchedFromApp;
            if (wasLaunchedByAm) {
                EventBus.getDefault().send(new EnterRecentsWindowAnimationCompletedEvent());
            }
    
            // Keep track of whether we launched from the nav bar button or via alt-tab
            if (launchState.launchedWithAltTab) {
                MetricsLogger.count(this, "overview_trigger_alttab", 1);
            } else {
                MetricsLogger.count(this, "overview_trigger_nav_btn", 1);
            }
    
            // Keep track of whether we launched from an app or from home
            if (launchState.launchedFromApp) {
                Task launchTarget = stack.getLaunchTarget();
                int launchTaskIndexInStack = launchTarget != null
                        ? stack.indexOfStackTask(launchTarget)
                        : 0;
                MetricsLogger.count(this, "overview_source_app", 1);
                // If from an app, track the stack index of the app in the stack (for affiliated tasks)
                MetricsLogger.histogram(this, "overview_source_app_index", launchTaskIndexInStack);
            } else {
                MetricsLogger.count(this, "overview_source_home", 1);
            }
    
            // Keep track of the total stack task count
            int taskCount = mRecentsView.getStack().getTaskCount();
            MetricsLogger.histogram(this, "overview_task_count", taskCount);
    
            // After we have resumed, set the visible state until the next onStop() call
            mIsVisible = true;
        }

    もしloadPlan.hasTasks()はfalseに等しいので、preLoadTasksでTaskをロードし、次に第2の部分であるTaskの取得に入ります.