Android11 FallbackHome启动和关闭流程分析

Android 7.0引入了新特性:Direct Boot Mode,设备启动后进入的一个新模式,直到用户解锁(unlock)设备此阶段结束。在这个模式下,系统调用 resolveHomeActivity 找到的是FallbackHome ,而不是我们的桌面应用。所以系统开始启动的是 FallbackHome 这个"桌面"。

c 复制代码
03-13 16:58:41.359   431   431 D test10  : ===getDefaultTaskDisplayArea===
03-13 16:58:41.359   431   431 D test10  : comp:null
ResolveInfo:ResolveInfo{b15783 com.android.settings/.FallbackHome p=-1000 m=0x108000}
03-13 16:58:41.361   431   431 D test10  : bestChoice:ResolveInfo{b15783 com.android.settings/.FallbackHome p=-1000 m=0x108000}
03-13 16:58:41.361   431   431 D test10  : aInfo:ActivityInfo{67e5d00 com.android.settings.FallbackHome}

那为什么找到是FallbackHome 呢?FallbackHome 位于 com.android.settings这个包下,看一下主配置文件

java 复制代码
//packages\apps\Settings\AndroidManifest.xml
 <activity android:name=".FallbackHome"
                  //......
            <intent-filter android:priority="-1000">
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.HOME" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
  </activity>


<application android:label="@string/settings_label"
            //......
            android:directBootAware="true"
            android:name=".SettingsApplication"
            android:appComponentFactory="androidx.core.app.CoreComponentFactory">

FallbackHome设置了HOME属性,且settings application配置了directBootAware属性,所以找到的是FallbackHome

FallbackHome的启动

FallbackHome的启动主要分为两个阶段

  1. systemserver告知Zygote要创建新进程
  2. 新进程通知AMS启动FallbackHome

systemserver告知Zygote要创建新进程

systemserver之间的调用这里就不详细分析,可以看一下调用的堆栈

c 复制代码
startSpecificActivity r:ActivityRecord{eebff5 u0 com.android.settings/.FallbackHome t2}
03-13 16:58:41.400   431   431 D test10  : java.lang.Exception
03-13 16:58:41.400   431   431 D test10  :      at com.android.server.wm.ActivityStackSupervisor.startSpecificActivity(ActivityStackSupervisor.java:979)
03-13 16:58:41.400   431   431 D test10  :      at com.android.server.wm.ActivityStack.resumeTopActivityInnerLocked(ActivityStack.java:1970)
03-13 16:58:41.400   431   431 D test10  :      at com.android.server.wm.ActivityStack.resumeTopActivityUncheckedLocked(ActivityStack.java:1516)
03-13 16:58:41.400   431   431 D test10  :      at com.android.server.wm.RootWindowContainer.resumeFocusedStacksTopActivities(RootWindowContainer.java:2311)
03-13 16:58:41.400   431   431 D test10  :      at com.android.server.wm.ActivityStarter.startActivityInner(ActivityStarter.java:1736)
03-13 16:58:41.400   431   431 D test10  :      at com.android.server.wm.ActivityStarter.startActivityUnchecked(ActivityStarter.java:1525)
03-13 16:58:41.400   431   431 D test10  :      at com.android.server.wm.ActivityStarter.executeRequest(ActivityStarter.java:1189)
03-13 16:58:41.400   431   431 D test10  :      at com.android.server.wm.ActivityStarter.execute(ActivityStarter.java:670)
03-13 16:58:41.400   431   431 D test10  :      at com.android.server.wm.ActivityStartController.startHomeActivity(ActivityStartController.java:207)
03-13 16:58:41.400   431   431 D test10  :      at com.android.server.wm.RootWindowContainer.startHomeOnTaskDisplayArea(RootWindowContainer.java:1549)
03-13 16:58:41.400   431   431 D test10  :      at com.android.server.wm.RootWindowContainer.startHomeOnDisplay(RootWindowContainer.java:1491)
03-13 16:58:41.400   431   431 D test10  :      at com.android.server.wm.RootWindowContainer.startHomeOnDisplay(RootWindowContainer.java:1475)
03-13 16:58:41.400   431   431 D test10  :      at com.android.server.wm.RootWindowContainer.startHomeOnAllDisplays(RootWindowContainer.java:1456)
03-13 16:58:41.400   431   431 D test10  :      at com.android.server.wm.ActivityTaskManagerService$LocalService.startHomeOnAllDisplays(ActivityTaskManagerService.java:6727)
03-13 16:58:41.400   431   431 D test10  :      at com.android.server.am.ActivityManagerService.systemReady(ActivityManagerService.java:9689)
03-13 16:58:41.400   431   431 D test10  :      at com.android.server.SystemServer.startOtherServices(SystemServer.java:2257)
03-13 16:58:41.400   431   431 D test10  :      at com.android.server.SystemServer.run(SystemServer.java:599)
03-13 16:58:41.400   431   431 D test10  :      at com.android.server.SystemServer.main(SystemServer.java:415)
03-13 16:58:41.400   431   431 D test10  :      at java.lang.reflect.Method.invoke(Native Method)
03-13 16:58:41.400   431   431 D test10  :      at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
03-13 16:58:41.400   431   431 D test10  :      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:925)

