美文网首页
Android 8.0系统启动流程_Launcher(四)

Android 8.0系统启动流程_Launcher(四)

作者: 晓涵说 | 来源:发表于2019-10-06 17:41 被阅读0次

    本系列主要介绍Android8.0系统启动过程中涉及到的initZygoteSystemServer和Launcher。
    在之前的三篇文章中,讲解了如下的过程:

    • 初始化化:电源上电,加载BootLoader程序; 启动init.cpp,解析init.rc配置文件;
    • 启动Zygote进程:启动虚拟机和注册JNI方法;注册Socket服务端,预加载资源;执行runSelectLoop()方法等待其他进程的注册;
    • 启动SystemServer进程:通过Zygote启动,创建Binder线程池、执行main方法;开启 三个系统服务(引导、核心和其他)。

    在完成以上三个过程后,我们的系统就开始加载Launcher应用,查看源码可以发现Launcher是作为一个APP应用执行的,其一般位于系统的packages/apps目录下,可以通过该应用启动系统中其他应用程序,提供快捷访问图标。

    一、Launcher的启动

    在这里插入图片描述

    1.1启动准备

    在SystemServer启动时,会先启动引导服务,其中包括PMS(PackageManagerService)和AMS(ActivityManagerService),其中PMS主要作用是系统中的APK的解析和安装;AMS主要用于四大组件的启动 和管理,因此LauncherActivity通过AMS启动。
    完成引导服务的启动后,开启启动其他服务。启动Launcher的入口为AMS的systemReady方法,

    frameworks\base\services\java\com\android\server\SystemServer.java
     private void startOtherServices() {
     ...
     //在此之前会做大量的准备工作,包括AMS、PMS 和NetworkScoreService等各种服务,完成以上操作后,表示activity manager可以运行
     mActivityManagerService.systemReady(() -> {
                Slog.i(TAG, "Making services ready");
                traceBeginAndSlog("StartActivityManagerReadyPhase");
                mSystemServiceManager.startBootPhase(
                        SystemService.PHASE_ACTIVITY_MANAGER_READY);
                        ...
                        }
                        ...
     ...
    }
    
    frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java
     public void systemReady(final Runnable goingCallback, TimingsTraceLog traceLog) {
            traceLog.traceBegin("PhaseActivityManagerReady");
            synchronized(this) {
    ...
                 mStackSupervisor.resumeFocusedStackTopActivityLocked();
                mUserController.sendUserSwitchBroadcastsLocked(-1, currentUserId);
    ...
        }   
    }
    

    1.2找到Launcher 的Activity

    AMS通过调用ActivityStack实现对堆栈中Activity对象的管理,我们的最终目的是查找到Launcher应用所在的Activity是如何被调用起来的?
    其流程如下:
    ActivityStackSuperior#resumeFocusedStackTopActivityLocked() ->ActivityStack#resumeTopActivityUncheckedLocked()->resumeTopActivityInnerLocked()
    在resumeTopActivityInnerLocked中,通过调用startHomeActivityLocked方法,开启启动Launcher的Activty。

    frameworks\base\services\core\java\com\android\server\am\ActivityStackSupervisor.java
     boolean resumeFocusedStackTopActivityLocked(
                ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
                
     if (targetStack != null && isFocusedStack(targetStack)) {
                return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
            }
            ...
            return false;
            
    
    frameworks\base\services\core\java\com\android\server\am\ActivityStack.java
    boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
    if (mStackSupervisor.inResumeTopActivity) {
                return false;
            }
             boolean result = false;
            try {
                mStackSupervisor.inResumeTopActivity = true;
                result = resumeTopActivityInnerLocked(prev, options);
            } finally {
                mStackSupervisor.inResumeTopActivity = false;
            }
            final ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */);
            if (next == null || !next.canTurnScreenOn()) {
                checkReadyForSleep();
            }
            return result;
    }
    
    frameworks\base\services\core\java\com\android\server\am\ActivityStackSupervisor.java
     private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
     ...
    return isOnHomeDisplay() &&
                    mStackSupervisor.resumeHomeStackTask(prev, reason);
                    ...
                     if (r != null && !r.finishing) {
                moveFocusableActivityStackToFrontLocked(r, myReason);
                return resumeFocusedStackTopActivityLocked(mHomeStack, prev, null);
            }
            return mService.startHomeActivityLocked(mCurrentUser, myReason);
    ...
    }
    

    1.3 启动Launcher

    frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java
     boolean startHomeActivityLocked(int userId, String reason) {
     //1 判断工厂模式和topAction
    if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL
                    && mTopAction == null) {
                return false;
            }
            //2 创建启动Launcher的Intent
            Intent intent = getHomeIntent();
            ActivityInfo aInfo = resolveActivityInfo(intent, STOCK_PM_FLAGS, userId);
            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); 
                    final String myReason = reason + ":" + userId + ":" + resolvedUserId;
                    //3 启动Launcdr
                    mActivityStarter.startHomeActivityLocked(intent, aInfo, myReason);
                }
            } else {
                Slog.wtf(TAG, "No home screen found for " + intent, new Throwable());
            }
            return true;
    }
    

    在注释1处是对运行模式和Action的判断,其中运行模式包括:非工厂模式、低级工厂模式和高级工厂模式。而Action的是是指启动该Intent的Action,默认是Intent.ACTION_MAIN,表示是该应用的第一个启动的Activity,一般在创建应用时,AndroidMainfest.xm中都会包含唯一个该标签的Action。
    而对于桌面应用,会增加Intent.HOME的标签,如果我们想自定义桌面应用,可在该应用的AndroidMainfest中的启动Activity的Action添加android.Intent.action.HOME,如下所示:

     <application
           ...
            <activity android:name=".MainActivity">
                <intent-filter>
                    <action android:name="android.intent.action.HOME"/>
                    <action android:name="android.intent.action.MAIN"/>
                    <category android:name="android.intent.category.LAUNCHER"/>
                </intent-filter>
            </activity>
        </application>
    

    启动Launer是在ActivityStarter的startHomeActivityLocked方法中完成,通过ActivityStackSupervisor将该Intent移动至HomeStack(用于存储Launcher的变量)的顶部,最终调用startActivityLocked方法启动该Intnet,实现对Launcer的启动。

     void startHomeActivityLocked(Intent intent, ActivityInfo aInfo, String reason) {
            mSupervisor.moveHomeStackTaskToTop(reason);
           ...
        }
    

    二 、Launcher桌面图标显示

    完成Launcer的启动后,作为一个独立的APP,Launcher开始执行应用的加载和桌面图标的显示。


    在这里插入图片描述

    2.1 加载APP

    packages\apps\Launcher3\src\com\android\launcher3\Launcher.java
    protected void onCreate(Bundle savedInstanceState) {
    ...
    //加载桌面颜色信息和监听主题变化
     WallpaperColorInfo wallpaperColorInfo = WallpaperColorInfo.getInstance(this);
      wallpaperColorInfo.setOnThemeChangeListener(this);
    ...
    //加载桌面应用信息
     LauncherAppState app = LauncherAppState.getInstance(this);
     ...
     mModel = app.setLauncher(this);
     ...
     //加载和设置桌面view
     mLauncherView = LayoutInflater.from(this).inflate(R.layout.launcher, null);
      setupViews();
      ...
       if (!mModel.startLoader(currentScreen)) {
                mDragLayer.setAlpha(0);
            } else {
                mWorkspace.setCurrentPage(currentScreen);
                setWorkspaceLoading(true);
            }
    }
    
    //设置launcher的监听,初始化model
    packages\apps\Launcher3\src\com\android\launcher3\LauncherAppState
     LauncherModel setLauncher(Launcher launcher) {
            getLocalProvider(mContext).setLauncherProviderChangeListener(launcher);
            mModel.initialize(launcher); //传入Launcher对象
            return mModel;
        }
    

    在设置监听时,传入的Callbacks 对象时Launcher,是为了在APP加载完成时,方便通过接口回调的形式返回值Launcher,
    下面开始加载App。

    packages\apps\Launcher3\src\com\android\launcher3\LauncherModel
      public void initialize(Callbacks callbacks) {
            synchronized (mLock) {
                Preconditions.assertUIThread();
                mCallbacks = new WeakReference<>(callbacks);
            }
        }
        //Callbacks 接口包含的内容如下,主要用到bindAllApplications
    public interface Callbacks extends LauncherAppWidgetHost.ProviderChangedListener {
          ...
            public void bindAllApplications(ArrayList<AppInfo> apps);
            public void bindAppsAddedOrUpdated(ArrayList<AppInfo> apps);
            public void bindAppsAdded(ArrayList<Long> newScreens,
                                      ArrayList<ItemInfo> addNotAnimated,
                                      ArrayList<ItemInfo> addAnimated);
            public void bindPromiseAppProgressUpdated(PromiseAppInfo app);
            public void bindShortcutsChanged(ArrayList<ShortcutInfo> updated, UserHandle user);
            public void bindWidgetsRestored(ArrayList<LauncherAppWidgetInfo> widgets);
            public void bindRestoreItemsChange(HashSet<ItemInfo> updates);
            public void bindWorkspaceComponentsRemoved(ItemInfoMatcher matcher);
            public void bindAppInfosRemoved(ArrayList<AppInfo> appInfos);
            public void bindAllWidgets(MultiHashMap<PackageItemInfo, WidgetItem> widgets);
          ...
        }
    

    加载的Task分析如下

    ...
    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.
                    mUiExecutor.execute(new Runnable() {
                                public void run() {
                                    oldCallbacks.clearPendingBinds();
                                }
                            });
                    // If there is already one running, tell it to stop.
                    stopLoader();
                    LoaderResults loaderResults = new LoaderResults(mApp, sBgDataModel,
                            mBgAllAppsList, synchronousBindPage, mCallbacks);//包含Callbacks对象
                    if (mModelLoaded && !mIsLoaderTaskRunning) {    //已经加载完成且没有正在加载
                       //加载完成后,开始将结果回调至Launcher
                        loaderResults.bindWorkspace();
                        loaderResults.bindAllApps(); //加载的回调
                        loaderResults.bindDeepShortcuts();
                        loaderResults.bindWidgets();
                        return true;
                    } else {
                   //开始不断的加载 工作区间、所有的APP、快捷图标和抽屉控件
                        startLoaderForResults(loaderResults);
                    }
                }
            }
            return false;
        }
    
    packages\apps\Launcher3\src\com\android\launcher3\LauncherModel
    public void startLoaderForResults(LoaderResults results) {
            synchronized (mLock) {
                 //停止加载
                stopLoader();
                //创建新的加载task
                mLoaderTask = new LoaderTask(mApp, mBgAllAppsList, sBgDataModel, results);
                //在WorkerThread中执行该task
                runOnWorkerThread(mLoaderTask);
            }
        }
       //加载中涉及的线程初始化
     packages\apps\Launcher3\src\com\android\launcher3\LauncherModel
    @Thunk static final HandlerThread sWorkerThread = new HandlerThread("launcher-loader");
        static {
            sWorkerThread.start();
        }
    @Thunk static final Handler sWorker = new Handler(sWorkerThread.getLooper());
    

    2.2 加载回调处理

    通过LauncherModel的加载线程,获取到了系统中所有的apps的信息,同时通过其Callbacks的接口,很方便的将结果传递出去,

    packages\apps\Launcher3\src\com\android\launcher3\Launcher.java
    public void bindAllApplications(final ArrayList<AppInfo> apps) {
            Runnable r = new RunnableWithId(RUNNABLE_ID_BIND_APPS) {
                public void run() {
                    bindAllApplications(apps);
                }
            };
         ...
                //加载完成后AllAppsContainerView数据更新
                mAppsView.setApps(apps);
            }
            if (mLauncherCallbacks != null) {
                mLauncherCallbacks.bindAllApplications(apps);
            }
        }
    

    数据回调值Launcher的bindAllApplications,开始对AllAppsContainerView界面进行数据设置,其设置的控制控件为AlphabeticalAppsList,通过调用AlphabeticalAppsList实现对数据的设置处理,其实现流程和Recycleview的设置比较类似。

    packages\apps\Launcher3\src\com\android\launcher3\allapps\AllAppsContainerView.java
     public void setApps(List<AppInfo> apps) {
            mApps.setApps(apps);
        }
    
    //数据传递控制控件中
    packages\apps\Launcher3\src\com\android\launcher3\allapps\AlphabeticalAppsList.java
    public void setApps(List<AppInfo> apps) {
            mComponentToAppMap.clear();
            addOrUpdateApps(apps);
        }
    
    packages\apps\Launcher3\src\com\android\launcher3\allapps\AllAppsContainerView.java
     @Override
        protected void onFinishInflate() {
    ...
             mAppsRecyclerView = findViewById(R.id.apps_list_view); //可以看到桌面应用部分的界面为RecyclerView
            mAppsRecyclerView.setApps(mApps);
            mAppsRecyclerView.setLayoutManager(mLayoutManager);
            mAppsRecyclerView.setAdapter(mAdapter);
            mAppsRecyclerView.setHasFixedSize(true);
    ...
    
    }
    

    AllAppsContainerView会在XML布局文件加载完成后,调用onFinishInflate方法,使加载的数据最终显示在桌面上。形成我们看到的桌面图标。

    2.3 点击桌面图标的跳转至应用

    在AllAppsContainerView设置adapter后,由于RecyclerView不包含setOnItemClickListener方法,因此一般是在Adapter中自定义实现,可通过回调的形式将点击事件传递出去,Launcher的执行流程如下:

    //packages\apps\Launcher3\src\com\android\launcher3\allapps\AllAppsContainerView.java
     public AllAppsContainerView(Context context, AttributeSet attrs, int defStyleAttr) {
          ...
            //创建新的Adapter
            mAdapter = new AllAppsGridAdapter(mLauncher, mApps, mLauncher, this);
            mSpringAnimationHandler = mAdapter.getSpringAnimationHandler();
            mApps.setAdapter(mAdapter);
           ...
        }
    

    设置点击的监听回调

    //packages\apps\Launcher3\src\com\android\launcher3\allapps\AllAppsGridAdapter.java
     public AllAppsGridAdapter(Launcher launcher, AlphabeticalAppsList apps, View.OnClickListener
                iconClickListener, View.OnLongClickListener iconLongClickListener) {
          ...
            mIconClickListener = iconClickListener;
          ...
        }
    

    点击事件的处理

    packages\apps\Launcher3\src\com\android\launcher3\Launcher.java
     public void onClick(View v) {
    ...
     Object tag = v.getTag();
            if (tag instanceof ShortcutInfo) {
                onClickAppShortcut(v);
            } else if (tag instanceof FolderInfo) {
                if (v instanceof FolderIcon) {
                    onClickFolderIcon(v);
                }
            } else if ((v instanceof PageIndicator) ||
                (v == mAllAppsButton && mAllAppsButton != null)) {
                onClickAllAppsButton(v);
            } else if (tag instanceof AppInfo) {
                startAppShortcutOrInfoActivity(v);
            } else if (tag instanceof LauncherAppWidgetInfo) {
                if (v instanceof PendingAppWidgetHostView) {
                    onClickPendingWidget((PendingAppWidgetHostView) v);
                }
            }
    }
    
    //点击桌面应用的快捷图标的处理
    protected void onClickAppShortcut(final View v) {
    ...
     startAppShortcutOrInfoActivity(v);
    ...
    }
    
     private void startAppShortcutOrInfoActivity(View v) {
            ItemInfo item = (ItemInfo) v.getTag();
            Intent intent;
            if (item instanceof PromiseAppInfo) {
                PromiseAppInfo promiseAppInfo = (PromiseAppInfo) item;
                intent = promiseAppInfo.getMarketIntent();
            } else {
                intent = item.getIntent();
            }
         ...
         //跳转至相应的应用
            boolean success = startActivitySafely(v, intent, item);
    ...
        }
    

    至此Launcher的启动过程便分析完,总结如下:

    1. 启动:SystemServer启动PMS和AMS,通过AMS的systemReady开始加载;
    2. 查找:查找流程如下ActivityStackSuperior#resumeFocusedStackTopActivityLocked() ->ActivityStack#resumeTopActivityUncheckedLocked()->resumeTopActivityInnerLocked();
    3. 显示:在resumeTopActivityInnerLocked中通过调用startHomeActivityLocked方法,启动Launcher的Activty,通过LauncherModel的加载线程处理,获取到所有的Apps信息,借助Callbacks的接口回调的形式将数据返回值Launcher,然后将数据赋值给AllAppsContainerView,使Apps的桌面图标显示至桌面中。
    4. 跳转:通过设置点击事件的回调处理,点击桌面图标后,通过startActivitySafely跳转至应用的Main界面。

    相关文章

      网友评论

          本文标题:Android 8.0系统启动流程_Launcher(四)

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