Android Framework AMS(02)AMS启动及相关初始化5-8

devtools/2024/12/22 21:07:21/

该系列文章总纲链接:专题总纲目录 Android Framework 总纲


本章关键点总结 & 说明:

说明:本章节主要涉及systemserver启动AMS及初始化AMS相关操作。同时由于该部分内容过多,因此拆成2个章节,本章节是第二章节,第一章节文章链接为:

Android Framework AMS(01)AMS启动及相关初始化1-4

systemserver在启动AMS(ActivityManagerService)时,不仅仅是做简单的AMS服务启动,还有很多的其他初始化相关操作,这里我们以SystemServer启动流程为主线,对AMS启动及相关逻辑进行初始化操作进行分析,接下来我们通过代码来看看具体的操作逻辑。相关代码如下:

// SystemServer//...// 定义系统服务的成员变量private ActivityManagerService mActivityManagerService;private SystemServiceManager mSystemServiceManager;private PowerManagerService mPowerManagerService;private PackageManagerService mPackageManagerService;//...private void startBootstrapServices() {// 启动引导服务,这些服务在系统启动的早期阶段被启动// ...// 关键点1:启动ActivityManagerService服务mActivityManagerService = mSystemServiceManager.startService(ActivityManagerService.Lifecycle.class).getService();// 关键点2:为ActivityManagerService设置系统服务管理器mActivityManagerService.setSystemServiceManager(mSystemServiceManager);// 启动PowerManagerService服务mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);// 关键点3:初始化电源管理mActivityManagerService.initPowerManagement();// 关键点4:将当前进程设置为系统进程mActivityManagerService.setSystemProcess();// ...}//...private void startCoreServices() {// 启动核心服务// ...// 为ActivityManagerService设置UsageStatsManager服务mActivityManagerService.setUsageStatsManager(LocalServices.getService(UsageStatsManagerInternal.class));// ...}//...private void startOtherServices() {// 启动其他服务// ...WindowManagerService wm = null;// ...// 关键点5:安装系统提供的ContentProvidersmActivityManagerService.installSystemProviders();// 初始化看门狗监控watchdog.init(context, mActivityManagerService);// 创建WindowManagerService服务wm = WindowManagerService.main(context, inputManager,mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,mActivityManagerService);// 关键点6:为ActivityManagerService设置WindowManagermActivityManagerService.setWindowManager(wm);final boolean safeMode = wm.detectSafeMode();if (safeMode) {// 检测安全模式// 进入安全模式mActivityManagerService.enterSafeMode();// 禁用JIT编译VMRuntime.getRuntime().disableJitCompilation();} else {// 启用JIT编译VMRuntime.getRuntime().startJitCompilation();}if (safeMode) {// 如果处于安全模式,显示安全模式覆盖层mActivityManagerService.showSafeModeOverlay();}// ...// 通知PowerManagerService系统已准备好mPowerManagerService.systemReady(mActivityManagerService.getAppOpsService());// 关键点7:当ActivityManagerService准备好后执行的操作mActivityManagerService.systemReady(new Runnable() {@Overridepublic void run() {// 启动系统服务管理器的下一个启动阶段mSystemServiceManager.startBootPhase(SystemService.PHASE_ACTIVITY_MANAGER_READY);try {//关键点8:开始监控本地崩溃mActivityManagerService.startObservingNativeCrashes();} catch (Throwable e) {// 报告错误reportWtf("observing native crashes", e);}// ...WebViewFactory.prepareWebViewInSystemServer();try {// 尝试启动系统用户界面startSystemUi(context);} catch (Throwable e) {reportWtf("starting System UI", e);}try {//尝试通知挂载服务系统已准备就绪if (mountServiceF != null) mountServiceF.systemReady();} catch (Throwable e) {reportWtf("making Mount Service ready", e);}//...//其他各种服务准备就绪//...}});// ...}

以上代码通过关键点的标注,共列出了8个重要的调用,并对这些调用进行了简单的描述。整理如下:

  • 关键点1:启动ActivityManagerService服务。
  • 关键点2:为ActivityManagerService设置系统服务管理器。
  • 关键点3:初始化电源管理。
  • 关键点4:将当前进程设置为系统进程。
  • 关键点5:安装系统提供的ContentProviders。
  • 关键点6:为ActivityManagerService设置WindowManager。
  • 关键点7:当ActivityManagerService准备好后执行的操作。
  • 关键点8:开始监控本地崩溃。