可以看出,首先在ActivityManagerService的systemReady方法中调用,一直执行到ActivityStackSupervisor的startSpecificActivity方法

c 复制代码
void startSpecificActivity(ActivityRecord r, boolean andResume, boolean checkConfig) {
       
       	//......

        final boolean isTop = andResume && r.isTopRunningActivity();
        mService.startProcessAsync(r, knownToBeDead, isTop, isTop ? "top-activity" : "activity");
    }

通过 startProcessAsync请求 Zygote创建 FallbackHome进程。startProcessAsync经过一步步的调用,最后调用到ProcessList的start方法

c 复制代码
//frameworks\base\services\core\java\com\android\server\am\ProcessList.java
@GuardedBy("mService")
    boolean startProcessLocked(ProcessRecord app, HostingRecord hostingRecord,
            int zygotePolicyFlags, boolean disableHiddenApiChecks, boolean disableTestApiChecks,
            boolean mountExtStorageFull, String abiOverride) {
		//......
		 // Start the process.  It will either succeed and return a result containing
            // the PID of the new process, or else throw a RuntimeException.
        final String entryPoint = "android.app.ActivityThread";

       return startProcessLocked(hostingRecord, entryPoint, app, uid, gids,
                    runtimeFlags, zygotePolicyFlags, mountExternal, seInfo, requiredAbi,
                    instructionSet, invokeWith, startTime);

}

注意这里的一个参数entryPoint为 "android.app.ActivityThread",调用其重载的方法,最后调用到Process的start方法

java 复制代码
//frameworks\base\core\java\android\os\Process.java

public static final ZygoteProcess ZYGOTE_PROCESS = new ZygoteProcess();

public static ProcessStartResult start(......) {
        return ZYGOTE_PROCESS.start(processClass, niceName, uid, gid, gids,
                    runtimeFlags, mountExternal, targetSdkVersion, seInfo,
                    abi, instructionSet, appDataDir, invokeWith, packageName,
                    zygotePolicyFlags, isTopApp, disabledCompatChanges,
                    pkgDataInfoMap, whitelistedDataInfoMap, bindMountAppsData,
  

ZYGOTE_PROCESS是 ZygoteProcess类对象,调用其start方法,进而调用其startViaZygote方法

java 复制代码
private Process.ProcessStartResult startViaZygote( ...... ){

	//一系列的参数设置,省略......
	
	//这里的processClass为android.app.ActivityThread
	argsForZygote.add(processClass);

    if (extraArgs != null) {
    	Collections.addAll(argsForZygote, extraArgs);
    }

        synchronized(mLock) {
            // The USAP pool can not be used if the application will not use the systems graphics
            // driver.  If that driver is requested use the Zygote application start path.
            return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi),
                                              zygotePolicyFlags,
                                              argsForZygote);
        }


}

1,调用openZygoteSocketIfNeeded 打开和 Zygote的链接

2,调用zygoteSendArgsAndGetResult发送参数并得到结果

先来看看openZygoteSocketIfNeeded 方法

java 复制代码
	@GuardedBy("mLock")
    private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
        try {
            attemptConnectionToPrimaryZygote();

            if (primaryZygoteState.matches(abi)) {
                return primaryZygoteState;
            }

            //......
    }
	
	@GuardedBy("mLock")
    private void attemptConnectionToPrimaryZygote() throws IOException {
        if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
            primaryZygoteState =
                    ZygoteState.connect(mZygoteSocketAddress, mUsapPoolSocketAddress);

            //......
        }
    }

调用ZygoteState的connect

