美文网首页Android系统源码学习
启动launcher进程的过程

启动launcher进程的过程

作者: 覆水无言 | 来源:发表于2019-12-18 14:09 被阅读0次

    android源码学习目录

    介绍

    了解launcher的都知道他是Android系统启动的第一应用,也就是我们通常说的手机主界面,它也是异常普通的Android app.

    1.SystemServer对launcher的启动

    上文已经介绍过SystemServer对Android系统的各个服务进行了启动,当全部服务启动完成后,会进行launcher的启动,这样才能让用户见到手机的界面。

    //systemServer的startOtherService函数内,
     
     mActivityManagerService.systemReady(() -> {
                Slog.i(TAG, "Making services ready");
                traceBeginAndSlog("StartActivityManagerReadyPhase");
                mSystemServiceManager.startBootPhase(
                        SystemService.PHASE_ACTIVITY_MANAGER_READY);
                traceEnd();
    
                ````
    
            }, BOOT_TIMINGS_TRACE_LOG);
    

    这里是Android systemServer服务启动最后启动launcher的入口,它调用了ActivityManagerService的systemReady函数,在activitymanagerserver准备好之后,就启动launcher app,

    // /framework/base/services/core/java/com/android/server/am/ActivityManagerService.java
    public void systemReady(final Runnable goingCallback, BootTimingsTraceLog traceLog) {
                 ......
    
                mStackSupervisor.resumeFocusedStackTopActivityLocked(); //1 
                mUserController.sendUserSwitchBroadcastsLocked(-1, currentUserId);
                traceLog.traceEnd(); // ActivityManagerStartApps
                traceLog.traceEnd(); // PhaseActivityManagerReady
            }
        }
    

    详细代码我们不需要了解,因为所要了解的知识太多,这里我们只了解个过程就可以了。重要的是注释1处的代码

    // mStackSuperVisor为ActivityStackSupervisor.java
    //   
     boolean resumeFocusedStackTopActivityLocked() {
            return resumeFocusedStackTopActivityLocked(null, null, null);
    }
    
    boolean resumeFocusedStackTopActivityLocked(
                ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
            if (targetStack != null && isFocusedStack(targetStack)) {
                return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);  
            }
            final ActivityRecord r = mFocusedStack.topRunningActivityLocked();
            if (r == null || r.state != RESUMED) {
                mFocusedStack.resumeTopActivityUncheckedLocked(null, null);  //1
            } else if (r.state == RESUMED) {
                // Kick off any lingering app transitions form the MoveTaskToFront operation.
                mFocusedStack.executeAppTransition(targetOptions);
            }
            return false;
        }
    
    

    代码会执行到注释1处,ActivityStack是Activity的堆栈,了解这个方法。

        boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
            .....
    
            if (prevTask != null && prevTask.getStack() == this &&
                    prevTask.isOverHomeStack() && prev.finishing && prev.frontOfTask) {
                if (DEBUG_STACK)  mStackSupervisor.validateTopActivitiesLocked();
                if (prevTask == nextTask) {
                    prevTask.setFrontOfTask();
                } else if (prevTask != topTask()) {
                    // This task is going away but it was supposed to return to the home stack.
                    // Now the task above it has to return to the home task instead.
                    final int taskNdx = mTaskHistory.indexOf(prevTask) + 1;
                    mTaskHistory.get(taskNdx).setTaskToReturnTo(HOME_ACTIVITY_TYPE);
                } else if (!isOnHomeDisplay()) {
                    return false;
                } else if (!isHomeStack()){
                    if (DEBUG_STATES) Slog.d(TAG_STATES,
                            "resumeTopActivityLocked: Launching home next");
                    return isOnHomeDisplay() &&
                            mStackSupervisor.resumeHomeStackTask(prev, "prevFinished");   //1
                }
            }
    
             ......
    
            if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
            return true;
        }
    

    这个函数的代码执行重要在注释1处,resumeHomeStackTask函数,

     // /framework/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java
        boolean resumeHomeStackTask(ActivityRecord prev, String reason) {
            ....
            return mService.startHomeActivityLocked(mCurrentUser, myReason);
        }
    

    这个函数调动了ActivityManagerService的startHomeActivityLocked函数,这个函数是launcher启动的关键函数。

        boolean startHomeActivityLocked(int userId, String reason) {
            ....
    
            Intent intent = getHomeIntent(); //1
            ActivityInfo aInfo = resolveActivityInfo(intent, STOCK_PM_FLAGS, userId);  //2
            if (aInfo != null) {
                intent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name));
              
                aInfo = new ActivityInfo(aInfo);
                aInfo.applicationInfo = getAppInfoForUser(aInfo.applicationInfo, userId);
                ProcessRecord app = getProcessRecordLocked(aInfo.processName,
                        aInfo.applicationInfo.uid, true);
                if (app == null || app.instr == null) {
                    intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
                    final int resolvedUserId = UserHandle.getUserId(aInfo.applicationInfo.uid);
                    // For ANR debugging to verify if the user activity is the one that actually
                    // launched.
                    final String myReason = reason + ":" + userId + ":" + resolvedUserId;
                    mActivityStarter.startHomeActivityLocked(intent, aInfo, myReason);  //3
                }
            } else {
                Slog.wtf(TAG, "No home screen found for " + intent, new Throwable());
            }
    
            return true;
        }
    

    这里代码就启动launcher的代码。分三部,构建intent,根据intent查找Activity信息,启动Activity。

    • 注释1处
        Intent getHomeIntent() {
            Intent intent = new Intent(mTopAction, mTopData != null ? Uri.parse(mTopData) : null);
            intent.setComponent(mTopComponent);
            intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
            if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
                intent.addCategory(Intent.CATEGORY_HOME);
            }
            return intent;
        }
    

    这里mTopAction为String mTopAction = Intent.ACTION_MAIN,ACTION_MAIN为android.intent.action.MAIN,这里我们知道这个是launcher的重要标记,我们开发launcher的时候也是用的这个将APP作为一个launcher。后续的代码为intent增加了一些参数。

    • 代码注释2处:
    // 在ActivityManagerService中
        private ActivityInfo resolveActivityInfo(Intent intent, int flags, int userId) {
            ActivityInfo ai = null;
            ComponentName comp = intent.getComponent();
            try {
                if (comp != null) {
                    // Factory test.
                    ai = AppGlobals.getPackageManager().getActivityInfo(comp, flags, userId); //从PackageManagerService中找到这个Activity
                } else {
                    ResolveInfo info = AppGlobals.getPackageManager().resolveIntent(
                            intent,
                            intent.resolveTypeIfNeeded(mContext.getContentResolver()),
                            flags, userId);
    
                    if (info != null) {
                        ai = info.activityInfo;
                    }
                }
            } catch (RemoteException e) {
                // ignore
            }
    
            return ai;
        }
    

    上诉代码目的只有一个,根据intent从PackageManagerService中找到这个Activity,

    • 注释3处:
      mActivityStarter.startHomeActivityLocked, 就是启动这个Activity的方法,从这个函数之后,运行就和普通的Activity启动一样了,这里我们不进行详细介绍,后续会对 ActivityManagerService是怎样运行的进行详细介绍。
    • 到这里systemService利用ActivityManagerService对系统启动第一个应用launcher已经完成了。

    2.Launcher的图标显示。

    我们知道我们手机上launcher启动后,会将我们手机上安装的所有应用进行列表展示。这是怎么操作的呢,从前面文章的分析我们知道这个必定会和包管理服务PackageManagerService有关,我们现在查看launcher主要的Activity启动后只怎样查找使用所有APP的。
    launcher启动的主Activity。

    // /packages/apps/launcher3/AndroidManifest.xml
            <activity
                android:name="com.android.launcher3.Launcher"
                android:launchMode="singleTask"
                android:clearTaskOnLaunch="true"
                android:stateNotNeeded="true"
                android:windowSoftInputMode="adjustPan|stateUnchanged"
                android:screenOrientation="nosensor"
                android:configChanges="keyboard|keyboardHidden|navigation"
                android:resizeableActivity="true"
                android:resumeWhilePausing="true"
                android:taskAffinity=""
                android:enabled="true">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.HOME" />
                    <category android:name="android.intent.category.DEFAULT" />
                    <category android:name="android.intent.category.MONKEY"/>
                </intent-filter>
            </activity>
    

    从上面的xml文件中可以看到"android.intent.action.MAIN注释的Activity为com.android.launcher3.Launcher,所以它就是launcher的第一个activity。

    1.1 Launcher的onCreate方法

     @Override
        protected void onCreate(Bundle savedInstanceState) {
            .....
    
            LauncherAppState app = LauncherAppState.getInstance(this);  // 1 创建launcherAppState
    
         ....
    
            mSharedPrefs = Utilities.getPrefs(this);
            mIsSafeModeEnabled = getPackageManager().isSafeMode();
            mModel = app.setLauncher(this);   // 2 设置LauncherAppState的Launcher
            mModelWriter = mModel.getWriter(mDeviceProfile.isVerticalBarLayout());
            mIconCache = app.getIconCache();
            ....
    
            mLauncherView = getLayoutInflater().inflate(R.layout.launcher, null);   // 3 加载布局文件
    
            setupViews();
            mDeviceProfile.layout(this, false /* notifyListeners */);
            mExtractedColors = new ExtractedColors();
            loadExtractedColorsAndColorItems();
    
            mPopupDataProvider = new PopupDataProvider(this);
    
            ((AccessibilityManager) getSystemService(ACCESSIBILITY_SERVICE))
                    .addAccessibilityStateChangeListener(this);
    
            lockAllApps();
    
            restoreState(savedInstanceState);
    
            if (LauncherAppState.PROFILE_STARTUP) {
                Trace.endSection();
            }
    
            // We only load the page synchronously if the user rotates (or triggers a
            // configuration change) while launcher is in the foreground
            int currentScreen = PagedView.INVALID_RESTORE_PAGE;
            if (savedInstanceState != null) {
                currentScreen = savedInstanceState.getInt(RUNTIME_STATE_CURRENT_SCREEN, currentScreen);
            }
            if (!mModel.startLoader(currentScreen)) {   //  4 开始加载APP信息
                // If we are not binding synchronously, show a fade in animation when
                // the first page bind completes.
                mDragLayer.setAlpha(0);
            } else {
                // Pages bound synchronously.
                mWorkspace.setCurrentPage(currentScreen);
    
                setWorkspaceLoading(true);
            }
            ....
        }
    
    • 注释1处:获取了LauncherAppState对象,并在注释2处将Laucher对象设置到了launcherAppState.
    
      LauncherModel setLauncher(Launcher launcher) {
            getLocalProvider(mContext).setLauncherProviderChangeListener(launcher);
            mModel.initialize(launcher);
            return mModel;
        }
    
    
       public void initialize(Callbacks callbacks) {
            synchronized (mLock) {
                Preconditions.assertUIThread();
                // Remove any queued UI runnables
                mHandler.cancelAll();
                mCallbacks = new WeakReference<>(callbacks);
            }
        }
    

    这里setLauncher就是将launcher类对象以弱引用方式放入mCallbacks, WeakReference就是弱引用。

    • 注释3处:加载了这个Activity的布局文件。
    • 注释4处:是很重要的一节,这里开始加载手机内所有APP的数据
    // packages/apps/Launcher3/src/com/android/launcher3/LauncherModel
        public boolean startLoader(int synchronousBindPage) { 
            synchronized (mLock) {
                ....
                if (mCallbacks != null && mCallbacks.get() != null) {
                    final Callbacks oldCallbacks = mCallbacks.get();
                    // Clear any pending bind-runnables from the synchronized load process.
                    runOnMainThread(new Runnable() {
                        public void run() {
                            oldCallbacks.clearPendingBinds(); //1清除原有的内容
                        }
                    });
    
                    // If there is already one running, tell it to stop.
                    stopLoaderLocked();
                    mLoaderTask = new LoaderTask(mApp.getContext(), synchronousBindPage); //构建LoaderTask
                    if (synchronousBindPage != PagedView.INVALID_RESTORE_PAGE
                            && mModelLoaded && !mIsLoaderTaskRunning) {
                        mLoaderTask.runBindSynchronousPage(synchronousBindPage);
                        return true;
                    } else {
                        sWorkerThread.setPriority(Thread.NORM_PRIORITY);
                        sWorker.post(mLoaderTask); //2 执行LoaderTask, sWorker是一个handler。
                    }
                }
            }
            return false;
        }
    
    • 注释1处进行了原有callback也就是launcher数据的清除
    • 注释2处进行了LoaderTask的构建,sWorker对loaderTask进行了执行。
    packages/apps/Launcher3/src/com/android/launcher3/LauncherModel--LoaderTask run函数
     public void run() {
                synchronized (mLock) {
                    if (mStopped) {
                        return;
                    }
                    mIsLoaderTaskRunning = true;
                }
    
                try {
                    if (DEBUG_LOADERS) Log.d(TAG, "step 1.1: loading workspace");
                    // Set to false in bindWorkspace()
                    mIsLoadingAndBindingWorkspace = true;
                    loadWorkspace();
    
                    verifyNotStopped();
                    if (DEBUG_LOADERS) Log.d(TAG, "step 1.2: bind workspace workspace");
                    bindWorkspace(mPageToBindFirst);
    
                    // Take a break
                    if (DEBUG_LOADERS) Log.d(TAG, "step 1 completed, wait for idle");
                    waitForIdle();
                    verifyNotStopped();
    
                    // second step
                    if (DEBUG_LOADERS) Log.d(TAG, "step 2.1: loading all apps");
                    loadAllApps();
    
                    .....
                }
            }
    
    

    上面函数每一步都有日志,翻译过来很好理解它做了什么,

    1. 加载和绑定工作区:Launcher是用工作区来显示系统安装的应用图标的,每个工作区都用来描述一个抽象桌面,它由N个桌面构成,每个桌面又分N个单元格。
    2. loadAllApps加载所有的APP
      private void loadAllApps() {
                ...
                mBgAllAppsList.clear();
                for (UserHandle user : profiles) {
                    // Query for the set of apps
                    final long qiaTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
                    final List<LauncherActivityInfo> apps = mLauncherApps.getActivityList(null, user); // 1获取所有APP的launcher-Activity信息
                    ....
                mHandler.post(new Runnable() {
                    public void run() {
    
                        final long bindTime = SystemClock.uptimeMillis();
                        final Callbacks callbacks = tryGetCallbacks(oldCallbacks);
                        if (callbacks != null) {
                            callbacks.bindAllApplications(added);  //2 绑定APP launcher信息。
                        } else {
                            Log.i(TAG, "not binding apps: no Launcher activity");
                        }
              .....
            }
    
    
    • 注释1处,获取所有APP的launcher Activity信息,因为每个APP,只要有界面就必定由一个launcher Activity。
    • 注释2处:将所有的APP信息绑定,对之前的分析我们知道callbacks是Launcher类,我们看看绑定了什么。
        public void bindAllApplications(final ArrayList<AppInfo> apps) {
            ...
    
            if (mAppsView != null) {
                mAppsView.setApps(apps);   //1 将APP数据添加到mAppsVIew内,
            }
            if (mLauncherCallbacks != null) {
                mLauncherCallbacks.bindAllApplications(apps);
            }
        }
    

    重要代码,mAppsView是AllAppsContainerView,位置为/packages/apps/Launcher3/src/com/android/launcher3/allapps/AllAppsContainerView,
    AllAppsContainerView中的mApps是AlphabeticalAppsList,设置给它保存了下来,这时候APP的数据就加载完成了 。

    1.2 APP数据的展示。

    在上一节我们在Launcher类的oncreate函数中了解到它对布局文件进行了解析,最后调用了setContentVIew为Activity进行了界面设置。

    mLauncherView = getLayoutInflater().inflate(R.layout.launcher, null);
    setContentView(mLauncherView);
    

    这个加载布局中包含上文中提到的AllAppsContainerView,在看AllAppContainerVIew中的一个函数。

        @Override
        protected void onFinishInflate() {
            super.onFinishInflate();
    
           ....
    
            // Load the all apps recycler view
            mAppsRecyclerView = (AllAppsRecyclerView) findViewById(R.id.apps_list_view);
            mAppsRecyclerView.setApps(mApps);
            mAppsRecyclerView.setLayoutManager(mLayoutManager);
            mAppsRecyclerView.setAdapter(mAdapter);
            mAppsRecyclerView.setHasFixedSize(true);
            mAppsRecyclerView.addOnScrollListener(mElevationController);
            mAppsRecyclerView.setElevationController(mElevationController);
    
            FocusedItemDecorator focusedItemDecorator = new FocusedItemDecorator(mAppsRecyclerView);
            mAppsRecyclerView.addItemDecoration(focusedItemDecorator);
            mAppsRecyclerView.preMeasureViews(mAdapter);
            mAdapter.setIconFocusListener(focusedItemDecorator.getFocusListener());
    
            if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP) {
                getRevealView().setVisibility(View.VISIBLE);
                getContentView().setVisibility(View.VISIBLE);
                getContentView().setBackground(null);
            }
        }
    
    

    这个函数会在这个控件所在的xml被加载完成后触发, 这里的代码我们熟悉了,这就是对一个recyeleView进行的数据、adapter、layoutManager的设置,这里的mAppRecyclerView就是重写了RecyclerView, 用来展示所有已安装应用的图标等信息。

    2 总结

    到这里launcher已经启动并显示了所有的已安装的APP,这里我们可以认为Android系统的启动过程完全结束了。我的文章也对对Android整个系统分析完成了,但是这个分析的过程很粗略,很多代码和细节都没有写。想了解的可以跟着这个思路再细化这个Android系统启动的过程文章,欢迎投稿。

    相关文章

      网友评论

        本文标题:启动launcher进程的过程

        本文链接:https://www.haomeiwen.com/subject/vvcunctx.html