Android 启动以及 USER_UNLOCKED的广播的发送

1. 开机各阶段

makefile 复制代码
```shell
boot_progress|bootAnimation:|wm_boot_animation_done
 
boot_progress_start: 6914   标志着kernel启动完成。Zygote开始启动  此时界面还是现实开机静态图片
 BootAnimation: BootAnimationStartTiming start time: 15202ms    界面开始开机动画
boot_progress_preload_start: 9509  Zygote开始加载资源
boot_progress_preload_end: 12251 Zygote加载资源结束
boot_progress_system_run: 12619 SystemServer开始启动
boot_progress_pms_start: 13424 PMS开始启动
boot_progress_pms_system_scan_start: 13482 PMS扫描/system目录下的安装包
boot_progress_pms_data_scan_start: 15598 PMS扫描/data目录下的安装包
boot_progress_pms_scan_end: 15633 PMS扫描结束
boot_progress_pms_ready: 16225 PMS初始化完毕
boot_progress_ams_ready: 22036 AMS就绪
android.intent.category.HOME: 先启动"Android正在启动" FallbackHome。
boot_progress_enable_screen: 24814 AMS启动完成后开始激活屏幕,从此以后
屏幕才能响应用户的触摸
wm_boot_animation_done: 27995 开机动画结束,这一步用户能直观感受到开
机结束
ACTION_LOCKED_BOOT_COMPLETED: Android7.0之后才有,在解锁前就会发出。
 
ActivityTaskManager: START u0 {act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10000100 cmp=com.android.launcher3/.Launcher} from uid 0, pid 0     启动launcher

```

wm_boot_animation_done : 开机动画结束,一般统计到这个时间点。

可以过滤 SystemServerTiming 看子服务启动时间。

Zygote32Timing 查看 zygote 加载各资源消耗的时间, 主要是 preloaded-classes 耗时。

2. Android 启动过程

  1. bootloader 启动 kernel

  2. kernel 启动后,首先启动 init 进程

  3. system\core\init\Init.cpp 在里面搭建系统运行环境,并解析启动init.rc。在init.zygote*.rc中启动 app_process(即zygote进程)。app_progress 入口在app_main.cpp。 里面启动ZygoteInit 和RuntimeInit。

  4. ZygoteInit 里面启动 SystemServer,并用ZygoteServer注册一个socket,死循环等待AMS的信息来创建应用进程。

3. SystemServer 启动过程

  1. 设置时间、时区、语言等

  2. startBootstrapServices:读配置,启动开机必备的服务:AMS、PMS等等

startCoreServices:其他重要服务,DropBox、电池、应用使用情况服务等

startOtherServices:通知、蓝牙、wifi等设备相关服务。

  1. 在AMS的systemReady 中调用startHomeActivityLocked 启动launcher。

  2. Launcher启动后,会在ActivityThread.handleResumeActivity中通过Idler 最终通过 finishBooting(里面设置sys.boot_completed 属性为1) 调用UserController.sendBootCompleted。这里涉及各种开机相关广播,在对credential-encrypted storage解锁后,BOOT_COMPLETED在UserController.finishUserUnlockedCompleted 中发出。

4. 几种开机广播

ACTION_LOCKED_BOOT_COMPLETED 表示解锁之前的 Direct Boot Mode 启动完成

ACTION_BOOT_COMPLETED 我们平时监听的开机广播

开机广播发送时机

Pasted image 20230412163530.png
go 复制代码
```shell
在Launcher启动时的handleResumeActivity,
ActivityTaskManagerService.activityIdle:
ActivityStackSupervisor.activityIdleInternalLocked:
    checkFinishBootingLocked: 检查是否初始化完成,需要所有启动应用的主线程是空闲的
        ActivityManagerService.finishBooting: 
            UserController.sendBootCompleted
                finishUserBoot
                    ACTION_LOCKED_BOOT_COMPLETED 发送;
                    maybeUnlockUser
                        unlockUserCleared
                        finishUserUnlocking:发送 SYSTEM_USER_UNLOCK_MSG 信息,finishUserUnlocked
                        finishUserUnlockedCompleted:ACTION_BOOT_COMPLETED 这里发送开机广播
                    
        ActivityTaskManagerService.postFinishBooting: 

```