接下来针对这8个关键点进行详细的解读。上一篇关注关键点1-4部分,本章节主要关注关键点5-8部分。

5 安装系统提供的ContentProviders

这里从代码

mActivityManagerService.installSystemProviders();

开始分析,对应代码实现如下:

//ActivityManagerServicepublic final void installSystemProviders() {List<ProviderInfo> providers;synchronized (this) {// 获取系统进程的记录// 这个进程是Android系统框架的核心部分,包含了许多系统服务和系统应用ProcessRecord app = mProcessNames.get("system", Process.SYSTEM_UID);// 生成系统应用的ContentProvider列表// 这些 ContentProvider 属于系统应用包,是系统框架的一部分。providers = generateApplicationProvidersLocked(app);if (providers != null) {// 遍历列表,检查每个Provider是否属于系统应用for (int i = providers.size() - 1; i >= 0; i--) {ProviderInfo pi = providers.get(i);// 检查Provider是否设置了FLAG_SYSTEM标志if ((pi.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {// 如果没有设置FLAG_SYSTEM标志,记录警告日志并从列表中移除providers.remove(i);}}}}// 如果最终的Provider列表不为空,则安装这些Providerif (providers != null) {mSystemThread.installSystemProviders(providers);}// 创建一个核心设置观察者,用于监听系统设置的变化mCoreSettingsObserver = new CoreSettingsObserver(this);}

installSystemProviders方法的主要作用是安装系统应用的ContentProvider。这些ContentProvider是系统正常运行所必需的,它们提供了对系统数据的访问和管理。通过同步代码块和检查FLAG_SYSTEM标志,确保只有属于系统应用的ContentProvider会被安装。此外,该方法还负责创建系统设置观察者,用于监控系统设置的变化。这个过程是系统启动和初始化阶段的关键部分,确保了系统应用能够正常提供服务。

installSystemProviders方法在Android的ActivityManagerService(AMS)中执行,其主要目的是初始化和注册系统级别的ContentProvider。那么为什么要这么做呢?总结如下:

  • 系统数据管理:系统级的ContentProvider提供了对核心系统数据的访问,如联系人、日历事件、系统设置等。这些数据需要被多个应用程序共享和访问。
  • 服务注册:通过installSystemProviders方法,系统可以将这些关键的ContentProvider注册到服务管理器(ServiceManager),使得其他应用和系统组件能够发现并与之通信。
  • 安全性:系统级的ContentProvider可以实施严格的安全策略,包括权限检查,确保只有授权的应用可以访问敏感数据。
  • 性能优化:预先加载和初始化这些ContentProvider有助于提高系统性能,因为它们在系统启动早期就已经准备就绪,减少了应用运行时的等待时间。
  • 跨应用通信:ContentProvider是Android中实现跨应用通信的重要机制。它们允许应用之间共享数据,而无需应用直接相互引用。
  • 系统服务支持:许多系统服务依赖于ContentProvider来存储和检索数据。这些服务可能包括设备策略管理器、备份服务等。
  • 一致性和可靠性:确保所有必要的系统ContentProvider都在系统启动时正确初始化,有助于提高整个系统的一致性和可靠性。
  • 用户体验:快速响应用户操作和提供流畅的用户体验需要系统服务和应用能够及时访问所需的数据。
  • 系统监控和管理:一些系统ContentProvider提供了系统运行状况和性能数据的访问,有助于系统监控和管理。
  • 初始化和配置:在系统启动过程中,installSystemProviders方法确保了所有必要的系统级ContentProvider被正确配置和初始化。

总结来说,installSystemProviders方法对于建立一个功能齐全、安全、高效的Android系统至关重要。它确保了系统应用和系统服务能够访问和管理核心数据,同时为应用提供了必要的数据共享机制。

最后,这里详细解读下涉及到的generateApplicationProvidersLocked方法,代码实现如下:

