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

该系列文章总纲链接:专题总纲目录 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.mzph.cn/pingmian/55595.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

18734 拓扑排序

### 思路 1. **建模问题**&#xff1a;将课程和依赖关系建模为有向图&#xff0c;其中课程是节点&#xff0c;依赖关系是有向边。 2. **选择算法**&#xff1a;使用拓扑排序算法来确定课程的学习顺序。由于需要确保输出唯一性&#xff0c;同等条件下编号小的课程排在前面&…

将自己写好的项目部署在自己的云服务器上

准备工作 这里呢我要下载的终端软件是Xshell 如图&#xff1a; 自己准备好服务器&#xff0c;我这里的是阿里云的服务器&#xff0c; 如图&#xff1a; 这两个准备好之后呢&#xff0c;然后对我们的项目进行打包。 如图&#xff1a; 这里双击打包就行了。 找到自己打成jar包…

桌面时钟哪个好?今年最热门的桌面时钟主题

桌面时钟可以让我们更方便的知道当前的时间&#xff0c;日期&#xff0c;因为它非常直观的展示在桌面上&#xff0c;当我们需要看时间的时候&#xff0c;一眼就可以看到了&#xff0c;这是一个非常便捷的功能&#xff0c;我们一起来看下《芝麻时钟》&#xff08;下载地址&#…

停车位识别数据集 图片数量12416张YOLO,xml和txt标签都有; 2类类别:space-empty,space-occupied;

YOLO停车位识别 图片数量12416张&#xff0c;xml和txt标签都有&#xff1b; 2类类别&#xff1a;space-empty&#xff0c;space-occupied&#xff1b; 用于yolo&#xff0c;Python&#xff0c;目标检测&#xff0c;机器学习&#xff0c;人工智能&#xff0c;深度学习&#xff0…

vSAN06:ESA与OSA对比、ESA安装、新架构、工作方式、自动策略管理、原生快照、数据压缩、故障处理

目录 vSAN ESAvSAN ESA 安装ESA新架构ESA工作方式ESA自动策略管理自适应RAID5策略 原生快照支持数据压缩的改进ESA故障处理 vSAN ESA vSAN ESA 安装 流程和OSA完全一致&#xff0c;但要注意要勾选启用vSAN ESA ESA和OSA的底层架构不一样&#xff0c;但是UI上是一致的。 生产环…

【2024最新】华为HCIE认证考试流程

HCIE是华为认证体系中最高级别的ICT技术认证&#xff0c;表示通过认证的人具有ICT领域专业知识和丰富实践经验。 HCIE认证方向&#xff1a;最高认证级别HCIE的技术方向有13个 下面以HCIE-Datacom为例给大家介绍一下&#xff1a; HCIE-Datacom认证考试流程&#xff1a; 1.笔试…

Hive3.x版本调优总结

文章目录 第 1 章 Explain 查看执行计划&#xff08;重点&#xff09;1.1 创建测试用表1&#xff09;建大表、小表和 JOIN 后表的语句2&#xff09;分别向大表和小表中导入数据 1.2 基本语法1.3 案例实操 第 2 章 Hive 建表优化2.1 分区表2.1.1 分区表基本操作2.1.2 二级分区2.…

vmvare虚拟机centos 忘记超级管理员密码怎么办?

vmvare虚拟机centos 忘记超级管理员密码怎么办?如何重置密码呢? 一、前置操作 重启vmvare虚拟机的过程中,长按住Shift键 选择第一个的时候,按下按键 e 进入编辑状态。 然后就会进入到类似这个界面中。 在下方界面 添加 init=/bin/sh,然后按下Ctrl+x进行保存退出。 init=/bi…

本田汽车投资SiLC Technologies:携手共促自动驾驶技术新飞跃

SiLC Technologies获本田汽车投资:加速自动驾驶技术革新 近日,硅谷光子学初创公司SiLC Technologies宣布获得本田汽车的投资,这一合作标志着双方将共同推进自动驾驶技术领域的革新与发展。本田此次投资不仅体现了对SiLC Technologies技术实力的认可,也彰显了本田在自动驾驶…