launcher 启动后, 调用到 ActivityThread.handleResumeActivity()

yaml 复制代码
```java
    @Override
    public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
            String reason) {
        ... ...
        // 往 loop 中添加了一条空闲消息
        Looper.myQueue().addIdleHandler(new Idler());
    }

private class Idler implements MessageQueue.IdleHandler {
2470          @Override
2471          public final boolean queueIdle() {
2472              ActivityClientRecord a = mNewActivities;
2473              boolean stopProfiling = false;
2474              if (mBoundApplication != null && mProfiler.profileFd != null
2475                      && mProfiler.autoStopProfiler) {
2476                  stopProfiling = true;
2477              }
2478              if (a != null) {
2479                  mNewActivities = null;
// 这里交给了 ActivityClient 
2480                  final ActivityClient ac = ActivityClient.getInstance();
2481                  ActivityClientRecord prev;
2482                  do {
2483                      if (localLOGV) Slog.v(
2484                          TAG, "Reporting idle of " + a +
2485                          " finished=" +
2486                          (a.activity != null && a.activity.mFinished));
2487                      if (a.activity != null && !a.activity.mFinished) {
2488                          ac.activityIdle(a.token, a.createdConfig, stopProfiling);
2489                          a.createdConfig = null;
2490                      }
2491                      prev = a;
2492                      a = a.nextIdle;
2493                      prev.nextIdle = null;
2494                  } while (a != null);
2495              }
2496              if (stopProfiling) {
2497                  mProfiler.stopProfiling();
2498              }
2499              return false;
2500          }
2501      }

```

Looper.myQueue().addIdleHandler(new Idler()); 往 loop 中添加了一条空闲消息,这个消息主要通知 ActivityTaskManagerService 当前 Activity 空闲了,这个时候可以去做一些其他的事情,比如执行上一个 Activity 的 onStop( ), onDestroy( ) ......

还有开机广播, 接着就来看看ActivityTaskManagerService.activityIdle():

arduino 复制代码
```java
      /** Reports the main thread is idle after the activity is resumed. */
50      public void activityIdle(IBinder token, Configuration config, boolean stopProfiling) {
51          try {
52              getActivityClientController().activityIdle(token, config, stopProfiling);
53          } catch (RemoteException e) {
54              e.rethrowFromSystemServer();
55          }
56      }

```

这里交给了 ActivityClientController 中的 activityIdle 来处理