c 复制代码
static ZygoteState connect(@NonNull LocalSocketAddress zygoteSocketAddress,
                @Nullable LocalSocketAddress usapSocketAddress)
                throws IOException {

            DataInputStream zygoteInputStream;
            BufferedWriter zygoteOutputWriter;
            final LocalSocket zygoteSessionSocket = new LocalSocket();

            if (zygoteSocketAddress == null) {
                throw new IllegalArgumentException("zygoteSocketAddress can't be null");
            }

            try {
                zygoteSessionSocket.connect(zygoteSocketAddress);
                zygoteInputStream = new DataInputStream(zygoteSessionSocket.getInputStream());
                zygoteOutputWriter =
                        new BufferedWriter(
                                new OutputStreamWriter(zygoteSessionSocket.getOutputStream()),
                                Zygote.SOCKET_BUFFER_SIZE);
            } catch (IOException ex) {
                try {
                    zygoteSessionSocket.close();
                } catch (IOException ignore) { }

                throw ex;
            }

            return new ZygoteState(zygoteSocketAddress, usapSocketAddress,
                                   zygoteSessionSocket, zygoteInputStream, zygoteOutputWriter,
                                   getAbiList(zygoteOutputWriter, zygoteInputStream));
        }

注意这里的 zygoteSocketAddress 即 Zygote.PRIMARY_SOCKET_NAME(zygote),调用connect连接名为zygote的socket服务,并初始化输入输出流,封装在ZygoteState对象中返回。该对象作为参数,传个zygoteSendArgsAndGetResult方法。 再来看一下zygoteSendArgsAndGetResult这个方法

java 复制代码
@GuardedBy("mLock")
    private Process.ProcessStartResult zygoteSendArgsAndGetResult(
            ZygoteState zygoteState, int zygotePolicyFlags, @NonNull ArrayList<String> args)
            throws ZygoteStartFailedEx {
        //......

        if (shouldAttemptUsapLaunch(zygotePolicyFlags, args)) {
            try {
                return attemptUsapSendArgsAndGetResult(zygoteState, msgStr);
            } catch (IOException ex) {
                // If there was an IOException using the USAP pool we will log the error and
                // attempt to start the process through the Zygote.
                Log.e(LOG_TAG, "IO Exception while communicating with USAP pool - "
                        + ex.getMessage());
            }
        }

        return attemptZygoteSendArgsAndGetResult(zygoteState, msgStr);
    }

private Process.ProcessStartResult attemptZygoteSendArgsAndGetResult(
            ZygoteState zygoteState, String msgStr) throws ZygoteStartFailedEx {
        try {
            final BufferedWriter zygoteWriter = zygoteState.mZygoteOutputWriter;
            final DataInputStream zygoteInputStream = zygoteState.mZygoteInputStream;

            zygoteWriter.write(msgStr);
            zygoteWriter.flush();

            // Always read the entire result from the input stream to avoid leaving
            // bytes in the stream for future process starts to accidentally stumble
            // upon.
            Process.ProcessStartResult result = new Process.ProcessStartResult();
            result.pid = zygoteInputStream.readInt();
            result.usingWrapper = zygoteInputStream.readBoolean();

            if (result.pid < 0) {
                throw new ZygoteStartFailedEx("fork() failed");
            }

            return result;
        } catch (IOException ex) {
            zygoteState.close();
            Log.e(LOG_TAG, "IO Exception while communicating with Zygote - "
                    + ex.toString());
            throw new ZygoteStartFailedEx(ex);
        }
    }

使用前面封装的ZygoteState 中的输入输出流,写入数据并返回结果。在 Android 11 Zygote启动流程 一文中提到,Zygote启动的时候,创建了Zygote服务端,并调用runSelectLoop,进入循环等待,等待客户端的请求。接收到请求调用processOneCommand方法。在processOneCommand方法中,先fork子进程,子进程fork成功,就在子进程中返回一个Runnable,并执行其run方法。这里的子进程是FallbackHome进程

新进程通知AMS启动FallbackHome

返回的Runnable是通过handleChildProc方法得到的

c 复制代码
private Runnable handleChildProc(ZygoteArguments parsedArgs,
            FileDescriptor pipeFd, boolean isZygote) {
        //......
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        if (parsedArgs.mInvokeWith != null) {
           //
        } else {
            if (!isZygote) {
                return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,
                        parsedArgs.mDisabledCompatChanges,
                        parsedArgs.mRemainingArgs, null /* classLoader */);
            } else {
                return ZygoteInit.childZygoteInit(parsedArgs.mTargetSdkVersion,
                        parsedArgs.mRemainingArgs, null /* classLoader */);
            }
        }
    }

剩下的就和systemserver启动流程一样,只不过这里是调用前面提到的android.app.ActivityThread类的main方法 。具体参考Android 11 SystemServer启动流程。来看看ActivityThread的main方法

