该系列文章总纲链接:专题总纲目录 Android Framework 总纲
本章关键点总结 & 说明:
说明:本章节主要解读AMS通过startActivity启动Activity的整个流程的整个流程的第二阶段:从ActivityThread启动到Activity拉起。
第一阶段文章链接为:
Android Framework AMS(04)startActivity分析-1(am启动到ActivityThread启动)
上一节中我们从adb shell am start 命令开始分析 Activity 的启动流程,直到通过调用Process.start方法通过socket向Zygote发送一个消息,传递相关信息,让Zygote创建一个对应的应用进程。当zygote进程 fork一个应用进程启动后,应用进程的入口是ActivityThread的main函数。
这一节我们以ActivityThread的main函数作为起点开始继续分析startActivity启动Activity的流程。
1 ActivityThread启动分析
ActivityThread的main函数,代码实现如下:
//ActivityThread
public static void main(String[] args) {
// 启动 SamplingProfilerIntegration,这是 Android 中用于性能监控和分析的组件
SamplingProfilerIntegration.start();
// 关闭 CloseGuard 错误检查。CloseGuard 用于跟踪资源(如流和数据库)是否被正确关闭
// 在发布版本中禁用,但在调试版本中可以使用 StrictMode 并通过 DropBox 而不是日志来报告
CloseGuard.setEnabled(false);
// 初始化 Environment,设置当前用户的配置环境
Environment.initForCurrentUser();
// 设置 libcore 事件日志的报告器
EventLogger.setReporter(new EventLoggingReporter());
// 添加 AndroidKeyStoreProvider,用于提供 Android 密钥存储的加密服务
Security.addProvider(new AndroidKeyStoreProvider());
// 设置 TrustedCertificateStore,确保在查找 CA 证书时使用正确的用户目录
final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
TrustedCertificateStore.setDefaultUserDirectory(configDir);
// 设置进程的主参数(ArgV0),这里用一个字符串 "<pre-initialized>" 作为临时值
Process.setArgV0("<pre-initialized>");
// 准备主循环器 Looper,这是 Android 消息循环机制的关键部分
Looper.prepareMainLooper();
// 创建 ActivityThread 实例并调用 attach 方法,进行一些初始化工作
ActivityThread thread = new ActivityThread();
thread.attach(false);
// 如果 sMainThreadHandler 为空,则设置为当前线程的 Handler
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
// 调试代码,如果启用,将打印出 Looper 中的所有消息
if (false) {
Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread"));
}
// 进入 Looper 消息循环,等待和分发消息,直到 Looper 退出
Looper.loop();
// 如果 Looper 意外退出,抛出异常
throw new RuntimeException("Main thread loop unexpectedly exited");
}
这里我们主要关注attach方法,代码实现如下:
//ActivityThread
private void attach(boolean system) {
sCurrentActivityThread = this;
mSystemThread = system;
// 当前线程不是系统线程时执行的操作
if (!system) {
//优化应用性能,首次绘制时启用 JIT 编译器,确保应用在执行时能够获得更好的性能
ViewRootImpl.addFirstDrawHandler(new Runnable() {
@Override
public void run() {
ensureJitEnabled();
}
});
// 设置调试时的应用程序名称,DDMS中看到的调试程序名
android.ddm.DdmHandleAppName.setAppName("<pre-initialized>", UserHandle.myUserId());
// 设置RuntimeInit应用程序对象,供调试使用
RuntimeInit.setApplicationObject(mAppThread.asBinder());
// 获取和AMS交互的代理
final IActivityManager mgr = ActivityManagerNative.getDefault();
// 关键方法:调用AMS的 attachApplication 方法,注册应用程序线程
mgr.attachApplication(mAppThread);
// 添加 GC 监视器,用于处理活动管理
BinderInternal.addGcWatcher(new Runnable() {
@Override public void run() {
if (!mSomeActivitiesChanged) {
return;
}
// 计算 Dalvik 内存使用情况,并在内存使用达到一定阈值时释放一些活动
Runtime runtime = Runtime.getRuntime();
long dalvikMax = runtime.maxMemory();
long dalvikUsed = runtime.totalMemory() - runtime.freeMemory();
if (dalvikUsed > ((3*dalvikMax)/4)) {
mSomeActivitiesChanged = false;
try {
mgr.releaseSomeActivities(mAppThread);
} catch (RemoteException e) {
}
}
}
});
} else {
//... 系统进程的初始化操作
}
// 设置 DropBox 报告器,用于收集系统崩溃和错误信息
DropBox.setReporter(new DropBoxReporter());
// 添加配置更改回调,用于处理屏幕配置更改
ViewRootImpl.addConfigCallback(new ComponentCallbacks2() {
//...
});
}
接下来我们主要关注关键方法即AMS的attachApplication方法。这里attachApplication的实现代码如下:
//ActivityManagerService
@Override
public final void attachApplication(IApplicationThread thread) {
synchronized (this) {
int callingPid = Binder.getCallingPid();
final long origId = Binder.clearCallingIdentity();
attachApplicationLocked(thread, callingPid);
Binder.restoreCallingIdentity(origId);
}
}
这里主要是调用attachApplicationLocked方法。接下来专注分析attachApplicationLocked方法。
1.1 AMS.attachApplicationLocked第一阶段代码分析
AMS.attachApplicationLocked第一阶段代码解读如下:
//ActivityManagerService
private final boolean attachApplicationLocked(IApplicationThread thread, int pid) {
// 获取正在附加的进程记录
ProcessRecord app;
if (pid != MY_PID && pid >= 0) {
synchronized (mPidsSelfLocked) {
//通过pid获取app
app = mPidsSelfLocked.get(pid);
}
} else {
app = null;
}
// 如果没有找到对应的进程记录,且进程ID有效,则杀死该进程
if (app == null) {
if (pid > 0 && pid != MY_PID) {
Process.killProcessQuiet(pid);
} else {
try {
thread.scheduleExit();
} catch (Exception e) {
// 忽略异常
}
}
return false; // 返回false,表示附加失败
}
// 如果该进程已经有线程关联,则处理应用已死的情况
if (app.thread != null) {
handleAppDiedLocked(app, true, true);
}
// 创建linkToDeath并关联到应用线程
final String processName = app.processName;
try {
AppDeathRecipient adr = new AppDeathRecipient(
app, pid, thread);
thread.asBinder().linkToDeath(adr, 0);
app.deathRecipient = adr;
} catch (RemoteException e) {
app.resetPackageList(mProcessStats);
startProcessLocked(app, "link fail", processName);
return false; // 如果链接失败,重置进程列表并重新启动进程
}
// 使进程记录处于活动状态
app.makeActive(thread, mProcessStats);
// 设置进程的调度参数
app.curAdj = app.setAdj = -100; // 设置当前和设定的调度调整值
app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT; // 设置调度组
// 重置进程的UI和调试状态
app.forcingToForeground = null;
updateProcessForegroundLocked(app, false, false);
app.hasShownUi = false;
app.debugging = false;
app.cached = false;
app.killedByAm = false;
// 移除之前设置的启动超时消息
mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
这段代码的主要目的是处理应用程序进程的attach操作的第一阶段。它主要做了:获取进程记录、处理应用死亡、创建应用死亡接收器、激活进程、设置调度参数、重置UI和调试状态以及移除启动超时消息等。
1.2 AMS.attachApplicationLocked第二阶段代码分析
AMS.attachApplicationLocked第二阶段代码解读如下:
//ActivityManagerService
private final boolean attachApplicationLocked(IApplicationThread thread, int pid) {
//...
// 第二阶段
// 检查是否处于正常模式或是否允许在启动过程中附加
boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info);
// 如果是正常模式,生成应用程序的内容提供者
List<ProviderInfo> providers = normalMode ? generateApplicationProvidersLocked(app) : null;
try {
//...
// 设置调试模式相关处理
// 设置性能分析文件和文件描述符相关处理
// 设置 OpenGL 追踪
//...
// 如果应用被启动用于恢复或完整备份,特殊设置
boolean isRestrictedBackupMode = false;
if (mBackupTarget != null && mBackupAppName.equals(processName)) {
isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
|| (mBackupTarget.backupMode == BackupRecord.RESTORE_FULL)
|| (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
}
// 确保包的 Dex 优化
ensurePackageDexOpt(app.instrumentationInfo != null
? app.instrumentationInfo.packageName
: app.info.packageName);
if (app.instrumentationClass != null) {
ensurePackageDexOpt(app.instrumentationClass.getPackageName());
}
// 获取应用程序信息
ApplicationInfo appInfo = app.instrumentationInfo != null
? app.instrumentationInfo : app.info;
app.compat = compatibilityInfoForPackageLocked(appInfo);
// 设置性能分析器信息相关处理
//...
// 关键方法:绑定应用程序
thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,
profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,
app.instrumentationUiAutomationConnection, testMode, enableOpenGlTrace,
isRestrictedBackupMode || !normalMode, app.persistent,
new Configuration(mConfiguration), app.compat,
getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked());
updateLruProcessLocked(app, false, null);
app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
} catch (Exception e) {
app.resetPackageList(mProcessStats);
app.unlinkDeathRecipient();
startProcessLocked(app, "bind fail", processName);
return false;
}
// 从持久启动进程和保持进程列表中移除该应用
mPersistentStartingProcesses.remove(app);
mProcessesOnHold.remove(app);
//...
这段代码的主要目的是处理应用程序的attach操作的第二阶段,包括设置调试模式、性能分析、备份/恢复模式等。它通过设置各种参数和调用 bindApplication 方法(最关键)来实现。如果在绑定过程中出现异常,它会进行适当的清理和重试操作。
1.3 AMS.attachApplicationLocked第三阶段代码分析
AMS.attachApplicationLocked第三阶段代码解读如下:
//ActivityManagerService
private final boolean attachApplicationLocked(IApplicationThread thread, int pid) {
//...
// 第三阶段
boolean badApp = false;
boolean didSomething = false;
// 如果处于正常模式,尝试将应用程序与顶层可见activity关联
if (normalMode) {
try {
//关键方法:为了确保用户界面能够正确响应用户的交互。
if (mStackSupervisor.attachApplicationLocked(app)) {
didSomething = true;
}
} catch (Exception e) {
//...
}
}
// 尝试处理service组件(这里的service实际上是AndroidManifest.xml 中声明的 Service
// 或者在代码中通过继承 Service 类并实例化的自定义服务)
if (!badApp) {
try {
//为了确保应用的服务能够正确启动和运行
didSomething |= mServices.attachApplicationLocked(app, processName);
} catch (Exception e) {
badApp = true;
}
}
// 如果有待处理的广播,尝试发送(实际上就是处理broadcast组件)
if (!badApp && isPendingBroadcastProcessLocked(pid)) {
try {
didSomething |= sendPendingBroadcastsLocked(app);
} catch (Exception e) {
badApp = true;
}
}
// 如果应用是备份目标,安排创建备份代理
if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.uid) {
ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
try {
thread.scheduleCreateBackupAgent(mBackupTarget.appInfo,
compatibilityInfoForPackageLocked(mBackupTarget.appInfo),
mBackupTarget.backupMode);
} catch (Exception e) {
badApp = true;
}
}
// 如果应用处理过程中出现严重错误,杀死应用并标记为死亡
if (badApp) {
app.kill("error during init", true);
handleAppDiedLocked(app, false, true);
return false;
}
// 如果没有执行任何操作,更新OOM调整
if (!didSomething) {
updateOomAdjLocked();
}
return true; // 返回成功
}
这段代码的主要目的是处理应用程序的attach操作的第三阶段,即在应用程序进程成功attach后,执行一系列的后续操作。包括处理可见activity、服务、广播和备份代理创建。如果在处理过程中出现错误,会进行适当的错误处理,包括杀死应用和更新系统状态。如果没有执行任何操作,会更新应用的 OOM 调整,以确保系统资源的合理分配。这个过程确保了应用程序能够正确地响应系统的各种管理操作,并且在出现错误时能够及时进行恢复。
总之,AMS.attachApplicationLocked 方法是 Android 应用程序启动流程中的核心环节,它确保了应用程序能够正确地绑定到系统服务并开始执行。这个过程涉及到多个关键的函数调用,包括绑定应用程序、处理可见活动、创建应用程序上下文和实例,以及调用应用程序的 onCreate 方法。如果在启动过程中遇到错误,attachApplicationLocked 方法还会负责错误处理,确保系统的稳定性。
接下来我们主要关注2个关键方法:
- 第二阶段的bindApplication方法:这是 IApplicationThread 接口的方法,用于在应用程序进程中创建应用程序的实例。这里最终会调用到handleBindApplication方法,它负责处理 BIND_APPLICATION 消息,执行应用程序的绑定逻辑。
- 第三阶段的realStartActivityLocked方法:在 ActivityStackSupervisor 类中,这个方法负责启动一个新的 Activity 实例。该方法是在第三阶段中ActivityStackSupervisor类中的attachApplicationLocked中会调用到次此方法。因此分析时会从attachApplicationLocked开始分析。
接下来我们针对这2个方法在2.1(bindApplication) 和 2.2(realStartActivityLocked) 中进行详细的分析。
2 AMS.attachApplicationLocked中关键方法继续分析
2.1 bindApplication代码分析
ActivityThread中的子类ApplicationThread的bindApplication代码实现如下所示:
//ActivityThread
//ApplicationThread
public final void bindApplication(String processName, ApplicationInfo appInfo,
List<ProviderInfo> providers, ComponentName instrumentationName,
ProfilerInfo profilerInfo, Bundle instrumentationArgs,
IInstrumentationWatcher instrumentationWatcher,
IUiAutomationConnection instrumentationUiConnection, int debugMode,
boolean enableOpenGlTrace, boolean isRestrictedBackupMode, boolean persistent,
Configuration config, CompatibilityInfo compatInfo, Map<String, IBinder> services,
Bundle coreSettings) {
if (services != null) {// 初始化服务管理器的缓存
ServiceManager.initServiceCache(services);
}
setCoreSettings(coreSettings);// 设置核心设置
IPackageManager pm = getPackageManager();
android.content.pm.PackageInfo pi = null;
try {
pi = pm.getPackageInfo(appInfo.packageName, 0, UserHandle.myUserId());
} catch (RemoteException e) {
}
if (pi != null) {
// 检查是否设置了共享用户ID或进程名称不是默认的
boolean sharedUserIdSet = (pi.sharedUserId != null);
boolean processNameNotDefault =
(pi.applicationInfo != null &&
!appInfo.packageName.equals(pi.applicationInfo.processName));
boolean sharable = (sharedUserIdSet || processNameNotDefault);
if (!sharable) {
// 注册应用程序信息
VMRuntime.registerAppInfo(appInfo.packageName, appInfo.dataDir,
appInfo.processName);
}
}
// 创建 AppBindData 对象
AppBindData data = new AppBindData();
data.processName = processName;
// ... data 数据初始化,各种赋值
// 发送绑定应用程序的消息
sendMessage(H.BIND_APPLICATION, data);
}
//...
//Handler消息处理
private class H extends Handler {
public void handleMessage(Message msg) {
switch (msg.what) {
//...
case BIND_APPLICATION:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");
AppBindData data = (AppBindData)msg.obj;
//关键方法调用
handleBindApplication(data);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
//...
}
//...
}
//...
}
这里最后调用的sendMessage将数据通过handler消息机制,通过handleBindApplication方法来处理。接下来我们主要分析该方法,代码实现如下:
//ActivityThread
private void handleBindApplication(AppBindData data) {
// 设置当前绑定的应用程序数据
mBoundApplication = data;
// 更新当前的配置和兼容性配置
mConfiguration = new Configuration(data.config);
mCompatConfiguration = new Configuration(data.config);
//...
// 设置进程的主名称
Process.setArgV0(data.processName);
// 设置调试时的应用程序名称
android.ddm.DdmHandleAppName.setAppName(data.processName, UserHandle.myUserId());
// 如果应用是持久化的,且设备不是高端图形设备,则禁用硬件加速
if (data.persistent) {
if (!ActivityManager.isHighEndGfx()) {
HardwareRenderer.disable(false);
}
}
//...
// 如果应用的目标 SDK 版本较低,则设置默认的 AsyncTask 执行器
if (data.appInfo.targetSdkVersion <= android.os.Build.VERSION_CODES.HONEYCOMB_MR1) {
AsyncTask.setDefaultExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
// 更新消息循环中的消息检查策略
Message.updateCheckRecycle(data.appInfo.targetSdkVersion);
// 设置默认时区和语言环境
TimeZone.setDefault(null);
Locale.setDefault(data.config.locale);
// 应用配置到资源管理器
mResourcesManager.applyConfigurationToResourcesLocked(data.config, data.compatInfo);
// 更新当前显示的 DPI
mCurDefaultDisplayDpi = data.config.densityDpi;
applyCompatConfiguration(mCurDefaultDisplayDpi);
// 获取应用程序信息
data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);
// 如果应用不支持屏幕密度,则启用兼容性模式
if ((data.appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES) == 0) {
mDensityCompatMode = true;
Bitmap.setDefaultDensity(DisplayMetrics.DENSITY_DEFAULT);
}
updateDefaultDensity();
// 创建应用程序上下文
final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);
// 设置临时文件夹的系统属性
if (!Process.isIsolated()) {
final File cacheDir = appContext.getCacheDir();
if (cacheDir != null) {
System.setProperty("java.io.tmpdir", cacheDir.getAbsolutePath());
setupGraphicsSupport(data.info, cacheDir);
}
}
// 设置日期和时间格式
final boolean is24Hr = "24".equals(mCoreSettings.getString(Settings.System.TIME_12_24));
DateFormat.set24HourTimePref(is24Hr);
// 设置调试时的视图属性
View.mDebugViewAttributes = mCoreSettings.getInt(Settings.Global.DEBUG_VIEW_ATTRIBUTES, 0) != 0;
// 如果应用是系统应用或更新的系统应用,启用 StrictMode 的调试日志
if ((data.appInfo.flags & (ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP)) != 0) {
StrictMode.conditionallyEnableDebugLogging();
}
// 如果应用的目标 SDK 版本大于 9,则UI主线程不允许使用网络耗时操作
if (data.appInfo.targetSdkVersion > 9) {
StrictMode.enableDeathOnNetwork();
}
// 获取连接管理服务,并设置系统属性
IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
if (b != null) {
IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
try {
final ProxyInfo proxyInfo = service.getDefaultProxy();
Proxy.setHttpProxySystemProperty(proxyInfo);
} catch (RemoteException e) {}
}
// 如果有 Instrumentation 信息,则进行初始化
if (data.instrumentationName != null) {
InstrumentationInfo ii = null;
try {
ii = appContext.getPackageManager().getInstrumentationInfo(data.instrumentationName, 0);
} catch (PackageManager.NameNotFoundException e) {}
// ...
// 初始化 Instrumentation
if (ii != null) {
// ...
mInstrumentation = (Instrumentation) ii.getClass().newInstance();
mInstrumentation.init(this, instrContext, appContext, new ComponentName(ii.packageName, ii.name), data.instrumentationWatcher, data.instrumentationUiAutomationConnection);
}
}
// 如果应用需要大堆,则清除 Dalvik 增长限制
if ((data.appInfo.flags & ApplicationInfo.FLAG_LARGE_HEAP) != 0) {
dalvik.system.VMRuntime.getRuntime().clearGrowthLimit();
}
// 允许线程进行磁盘写操作
final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskWrites();
try {
// 创建应用程序实例
Application app = data.info.makeApplication(data.restrictedBackupMode, null);
mInitialApplication = app;
if (!data.restrictedBackupMode) {
// 安装内容提供者ContentProvidwer
List<ProviderInfo> providers = data.providers;
if (providers != null) {
installContentProviders(app, providers);
mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000);
}
}
// 调用 Instrumentation 的 onCreate
mInstrumentation.onCreate(data.instrumentationArgs);
//...
// 调用应用程序的 onCreate
//...
mInstrumentation.callApplicationOnCreate(app);
} finally {
// 恢复 StrictMode 策略
StrictMode.setThreadPolicy(savedPolicy);
}
}
handleBindApplication 方法是 Android 应用程序启动过程中的关键步骤,它负责设置应用程序运行时的关键配置和环境。这个过程包括配置应用程序上下文、设置日期时间格式、配置 StrictMode、设置 HTTP 代理、初始化 Instrumentation 以及创建应用程序实例等。这些步骤确保了应用程序能够在正确的环境中运行,并且能够及时响应系统的各种管理操作。环境构建好了,接下来就是启动Activity了。
我们继续分析attachApplicationLocked中realStartActivityLocked的实现。
2.2 realStartActivityLocked分析
realStartActivityLocked是在ActivityThread中的attachApplicationLocked中调用的,该方法代码实现如下所示:
//ActivityStackSupervisor
boolean attachApplicationLocked(ProcessRecord app) throws RemoteException {
final String processName = app.processName; // 获取应用程序进程的名称
boolean didSomething = false; // 标记是否执行了启动 Activity 的操作
// 遍历所有显示(屏幕)的 ActivityStack
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
// 遍历每个显示中的 ActivityStack
for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = stacks.get(stackNdx);
// 只处理前台的 ActivityStack
if (!isFrontStack(stack)) {
continue;
}
// 获取顶层正在运行的 Activity
ActivityRecord hr = stack.topRunningActivityLocked(null);
if (hr != null) {
// 如果顶层 Activity 的应用记录为空,并且它的 UID 和进程名称与当前应用记录匹配
if (hr.app == null && app.uid == hr.info.applicationInfo.uid
&& processName.equals(hr.processName)) {
try {
// 尝试启动该 Activity
if (realStartActivityLocked(hr, app, true, true)) {
didSomething = true; // 如果成功启动,标记为已执行操作
}
} catch (RemoteException e) {
// 异常处理
// ...
}
}
}
}
}
// 如果没有执行任何 Activity 启动操作,确保所有 Activity 可见
if (!didSomething) {
ensureActivitiesVisibleLocked(null, 0);
}
return didSomething; // 返回是否执行了启动 Activity 的操作
}
attachApplicationLocked 方法的主要目的是在应用程序进程启动后,检查并启动该进程中的顶层 Activity。这个过程包括遍历 ActivityStack、检查顶层 Activity 的状态、尝试启动 Activity 以及异常处理。如果没有启动任何 Activity,它会确保所有 Activity 都是可见的。这里的关键方法是尝试启动Activity的realStartActivityLocked方法,接下来我们继续分析该方法。代码实现如下:
//ActivityStackSupervisor
final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app, boolean andResume, boolean checkConfig)
throws RemoteException {
// 冻结屏幕以准备启动 Activity
r.startFreezingScreenLocked(app, 0);
// 设置应用可见
mWindowManager.setAppVisibility(r.appToken, true);
// 开始启动计时
r.startLaunchTickingLocked();
// 检查并更新配置
if (checkConfig) {
Configuration config = mWindowManager.updateOrientationFromAppTokens(
mService.mConfiguration,
r.mayFreezeScreenLocked(app) ? r.appToken : null);
mService.updateConfigurationLocked(config, r, false, false);
}
r.app = app;
app.waitingToKill = null;
r.launchCount++;
r.lastLaunchTime = SystemClock.uptimeMillis();
// 将 Activity 添加到应用的 Activity 列表
int idx = app.activities.indexOf(r);
if (idx < 0) {
app.activities.add(r);
}
// 更新 LRU 列表和内存调整
mService.updateLruProcessLocked(app, true, null);
mService.updateOomAdjLocked();
// 获取目标 ActivityStack
final ActivityStack stack = r.task.stack;
try {
// 确保应用线程不为空
if (app.thread == null) {
throw new RemoteException();
}
List<ResultInfo> results = null;
List<ReferrerIntent> newIntents = null;
if (andResume) {
results = r.results;
newIntents = r.newIntents;
}
// 如果是启动主屏幕 Activity
if (r.isHomeActivity() && r.isNotResolverActivity()) {
mService.mHomeProcess = r.task.mActivities.get(0).app;
}
// 确保包的 Dex 优化
mService.ensurePackageDexOpt(r.intent.getComponent().getPackageName());
// 设置 Activity 不再睡眠
r.sleeping = false;
r.forceNewConfig = false;
// 显示兼容性对话框
mService.showAskCompatModeDialogLocked(r);
// 设置兼容性信息
r.compat = mService.compatibilityInfoForPackageLocked(r.info.applicationInfo);
// 性能分析相关
//...
app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_TOP);
// 关键方法:调度启动 Activity
app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),
r.compat, r.launchedFromPackage, r.task.voiceInteractor, app.repProcState,
r.icicle, r.persistentState, results, newIntents, !andResume,
mService.isNextTransitionForward(), profilerInfo);
// 处理重量级应用
if ((app.info.flags & ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
if (app.processName.equals(app.info.packageName)) {
mService.mHeavyWeightProcess = app;
Message msg = mService.mHandler.obtainMessage(
ActivityManagerService.POST_HEAVY_NOTIFICATION_MSG);
msg.obj = r;
mService.mHandler.sendMessage(msg);
}
}
} catch (RemoteException e) {
//...
throw e;
}
// 标记 Activity 未启动失败
r.launchFailed = false;
// 更新 LRU 列表
stack.updateLRUListLocked(r);
// 如果需要resume
if (andResume) {
//关键方法:最小化resume Activity
stack.minimalResumeActivityLocked(r);
} else {
r.state = ActivityState.STOPPED;
r.stopped = true;
}
// 如果是前台栈,则启动设置 Activity
if (isFrontStack(stack)) {
mService.startSetupActivityLocked();
}
// 更新服务连接活动
mService.mServices.updateServiceConnectionActivitiesLocked(r.app);
return true; // 返回成功
}
realStartActivityLocked 方法是 Android 系统中启动 Activity 的核心方法。它负责处理从 Activity 的启动到恢复的完整流程,包括冻结屏幕、设置应用可见、更新配置、添加到应用的 Activity 列表、内存调整、启动 Activity、处理重量级应用、异常处理、更新 LRU 列表、恢复 Activity 以及启动设置 Activity。这个过程确保了 Activity 能够正确地启动并响应用户的交互。
接下来我们主要关注scheduleLaunchActivity方法:app.thread.scheduleLaunchActivity(...) 是一个在 ActivityThread 类中调用的方法,用于调度新的 Activity 的启动。这个方法通过应用程序线程 (app.thread) 向应用程序进程发送启动 Activity 的请求。接下来开始scheduleLaunchActivity代码的分析。ActivityThread中的子类ApplicationThread的scheduleLaunchActivity代码实现如下所示:
//ActivityThread
//ApplicationThread
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,
String referrer, IVoiceInteractor voiceInteractor, int procState, Bundle state,
PersistableBundle persistentState, List<ResultInfo> pendingResults,
List<ReferrerIntent> pendingNewIntents, boolean notResumed, boolean isForward,
ProfilerInfo profilerInfo) {
// 更新进程状态
updateProcessState(procState, false);
// 创建一个新的 ActivityClientRecord 来存储 Activity 的启动信息
ActivityClientRecord r = new ActivityClientRecord();
// 设置 Activity 的令牌、标识符、Intent 等信息
r.token = token;
r.ident = ident;
r.intent = intent;
// ...
// 更新待处理的配置信息
updatePendingConfiguration(curConfig);
// 通过消息队列发送启动 Activity 的消息
sendMessage(H.LAUNCH_ACTIVITY, r);
}
private class H extends Handler {
//...
public void handleMessage(Message msg) {
switch (msg.what) {
case LAUNCH_ACTIVITY: {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
r.packageInfo = getPackageInfoNoCheck(
r.activityInfo.applicationInfo, r.compatInfo);
handleLaunchActivity(r, null);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} break;
//...
}
//...
}
//...
}
//...
这里最后处理消息的方法是handleLaunchActivity,代码实现如下:
//ActivityThread
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
// 取消调度 GC(垃圾回收)Idler,准备启动 Activity
unscheduleGcIdler();
// 标记有 Activity 状态改变
mSomeActivitiesChanged = true;
// 处理配置变更
handleConfigurationChanged(null, null);
// 初始化 WindowManagerGlobal
WindowManagerGlobal.initialize();
// 关键方法:执行 Activity 的启动
Activity a = performLaunchActivity(r, customIntent);
// 如果成功创建了 Activity
if (a != null) {
// 记录创建时的配置
r.createdConfig = new Configuration(mConfiguration);
// 保存之前的状态
Bundle oldState = r.state;
//关键方法: resume Activity
handleResumeActivity(r.token, false, r.isForward,
!r.activity.mFinished && !r.startsNotResumed);
// 如果 Activity 没有结束并且没有在启动时恢复
if (!r.activity.mFinished && r.startsNotResumed) {
try {
// 标记为已调用 onPause
r.activity.mCalled = false;
// 调用 Activity 的 onPause 方法
mInstrumentation.callActivityOnPause(r.activity);
// ...
} catch (Exception e) {
// ...
throw e;
}
r.paused = true;
}
} else {
// 如果启动 Activity 失败
try {
// 通知 ActivityManager 结束 Activity
ActivityManagerNative.getDefault()
.finishActivity(r.token, Activity.RESULT_CANCELED, null, false);
} catch (RemoteException ex) {
// Ignore
}
}
}
handleLaunchActivity 方法是 Android ActivityThread 类中的关键方法,负责处理 Activity 的启动逻辑。它包括取消垃圾回收的调度、处理配置变更、初始化 WindowManagerGlobal、执行 Activity 的启动相关操作,以及处理 Activity 启动失败的情况。这个过程确保了 Activity 能够正确地启动并响应用户的交互。其中最重要的是执行 Activity 的启动相关操作。
接下来对关键方法performLaunchActivity和handleResumeActivity分别进行解读。
2.2.1 performLaunchActivity方法解读
ActivityThread.performLaunchActivity 方法代码实现如下:
//ActivityThread
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
ActivityInfo aInfo = r.activityInfo; // 获取Activity的信息
if (r.packageInfo == null) {
r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
Context.CONTEXT_INCLUDE_CODE);
}
ComponentName component = r.intent.getComponent(); // 获取Intent中指定的组件
if (component == null) {
component = r.intent.resolveActivity( // 如果组件未指定,解析组件
mInitialApplication.getPackageManager());
r.intent.setComponent(component); // 设置解析后的组件到Intent
}
if (r.activityInfo.targetActivity != null) {
component = new ComponentName(r.activityInfo.packageName,
r.activityInfo.targetActivity);
}
Activity activity = null;
try {
java.lang.ClassLoader cl = r.packageInfo.getClassLoader(); // 获取ClassLoader
activity = mInstrumentation.newActivity( // 使用Instrumentation创建Activity实例
cl, component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl); // 为Intent设置ClassLoader
r.intent.prepareToEnterProcess(); // 准备进入进程
if (r.state != null) {
r.state.setClassLoader(cl);
}
} catch (Exception e) {
//...
}
try {
Application app = r.packageInfo.makeApplication(false, mInstrumentation); // 创建Application实例
if (activity != null) {
Context appContext = createBaseContextForActivity(r, activity); // 创建Activity上下文
CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager()); // 加载标题
Configuration config = new Configuration(mCompatConfiguration); // 创建Configuration
activity.attach(appContext, this, getInstrumentation(), r.token, // 绑定Activity
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor);
if (customIntent != null) {
activity.mIntent = customIntent; // 如果有自定义Intent,设置之
}
r.lastNonConfigurationInstances = null;
activity.mStartedActivity = false; // 标记Activity尚未启动
int theme = r.activityInfo.getThemeResource();
if (theme != 0) {
activity.setTheme(theme);
}
activity.mCalled = false; // 标记onCreate尚未调用
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState); // 调用onCreate
} else {
mInstrumentation.callActivityOnCreate(activity, r.state); // 调用onCreate
}
r.activity = activity; // 设置ActivityClientRecord中的Activity
r.stopped = true; // 标记Activity已停止
if (!r.activity.mFinished) {
activity.performStart(); // 执行start操作,调用onStart系列方法
r.stopped = false; // 标记Activity未停止
}
if (!r.activity.mFinished) {
if (r.isPersistable()) {
if (r.state != null || r.persistentState != null) {
mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state, // 恢复状态
r.persistentState);
}
} else if (r.state != null) {
mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state); // 恢复状态
}
}
if (!r.activity.mFinished) {
activity.mCalled = false; // 标记onPostCreate尚未调用
if (r.isPersistable()) {
mInstrumentation.callActivityOnPostCreate(activity, r.state, // 调用onPostCreate
r.persistentState);
} else {
mInstrumentation.callActivityOnPostCreate(activity, r.state); // 调用onPostCreate
}
}
}
r.paused = true; // 标记Activity已暂停
mActivities.put(r.token, r); // 将ActivityClientRecord添加到映射中
} catch (Exception e) {
// Handle exceptions during activity resuming
}
return activity; // 返回Activity实例
}
performLaunchActivity 方法负责实际的 Activity 创建和初始化工作。它首先解析 Activity 的组件名称,然后使用类加载器创建 Activity 实例。接着,它为 Activity 设置上下文、加载标签和配置,绑定 Activity 并调用其生命周期方法,如 onCreate、onStart 和 onPostCreate。如果在任何时候 Activity 被标记为已完成,它将停止进一步的操作。这个过程确保了 Activity 能够正确地响应用户的启动请求,并在出现问题时能够进行适当的异常处理。最终,该方法返回新创建的 Activity 实例。
2.2.2 handleResumeActivity方法解读
ActivityThread.handleResumeActivity 方法代码实现如下:
//ActivityThread
//关键流程:step1
final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward, boolean reallyResume) {
unscheduleGcIdler(); // 取消垃圾回收的定时器,准备恢复 Activity
mSomeActivitiesChanged = true; // 标记有 Activity 状态改变
// 关键方法:resume Activity 的操作
ActivityClientRecord r = performResumeActivity(token, clearHide);
if (r != null) {
final Activity a = r.activity;
final int forwardBit = isForward ?
WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION : 0; // 设置前进导航的标志
boolean willBeVisible = !a.mStartedActivity; // 检查 Activity 是否将要变为可见
if (!willBeVisible) {
try {
willBeVisible = ActivityManagerNative.getDefault().willActivityBeVisible(
a.getActivityToken()); // 查询 Activity 是否将要变为可见
} catch (RemoteException e) {
}
}
if (r.window == null && !a.mFinished && willBeVisible) {
// 如果 Activity 的窗口为空,且 Activity 未结束,且将要变为可见,则创建窗口
r.window = r.activity.getWindow();
View decor = r.window.getDecorView();
decor.setVisibility(View.INVISIBLE); // 设置窗口的装饰视图为不可见
ViewManager wm = a.getWindowManager(); // 获取窗口管理器
WindowManager.LayoutParams l = r.window.getAttributes(); // 获取窗口参数
a.mDecor = decor; // 设置 Activity 的装饰
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION; // 设置窗口类型
l.softInputMode |= forwardBit; // 设置软键盘模式
if (a.mVisibleFromClient) {
a.mWindowAdded = true; // 标记窗口已添加
wm.addView(decor, l); // 将装饰视图添加到窗口管理器
}
} else if (!willBeVisible) {
r.hideForNow = true; // 如果 Activity 不将要变为可见,则暂时隐藏
}
cleanUpPendingRemoveWindows(r); // 清理待处理的移除窗口
if (!r.activity.mFinished && willBeVisible
&& r.activity.mDecor != null && !r.hideForNow) {
// 如果 Activity 未结束,将要变为可见,且mDecor不为空,则进行可见性处理
if (r.newConfig != null) {
performConfigurationChanged(r.activity, r.newConfig); // 执行配置更改
freeTextLayoutCachesIfNeeded(r.activity.mCurrentConfig.diff(r.newConfig)); // 释放文本布局缓存
r.newConfig = null; // 清除新配置
}
WindowManager.LayoutParams l = r.window.getAttributes(); // 获取窗口参数
if ((l.softInputMode
& WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION)
!= forwardBit) {
// 如果软键盘模式的标志不匹配,则更新标志
l.softInputMode = (l.softInputMode
& (~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION))
| forwardBit;
if (r.activity.mVisibleFromClient) {
ViewManager wm = a.getWindowManager(); // 获取窗口管理器
View decor = r.window.getDecorView(); // 获取装饰视图
wm.updateViewLayout(decor, l); // 更新视图布局
}
}
r.activity.mVisibleFromServer = true; // 标记 Activity 在服务器端可见
mNumVisibleActivities++; // 增加可见 Activity 计数
if (r.activity.mVisibleFromClient) {
r.activity.makeVisible(); // 使 Activity 可见
}
}
if (!r.onlyLocalRequest) {
r.nextIdle = mNewActivities; // 设置下一个空闲的 Activity
mNewActivities = r; // 设置新的 Activity
Looper.myQueue().addIdleHandler(new Idler()); // 添加空闲处理器
}
r.onlyLocalRequest = false; // 清除本地请求标志
if (reallyResume) {
try {
ActivityManagerNative.getDefault().activityResumed(token); // 通知 AMS Activity 已resume
} catch (RemoteException ex) {
}
}
} else {
try {
ActivityManagerNative.getDefault()
.finishActivity(token, Activity.RESULT_CANCELED, null, false); // 如果 Activity 无法resume,通知 AMS 结束 Activity
} catch (RemoteException ex) {
}
}
}
//关键流程:step2
public final ActivityClientRecord performResumeActivity(IBinder token, boolean clearHide) {
// 根据 IBinder token 获取对应的 ActivityClientRecord 对象
ActivityClientRecord r = mActivities.get(token);
if (r != null && !r.activity.mFinished) {
// 如果需要清除隐藏状态
if (clearHide) {
r.hideForNow = false; // 清除隐藏标记
r.activity.mStartedActivity = false; // 重置开始活动标记
}
try {
// 通知 Fragments 状态不会保存,因为 Activity 即将恢复
r.activity.mFragments.noteStateNotSaved();
// 如果有待处理的 Intent,分发它们
if (r.pendingIntents != null) {
deliverNewIntents(r, r.pendingIntents);
r.pendingIntents = null; // 清除待处理的 Intent 列表
}
// 如果有待处理的结果,分发它们
if (r.pendingResults != null) {
deliverResults(r, r.pendingResults);
r.pendingResults = null; // 清除待处理的结果列表
}
// resume Activity
r.activity.performResume();
// 更新 ActivityClientRecord 的状态
r.paused = false; // 标记 Activity 未暂停
r.stopped = false; // 标记 Activity 未停止
r.state = null; // 清除保存的状态
r.persistentState = null; // 清除持久化的状态
} catch (Exception e) {
//...
}
}
return r;
}
handleResumeActivity 方法负责处理 Activity 的恢复逻辑。它首先取消垃圾回收的定时器,然后执行恢复操作,更新 Activity 的可见性和窗口状态,并与 ActivityManager 通信以确保 Activity 的状态一致。如果 Activity 无法恢复,它会通知 ActivityManager 结束该 Activity。这个过程确保了 Activity 在用户交互和系统配置更改时能够正确地恢复到前台,同时保持了应用程序的响应性和稳定性。
handleResumeActivity方法中最关键的调用是performResumeActivity 方法。该方法是 Android 系统中resume Activity 状态的关键方法。它负责准备 Activity 从停止或暂停状态转换到运行状态,包括清除隐藏状态、分发待处理的 Intent 和结果、调用 Activity 的 performResume 方法来执行实际的恢复操作,并更新 ActivityClientRecord 的状态。这里最终会调用到Atcivity的onResume方法。
从activity角度来看,通过performLaunchActivity调用activity中的onCreate、onStart方法,通过handleResumeActivity调用activity中的onResume方法。
3 AMS.attachApplicationLocked流程分析额外知识补充
3.1 isPersistable方法详细解读
在 Android 系统的源代码中,isPersistable 方法是 ActivityClientRecord 类的一个实例方法,用于确定与之关联的 Activity 是否能够保存其状态。
当 Activity 因为配置更改(例如屏幕旋转)而需要被重新创建时,Android 系统提供了一种机制来保存和恢复 Activity 的状态。这个状态包括 Activity 的成员变量、保存的对话框、输入状态等。如果 Activity 标记为 persistable,这意味着:
- 状态保存:Activity 可以保存其状态,以便在 Activity 被销毁并重新创建时能够恢复这些状态。
- 跨配置更改保持状态:当发生配置更改(如屏幕旋转、语言更改等)时,Activity 的状态可以被保存,并且可以在新的 Activity 实例中恢复。
- 兼容性:对于需要跨不同的系统配置或设备保持状态的 Activity,isPersistable 返回 true 表示该 Activity 需要使用这种状态保存和恢复机制。
在 performLaunchActivity 方法中,isPersistable 方法的返回值用于决定是否需要调用 Instrumentation 的 callActivityOnCreate 方法来传递保存的状态,以及是否需要在 Activity 重新创建后调用 callActivityOnRestoreInstanceState 方法来恢复状态。代码部分如下:
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
简而言之,isPersistable 表示 Activity 是否需要参与状态保存和恢复的过程,这对于确保用户体验的连续性至关重要。如果 Activity 不标记为 persistable,则在配置更改时不会保存和恢复状态,可能会导致用户体验中断。
3.2 Eventlog机制解读
Android 的 EventLog 机制是系统层面的日志记录系统,用于跟踪和记录系统关键事件,如系统启动、应用生命周期事件、系统异常等。这些日志对于系统调试和问题诊断非常有用。
EventLog 机制的工作原理解读如下:
- 事件标记(Event Tag):每个事件都有一个唯一的标记,通常存储在 /system/etc/event-log-tags 文件中。这些标记定义了事件的类型和它们可以携带的数据类型。
- 事件写入(Event Write):系统或应用在特定事件发生时,通过调用 EventLog.writeEvent 方法将事件写入日志。这个方法接受一个事件标记和一系列参数,这些参数可以是整数、长整数、字符串等。
- 日志查看:开发者可以使用 adb logcat 命令查看事件日志。例如,使用 adb logcat -b events 可以查看事件日志。
- 日志分析:事件日志可以被分析以诊断问题,如性能问题、系统崩溃、应用行为等。
EventLog.writeEvent 方法的逻辑:
EventLog.writeEvent 方法接受一个事件标记和一个可变参数列表,这些参数是与事件相关的数据。方法将事件标记和参数封装成一条日志记录,并将其写入系统的事件日志系统。这些日志记录可以被系统或第三方工具读取和分析。
示例代码注释:
final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward, boolean reallyResume) {
// ... 省略其他代码 ...
if (reallyResume) {
try {
// 当 Activity 真正恢复时,记录事件日志
EventLog.writeEvent(EventLogTags.AM_ACTIVITY_RESUMED, token);
} catch (RemoteException ex) {
// 忽略远程异常
}
}
// ... 省略其他代码 ...
}
在这个示例中,当一个 Activity 真正恢复时,使用 EventLog.writeEvent 方法记录一个 AM_ACTIVITY_RESUMED 事件,并将 Activity 的 token 作为参数传递。
总之,EventLog 机制是 Android 系统用于记录关键系统事件的工具。通过 EventLog.writeEvent 方法,系统可以在事件发生时写入事件日志,这些日志可以被用来分析和诊断系统问题。
3.3 Dropbox机制解读
Android 的 Dropbox 机制是系统级别的日志记录服务,用于收集和存储系统运行时产生的各种异常信息,如应用程序崩溃(App Crash)、原生崩溃(Native Crash)、应用程序无响应(ANR)、内核恐慌(Kernel Panic)等。这些日志文件通常存储在 /data/system/dropbox 目录下,对于开发者和系统管理员来说,是诊断和分析系统问题的重要资源。
Dropbox 基本逻辑解读如下:
- 事件捕获:当系统发生异常事件时,如应用崩溃或ANR,系统服务会捕获这些事件并生成日志条目。
- 日志存储:这些日志条目会被写入到 Dropbox 的指定目录中,每个条目通常包含时间戳、事件类型和详细日志内容。
- 日志管理:Dropbox 服务会根据配置的策略管理这些日志文件,如限制文件数量和大小,以及清理旧文件。
- 接口访问:系统提供了 DropBoxManager 接口,允许应用通过 Context.DROPBOX_SERVICE 获取 DropBoxManager 实例,并进行日志的添加和查询操作。
- 广播通知:当新的日志条目被添加到 Dropbox 时,系统会发送一个 android.intent.action.DROPBOX_ENTRY_ADDED 广播,允许有权限的应用监听这个广播并作出响应。
- 权限控制:访问 Dropbox 日志通常需要 android.permission.READ_LOGS 权限,这通常只授予系统应用或具有特殊权限的应用。
Dropbox 机制的设计目的是为了提供一个可靠的系统级日志记录服务,帮助开发者和系统管理员在应用或系统出现问题时能够快速定位和解决问题。通过集中管理日志文件,Dropbox 确保了日志数据的完整性和可访问性,同时也提供了一种机制来控制日志文件的存储和生命周期。
假设你是一个应用开发者,想要记录一些自定义的日志信息到Dropbox中。请注意,下面的示例代码需要在具有相应权限的系统应用或者具有READ_LOGS
权限的应用中运行。DropboxLogger的封装类参考代码如下所示:
import android.content.Context;
import android.os.DropBoxManager;
public class DropboxLogger {
private Context mContext;
private DropBoxManager mDropBoxManager;
public DropboxLogger(Context context) {
this.mContext = context;
this.mDropBoxManager = (DropBoxManager) context.getSystemService(Context.DROPBOX_SERVICE);
}
public void logError(String tag, String message) {
if (mDropBoxManager != null) {
DropBoxManager.Entry entry = new DropBoxManager.Entry(tag, message.getBytes());
mDropBoxManager.addData(tag, message.getBytes(), 0);
System.out.println("Logged to Dropbox: " + message);
} else {
System.out.println("DropBoxManager is not available.");
}
}
}
在这个示例中,我们创建了一个DropboxLogger
类,它提供了一个logError
方法,用于将错误信息记录到Dropbox中。这个方法接受一个标签(tag)和消息(message),然后使用DropBoxManager
将消息添加到Dropbox中。在系统应用开发中,参考使用方式如下:
public class MyApp extends Application {
@Override
public void onCreate() {
super.onCreate();
DropboxLogger logger = new DropboxLogger(this);
logger.logError("MY_APP_ERROR", "This is a test error message.");
}
}
通过这个示例,可以看到Dropbox机制如何使用,类似于EventLog.writeEvent
的方式。这些日志信息对于系统问题诊断非常有用。