//ActivityManagerServiceprivate final List<ProviderInfo> generateApplicationProvidersLocked(ProcessRecord app) {List<ProviderInfo> providers = null;try {// 查询该应用进程的ContentProviderproviders = AppGlobals.getPackageManager().queryContentProviders(app.processName, app.uid,STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);} catch (RemoteException ex) {}int userId = app.userId;if (providers != null) {int N = providers.size();app.pubProviders.ensureCapacity(N + app.pubProviders.size());for (int i=0; i<N; i++) {ProviderInfo cpi = providers.get(i);boolean singleton = isSingleton(cpi.processName, cpi.applicationInfo, cpi.name, cpi.flags);// 单例ContentProvider且不是默认用户,移除if (singleton && UserHandle.getUserId(app.uid) != 0) {providers.remove(i);N--;i--;continue;}// 创建ComponentNameComponentName comp = new ComponentName(cpi.packageName, cpi.name);// 尝试获取已有的ContentProviderRecordContentProviderRecord cpr = mProviderMap.getProviderByClass(comp, userId);if (cpr == null) {// 如果没有找到,创建新的ContentProviderRecordcpr = new ContentProviderRecord(this, cpi, app.info, comp, singleton);mProviderMap.putProviderByClass(comp, cpr);}app.pubProviders.put(cpi.name, cpr);// 如果ContentProvider不是多进程的,添加到应用包列表if (!cpi.multiprocess || !"android".equals(cpi.packageName)) {app.addPackage(cpi.applicationInfo.packageName, cpi.applicationInfo.versionCode, mProcessStats);}ensurePackageDexOpt(cpi.applicationInfo.packageName);}}return providers;}

generateApplicationProvidersLocked方法的目的是初始化和注册系统应用的ContentProvider,确保它们可以为整个系统提供必要的数据访问服务。具体来说,该方法会查询系统应用包中的所有 ContentProvider,包括:

  • 系统设置 ContentProvider:如 SettingsProvider,提供了对系统设置的访问。
  • 账户 ContentProvider:如 AccountsProvider,管理账户信息。
  • 联系人 ContentProvider:如 ContactsProvider,管理联系人数据。
  • 其他系统 ContentProvider:任何其他包含在系统应用包中的 ContentProvider。

这些 ContentProvider 通常位于系统应用的包名(如 android)下,并且对于系统的正常运行和应用的数据访问至关重要。

6 为ActivityManagerService设置WindowManager

这里从代码

mActivityManagerService.setWindowManager(wm);

开始分析,对应代码实现如下:

//ActivityManagerServicepublic void setWindowManager(WindowManagerService wm) {mWindowManager = wm;mStackSupervisor.setWindowManager(wm);}

这里的设计很简单,但我们要了解这样设计背后的意义:

  • 协调窗口和活动管理:通过设置窗口管理器的引用,AMS和ActivityStackSupervisor可以与窗口管理器进行交互,确保活动和窗口的正确创建和显示。
  • 提供窗口上下文:WindowManagerService提供了必要的上下文和工具,使AMS能够为应用程序创建和管理窗口。
  • 支持动态界面更新:在Android系统中,窗口和活动经常需要动态更新。例如,当用户切换应用程序或启动新活动时,窗口管理器负责更新用户界面。
  • 确保系统组件一致性:setWindowManager方法确保AMS和ActivityStackSupervisor使用的是同一个WindowManagerService实例,这有助于保持系统组件之间的一致性和同步。

总之,setWindowManager方法在AMS中至关重要,因为它确保了活动管理器(AMS)和活动堆栈监管者(ActivityStackSupervisor)能够与窗口管理器(WindowManagerService)进行通信和协调。这种设置对于正确管理应用程序的窗口和活动至关重要,特别是在处理复杂的用户界面场景时。

这里详细解读下涉及到的mStackSupervisor.setWindowManager方法,代码实现如下:

//ActivityStackSupervisorvoid setWindowManager(WindowManagerService wm) {synchronized (mService) {// 设置ActivityStackSupervisor使用的窗口管理器mWindowManager = wm;// 获取显示管理服务mDisplayManager =(DisplayManager)mService.mContext.getSystemService(Context.DISPLAY_SERVICE);// 注册显示管理服务的监听器mDisplayManager.registerDisplayListener(this, null);// 获取所有显示的数组Display[] displays = mDisplayManager.getDisplays();// 遍历所有显示for (int displayNdx = displays.length - 1; displayNdx >= 0; --displayNdx) {// 获取显示IDfinal int displayId = displays[displayNdx].getDisplayId();// 创建ActivityDisplay对象ActivityDisplay activityDisplay = new ActivityDisplay(displayId);//...// 将ActivityDisplay对象添加到映射中mActivityDisplays.put(displayId, activityDisplay);}// 在默认显示上创建主堆栈createStackOnDisplay(HOME_STACK_ID, Display.DEFAULT_DISPLAY);// 设置主堆栈、焦点堆栈和最后焦点的堆栈为刚创建的主堆栈mHomeStack = mFocusedStack = mLastFocusedStack = getStack(HOME_STACK_ID);// 获取输入管理服务的内部服务mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);// 初始化LeanbackOnlyDevice标志,现在可以获得有效的PackageManager引用mLeanbackOnlyDevice = isLeanbackOnlyDevice();}}