java 复制代码
```java

 public void activityIdle(IBinder token, Configuration config, boolean stopProfiling) {
141          final long origId = Binder.clearCallingIdentity();
142          try {
143              synchronized (mGlobalLock) {
144                  Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "activityIdle");
145                  final ActivityRecord r = ActivityRecord.forTokenLocked(token);
146                  if (r == null) {
147                      return;
148                  }
// 这里其实还是回到了 ActivityTaskSupervisor 
149                  mTaskSupervisor.activityIdleInternal(r, false /* fromTimeout */,
150                          false /* processPausingActivities */, config);
151                  if (stopProfiling && r.hasProcess()) {
152                      r.app.clearProfilerIfNeeded();
153                  }
154              }
155          } finally {
156              Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
157              Binder.restoreCallingIdentity(origId);
158          }
159      }
```
yaml 复制代码
``java
 void activityIdleInternal(ActivityRecord r, boolean fromTimeout,
1578              boolean processPausingActivities, Configuration config) {
1579          if (DEBUG_ALL) Slog.v(TAG, "Activity idle: " + r);
1580  
1581          if (r != null) {
1582              if (DEBUG_IDLE) Slog.d(TAG_IDLE, "activityIdleInternal: Callers="
1583                      + Debug.getCallers(4));
1584              mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
1585              r.finishLaunchTickingLocked();
1586              if (fromTimeout) {
1587                  reportActivityLaunched(fromTimeout, r, INVALID_DELAY, -1 /* launchState */);
1588              }
1589  
1590              // This is a hack to semi-deal with a race condition
1591              // in the client where it can be constructed with a
1592              // newer configuration from when we asked it to launch.
1593              // We'll update with whatever configuration it now says
1594              // it used to launch.
1595              if (config != null) {
1596                  r.setLastReportedGlobalConfiguration(config);
1597              }
1598  
1599              // We are now idle.  If someone is waiting for a thumbnail from
1600              // us, we can now deliver.
1601              r.idle = true;
1602  
1603              // Check if able to finish booting when device is booting and all resumed activities
1604              // are idle.
               // 1.检查是否初始化完成,需要所有启动应用的主线程是空闲的
1605              if ((mService.isBooting() && mRootWindowContainer.allResumedActivitiesIdle())
1606                      || fromTimeout) {
1607                  checkFinishBootingLocked();
1608              }
1609  
1610              // When activity is idle, we consider the relaunch must be successful, so let's clear
1611              // the flag.
1612              r.mRelaunchReason = RELAUNCH_REASON_NONE;
1613          }
1614  
1615          if (mRootWindowContainer.allResumedActivitiesIdle()) {
1616              if (r != null) {
1617                  mService.scheduleAppGcsLocked();
1618                  mRecentTasks.onActivityIdle(r);
1619              }
1620  
1621              if (mLaunchingActivityWakeLock.isHeld()) {
1622                  mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
1623                  if (VALIDATE_WAKE_LOCK_CALLER &&
1624                          Binder.getCallingUid() != Process.myUid()) {
1625                      throw new IllegalStateException("Calling must be system uid");
1626                  }
1627                  mLaunchingActivityWakeLock.release();
1628              }
1629              mRootWindowContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
1630          }
1631  
1632          // Atomically retrieve all of the other things to do.
             // 2. 处理 stop 和 destory 的 activity 
1633          processStoppingAndFinishingActivities(r, processPausingActivities, "idle");
1634  
1635          if (DEBUG_IDLE) {
1636              Slogf.i(TAG, "activityIdleInternal(): r=%s, mStartingUsers=%s", r, mStartingUsers);
1637          }
1638  
1639          if (!mStartingUsers.isEmpty()) {
1640              final ArrayList<UserState> startingUsers = new ArrayList<>(mStartingUsers);
1641              mStartingUsers.clear();
1642              // Complete user switch.
1643              for (int i = 0; i < startingUsers.size(); i++) {
1644                  UserState userState = startingUsers.get(i);
1645                  Slogf.i(TAG, "finishing switch of user %d", userState.mHandle.getIdentifier());
1646                  mService.mAmInternal.finishUserSwitch(userState);
1647              }
1648          }
1649  
1650          mService.mH.post(() -> mService.mAmInternal.trimApplications());
1651      }
1652  

```

上面的逻辑主要分为 3块, 其中 2 中是处理 Activity 的生命周期。

1 中就会去发送开机广播

``

mService.isBooting() 这里返回 true, 在ActivityManagerService.systemReady()里赋的值

mRootWindowContainer.allResumedActivitiesIdle() 这里就是判断启动过的 Activity 主线程是否全是空闲的,如果不是空闲,就会一直等,直到所有都是空闲的才会在这里往下执行。(这也就是为什么有时候系统开机广播会在开机之后几分钟才发送)

再往下看看 checkFinishBootingLocked()

yaml 复制代码
```java
1560      /**
1561       * Called when all resumed tasks/root-tasks are idle.
1562       */
1563      @GuardedBy("mService")
1564      private void checkFinishBootingLocked() {
1565          final boolean booting = mService.isBooting();
1566          boolean enableScreen = false;
              // 置为 false
1567          mService.setBooting(false);
1568          if (!mService.isBooted()) {
1569              mService.setBooted(true);
1570              enableScreen = true;
1571          }
1572          if (booting || enableScreen) {
                  // 
1573              mService.postFinishBooting(booting, enableScreen);
1574          }
1575      }
1576  