c 复制代码
public static void main(String[] args) {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");

        //......

        Looper.prepareMainLooper();

		//......
        ActivityThread thread = new ActivityThread();
        thread.attach(false, startSeq);

        //......
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

创建 ActivityThread 对象并执行其attach方法

c 复制代码
@UnsupportedAppUsage
    private void attach(boolean system, long startSeq) {
        sCurrentActivityThread = this;
        mSystemThread = system;
        if (!system) {
            android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",
                                                    UserHandle.myUserId());
            RuntimeInit.setApplicationObject(mAppThread.asBinder());
            final IActivityManager mgr = ActivityManager.getService();
            try {
                mgr.attachApplication(mAppThread, startSeq);

		//......

获取AMS代理类对象,通过binder调用,调用AMS的attachApplication方法

c 复制代码
@Override
    public final void attachApplication(IApplicationThread thread, long startSeq) {
        if (thread == null) {
            throw new SecurityException("Invalid application interface");
        }
        synchronized (this) {
            int callingPid = Binder.getCallingPid();
            final int callingUid = Binder.getCallingUid();
            final long origId = Binder.clearCallingIdentity();
            attachApplicationLocked(thread, callingPid, callingUid, startSeq);
            Binder.restoreCallingIdentity(origId);
        }
    }

继续调用attachApplicationLocked方法

c 复制代码
@GuardedBy("this")
 private boolean attachApplicationLocked(@NonNull IApplicationThread thread,
            int pid, int callingUid, long startSeq) {
		
		//......
		
		//创建Application并执行其oncreate方法
		thread.bindApplication(processName, appInfo, providerList,
                        instr2.mClass,
                        profilerInfo, instr2.mArguments,
                        instr2.mWatcher,
                        instr2.mUiAutomationConnection, testMode,
                        mBinderTransactionTrackingEnabled, enableTrackAllocation,
                        isRestrictedBackupMode || !normalMode, app.isPersistent(),
                        new Configuration(app.getWindowProcessController().getConfiguration()),
                        app.compat, getCommonServicesLocked(app.isolated),
                        mCoreSettingsObserver.getCoreSettingsLocked(),
                        buildSerial, autofillOptions, contentCaptureOptions,
                        app.mDisabledCompatChanges);

	//......
	
		// See if the top visible activity is waiting to run in this process...
        if (normalMode) {
            try {
                didSomething = mAtmInternal.attachApplication(app.getWindowProcessController());//启动Activity
            } catch (Exception e) {
                Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
                badApp = true;
            }
        }

}

接下来就是AMS通知FallbackHome进程,执行FallbackHome的生命周期。FallbackHome就会启动起来

FallbackHome的退出

来看一下FallbackHome的onCreate方法

java 复制代码
@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

       //......

        registerReceiver(mReceiver, new IntentFilter(Intent.ACTION_USER_UNLOCKED));
        maybeFinish();
    }

注册了一个ACTION_USER_UNLOCKED的广播,并在这里调用了maybeFinish方法。接收到这个广播也是调用maybeFinish

c 复制代码
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            maybeFinish();
        }
    };

所以接下来看看maybeFinish到底干了什么

c 复制代码
private void maybeFinish() {
        if (getSystemService(UserManager.class).isUserUnlocked()) {
            final Intent homeIntent = new Intent(Intent.ACTION_MAIN)
                    .addCategory(Intent.CATEGORY_HOME);
            final ResolveInfo homeInfo = getPackageManager().resolveActivity(homeIntent, 0);
            if (Objects.equals(getPackageName(), homeInfo.activityInfo.packageName)) {
                if (UserManager.isSplitSystemUser()
                        && UserHandle.myUserId() == UserHandle.USER_SYSTEM) {
                    // This avoids the situation where the system user has no home activity after
                    // SUW and this activity continues to throw out warnings. See b/28870689.
                    return;
                }
                Log.d(TAG, "User unlocked but no home; let's hope someone enables one soon?");
                mHandler.sendEmptyMessageDelayed(0, 500);
            } else {
                Log.d(TAG, "User unlocked and real home found; let's go!");
                getSystemService(PowerManager.class).userActivity(
                        SystemClock.uptimeMillis(), false);
                finish();
            }
        }
    }

如果系统已经解锁并且查找到的Launcher不是自己时就finish自己。所以可以理解为:FallbackHome注册了ACTION_USER_UNLOCKED这个广播,当接收到这个广播时,如果系统已经解锁并且查找到的Launcher不是自己时就finish自己。ACTION_USER_UNLOCKED这个广播是在哪里发出的呢?