mStackSupervisor.setWindowManager方法的主要作用是设置窗口管理器并进行一系列初始化工作,包括获取显示管理服务、注册显示监听器、创建显示相关的数据结构、初始化主堆栈和焦点堆栈,以及获取输入管理服务。这些步骤确保了ActivityStackSupervisor能够正确管理活动的显示和堆栈,无论设备有多少个显示,以及是否为特定模式(如Leanback模式)的设备。

7 当ActivityManagerService准备好后执行的操作

这里从代码

//SystemServerprivate void startOtherServices() {// 启动其他服务//...mActivityManagerService.systemReady(new Runnable() {@Overridepublic void run() {//...}});//...}

开始分析,因ActivityManagerService.systemReady的代码较长,因此这里分成3个阶段进行解读。具体如下。

7.1 systemReady第一阶段(主要以升级相关逻辑为主)

systemReady第一阶段代码实现如下:

//ActivityManagerService
// 该方法在系统启动时调用,用于执行系统服务的初始化public void systemReady(final Runnable goingCallback) {//第一阶段synchronized(this) {// 检查系统是否已经准备好,如果已经准备好,运行传入的回调并返回if (mSystemReady) {if (goingCallback != null) {goingCallback.run();}return;}// 更新当前的用户配置文件信息,这些信息用于安全检查updateCurrentProfileIdsLocked();// 如果最近任务列表为空,则尝试从持久化存储中恢复最近任务if (mRecentTasks == null) {mRecentTasks = mTaskPersister.restoreTasksLocked();// 如果恢复了最近任务,创建对应的任务堆栈if (!mRecentTasks.isEmpty()) {mStackSupervisor.createStackForRestoredTaskHistory(mRecentTasks);}// 清理最近任务列表,移除不再需要的任务cleanupRecentTasksLocked(UserHandle.USER_ALL);// 开始持久化保存任务列表mTaskPersister.startPersisting();}// 检查是否有系统更新的广播接收器需要运行if (!mDidUpdate) {// 如果已经在等待更新,那么直接返回if (mWaitingUpdate) {return;}// 创建一个列表来记录完成的广播接收器final ArrayList<ComponentName> doneReceivers = new ArrayList<ComponentName>();// 设置正在等待更新的标志mWaitingUpdate = true;// 调用deliverPreBootCompleted来执行系统更新相关的广播接收器deliverPreBootCompleted(new Runnable() {public void run() {// 同步代码块,确保线程安全synchronized (ActivityManagerService.this) {// 设置系统更新完成的标志mDidUpdate = true;}// 记录完成的广播接收器writeLastDonePreBootReceivers(doneReceivers);// 显示系统更新完成的消息showBootMessage(mContext.getText(R.string.android_upgrading_complete),false);// 递归调用systemReady,继续执行系统启动的下一阶段systemReady(goingCallback);}}, doneReceivers, UserHandle.USER_OWNER);// 如果还在等待更新,那么返回if (mWaitingUpdate) {return;}// 设置系统更新完成的标志mDidUpdate = true;}// 通知AppOpsService系统已经准备好mAppOpsService.systemReady();// 设置系统已经准备好的标志mSystemReady = true;}//...}

systemReady方法的第一阶段主要负责初始化系统的关键部分,包括更新用户配置文件信息、恢复最近任务、执行系统更新广播接收器等。这些步骤确保了系统在启动过程中能够正确地恢复状态,为用户使用做好准备。

7.2 systemReady第二阶段(以kill掉AMS之前启动的应用进程为主)

systemReady第二阶段代码实现如下:

//ActivityManagerService
// 该方法在系统启动时调用,用于执行系统服务的初始化public void systemReady(final Runnable goingCallback) {//...// 第二阶段:清理不应该在启动过程中运行的进程ArrayList<ProcessRecord> procsToKill = null;synchronized(mPidsSelfLocked) {for (int i = mPidsSelfLocked.size()-1; i >= 0; i--) {ProcessRecord proc = mPidsSelfLocked.valueAt(i);// 检查进程是否允许在启动过程中运行if (!isAllowedWhileBooting(proc.info)){if (procsToKill == null) {procsToKill = new ArrayList<ProcessRecord>();}procsToKill.add(proc);}}}// 同步代码块,确保线程安全synchronized(this) {// 清理更新进程if (procsToKill != null) {for (int i = procsToKill.size()-1; i >= 0; i--) {ProcessRecord proc = procsToKill.get(i);Slog.i(TAG, "Removing system update proc: " + proc);// 移除不应该在启动过程中运行的进程removeProcessLocked(proc, true, false, "system update done");}}// 标记为不再清理更新进程,准备启动真正的进程mProcessesReady = true;}// 同步代码块,确保线程安全synchronized(this) {// 处理工厂测试模式if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL) {ResolveInfo ri = mContext.getPackageManager().resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),STOCK_PM_FLAGS);CharSequence errorMsg = null;if (ri != null) {ActivityInfo ai = ri.activityInfo;ApplicationInfo app = ai.applicationInfo;if ((app.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {mTopAction = Intent.ACTION_FACTORY_TEST;mTopData = null;mTopComponent = new ComponentName(app.packageName, ai.name);} else {errorMsg = mContext.getResources().getText(com.android.internal.R.string.factorytest_not_system);}} else {errorMsg = mContext.getResources().getText(com.android.internal.R.string.factorytest_no_action);}if (errorMsg != null) {mTopAction = null;mTopData = null;mTopComponent = null;Message msg = Message.obtain();msg.what = SHOW_FACTORY_ERROR_MSG;msg.getData().putCharSequence("msg", errorMsg);mHandler.sendMessage(msg);}}}// 检索系统设置retrieveSettings();// 加载系统资源loadResourcesOnSystemReady();// 同步代码块,确保线程安全synchronized (this) {// 读取授权的URI权限readGrantedUriPermissionsLocked();}// 如果有传入的回调,运行它if (goingCallback != null) goingCallback.run();// 通知电池统计服务用户开始运行mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_USER_RUNNING_START,Integer.toString(mCurrentUserId), mCurrentUserId);// 通知电池统计服务用户进入前台mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_USER_FOREGROUND_START,Integer.toString(mCurrentUserId), mCurrentUserId);// 启动用户会话mSystemServiceManager.startUser(mCurrentUserId);//...

systemReady方法的第二阶段主要负责清理更新进程、记录系统就绪事件、应用设置、加载资源以及启动用户会话。这些步骤确保了系统在启动完成后能够正常运行应用程序,并为用户提供服务。

7.3 systemReady第三阶段(以启动系统应用、发广播、恢复前台活动为主)

systemReady第三阶段代码实现如下:

//ActivityManagerService
// 该方法在系统启动时调用,用于执行系统服务的初始化public void systemReady(final Runnable goingCallback) {//...// 第三阶段:启动应用程序和发送用户启动广播synchronized (this) {// 如果不是工厂测试模式if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) {try {// 获取所有持久应用的列表List apps = AppGlobals.getPackageManager().getPersistentApplications(STOCK_PM_FLAGS);if (apps != null) {int N = apps.size();for (int i = 0; i < N; i++) {ApplicationInfo info = (ApplicationInfo)apps.get(i);// 添加非"android"包的应用到系统中if (info != null && !info.packageName.equals("android")) {addAppLocked(info, false, null /* ABI override */);}}}} catch (RemoteException ex) {// 由于PackageManagerService在同一个进程中,这个异常不会发生}}// 启动初始活动mBooting = true;startHomeActivityLocked(mCurrentUserId);try {// 检查是否有系统UID错误if (AppGlobals.getPackageManager().hasSystemUidErrors()) {Message msg = Message.obtain();msg.what = SHOW_UID_ERROR_MSG;mHandler.sendMessage(msg);}} catch (RemoteException e) {// 忽略异常}// 清除调用者身份,以便以系统身份发送广播long ident = Binder.clearCallingIdentity();try {// 发送ACTION_USER_STARTED广播,通知所有用户相关的应用Intent intent = new Intent(Intent.ACTION_USER_STARTED);intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY| Intent.FLAG_RECEIVER_FOREGROUND);intent.putExtra(Intent.EXTRA_USER_HANDLE, mCurrentUserId);broadcastIntentLocked(null, null, intent,null, null, 0, null, null, null, AppOpsManager.OP_NONE,false, false, MY_PID, Process.SYSTEM_UID, mCurrentUserId);// 发送ACTION_USER_STARTING广播,通知用户启动intent = new Intent(Intent.ACTION_USER_STARTING);intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);intent.putExtra(Intent.EXTRA_USER_HANDLE, mCurrentUserId);broadcastIntentLocked(null, null, intent,null, new IIntentReceiver.Stub() {@Overridepublic void performReceive(Intent intent, int resultCode, String data,Bundle extras, boolean ordered, boolean sticky, int sendingUser)throws RemoteException {}}, 0, null, null,INTERACT_ACROSS_USERS, AppOpsManager.OP_NONE,true, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);} catch (Throwable t) {Slog.wtf(TAG, "Failed sending first user broadcasts", t);} finally {// 恢复调用者身份Binder.restoreCallingIdentity(ident);}// 恢复前台活动mStackSupervisor.resumeTopActivitiesLocked();// 发送用户切换广播sendUserSwitchBroadcastsLocked(-1, mCurrentUserId);}}