```

注意这里的 booting 和 booted, 通过 booting 来判断,执行一次就会被设置为 false.

也就是方法只会执行一次。

yaml 复制代码
```java
frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java

5181      void postFinishBooting(boolean finishBooting, boolean enableScreen) {
5182          mH.post(() -> {
5183              if (finishBooting) {
                      // 这里会执行 ActivityManagerService 的finishBooting
5184                  mAmInternal.finishBooting();
5185              }
5186              if (enableScreen) {
                     // 这里中间通过转发下,会执行到 WindowManagerService的enableScreenAfterBoot()
5187                  mInternal.enableScreenAfterBoot(isBooted());
5188              }
5189          });
5190      }
5191  
```
ini 复制代码
```java

    final void finishBooting() {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "FinishBooting");
 
        synchronized (this) {
            if (!mBootAnimationComplete) {
                mCallFinishBooting = true;
                return;
            }
            mCallFinishBooting = false;
        }
        ... ...
    }
 
    @Override
    public void bootAnimationComplete() {
        final boolean callFinishBooting;
        synchronized (this) {
            callFinishBooting = mCallFinishBooting;
            mBootAnimationComplete = true;
        }
        if (callFinishBooting) {
            finishBooting();
        }
    }
```

这里的mBootAnimationComplete默认是false,直接就给返回了,如果不返回就会去执行发送开机广播了

开机动画: bootAnimationComplete(), 这里将 mBootAnimationComplete 置为 true

还是会去执行 finishBooting()

bootAnimationComplete() 什么时候执行呢?

WindowManagerService.enableScreenAfterBoot()

yaml 复制代码
```java
public void enableScreenAfterBoot() {
3834          synchronized (mGlobalLock) {
3835              ProtoLog.i(WM_DEBUG_BOOT, "enableScreenAfterBoot: mDisplayEnabled=%b "
3836                              + "mForceDisplayEnabled=%b mShowingBootMessages=%b mSystemBooted=%b. "
3837                              + "%s",
3838                      mDisplayEnabled, mForceDisplayEnabled, mShowingBootMessages, mSystemBooted,
3839                      new RuntimeException("here").fillInStackTrace());
3840              if (mSystemBooted) {
3841                  return;
3842              }
3843              mSystemBooted = true;
3844              hideBootMessagesLocked();
3845              // If the screen still doesn't come up after 30 seconds, give
3846              // up and turn it on.
3847              mH.sendEmptyMessageDelayed(H.BOOT_TIMEOUT, 30 * 1000);
3848          }
3849  
3850          mPolicy.systemBooted();
3851  
3852          performEnableScreen();
3853      }

 private void performEnableScreen() {
        ... ...
        try {
            mActivityManager.bootAnimationComplete();
        } catch (RemoteException e) {
        }
        ... ...

```

enableScreenAfterBoot() 只会执行一次,但是 performEnableScreen() 可能会执行多次,内部会每隔 200ms 去查询动画是否完成,如果完成了,就会执行ActivityManagerService.bootAnimationComplete()

又执行回去,也就是再回去`ActivityManagerService.finishBooting():

arduino 复制代码
```java
    final void finishBooting() {
        ... ...
        mUserController.sendBootCompleted(... ...);
        ... ...
    }

```

又转到UserController类中去了,这是ActivityManagerService的一个帮助类,先来看下它的调用链:

rust 复制代码
```shell

UserController:

sendBootCompleted() -> finishUserBoot() -> maybeUnlockUser() -> unlockUserCleared() -> finishUserUnlocking -> handler 发送 SYSTEM_USER_UNLOCK_MSG 消息 -> finishUserUnlocked() -> finishUserUnlockedCompleted()

```
java 复制代码
```java

    private void finishUserUnlockedCompleted(UserState uss) {
        ... ...
        final Intent bootIntent = new Intent(Intent.ACTION_BOOT_COMPLETED, null);
        bootIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
        bootIntent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT
                | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND
                | Intent.FLAG_RECEIVER_OFFLOAD);
        // Widget broadcasts are outbound via FgThread, so to guarantee sequencing
        // we also send the boot_completed broadcast from that thread.
        final int callingUid = Binder.getCallingUid();
        final int callingPid = Binder.getCallingPid();
        FgThread.getHandler().post(() -> {
            mInjector.broadcastIntent(bootIntent, null,
                    new IIntentReceiver.Stub() {
                        @Override
                        public void performReceive(Intent intent, int resultCode, String data,
                                Bundle extras, boolean ordered, boolean sticky, int sendingUser)
                                        throws RemoteException {
                            Slog.i(UserController.TAG, "Finished processing BOOT_COMPLETED for u"
                                    + userId);
                            mBootCompleted = true;
                        }
                    }, 0, null, null,
                    new String[]{android.Manifest.permission.RECEIVE_BOOT_COMPLETED},
                    AppOpsManager.OP_NONE, null, true, false, MY_PID, SYSTEM_UID,
                    callingUid, callingPid, userId);
        });
    }

```

这里先是封装了Intent.ACTION_BOOT_COMPLETED这个广播意图,同时还传了一个android.Manifest.permission.RECEIVE_BOOT_COMPLETED权限,然后转交给UserController.Injector.broadcastIntent():

arduino 复制代码
```java
        protected int broadcastIntent(Intent intent, String resolvedType,
                IIntentReceiver resultTo, int resultCode, String resultData,
                Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions,
                boolean ordered, boolean sticky, int callingPid, int callingUid, int realCallingUid,
                int realCallingPid, int userId) {
            // TODO b/64165549 Verify that mLock is not held before calling AMS methods
            synchronized (mService) {
                return mService.broadcastIntentLocked(null, null, intent, resolvedType, resultTo,
                        resultCode, resultData, resultExtras, requiredPermissions, appOp, bOptions,
                        ordered, sticky, callingPid, callingUid, realCallingUid, realCallingPid,
                        userId);
            }
        }
```

这里又调用到ActivityManagerService.broadcastIntentLocked(),到这里就不在往下看了,后面就是去执行发送广播的逻辑。

对于有些广播接收不到,比如报如下错误:

W BroadcastQueue: Background execution not allowed:******************

类似这类错误,就可以在BroadcastQueue这个类里面找到抛这个异常的地方,然后基于抛这个异常的判断看看怎么去处理

相关推荐
C4rpeDime35 分钟前
自建MD5解密平台-续
android
鲤籽鲲2 小时前
C# Random 随机数 全面解析
android·java·c#
m0_548514776 小时前
2024.12.10——攻防世界Web_php_include
android·前端·php
凤邪摩羯6 小时前
Android-性能优化-03-启动优化-启动耗时
android
凤邪摩羯6 小时前
Android-性能优化-02-内存优化-LeakCanary原理解析
android
喀什酱豆腐7 小时前
Handle
android
m0_748232928 小时前
Android Https和WebView
android·网络协议·https
m0_748251729 小时前
Android webview 打开本地H5项目(Cocos游戏以及Unity游戏)
android·游戏·unity
m0_7482546611 小时前
go官方日志库带色彩格式化
android·开发语言·golang
zhangphil11 小时前
Android使用PorterDuffXfermode模式PorterDuff.Mode.SRC_OUT橡皮擦实现“刮刮乐”效果,Kotlin(2)
android·kotlin