昇思学习打卡营第31天|深度解密 CycleGAN 图像风格迁移:从草图到线稿的无缝转化

1. 简介 图像风格迁移是计算机视觉领域中的一个热门研究方向&#xff0c;其中 CycleGAN (循环对抗生成网络) 在无监督领域取得了显著的突破。与传统需要成对训练数据的模型如 Pix2Pix 不同&#xff0c;CycleGAN 不需要严格的成对数据&#xff0c;只需两类图片域数据&#xff0c…

IDEA:增加类注释模板和方法注释模板

文章目录 概要配置类注释模板配置方法模版 概要 配置类注释和方法注释 配置类注释模板 点击setting->Editor->File and Code Templates&#xff0c;然后找到Class&#xff0c;如下图&#xff1a; 注意勾掉Reformat according to style&#xff0c;否则会格式化。 注…

动态规划算法专题(四):子串、子数组系列

目录 1、最大子数组和 1.1 算法原理 1.2 算法代码 2、环形子数组的最大和 2.1 算法原理 2.2 算法代码 3、乘积最大子数组 3.1 算法原理 3.2 算法代码 4、乘积为正数的最长子数组长度 4.1 算法原理 4.2 算法代码 5、等差数列划分 5.1 算法原理 5.2 算法代码 6、…

COSPLAY大赛静态HTML网页模板源码

源码名称&#xff1a;COSPLAY大赛静态HTML网页模板 源码介绍&#xff1a;一款cosplay大赛HTML网页模板源码&#xff0c;过往参赛选手会自动从腾讯大赛获取&#xff0c;可用于cosplay大赛&#xff0c;漫展等。 需求环境&#xff1a;H5 下载地址&#xff1a; https://www.5188…

k8s的控制节点不能访问node节点容器的ip地址

master控制node服务器添加容器后,访问不了该node服务器容器的ip,只能在node服务器访问 排查后发现是k8s的master服务器和node节点的网址网段和k8s初始化时提示的ip网段不一致 我之前是192.168.137.50, 实际上master主机期望的是192.168.1.50 解决方案: 1.删除服务器后重建ma…

【api连接ChatGPT的最简单方式】

通过api连接ChatGPT的最简单方式 建立client 其中base_url为代理&#xff0c;若连接官网可省略&#xff1b;配置环境变量 from openai import OpenAI client OpenAI(base_url"https://api.chatanywhere.tech/v1" )或给出api和base_url client OpenAI(api_key&…

Redis:string类型

Redis&#xff1a;string类型 string命令设置与读取SETGETMSETMGET 数字操作INCRINCRBYDECRDECRBYINCRBYFLOAT 字符串操作APPENDSTRLENGETRANGESETRANGE 内部编码intembstrraw 在Redis中&#xff0c;字符串string存储的是二进制&#xff0c;以byte为单位&#xff0c;输入的二进…

Pikachu-Unsafe FileUpload-客户端check

上传图片&#xff0c;点击查看页面的源码&#xff0c; 可以看到页面的文件名校验是放在前端的&#xff1b;而且也没有发起网络请求&#xff1b; 所以&#xff0c;可以通过直接修改前端代码&#xff0c;删除 checkFileExt(this.value) 这部分&#xff1b; 又或者先把文件名改成…

java代理模式(动态代理、静态代理、需要实现类的JDK代理、不需要实现类的JDK动态代理、CGLIB代理)

静态代理简单使用 静态代理是代理模式的一种实现方式&#xff0c;它在编译时就已经确定了被代理对象和代理对象的关系。在静态代理中&#xff0c;需要手动创建一个代理类&#xff0c;该代理类与被代理对象实现相同的接口或继承相同的父类&#xff0c;并在代理类的方法中调用被…

C++基类构造器的自动调用

C基类构造器的自动调用 虽然基类的构造器和解构器不会被派生类继承&#xff0c;但它们会被派生类的构造器和解构器自动调用&#xff0c;今天我们用代码实证一下。 验证代码 源代码&#xff0c;仔细看注释内容&#xff1a; D:\YcjWork\CppTour>vim c2004.cpp #include &l…

《RabbitMQ篇》基本概念介绍

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