systemReady方法的第三阶段主要负责处理工厂测试模式、启动系统的应用、发送用户启动广播、恢复前台活动等。这些步骤确保了系统在启动完成后能够正常运行应用程序,并为用户提供服务。

8 开始监控本地崩溃

这里从代码

mActivityManagerService.startObservingNativeCrashes();

开始分析,对应代码实现如下:

//ActivityManagerServicepublic void startObservingNativeCrashes() {final NativeCrashListener ncl = new NativeCrashListener(this);ncl.start();}

NativeCrashListener 是继承Thread的,实际上就是开启了一个线程。

8.1 解读 NativeCrashListener线程逻辑

NativeCrashListener 线程的实现是run方法,该部分代码忽略了异常处理和日志的打印的逻辑,关键代码如下:

// NativeCrashListenerpublic void run() {// 用于接收信号的字节数组final byte[] ackSignal = new byte[1];// 删除已存在的socket文件{File socketFile = new File(DEBUGGERD_SOCKET_PATH);if (socketFile.exists()) {socketFile.delete();}}try {// 创建一个UNIX domain socketFileDescriptor serverFd = Os.socket(AF_UNIX, SOCK_STREAM, 0);final InetUnixAddress sockAddr = new InetUnixAddress(DEBUGGERD_SOCKET_PATH);// 绑定socket到指定路径Os.bind(serverFd, sockAddr, 0);// 监听socket连接Os.listen(serverFd, 1);// 无限循环等待debuggerd的连接while (true) {InetSocketAddress peer = new InetSocketAddress();FileDescriptor peerFd = null;try {// 接受连接peerFd = Os.accept(serverFd, peer);// 检查连接的凭证,只允许超级用户连接StructUcred credentials =Os.getsockoptUcred(peerFd, SOL_SOCKET, SO_PEERCRED);if (credentials.uid == 0) {// 消费崩溃数据consumeNativeCrashData(peerFd);}} finally {// 无论处理过程中是否发生异常,都要发送确认信号给debuggerdif (peerFd != null) {try {Os.write(peerFd, ackSignal, 0, 1);} finally {// 关闭socket连接Os.close(peerFd);}}}}}//...}

NativeCrashListener的run方法主要负责监听和处理由debuggerd发送的native崩溃信号。它通过创建一个socket服务器,等待debuggerd的连接,并在连接建立后处理崩溃数据。这个过程确保了系统能够及时响应native崩溃,从而提高系统的稳定性。

接下来我们来看看对于这些崩溃数据是如何处理的,即consumeNativeCrashData的代码实现,具体如下:

// NativeCrashListener// 处理崩溃的native进程发送的数据void consumeNativeCrashData(FileDescriptor fd) {// 创建一个字节缓冲区用于读取数据final byte[] buf = new byte[4096];// 创建一个字节输出流用于收集崩溃数据final ByteArrayOutputStream os = new ByteArrayOutputStream(4096);try {// 设置读取和写入的超时时间StructTimeval timeout = StructTimeval.fromMillis(SOCKET_TIMEOUT_MILLIS);Os.setsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO, timeout);Os.setsockoptTimeval(fd, SOL_SOCKET, SO_SNDTIMEO, timeout);// 首先读取崩溃的进程ID和信号号int headerBytes = readExactly(fd, buf, 0, 8);int pid = unpackInt(buf, 0);  // 进程IDint signal = unpackInt(buf, 4);  // 信号号if (pid > 0) {// 根据进程ID获取崩溃进程的记录final ProcessRecord pr;synchronized (mAm.mPidsSelfLocked) {pr = mAm.mPidsSelfLocked.get(pid);}if (pr != null) {// 持久进程不进行崩溃报告if (pr.persistent) {return;}int bytes;// 循环读取崩溃数据直到读取完毕do {bytes = Os.read(fd, buf, 0, buf.length);if (bytes > 0) {if (buf[bytes-1] == 0) {os.write(buf, 0, bytes-1);break;}os.write(buf, 0, bytes);}} while (bytes > 0);// 标记进程为正在崩溃状态synchronized (mAm) {pr.crashing = true;pr.forceCrashReport = true;}// 将崩溃报告转换为字符串final String reportString = new String(os.toByteArray(), "UTF-8");// 创建一个崩溃报告线程(new NativeCrashReporter(pr, signal, reportString)).start();}}}// 异常处理略...}

consumeNativeCrashData方法用于处理崩溃的native进程发送的数据。它读取崩溃数据,生成崩溃报告,并启动一个线程来处理这个报告。对应的处理报告的线程为NativeCrashReporter,它的run方法代码实现如下:

//NativeCrashListenerclass NativeCrashReporter extends Thread {//...@Overridepublic void run() {try {// 创建CrashInfo对象,封装崩溃信息CrashInfo ci = new CrashInfo();ci.exceptionClassName = "Native crash";ci.exceptionMessage = Os.strsignal(mSignal);ci.throwFileName = "unknown";ci.throwClassName = "unknown";ci.throwMethodName = "unknown";ci.stackTrace = mCrashReport;// 调用AMS的handleApplicationCrashInner方法处理崩溃mAm.handleApplicationCrashInner("native_crash", mApp, mApp.processName, ci);}//...}}

继续分析AMS的handleApplicationCrashInner方法,代码实现如下:

//ActivityManagerService// 处理应用程序崩溃的方法void handleApplicationCrashInner(String eventType, ProcessRecord r, String processName,ApplicationErrorReport.CrashInfo crashInfo) {// 将崩溃事件记录到系统事件日志中,包括崩溃的进程ID、用户ID、进程名称// 、进程标志、异常类名、异常信息、发生异常的文件名和行号等信息EventLog.writeEvent(EventLogTags.AM_CRASH, Binder.getCallingPid(),UserHandle.getUserId(Binder.getCallingUid()), processName,r == null ? -1 : r.info.flags,crashInfo.exceptionClassName,crashInfo.exceptionMessage,crashInfo.throwFileName,crashInfo.throwLineNumber);// 将崩溃的错误信息添加到DropBox中// DropBox是一个系统服务,用于收集和存储系统和应用程序的错误报告,供后续分析和调试使用addErrorToDropBox(eventType, r, processName, null, null, null, null, null, crashInfo);// 执行崩溃处理逻辑,包括重启应用程序、通知用户、记录崩溃信息等crashApplication(r, crashInfo);}

handleApplicationCrashInner方法是一个关键的系统方法,用于处理应用程序崩溃事件。它通过记录崩溃信息、添加错误报告到DropBox以及执行崩溃处理,确保了系统能够适当地响应崩溃事件,同时为后续的错误分析和调试提供了必要的信息。这部分至此就不再继续分析了,再往后就是一堆崩溃信息的详细处理了,我们只需要了解到最终崩溃的处理是在AMS中处理即可。其他的可根据自己的需要继续深入分析。

8.2 关于崩溃处理的理解总结