Android11开机动画退出流程分析一文中,有分析到,开机动画的退出是在performEnableScreen 方法中。退出开机动画后,调用AMS的bootAnimationComplete方法,然后调用到其finishBooting,我们从finishBooting开始分析

java 复制代码
final void finishBooting() {
	//......
	
	mUserController.sendBootCompleted(
                    new IIntentReceiver.Stub() {
                        @Override
                        public void performReceive(Intent intent, int resultCode,
                                String data, Bundle extras, boolean ordered,
                                boolean sticky, int sendingUser) {
                            synchronized (ActivityManagerService.this) {
                                mOomAdjuster.mCachedAppOptimizer.compactAllSystem();
                                requestPssAllProcsLocked(SystemClock.uptimeMillis(), true, false);
                            }
                        }
                    });

	//......

}

调用到UserController对象的sendBootCompleted方法,其源码路径为frameworks\base\services\core\java\com\android\server\am\UserController.java

java 复制代码
void sendBootCompleted(IIntentReceiver resultTo) {
        final boolean systemUserFinishedBooting;

        // Get a copy of mStartedUsers to use outside of lock
        SparseArray<UserState> startedUsers;
        synchronized (mLock) {
            systemUserFinishedBooting = mCurrentUserId != UserHandle.USER_SYSTEM;
            startedUsers = mStartedUsers.clone();
        }
        for (int i = 0; i < startedUsers.size(); i++) {
            UserState uss = startedUsers.valueAt(i);
            if (systemUserFinishedBooting && uss.mHandle.isSystem()) {
                // On Automotive, at this point the system user has already been started and
                // unlocked, and some of the tasks we do here have already been done. So skip those
                // in that case.
                // TODO(b/132262830): this workdound shouldn't be necessary once we move the
                // headless-user start logic to UserManager-land
                Slog.d(TAG, "sendBootCompleted(): skipping on non-current system user");
                continue;
            }
            finishUserBoot(uss, resultTo);
        }
    }

继续调用finishUserBoot,最终调用到 finishUserUnlocking

c 复制代码
private boolean finishUserUnlocking(final UserState uss) {
	//......
	
		mHandler.obtainMessage(USER_UNLOCK_MSG, userId, 0, uss).sendToTarget();
	//......
}

发送USER_UNLOCK_MSG消息,接收消息后,调用 finishUserUnlocked

c 复制代码
void finishUserUnlocked(final UserState uss) {

		// Dispatch unlocked to external apps
        final Intent unlockedIntent = new Intent(Intent.ACTION_USER_UNLOCKED);
        unlockedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
        unlockedIntent.addFlags(
                Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND);
        mInjector.broadcastIntent(unlockedIntent, null, null, 0, null,
                null, null, AppOpsManager.OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
                Binder.getCallingUid(), Binder.getCallingPid(), userId);

		//......
		
		finishUserUnlockedCompleted(uss);//发送开机广播

}

可以看出,就是在这里发出解锁广播和开机广播的。

总结

本文简单的介绍了FallbackHome启动和关闭的代码调用流程。

启动流程主要分为以下几步

  1. Systemserver进程通过socket,通知Zygote创建新进程
  2. 新进程创建成功,新进程通知Systemserver可以启动FallbackHome
  3. Systemserver通知FallbackHome,执行其生命周期

FallbackHome退出的话,是接收到ACTION_USER_UNLOCKED广播,判断是否解锁并且查找到的Launcher不是自己时,就退出自己

相关推荐
带电的小王30 分钟前
WhisperKit: Android 端测试 Whisper -- Android手机(Qualcomm GPU)部署音频大模型
android·智能手机·whisper·qualcomm
梦想平凡43 分钟前
PHP 微信棋牌开发全解析:高级教程
android·数据库·oracle
元争栈道1 小时前
webview和H5来实现的android短视频(短剧)音视频播放依赖控件
android·音视频
阿甘知识库2 小时前
宝塔面板跨服务器数据同步教程:双机备份零停机
android·运维·服务器·备份·同步·宝塔面板·建站
元争栈道3 小时前
webview+H5来实现的android短视频(短剧)音视频播放依赖控件资源
android·音视频
MuYe3 小时前
Android Hook - 动态加载so库
android
居居飒3 小时前
Android学习(四)-Kotlin编程语言-for循环
android·学习·kotlin
Henry_He6 小时前
桌面列表小部件不能点击的问题分析
android
工程师老罗7 小时前
Android笔试面试题AI答之Android基础(1)
android
qq_397562318 小时前
android studio更改应用图片,和应用名字。
android·ide·android studio