美文网首页Android开发经验谈Android技术知识Android开发
Android 系统应用 - Launcher 的启动过程

Android 系统应用 - Launcher 的启动过程

作者: 你也不知道 | 来源:发表于2020-05-11 12:31 被阅读0次

    相关文章链接:

    1. Android Framework - 学习启动篇

    2. Android 系统服务 - AMS 的启动过程

    3. Android 系统服务 - PMS 的启动过程

    4. Android Framework - 开机启动 Init 进程

    相关源码文件:

    
    /frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
    
    /apps/Launcher3/src/com/android/launcher3/launcher3.java
    
    /apps/Launcher3/src/com/android/launcher3/LauncherModel.java
    
    /apps/Launcher3/src/com/android/launcher3/LauncherAppsCompatV16.java
    
    /frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
    
    /frameworks/base/cmds/bootanimation/bootanimation_main.cpp
    
    

    1. 启动入口分析

    
        public void systemReady(final Runnable goingCallback) { 
    
          synchronized (this) {
    
            // 启动 Launcher
    
            startHomeActivityLocked(mCurrentUserId, "systemReady");
    
          }
    
        }
    
        boolean startHomeActivityLocked(int userId, String reason) {
    
            // 获取 Launcher 的启动意图
    
            Intent intent = getHomeIntent();
    
            // 通过意图解析到 ActivityInfo
    
            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);
    
                // 通过进程名和uid 查询进程信息
    
                ProcessRecord app = getProcessRecordLocked(aInfo.processName,
    
                        aInfo.applicationInfo.uid, true);
    
                // 这里进程还没启动 app 为 null
    
                if (app == null || app.instrumentationClass == null) {
    
                    intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
    
                    mStackSupervisor.startHomeActivity(intent, aInfo, reason);
    
                }
    
            }
    
            return true;
    
        }
    
        Intent getHomeIntent() {
    
            Intent intent = new Intent(mTopAction, mTopData != null ? Uri.parse(mTopData) : null);
    
            intent.setComponent(mTopComponent);
    
            if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
    
                // 用 CATEGORY_HOME 去查询
    
                intent.addCategory(Intent.CATEGORY_HOME);
    
            }
    
            return intent;
    
        }
    
    

    Launcher 启动的入口方法在 AMS 的 systemReady 方法中,首先会通过意图向 PMS 发起解析请求,PMS 查询返回 ActivityInfo 对象,注意这里的 category 是 CATEGORY_HOME ;然后通过进程的名字和 uid 去查询是否启动了进程,目前 Launcher 进程的 ProcessRecord 肯定是空;最后调用 startHomeActivity 方法去启动和创建 Launcher 。关于 Launcher 进程的创建和 Launcher Activity 的启动流程这里先不讲,在后面分析四大组件的启动过程时会详细讲到。

    2. 查询解析填充所有 App 信息

    
        protected void onCreate(Bundle savedInstanceState) {
    
            super.onCreate(savedInstanceState);
    
            // 初始化 Model
    
            LauncherAppState app = LauncherAppState.getInstance();
    
            mModel = app.setLauncher(this);
    
            setContentView(R.layout.launcher);
    
            if (!mRestoring) {
    
                if (DISABLE_SYNCHRONOUS_BINDING_CURRENT_PAGE) {
    
                    // If the user leaves launcher, then we should just load items asynchronously when
    
                    // they return.
    
                    mModel.startLoader(PagedView.INVALID_RESTORE_PAGE);
    
                } else {
    
                    // We only load the page synchronously if the user rotates (or triggers a
    
                    // configuration change) while launcher is in the foreground
    
                    mModel.startLoader(mWorkspace.getRestorePage());
    
                }
    
            }
    
        }
    
        public void startLoader(int synchronousBindPage, int loadFlags) {
    
            synchronized (mLock) {
    
                if (mCallbacks != null && mCallbacks.get() != null) {
    
                    mLoaderTask = new LoaderTask(mApp.getContext(), loadFlags);
    
                    if (synchronousBindPage != PagedView.INVALID_RESTORE_PAGE
    
                            && mAllAppsLoaded && mWorkspaceLoaded && !mIsLoaderTaskRunning) {
    
                        mLoaderTask.runBindSynchronousPage(synchronousBindPage);
    
                    } else {
    
                        sWorkerThread.setPriority(Thread.NORM_PRIORITY);
    
                        sWorker.post(mLoaderTask);
    
                    }
    
                }
    
            }
    
        }
    
        public void run() {
    
          loadAndBindAllApps();
    
        }
    
        private void loadAllApps() {
    
          final List<LauncherActivityInfoCompat> apps = mLauncherApps.getActivityList(null, user);
    
          for (int i = 0; i < apps.size(); i++) {
    
            LauncherActivityInfoCompat app = apps.get(i);
    
            mBgAllAppsList.add(new AppInfo(mContext, app, user, mIconCache));
    
          }
    
    
    
          mHandler.post(new Runnable() {
    
            public void run() {
    
              final Callbacks callbacks = tryGetCallbacks(oldCallbacks);
    
              if (callbacks != null) {
    
                callbacks.bindAllApplications(added);
    
              } else {
    
                ...   
    
              }
    
          }});
    
        }
    
        public List<LauncherActivityInfoCompat> getActivityList(String packageName, UserHandleCompat user) {
    
            final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
    
            mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
    
            mainIntent.setPackage(packageName);
    
            // 像 PMS 发起查询所有 ResolveInfo 信息
    
            List<ResolveInfo> infos = mPm.queryIntentActivities(mainIntent, 0);
    
            List<LauncherActivityInfoCompat> list = new ArrayList<LauncherActivityInfoCompat>(infos.size());
    
            for (ResolveInfo info : infos) {
    
                list.add(new LauncherActivityInfoCompatV16(mContext, info));
    
            }
    
            return list;
    
        }
    
    

    Launcher 应用的 onCreate 方法中会调用 mModel 的 startLoader 方法去查询所有的 App 应用信息,该方法的内部实际调用的是 PKMS 的 queryIntentActivities 方法。并且会将所有查询到的 Apk 信息,通过回调的方式通知 Launcher 去填充我们桌面的 RecyclerView 界面。注意这里查询的 Action 和 Category 分别是 ACTION_MAIN 和 CATEGORY_LAUNCHER ,因为我们在 AndroidMnifest.xml 中一般都会有如下配置。

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

    3. 启动和关闭开机画面

    启动完 Launcher 后系统会帮我们关闭开机启动的画面,所以这里我们顺便讲一下开机画面的启动和关闭。我们首先来分析一下开机动画的启动,开机动画其实是 init 进程中解析到的一个服务,只不过 init.rc 脚本中的配置是 disable 。也就是说 init 进程启动的时候只会解析到,而不会启动开机动画的进程,因为开机动画进程需要处理渲染,因此必须要依赖 SurfaceFlinger 进程初始化完毕。

    
    service bootanim /system/bin/bootanimation
    
      class core
    
      user graphics
    
      group graphics audio
    
      disabled
    
      oneshot
    
    void SurfaceFlinger::init() {
    
        // start boot animation
    
        startBootAnim();
    
    }
    
    void SurfaceFlinger::startBootAnim() {
    
        // start boot animation
    
        property_set("service.bootanim.exit", "0");
    
        property_set("ctl.start", "bootanim");
    
    }
    
    

    SurfaceFlinger 初始化完毕后会通过 property_set 这种方式去通知 init 进程启动 bootanim 进程,因此我们只需要找到 bootanim 进程的启动源码即可。

    
    int main()
    
    {
    
        setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_DISPLAY);
    
        char value[PROPERTY_VALUE_MAX];
    
        property_get("debug.sf.nobootanimation", value, "0");
    
        int noBootAnimation = atoi(value);
    
        ALOGI_IF(noBootAnimation,  "boot animation disabled");
    
        if (!noBootAnimation) {
    
            // 打开 binder 驱动
    
            sp<ProcessState> proc(ProcessState::self());
    
            ProcessState::self()->startThreadPool();
    
            // create the boot animation object
    
            sp<BootAnimation> boot = new BootAnimation();
    
            IPCThreadState::self()->joinThreadPool();
    
        }
    
        return 0;
    
    }
    
    void BootAnimation::onFirstRef() {
    
        status_t err = mSession->linkToComposerDeath(this);
    
        ALOGE_IF(err, "linkToComposerDeath failed (%s) ", strerror(-err));
    
        if (err == NO_ERROR) {
    
            run("BootAnimation", PRIORITY_DISPLAY);
    
        }
    
    }
    
    status_t BootAnimation::readyToRun() {
    
        mAssets.addDefaultAssets();
    
        // 获取初始化 layer
    
        ...
    
        // 初始化 opengl and egl
    
        ...
    
        // 初始化打开开机启动 zip 包
    
        ...
    
        return NO_ERROR;
    
    }
    
    bool BootAnimation::threadLoop()
    
    {
    
        bool r;
    
        // We have no bootanimation file, so we use the stock android logo
    
        // animation.
    
        if (mZip == NULL) {
    
            ...
    
        } else {
    
            r = movie();
    
        }
    
        // 销毁 opengl 和 egl
    
        eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
    
        eglDestroyContext(mDisplay, mContext);
    
        eglDestroySurface(mDisplay, mSurface);
    
        mFlingerSurface.clear();
    
        mFlingerSurfaceControl.clear();
    
        eglTerminate(mDisplay);
    
        IPCThreadState::self()->stopProcess();
    
        return r;
    
    }
    
    bool BootAnimation::movie()
    
    {
    
        String8 desString;
    
        // 读取 desc.txt 配置文件
    
        if (!readFile("desc.txt", desString)) {
    
            return false;
    
        }
    
        char const* s = desString.string();
    
        // 解析描述文件
    
        for (;;) {
    
            ...
    
        }
    
        for (size_t i=0 ; i<pcount ; i++) {
    
            for (int r=0 ; !part.count || r<part.count ; r++) {
    
                // opengl 绘制操作
    
                glClearColor(
    
                        part.backgroundColor[0],
    
                        part.backgroundColor[1],
    
                        part.backgroundColor[2],
    
                        1.0f);
    
                for (size_t j=0 ; j<fcount && (!exitPending() || part.playUntilComplete) ; j++) {
    
                    const Animation::Frame& frame(part.frames[j]);
    
                    nsecs_t lastFrame = systemTime();
    
                    ...
    
                    if (r > 0) {
    
                        glBindTexture(GL_TEXTURE_2D, frame.tid);
    
                    } else {
    
                        ...
    
                        initTexture(frame);
    
                    }
    
    
    
                    // specify the y center as ceiling((mHeight - animation.height) / 2)
    
                    // which is equivalent to mHeight - (yc + animation.height)
    
                    glDrawTexiOES(xc, mHeight - (yc + animation.height),
    
                                  0, animation.width, animation.height);
    
                    eglSwapBuffers(mDisplay, mSurface);
    
                    // 不断绘制时检测是否需要退出
    
                    checkExit();
    
                }
    
                // 如果退出了就跳出结束绘制
    
                if(exitPending() && !part.count)
    
                    break;
    
            }
    
            // free the textures for this part
    
            if (part.count != 1) {
    
                for (size_t j=0 ; j<fcount ; j++) {
    
                    const Animation::Frame& frame(part.frames[j]);
    
                    glDeleteTextures(1, &frame.tid);
    
                }
    
            }
    
        }
    
        return false;
    
    }
    
    // 读取 service.bootanim.exit 值是否是 1
    
    #define EXIT_PROP_NAME "service.bootanim.exit"
    
    void BootAnimation::checkExit() {
    
        // Allow surface flinger to gracefully request shutdown
    
        char value[PROPERTY_VALUE_MAX];
    
        property_get(EXIT_PROP_NAME, value, "0");
    
        int exitnow = atoi(value);
    
        if (exitnow) {
    
            requestExit();
    
            if (mAudioPlayer != NULL) {
    
                mAudioPlayer->requestExit();
    
            }
    
        }
    
    }
    
    

    启动动画底层采用的是 opengles 的方式来渲染绘制的,绘制的内容是本地的一个启动动画资源包,在绘制的过程中会不断的判断是否需要退出,读取的字段是 service.bootanim.exit ,为 1 代表需要 break 退出循环绘制。因此我们只需要找到 service.bootanim.exit 在哪里设置为 1 的,便可找到退出启动动画的入口。关闭动画的入口还是在 SurfaceFlinger 中只是这个调用流程比较复杂而已:

    
        final void handleResumeActivity(IBinder token,
    
                boolean clearHide, boolean isForward, boolean reallyResume) {
    
            ActivityClientRecord r = performResumeActivity(token, clearHide);
    
            if (r != null) {
    
                if (!r.onlyLocalRequest) {
    
                    r.nextIdle = mNewActivities;
    
                    mNewActivities = r;
    
                    // 添加了一个 IdleHandler 消息
    
                    Looper.myQueue().addIdleHandler(new Idler());
    
                }
    
            } else {
    
                ...
    
            }
    
        }
    
        private class Idler implements MessageQueue.IdleHandler {
    
            @Override
    
            public final boolean queueIdle() {
    
                ActivityClientRecord a = mNewActivities;
    
                if (a != null) {
    
                    mNewActivities = null;
    
                    IActivityManager am = ActivityManagerNative.getDefault();
    
                    ActivityClientRecord prev;
    
                    do {
    
                        if (a.activity != null && !a.activity.mFinished) {
    
                            try {
    
                                // 调用 AMS 的 activityIdle
    
                                am.activityIdle(a.token, a.createdConfig, stopProfiling);
    
                            } catch (RemoteException ex) {
    
                                // Ignore
    
                            }
    
                        }
    
                    } while (a != null);
    
                }
    
                return false;
    
            }
    
        }
    
        @Override
    
        public final void activityIdle(IBinder token, Configuration config, boolean stopProfiling) {
    
            synchronized (this) {
    
                ActivityStack stack = ActivityRecord.getStackLocked(token);
    
                if (stack != null) {
    
                    ActivityRecord r = mStackSupervisor.activityIdleInternalLocked(token, false, config);
    
                }
    
            }
    
            Binder.restoreCallingIdentity(origId);
    
        }
    
        // Checked.
    
        final ActivityRecord activityIdleInternalLocked(final IBinder token, boolean fromTimeout,
    
                Configuration config) {
    
            ActivityRecord r = ActivityRecord.forTokenLocked(token);
    
            if (r != null) {
    
                ...
    
                if (isFrontStack(r.task.stack) || fromTimeout) {
    
                    booting = checkFinishBootingLocked();
    
                }
    
            }
    
            ...
    
            return r;
    
        }
    
        private boolean checkFinishBootingLocked() {
    
            final boolean booting = mService.mBooting;
    
            boolean enableScreen = false;
    
            mService.mBooting = false;
    
            if (!mService.mBooted) {
    
                mService.mBooted = true;
    
                enableScreen = true;
    
            }
    
            if (booting || enableScreen) {
    
                mService.postFinishBooting(booting, enableScreen);
    
            }
    
            return booting;
    
        }
    
        void enableScreenAfterBoot() {
    
            mWindowManager.enableScreenAfterBoot();
    
            synchronized (this) {
    
                updateEventDispatchingLocked();
    
            }
    
        }
    
        public void performEnableScreen() {
    
            synchronized(mWindowMap) {
    
                if (!mBootAnimationStopped) {
    
                    // 像 SurfaceFlinger 进程发起关闭开机界面的消息
    
                    try {
    
                        IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger");
    
                        if (surfaceFlinger != null) {
    
                            Parcel data = Parcel.obtain();
    
                            data.writeInterfaceToken("android.ui.ISurfaceComposer");
    
                            surfaceFlinger.transact(IBinder.FIRST_CALL_TRANSACTION, // BOOT_FINISHED
    
                                    data, null, 0);
    
                            data.recycle();
    
                        }
    
                    } catch (RemoteException ex) {
    
                        ...
    
                    }
    
                    mBootAnimationStopped = true;
    
                }
    
                ...
    
              }
    
            }
    
        }
    
        void SurfaceFlinger::bootFinished() {
    
          ...
    
          // 把 service.bootanim.exit 属性设置为 1 ,bootanim 进程读到 1 时就会退出开机启动动画
    
          property_set("service.bootanim.exit", "1");
    
        }
    
    

    关闭开机启动动画的流程还是比较复杂的,我们来缕一缕整个逻辑,我们的 Launcher 进程启动后会启动我们 Launcher Activity 界面,而 Activity 的生命周期调用都是由 ActivityThread 来执行的,其中就会执行到 handleResumeActivity 方法,在该方法中会添加一个 IdleHandler 消息,会调用到 AMS 的 activityIdle 方法,AMS 会调用 WMS 的 enableScreenAfterBoot 方法,WMS 会跨进程通知 SurfaceFlinger 去关闭我们的开机启动动画。

    视频地址:https://pan.baidu.com/s/1LZ-kHXQyxa9995I_P1ajfg

    视频密码:o71f

    相关文章

      网友评论

        本文标题:Android 系统应用 - Launcher 的启动过程

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