Android开机向导启动流程分析

Android开机向导启动流程

首先来看Android启动流程:
1、Bootloader(系统启动加载器,将Linux加载到RAM);
2、Kernel
3、init进程
4、Zygote(Zygote进程是整个android系统的根进程,fork出System server进程);
5、system_server(Android系统的核心进程,负责启动各种系统服务);
6、System Services(由system_server调用startBootstrapServices()、startCoreServices()、startOtherServices()三个方法启动各种服务,其中重要的服务启动顺序如下:
        ActivityManagerService
        PowerManagerService
        PackageManagerService
        WindowManagerService
        StorageManagerService);
接下来就是开机向导的启动过程。

一、在SystemServer类的startOtherServices()方法中,当启动了所有需要的服务后,会调用ActivityManagerService类的systemReady()方法,代码如下:

private void startOtherServices() {
        final Context context = mSystemContext;
        VibratorService vibrator = null;
        ...       
        // We now tell the activity manager it is okay to run third party
        // code.  It will call back into us once it has gotten to the state
        // where third party code can really run (but before it has actually
        // started launching the initial applications), for us to complete our
        // initialization.
        mActivityManagerService.systemReady(() -> {
            Slog.i(TAG, "Making services ready");
            traceBeginAndSlog("StartActivityManagerReadyPhase");
            mSystemServiceManager.startBootPhase(
                    SystemService.PHASE_ACTIVITY_MANAGER_READY);
            traceEnd();
            traceBeginAndSlog("StartObservingNativeCrashes");
        ...
}

二、ActivityManagerService类的systemReady()方法会调用startHomeActivityLocked()方法,开始执行启动HomeActivity的操作。

public void systemReady(final Runnable goingCallback, TimingsTraceLog traceLog) {
	...
	startHomeActivityLocked(currentUserId, "systemReady");
	...
}

我们来看startHomeActivityLocked()方法:

	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;
    }

    boolean startHomeActivityLocked(int userId, String reason) {
        if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL
                && mTopAction == null) {
            // We are running in factory test mode, but unable to find
            // the factory test app, so just sit around displaying the
            // error message and don't try to start anything.
            return false;
        }
        Intent intent = getHomeIntent();
        ActivityInfo aInfo = resolveActivityInfo(intent, STOCK_PM_FLAGS, userId);
        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() | 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);
            }
        } else {
            Slog.wtf(TAG, "No home screen found for " + intent, new Throwable());
        }

        return true;
    }

首先调用getHomeIntent()方法,该方法为Intent对象添加了Intent.CATEGORY_HOME常量,之后调用了ActivityStarter类的startHomeActivityLocked()方法,然后就是Activity的启动流程啦,关于Activity的启动流程请看我上一篇博客Activity启动流程分析。最后响应android.intent.category.HOME属性的应用就被启动了。

三、通过上面的流程,我们知道,Android通过ActivityManagerService类中的startHomeActivityLocked方法,发送一个带有android.intent.category.HOME的intent来启动响应该属性的应用。一般Launcher的AndroidManifest配置文件中都会有该属性,所以系统的Launcher就是这样被启动了。

再来看Android中的Provision应用(/packages/apps/provision),Provision其实就是类似刚出厂时或者恢复出厂设置之后,一步一步引导用户完成各种设置的Setup Wizard程序,就是我们所说的开机向导,它的主要作用是:引导用户进行一些基本设置。在原生的Android系统中,Provision只有一个空白的Activity,我们可以根据需求自己定制开机向导。
来看看Provision应用的AndroidManifest配置文件:

	<application>
        <activity android:name="DefaultActivity"
                android:theme="@android:style/Theme.NoDisplay"
                android:excludeFromRecents="true">
            <intent-filter android:priority="3">
                <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.SETUP_WIZARD" />
            </intent-filter>
        </activity>
    </application>

可以看到Provision也会响应android.intent.category.HOME属性,并且它的android:priority属性值为3,整数值越大,优先级越高,可见它的优先级要比一般的Launcher高,所以在AMS的startHomeActivityLocked()方法启动HomeLauncher的时候会先启动Provision应用,即开机向导,然后才启动Launcher。

看一下Provision中DefaultActivity.java源码:

public class DefaultActivity extends Activity {

    @Override
    protected void onCreate(Bundle icicle) {
        super.onCreate(icicle);

        // Add a persistent setting to allow other apps to know the device has been provisioned.
        Settings.Global.putInt(getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 1);
        Settings.Secure.putInt(getContentResolver(), Settings.Secure.USER_SETUP_COMPLETE, 1);
        Settings.Secure.putInt(getContentResolver(), Settings.Secure.TV_USER_SETUP_COMPLETE, 1);

        // remove this activity from the package manager.
        PackageManager pm = getPackageManager();
        ComponentName name = new ComponentName(this, DefaultActivity.class);
        pm.setComponentEnabledSetting(name, PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
                PackageManager.DONT_KILL_APP);

        // terminate the activity.
        finish();
    }
}

首先在Global表中将DEVICE_PROVISIONED属性设置为1(这个标志很重要,因为很多地方都会检查该标志是否被置为1来决定是否要走正常的流程,比如锁屏、各种Service等),在Secure表中将USER_SETUP_COMPETE属性和TV_USER_SETUP_COMPLETE属性设置为1。然后通过PackageManager对象的setComponentEnabledSetting()方法将自己设置成不可用状态,所以开机向导只会执行一次。最后关闭Activity。

如果开机向导没有执行,DEVICE_PROVISIONED属性没有被设置为1,则会导致很多功能不可用,比如无法锁屏、按home键没有反应等。

  • 5
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值