android 开机启动桌面Activity(Launcher )的过程(一)

我们都知道android手机开机后会首先看到"ANDROID"启动页面,然后看到手机桌面,而手机桌面就是android机子启动的第一个Activity。那么android系统是如何启动这个HOME Activity的呢?
在这里插入图片描述

借助前面博文《android zygote进程启动到SystemServer进程启动过程》我们知道,通电开机后会走到SystemServer.javarun( ) 方法。

run方法大概可以分为下面几步:

  • 首先设置时间、市区、语言等环境,然后设置虚拟机的一些属性参数
  • 然后调用Looper.prepareMainLooper()创建主线程,即我们熟知的UI线程
  • 接着加载android_servers底层库,初始化系统上下文对象
  • 再接着就是初始化各种系统服务,例如:SystemServiceManager、ActivityServiceManager、WifiService等
  • 最后调用Looper.loop()开启死循环,以处理各种事件消息

在初始化上下文对象之后会启动各种系统服务:

startBootstrapServices();  //启动引导服务
startCoreServices();       //启动核心服务
startOtherServices();      //启动其他服务
1、 我们来看startOtherServices()
    private void startOtherServices() {
        //.......
        mActivityManagerService.systemReady(() -> {
            //.......
        }, BOOT_TIMINGS_TRACE_LOG);
    }

上面启动一堆堆的服务后会调用ActivityManagerService的systemReady( )方法:

	public void systemReady(final Runnable goingCallback, TimingsTraceLog traceLog) {
        //.......
        synchronized (this) {
             //.......
            startHomeActivityLocked(currentUserId, "systemReady");
           //.......
        }
    }
2、接着调用startHomeActivityLocked( ) 开始准备启动HOME Activity的前奏工作
	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));
            // Don't do this if the home app is currently being
            // instrumented.
            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() | 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;
                mActivityStartController.startHomeActivity(intent, aInfo, myReason);   //注释3
            }
        } else {
            Slog.wtf(TAG, "No home screen found for " + intent, new Throwable());
        }
        return true;
    }
注释1:getHomeIntent()将会返回附带Intent.CATEGORY_HOME属性的Intent,方面后续从系统的AndroidManifest.xml中查找对应的Activity。
	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;
    }
注释2:resolveActivityInfo()这里将会查找出桌面Activity,然后返回ActivityInfo对象。
注释3:最后调用ActivityStartController的startHomeActivity( )方法启动HOME Activity。

我们将目光放在注释2:

	private ActivityInfo resolveActivityInfo(Intent intent, int flags, int userId) {
        ActivityInfo ai = null;
        ComponentName comp = intent.getComponent();
        try {
            if (comp != null) {  //comp默认为null
                // Factory test.
                ai = AppGlobals.getPackageManager().getActivityInfo(comp, flags, userId);
            } 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;
    }
3、我们来看AppGlobals.getPackageManager().resolveIntent()这一步

AppGlobals.getPackageManager()返回IPackageManager对象,但IPackageManager是一个借口,经过查找,可以知道返回的是PackageManagerService对象,接着调用其resolveIntent()方法:

	@Override
    public ResolveInfo resolveIntent(Intent intent, String resolvedType,  int flags, int userId) {
        return resolveIntentInternal(intent, resolvedType, flags, userId, false,  Binder.getCallingUid());
    }

    private ResolveInfo resolveIntentInternal(Intent intent, String resolvedType,
            int flags, int userId, boolean resolveForStart, int filterCallingUid) {
        try {
        	//日志跟踪
            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveIntent");

			//启动后userId都会有一个id,故此不为null
            if (!sUserManager.exists(userId)) return null;
            	 
            final int callingUid = Binder.getCallingUid();
            flags = updateFlagsForResolve(flags, userId, intent, filterCallingUid, resolveForStart);
            //检查权限
            mPermissionManager.enforceCrossUserPermission(callingUid, userId,  false , false, "resolve intent");
            
			//日志跟踪
            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "queryIntentActivities");
            
            //重头戏:查找出Intent.CATEGORY_HOME的Activity
            final List<ResolveInfo> query = queryIntentActivitiesInternal(intent, resolvedType,
                    flags, filterCallingUid, userId, resolveForStart, true /*allowDynamicSplits*/);
            //日志跟踪
            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
            
			//帅选出d对应的HomeActivity,然后返回该Activity的相关信息
            final ResolveInfo bestChoice = chooseBestActivity(intent, resolvedType, flags, query, userId);
           
            return bestChoice;
        } finally {
            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
        }
    }
首先查找出附带Intent.CATEGORY_HOME属性的Activity,然后帅选出对应的Activity,即Launcher.java,然后返回该Activity的相关信息,然后调用前面第3点提到的注释3方法。

注释3:调用ActivityStartController的startHomeActivity( )方法启动Launcher

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

        mLastHomeActivityStartResult = obtainStarter(intent, "startHomeActivity: " + reason)
                .setOutActivity(tmpOutRecord)
                .setCallingUid(0)
                .setActivityInfo(aInfo)
                .execute();
        mLastHomeActivityStartRecord = tmpOutRecord[0];
        if (mSupervisor.inResumeTopActivity) {
            // If we are in resume section already, home activity will be initialized, but not
            // resumed (to avoid recursive resume) and will stay that way until something pokes it
            // again. We need to schedule another resume.
            mSupervisor.scheduleResumeTopActivities();
        }
    }

至于怎么去查找和帅选出对应的Home Activity,后续我们再去探讨。以上就是开启桌面Activity的部分过程。

发布了27 篇原创文章 · 获赞 32 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/luoyingxing/article/details/87856870