当应用程序发生崩溃时,系统会通过一系列机制来处理崩溃并生成崩溃报告。以下是整个过程的概述:

  1. 应用崩溃:当应用程序发生崩溃(通常是由于native代码异常,如段错误、总线错误等)时,系统会捕获到这个崩溃信号。
  2. 生成崩溃报告:系统服务debuggerd会生成崩溃报告。这个报告包含了崩溃时的堆栈跟踪、寄存器状态、运行的线程等信息。
  3. 建立socket连接:debuggerd会尝试建立一个socket连接,将崩溃报告发送给ActivityManagerService(AMS)或其他监听崩溃的服务。
  4. 监听崩溃:在AMS中,NativeCrashListener线程会监听崩溃。它会创建一个socket服务器,并等待debuggerd的连接。
  5. 接收崩溃报告:当debuggerd与AMS的socket服务器建立连接后,AMS的NativeCrashListener线程会接收到崩溃报告。
  6. 处理崩溃:AMS会处理崩溃报告,这可能包括记录崩溃信息、通知开发者、重启应用程序或执行其他错误恢复操作。
  7. 发送确认信号:AMS会向debuggerd发送一个确认信号,表明崩溃报告已经收到。
  8. 关闭socket连接:处理完崩溃报告后,AMS会关闭socket连接。
  9. 用户通知:如果应用程序崩溃导致用户体验受到影响,系统可能会向用户显示一个崩溃通知,让用户知道应用程序发生了问题。
  10. 崩溃转储(可选):在某些情况下,系统可能会将崩溃信息转储到磁盘上的一个文件中,以供后续分析。
  11. 重启应用程序:如果可能,系统会尝试重启崩溃的应用程序,为用户提供尽可能无缝的体验。

这个过程确保了应用程序崩溃时,系统能够捕获必要的信息,并采取适当的措施来恢复或通知用户。通过这种方式,系统能够提高应用程序的稳定性和用户体验。


http://www.ppmy.cn/devtools/122367.html

相关文章

【FPGA开发】Xilinx FPGA差分输入时钟的使用方法

正文 以前在使用ZYNQ的领航者ZYNQ7020进行FPGA学习时&#xff0c;它们使用的单端50M的输入时钟&#xff0c;在verlog代码编写上比较简单&#xff0c;而现在使用Alinx的AXU3EG开发板时&#xff0c;发现它使用的是200M的差分输入时钟&#xff0c;哪这个时候&#xff0c;输入时钟要…

【分布式微服务云原生】Redis:如何实现高性能与高可用性的终极指南

Redis&#xff1a;如何实现高性能与高可用性的终极指南 摘要 Redis&#xff0c;作为当今最受欢迎的内存数据结构存储系统&#xff0c;以其卓越的性能和高可用性著称。本文将深入探讨Redis背后的底层原理&#xff0c;分析其如何通过内存存储、单线程模型、高效的数据结构、持久…

《RabbitMQ篇》基本概念介绍

MQ功能 解耦 MQ允许不同系统或组件之间松散耦合。发送者和接收者不需要直接连接&#xff0c;从而提高了系统的灵活性和可维护性。异步处理 使用MQ可以实现异步消息传递&#xff0c;发送者可以将消息放入队列后立即返回&#xff0c;不必等待接收者处理。这提高了系统的响应速度…

CSS实现服务卡片

CSS实现服务卡片 效果展示 CSS 知识点 回顾整体CSS知识点灵活运用CSS知识点 页面整体布局 <div class"container"><div class"card"><div class"box"><div class"icon"><ion-icon name"color-pal…

【算法】DFS 系列之 穷举/暴搜/深搜/回溯/剪枝(下篇)

【ps】本篇有 8 道 leetcode OJ。 目录 一、算法简介 二、相关例题 1&#xff09;字母大小写全排列 .1- 题目解析 .2- 代码编写 2&#xff09;优美的排列 .1- 题目解析 .2- 代码编写 3&#xff09;N 皇后 .1- 题目解析 .2- 代码编写 4&#xff09;有效的数独 .1-…

计算机网络:计算机网络概述 —— 初识计算机网络

文章目录 计算机网络组成部分网络架构协议与标准网络设备网络类型作用实际应用案例 计算机网络 计算机网络是指将多台计算机通过通信设备和通信链路连接起来&#xff0c;以实现数据和信息的交换和共享的技术和系统。它是现代信息社会的基础设施之一&#xff0c;也是互联网的基…

国庆节快乐前端(HTML+CSS+JavaScript+BootStrap.min.css)

一、效果展示 二、制作缘由 最近&#xff0c;到了国庆节&#xff0c;自己呆在学校当守校人&#xff0c;太无聊了&#xff0c;顺便做一个小demo帮祖国目前庆生&#xff01;&#xff01;&#xff01; 三、项目目录结构 四、准备工作 (1)新建好对应的文件目录 为了方便&#xff…

SVN版本回退

SVN 版本回退三种方法&#xff1a; Update item to this version 假设我们的项目文件一共有8个版本&#xff0c;它版本号分别是1&#xff0c;2&#xff0c;3&#xff0c;4&#xff0c;5&#xff0c;6&#xff0c;7&#xff0c;8。 这个选项的作用是将文件版本更新到对应所选的…