美文网首页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