如果你进阶的路上缺乏方向,可以加入我们的圈子和安卓开发者们一起学习交流!
-
Android进阶学习全套手册
-
Android对标阿里P7学习视频
-
BATJ大厂Android高频面试题
最后,借用我最喜欢的乔布斯语录,作为本文的结尾:
人这一辈子没法做太多的事情,所以每一件都要做得精彩绝伦。
你的时间有限,所以不要为别人而活。不要被教条所限,不要活在别人的观念里。不要让别人的意见左右自己内心的声音。
最重要的是,勇敢的去追随自己的心灵和直觉,只有自己的心灵和直觉才知道你自己的真实想法,其他一切都是次要。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
while (tr.getCause() != null) {
tr = tr.getCause();
if (tr.getStackTrace() != null && tr.getStackTrace().length > 0) {
rootTr = tr;
}
String msg = tr.getMessage();
if (msg != null && msg.length() > 0) {
exceptionMessage = msg;
}
}
// Crash 异常类名称
exceptionClassName = rootTr.getClass().getName();
if (rootTr.getStackTrace().length > 0) {
StackTraceElement trace = rootTr.getStackTrace()[0];
// 获取 trace 文件名、类名、方法名、Crash 行号
throwFileName = trace.getFileName();
throwClassName = trace.getClassName();
throwMethodName = trace.getMethodName();
throwLineNumber = trace.getLineNumber();
} else {
throwFileName = "unknown";
... ...
}
exceptionMessage = sanitizeString(exceptionMessage);
}
三、handleApplicationCrash处理分析
============================
`handleApplicationCrash` 会通过 `JNI`接口调用`AMS`中的方法。
//发送 Crash 弹窗handler,直到Dialog dismiss
ActivityManager.getService().handleApplicationCrash(
mApplicationObject, new ApplicationErrorReport.ParcelableCrashInfo(e));
`ActivityManagerService.java`
`handleApplicationCrash` 通过`JNI` 回调用 `AMS`中的`handleApplicationCrash`方法,进而调用`AMS` 中的内部方法`handleApplicationCrashInner`。
handleApplicationCrash
* 1.当远程`IBinder`对象为空`Null`时,则进程名为`system_server`;
* 2.当远程`IBinder`对象不为空,且`ProcessRecord`为空时,则进程名为`unknown`;
* 3.当远程`IBinder`对象不为空,且`ProcessRecord`不为空时,则进程名为`ProcessRecord`对象中相应进程名。
// 当app Crash 时候,会调用此方法。
//调用结束后 ,app 进程就会推出
public void handleApplicationCrash(IBinder app,
ApplicationErrorReport.ParcelableCrashInfo crashInfo) {
// findAppProcess 详见 3.1 分析
ProcessRecord r = findAppProcess(app, "Crash");
// system_server 进程 为Null
final String processName = app == null ? "system_server"
: (r == null ? "unknown" : r.processName);
//handleApplicationCrashInner 详见 4 分析
handleApplicationCrashInner("crash", r, processName, crashInfo);
}
`handleApplicationCrashInner`主要是调用 `AppErrors`类中的`crashApplication` 方法处理。
void handleApplicationCrashInner(String eventType, ProcessRecord r, String processName,
ApplicationErrorReport.CrashInfo crashInfo) {
... ...
//调用APP Error 类方法中的 crashApplication
mAppErrors.crashApplication(r, crashInfo);
}
### 3.1 findAppProcess
`ActivityManagerService.java`
`findAppProcess`主要是通过`for`循环遍历查找出`IBinder`对应的`Process`.
private ProcessRecord findAppProcess(IBinder app, String reason) {
... ...
synchronized (this) {
final int NP = mProcessNames.getMap().size();
for (int ip=0; ip<NP; ip++) {
SparseArray<ProcessRecord> apps = mProcessNames.getMap().valueAt(ip);
final int NA = apps.size();
for (int ia=0; ia<NA; ia++) {
ProcessRecord p = apps.valueAt(ia);
//当找到目标进程则返回
if (p.thread != null && p.thread.asBinder() == app) {
return p;
}
}
}
//如果代码执行到这里,表明无法找到应用所在的进程
return null;
}
}
其中 `mProcessNames = new ProcessMap<ProcessRecord>();`对于代码`mProcessNames.getMap()`返回的是`mMap`,而`mMap= new ArrayMap<String, SparseArray<ProcessRecord>>()`;
知识延伸:`SparseArray`和`ArrayMap`是`Android`专门针对内存优化而设计的取代`Java API`中的`HashMap`的数据结构。
对于`key`是`int`类型则使用`SparseArray`,可避免自动装箱过程;
对于`key`为其他类型则使用`ArrayMap`。
`HashMap`的查找和插入时间复杂度为`O(1)`的代价是牺牲大量的内存来实现的,而`SparseArray`和`ArrayMap`性能略逊于`HashMap`,但更`节省内存`。
再回到`mMap`,这是以进程`name`为`key`,再以`(uid为key,以ProcessRecord为Value的)`结构体作为`value`。下面看看其`get()`和`put()`方法
public E get(String name, int uid) {
SparseArray<E> uids = mMap.get(name);
if (uids == null) return null;
return uids.get(uid);
}
public E put(String name, int uid, E value) {
SparseArray<E> uids = mMap.get(name);
if (uids == null) {
uids = new SparseArray<E>(2);
mMap.put(name, uids);
}
uids.put(uid, value);
return value;
}
`findAppProcess()`根据`app(IBinder类型)`来查询相应的目标对象`ProcessRecord`。
有了进程记录对象`ProcessRecord`和进程名`processName`,则进入执行`Crash`处理方法 `AppErrors.java`,继续往下看。
四、handleApplicationCrashInner 处理分析
==================================
`ActivityManagerService.java`
void handleApplicationCrashInner(String eventType, ProcessRecord r, String processName,
ApplicationErrorReport.CrashInfo crashInfo) {
... ...
//将错误信息追加到DropBox
addErrorToDropBox(eventType, r, processName, null, null, null, null, null, crashInfo);
//【见小节5】
mAppErrors.crashApplication(r, crashInfo);
}
其中`addErrorToDropBox`是将`Crash`的信息输出到目录`/data/system/dropbox`。例如`system_server`的`dropbox`文件名为`system_server_crash@xxx.txt (xxx代表的是时间戳)`
五、APP Error info分析
==================
`AppErrors.java`
AppErrors 主要是 控制`APP Crash`的场景条件。
void crashApplication(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo) {
... ...
try {
// 调用内部 crashApplicationInner方法
crashApplicationInner(r, crashInfo, callingPid, callingUid);
} finally {
Binder.restoreCallingIdentity(origId);
}
}
`crashApplicationInner`内部方法
void crashApplicationInner(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo,
int callingPid, int callingUid) {
... ...
AppErrorResult result = new AppErrorResult();
TaskRecord task;
synchronized (mService) {
// 如果是通过IActivityController 实例导致的Crash ,则不显示弹窗
// 详见5.1
if (handleAppCrashInActivityController(r, crashInfo, shortMsg, longMsg, stackTrace,
timeMillis, callingPid, callingUid)) {
return;
}
... ...
AppErrorDialog.Data data = new AppErrorDialog.Data();
data.result = result;
data.proc = r;
// 无法势必的进程 也不显示Crash 弹窗【见小节6】
if (r == null || !makeAppCrashingLocked(r, shortMsg, longMsg, stackTrace, data)) {
return;
}
final Message msg = Message.obtain();
msg.what = ActivityManagerService.SHOW_ERROR_UI_MSG;
task = data.task;
msg.obj = data;
//发送消息SHOW_ERROR_MSG,弹出提示crash的对话框,等待用户选择【见小节10】
mService.mUiHandler.sendMessage(msg);
}
//进入阻塞等待,直到用户选择crash对话框"退出"或者"退出并报告"
int res = result.get();
Intent appErrorIntent = null;
MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_APP_CRASH, res);
if (res == AppErrorDialog.TIMEOUT || res == AppErrorDialog.CANCEL) {
res = AppErrorDialog.FORCE_QUIT;
}
… …
}
### 5.1 handleAppCrashInActivityController
`handleAppCrashInActivityController`,通过`IActivityController` 实例导致的`Crash` ,则不显示弹窗.
`AppError.java`
private boolean handleAppCrashInActivityController(ProcessRecord r,
ApplicationErrorReport.CrashInfo crashInfo,
String shortMsg, String longMsg,
String stackTrace, long timeMillis,
int callingPid, int callingUid) {
... ...
// 当存在ActivityController的情况,比如monkey
try {
String name = r != null ? r.processName : null;
int pid = r != null ? r.pid : callingPid;
int uid = r != null ? r.info.uid : callingUid;
//调用monkey的 appCrashed
if (!mService.mController.appCrashed(name, pid,
shortMsg, longMsg, timeMillis, crashInfo.stackTrace)) {
if ("1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"))
&& "Native crash".equals(crashInfo.exceptionClassName)) {
Slog.w(TAG, "Skip killing native crashed app " + name
+ "(" + pid + ") during testing");
} else {
Slog.w(TAG, "Force-killing crashed app " + name
+ " at watcher's request");
if (r != null) {
//调用`makeAppCrashingLocked`,继续处理crash流程
// 详见 小结 6
if (!makeAppCrashingLocked(r, shortMsg, longMsg, stackTrace, null))
{
r.kill("crash", true);
}
} else {
// Huh.
Process.killProcess(pid);
ActivityManagerService.killProcessGroup(uid, pid);
}
}
return true;
}
} catch (RemoteException e) {
mService.mController = null;
Watchdog.getInstance().setActivityController(null);
}
return false;
}
该方法主要做的两件事:
* 调用`makeAppCrashingLocked`,继续处理`Crash`流程;
* 发送消息`SHOW_ERROR_MSG`,弹出提示`Crash`的对话框,等待用户选择;
接下来我们看`makeAppCrashingLocked`实现。
六、makeAppCrashingLocked处理分析
===========================
`AppError.java`
private boolean makeAppCrashingLocked(ProcessRecord app,
String shortMsg, String longMsg, String stackTrace, AppErrorDialog.Data data) {
app.crashing = true;
//封装crash信息到crashingReport对象
app.crashingReport = generateProcessError(app,
ActivityManager.ProcessErrorStateInfo.CRASHED, null, shortMsg, longMsg, stackTrace);
//【见小节7】
startAppProblemLocked(app);
//停止屏幕冻结【见小节8】
app.stopFreezingAllLocked();
//【见小节9】
return handleAppCrashLocked(app, "force-crash" /*reason*/, shortMsg, longMsg, stackTrace,
data);
}
七、startAppProblemLocked处理分析
===========================
`AppError.java`
`startAppProblemLocked` 该方法主要功能:
* 获取当前用户下的`crash`应用的`error receiver`;
* 忽略当前`App`的广播接收;
void startAppProblemLocked(ProcessRecord app) {
// 如果不是当前user正在运行 app,这置为空
app.errorReportReceiver = null;
for (int userId : mService.mUserController.getCurrentProfileIds()) {
if (app.userId == userId) {
//获取当前用户下的crash应用的error receiver【见小节7.1】
app.errorReportReceiver = ApplicationErrorReport.getErrorReportReceiver(
mContext, app.info.packageName, app.info.flags);
}
}
//忽略当前app的广播接收【见小节7.2】
mService.skipCurrentReceiverLocked(app);
}
### 7.1 getErrorReportReceiver
`ApplicationErrorReport.java`
获取当前用户下的`Crash`应用的`error receiver`
public static ComponentName getErrorReportReceiver(Context context,
String packageName, int appFlags) {
//检查Settings中的"send_action_app_error"是否使能错误报告的功能
int enabled = Settings.Global.getInt(context.getContentResolver(),
Settings.Global.SEND_ACTION_APP_ERROR, 0);
if (enabled == 0) {
//1.当未使能时,则直接返回
return null;
}
PackageManager pm = context.getPackageManager();
// look for receiver in the installer package
String candidate = null;
ComponentName result = null;
try {
//获取该crash应用的安装器的包名
candidate = pm.getInstallerPackageName(packageName);
} catch (IllegalArgumentException e) {
// the package could already removed
}
if (candidate != null) {
result = getErrorReportReceiver(pm, packageName, candidate);
if (result != null) {
//2.当找到该crash应用的安装器,则返回;
return result;
}
}
//该系统属性名为"ro.error.receiver.system.apps"
if ((appFlags&ApplicationInfo.FLAG_SYSTEM) != 0) {
candidate = SystemProperties.get(SYSTEM_APPS_ERROR_RECEIVER_PROPERTY);
// 通过上下文对象传参,调用类内部方法
result = getErrorReportReceiver(pm, packageName, candidate);
if (result != null) {
//3.当crash应用是系统应用时,且系统属性指定error receiver时,则返回;
return result;
}
}
//该默认属性名为"ro.error.receiver.default"
candidate = SystemProperties.get(DEFAULT_ERROR_RECEIVER_PROPERTY);
//4.当默认属性值指定error receiver时,则返回;
return getErrorReportReceiver(pm, packageName, candidate);
}
`getErrorReportReceiver:`这是同名不同输入参数的另一个方法:
static ComponentName getErrorReportReceiver(PackageManager pm, String errorPackage,
String receiverPackage) {
if (receiverPackage == null || receiverPackage.length() == 0) {
return null;
}
//当安装应用程序的安装器Crash,则直接返回
if (receiverPackage.equals(errorPackage)) {
return null;
}
//ACTION_APP_ERROR值为"android.intent.action.APP_ERROR"
Intent intent = new Intent(Intent.ACTION_APP_ERROR);
intent.setPackage(receiverPackage);
ResolveInfo info = pm.resolveActivity(intent, 0);
if (info == null || info.activityInfo == null) {
return null;
}
//创建包名为receiverPackage的组件
return new ComponentName(receiverPackage, info.activityInfo.name);
}
### 7.2 skipCurrentReceiverLocked
`ActivityManagerService.java`
忽略当前`app`的广播接收
void skipCurrentReceiverLocked(ProcessRecord app) {
for (BroadcastQueue queue : mBroadcastQueues) {
// 会调用BroadcastQueue 中的方法【见小节7.2.1】
queue.skipCurrentReceiverLocked(app);
}
}
### 7.2.1 skipCurrentReceiverLocked
`BroadcastQueue.java` `skipCurrentReceiverLocked`忽略当前app的广播接收.
public void skipCurrentReceiverLocked(ProcessRecord app) {
BroadcastRecord r = null;
//查看app进程中的广播
if (mOrderedBroadcasts.size() > 0) {
BroadcastRecord br = mOrderedBroadcasts.get(0);
// 判断是否一致
if (br.curApp == app) {
r = br;
}
}
... ...
if (r != null) {
// 见7.2.2
skipReceiverLocked(r);
}
}
### 7.2.2 skipReceiverLocked
`BroadcastQueue.java`
private void skipReceiverLocked(BroadcastRecord r) {
logBroadcastReceiverDiscardLocked(r);
//结束app进程的广播结束
finishReceiverLocked(r, r.resultCode, r.resultData,
r.resultExtras, r.resultAbort, false);
//执行广播调度
scheduleBroadcastsLocked();
}
八、stopFreezingAllLocked处理分析
===========================
`AppError.java`中的 `makeAppCrashingLocked`方法(第6步),会调用`stopFreezingAllLocked` 方法
`ProcessRecord.java`
public void stopFreezingAllLocked() {
int i = activities.size();
while (i > 0) {
i--;
// 停止进程里所有的`Activity`. 详见8.1
activities.get(i).stopFreezingScreenLocked(true);
}
}
其中`activities`类型为`ArrayList<ActivityRecord>`,停止进程里所有的`Activity`.
#### 8.1 AR.stopFreezingScreenLocked
`ActivityRecord.java`,`stopFreezingScreenLocked`停止进程里所有的`Activity`.
public void stopFreezingScreenLocked(boolean force) {
if (force || frozenBeforeDestroy) {
frozenBeforeDestroy = false;
// mWindowContainerController 见【8.1.1】
mWindowContainerController.stopFreezingScreen(force);
}
}
##### 8.1.1mWindowContainerController.stopFreezingScreen
`stopFreezingScreen.java`
public void stopFreezingScreen(boolean force) {
synchronized(mWindowMap) {
if (mContainer == null) {
return;
}
if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Clear freezing of " + mToken + ": hidden="
+ mContainer.isHidden() + " freezing=" + mContainer.isFreezingScreen());
mContainer.stopFreezingScreen(true, force);
}
}
##### 8.1.1.1 WMS.stopFreezingScreenLocked
`WindowManagerService.java`
@Override
public void stopFreezingScreen() {
... ...
synchronized(mWindowMap) {
if (mClientFreezingScreen) {
mClientFreezingScreen = false;
mLastFinishedFreezeSource = "client";
final long origId = Binder.clearCallingIdentity();
try {
// 详见 8.1.1.2
stopFreezingDisplayLocked();
} finally {
Binder.restoreCallingIdentity(origId);
}
}
}
}
#### 8.1.1.2 stopFreezingDisplayLocked();
`WindowManagerService.java`
该方法主要功能:
处理屏幕旋转相关逻辑;
移除冻屏的超时消息;
屏幕旋转动画的相关操作;
使能输入事件分发功能;
`display`冻结时,执行`gc`操作;
更新当前的屏幕方向;
向`mH`发送`configuraion`改变的消息
rivate void stopFreezingDisplayLocked() {
if (!mDisplayFrozen) {
return; //显示没有冻结,则直接返回
}
//往往跟屏幕旋转相关
...
mDisplayFrozen = false;
//从上次冻屏到现在的总时长
mLastDisplayFreezeDuration = (int)(SystemClock.elapsedRealtime() - mDisplayFreezeTime);
//移除冻屏的超时消息
mH.removeMessages(H.APP_FREEZE_TIMEOUT);
mH.removeMessages(H.CLIENT_FREEZE_TIMEOUT);
boolean updateRotation = false;
//获取默认的DisplayContent
final DisplayContent displayContent = getDefaultDisplayContentLocked();
final int displayId = displayContent.getDisplayId();
ScreenRotationAnimation screenRotationAnimation =
mAnimator.getScreenRotationAnimationLocked(displayId);
//屏幕旋转动画的相关操作
if (CUSTOM_SCREEN_ROTATION && screenRotationAnimation != null
&& screenRotationAnimation.hasScreenshot()) {
DisplayInfo displayInfo = displayContent.getDisplayInfo();
boolean isDimming = displayContent.isDimming();
if (!mPolicy.validateRotationAnimationLw(mExitAnimId, mEnterAnimId, isDimming)) {
mExitAnimId = mEnterAnimId = 0;
}
//加载动画最大时长为10s
if (screenRotationAnimation.dismiss(mFxSession, MAX_ANIMATION_DURATION,
getTransitionAnimationScaleLocked(), displayInfo.logicalWidth,
displayInfo.logicalHeight, mExitAnimId, mEnterAnimId)) {
scheduleAnimationLocked();
} else {
screenRotationAnimation.kill();
mAnimator.setScreenRotationAnimationLocked(displayId, null);
updateRotation = true;
}
} else {
if (screenRotationAnimation != null) {
screenRotationAnimation.kill();
mAnimator.setScreenRotationAnimationLocked(displayId, null);
}
updateRotation = true;
}
//经过层层调用到InputManagerService服务,IMS服务使能输入事件分发功能
mInputMonitor.thawInputDispatchingLw();
boolean configChanged;
//当display被冻结时不再计算屏幕方向,以避免不连续的状态。
configChanged = updateOrientationFromAppTokensLocked(false);
//display冻结时,执行gc操作
mH.removeMessages(H.FORCE_GC);
mH.sendEmptyMessageDelayed(H.FORCE_GC, 2000);
//mScreenFrozenLock的类型为PowerManager.WakeLock,即释放屏幕冻结的锁
mScreenFrozenLock.release();
if (updateRotation) {
//更新当前的屏幕方向
configChanged |= updateRotationUncheckedLocked(false);
}
if (configChanged) {
//向mH发送configuraion改变的消息
mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
}
}
九、 AppErrors.handleAppCrashLocked()
-----------------------------------
`AppErrors.java`
1.当同一进程在时间间隔小于`1分钟`时连续两次`Crash`,则执行的情况下:
#### 对于非`persistent`进程:
* \[9.1\] mStackSupervisor.handleAppCrashLocked(app);
* \[9.2\] removeProcessLocked(app, false, false, “crash”);
* \[9.3\] mStackSupervisor.resumeTopActivitiesLocked();
#### 对于`persistent`进程,则只执行
* \[9.3\] mStackSupervisor.resumeTopActivitiesLocked();
2.否则执行
* \[9.4\] mStackSupervisor.finishTopCrashedActivitiesLocked(app, reason);
boolean handleAppCrashLocked(ProcessRecord app, String reason,
String shortMsg, String longMsg, String stackTrace, AppErrorDialog.Data data) {
final long now = SystemClock.uptimeMillis();
final boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0;
final boolean procIsBoundForeground =
(app.curProcState == ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE);
Long crashTime;
Long crashTimePersistent;
boolean tryAgain = false;
if (!app.isolated) {
crashTime = mProcessCrashTimes.get(app.info.processName, app.uid);
crashTimePersistent = mProcessCrashTimesPersistent.get(app.info.processName, app.uid);
} else {
crashTime = crashTimePersistent = null;
}
// Bump up the crash count of any services currently running in the proc.
//运行在当前进程中的所有服务的crash次数操作
for (int i = app.services.size() - 1; i >= 0; i--) {
// list 所有的Service
ServiceRecord sr = app.services.valueAt(i);
// Service 一会自动起来 重置count 为1,否则+1
if (now > sr.restartTime + ProcessList.MIN_CRASH_INTERVAL) {
sr.crashCount = 1;
} else {
sr.crashCount++;
}
// 允许重启正在Crash的服务以及 前台Service,wallpapers 等
if (sr.crashCount < mService.mConstants.BOUND_SERVICE_MAX_CRASH_RETRY
&& (sr.isForeground || procIsBoundForeground)) {
tryAgain = true;
}
}
//当同一个进程,连续两次crash的时间间隔小于1分钟时,则认为crash太过于频繁
if (crashTime != null && now < crashTime + ProcessList.MIN_CRASH_INTERVAL) {
Slog.w(TAG, "Process " + app.info.processName
+ " has crashed too many times: killing!");
EventLog.writeEvent(EventLogTags.AM_PROCESS_CRASHED_TOO_MUCH,
app.userId, app.info.processName, app.uid);
//【见小节9.1】
mService.mStackSupervisor.handleAppCrashLocked(app);
if (!app.persistent) {
//不再重启非persistent进程,除非用户显式地调用
EventLog.writeEvent(EventLogTags.AM_PROC_BAD, app.userId, app.uid,
app.info.processName);
if (!app.isolated) {
//将当前app加入到mBadProcesses
mBadProcesses.put(app.info.processName, app.uid,
new BadProcessInfo(now, shortMsg, longMsg, stackTrace));
mProcessCrashTimes.remove(app.info.processName, app.uid);
}
app.bad = true;
app.removed = true;
//移除非persistent 进程的所有服务,保证不再重启【见小节9.2】
mService.removeProcessLocked(app, false, tryAgain, "crash");
//恢复最顶部的Activity【见小节9.3】
mService.mStackSupervisor.resumeFocusedStackTopActivityLocked();
if (!showBackground) {
return false;
}
}
mService.mStackSupervisor.resumeFocusedStackTopActivityLocked();
} else {
//此处reason="force-crash"【见小节9.4】
final TaskRecord affectedTask =
mService.mStackSupervisor.finishTopRunningActivityLockedfinishTopRunningActivityLocked(app, reason);
if (data != null) {
data.task = affectedTask;
}
if (data != null && crashTimePersistent != null
&& now < crashTimePersistent + ProcessList.MIN_CRASH_INTERVAL) {
data.repeating = true;
}
}
if (data != null && tryAgain) {
data.isRestartableForService = true;
}
//当桌面Home 进程 应用crash,并且被三方app所取代,那么需要清空桌面应用的偏爱选项。
final ArrayList<ActivityRecord> activities = app.activities;
if (app == mService.mHomeProcess && activities.size() > 0
&& (mService.mHomeProcess.info.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
final ActivityRecord r = activities.get(activityNdx);
if (r.isActivityTypeHome()) {
Log.i(TAG, "Clearing package preferred activities from " + r.packageName);
try {
//清空偏爱应用
ActivityThread.getPackageManager()
.clearPackagePreferredActivities(r.packageName);
} catch (RemoteException c) {
// pm is in same process, this will never happen.
}
}
}
}
if (!app.isolated) {
//无法记录孤立进程的crash时间点,由于他们并没有一个固定身份.
mProcessCrashTimes.put(app.info.processName, app.uid, now);
mProcessCrashTimesPersistent.put(app.info.processName, app.uid, now);
}
//当app存在crash的handler,那么交给其处理
if (app.crashHandler != null) mService.mHandler.post(app.crashHandler);
return true;
}
9.1 ASS.handleAppCrashLocked
============================
`ActivityStackSupervisor.java`
void handleAppCrashLocked(ProcessRecord app) {
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = display.getChildAt(stackNdx);
//调用ActivityStack【见小节9.1.1】
stack.handleAppCrashLocked(app);
}
}
}
9.1.1 AS.handleAppCrashLocked
-----------------------------
`ActivityStack.java`
void handleAppCrashLocked(ProcessRecord app) {
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
final ActivityRecord r = activities.get(activityNdx);
if (r.app == app) {
Slog.w(TAG, " Force finishing activity "
+ r.intent.getComponent().flattenToShortString());
// Force the destroy to skip right to removal.
r.app = null;
mWindowManager.prepareAppTransition(TRANSIT_CRASHING_ACTIVITY_CLOSE,
false /* alwaysKeepCurrent */);
//结束当前activity
finishCurrentActivityLocked(r, FINISH_IMMEDIATELY, false,
"handleAppCrashedLocked");
}
}
}
}
这里的`mTaskHistory`数据类型为`ArrayList`,记录着所有先前的后台`activities`。遍历所有`activities`,找到位于该`ProcessRecord`的所有`ActivityRecord`,并结束该`Acitivity`。
9.2 AMS.removeProcessLocked
---------------------------
`ActivityManagerService.java`
@GuardedBy("this")
boolean removeProcessLocked(ProcessRecord app,
boolean callerWillRestart, boolean allowRestart, String reason) {
final String name = app.processName;
final int uid = app.uid;
if (DEBUG_PROCESSES) Slog.d(TAG_PROCESSES,
"Force removing proc " + app.toShortString() + " (" + name + "/" + uid + ")");
ProcessRecord old = mProcessNames.get(name, uid);
if (old != app) {
// This process is no longer active, so nothing to do.
Slog.w(TAG, "Ignoring remove of inactive process: " + app);
return false;
}
//从mProcessNames移除该进程
removeProcessNameLocked(name, uid);
if (mHeavyWeightProcess == app) {
mHandler.sendMessage(mHandler.obtainMessage(CANCEL_HEAVY_NOTIFICATION_MSG,
mHeavyWeightProcess.userId, 0));
mHeavyWeightProcess = null;
}
boolean needRestart = false;
if ((app.pid > 0 && app.pid != MY_PID) || (app.pid == 0 && app.pendingStart)) {
int pid = app.pid;
if (pid > 0) {
synchronized (mPidsSelfLocked) {
mPidsSelfLocked.remove(pid);
mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
}
mBatteryStatsService.noteProcessFinish(app.processName, app.info.uid);
if (app.isolated) {
mBatteryStatsService.removeIsolatedUid(app.uid, app.info.uid);
getPackageManagerInternalLocked().removeIsolatedUid(app.uid);
}
}
boolean willRestart = false;
//对于非孤立的persistent进程设置成可重启flags
if (app.persistent && !app.isolated) {
if (!callerWillRestart) {
willRestart = true;
} else {
needRestart = true;
}
}
// 杀进程【9.2.1】
app.kill(reason, true);
//移除进程并清空该进程相关联的activity/service等组件 【9.2.2】
handleAppDiedLocked(app, willRestart, allowRestart);
if (willRestart) {
//此处willRestart=false,不进入该分支
removeLruProcessLocked(app);
addAppLocked(app.info, null, false, null /* ABI override */);
}
} else {
mRemovedProcesses.add(app);
}
return needRestart;
}
* `mProcessNames`数据类型为`ProcessMap`,这是以进程名为`key`,记录着所有的`ProcessRecord`信息
* `mPidsSelfLocked`数据类型为`SparseArray`,这是以`pid`为`key`,记录着所有的`ProcessRecord`信息。该对象的同步保护是通过自身锁,而非全局`ActivityManager`锁。
9.2.1 app.kill
--------------
`ProcessRecord.java]`
void kill(String reason, boolean noisy) {
//通过am 杀进程
if (!killedByAm) {
// 如果不想让am kill 当前进程,可以在这地方跳过
if (!mService.mAmsExt.shouldKilledByAm(this.processName, reason)) {
return;
}
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "kill");
if (mService != null && (noisy || info.uid == mService.mCurOomAdjUid)) {
mService.reportUidInfoMessageLocked(TAG,
"Killing " + toShortString() + " (adj " + setAdj + "): " + reason,
info.uid);
}
if (pid > 0) {
EventLog.writeEvent(EventLogTags.AM_KILL, userId, pid, processName, setAdj, reason);
// pid > 0 杀进程以及所在的进程组
Process.killProcessQuiet(pid);
ActivityManagerService.killProcessGroup(uid, pid);
} else {
pendingStart = false;
}
if (!persistent) {
killed = true;
killedByAm = true;
}
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
}
此处reason为“crash”.
9.2.2 handleAppDiedLocked
-------------------------
`ActivityManagerService.java`
// 通过AM 移除当前存在的进程,不存在,则清除当前进程包含的所有内容
@GuardedBy("this")
private final void handleAppDiedLocked(ProcessRecord app,
boolean restarting, boolean allowRestart) {
int pid = app.pid;
final boolean clearLaunchStartTime = !restarting && app.removed && app.foregroundActivities;
//清除应用中service/receiver/ContentProvider信息
boolean kept = cleanUpApplicationRecordLocked(app, restarting, allowRestart, -1,
false /*replacingPid*/);
if (!kept && !restarting) {
// 根据LRU 算法移除 app 进程
removeLruProcessLocked(app);
if (pid > 0) {
//从list 移除对应的pid
ProcessList.remove(pid);
}
}
if (mProfileProc == app) {
clearProfilerLocked();
}
//清除应用中activity相关信息
boolean hasVisibleActivities = mStackSupervisor.handleAppDiedLocked(app);
app.clearRecentTasks();
app.activities.clear();
if (app.instr != null) {
Slog.w(TAG, "Crash of app " + app.processName
+ " running instrumentation " + app.instr.mClass);
Bundle info = new Bundle();
info.putString("shortMsg", "Process crashed.");
finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
}
mWindowManager.deferSurfaceLayout();
try {
if (!restarting && hasVisibleActivities
&& !mStackSupervisor.resumeFocusedStackTopActivityLocked()) {
// If there was nothing to resume, and we are not already restarting this process, but
// there is a visible activity that is hosted by the process... then make sure all
// visible activities are running, taking care of restarting this process.
mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
}
} finally {
mWindowManager.continueSurfaceLayout();
}
// TODO (b/67683350)
// When an app process is removed, activities from the process may be relaunched. In the
// case of forceStopPackageLocked the activities are finished before any window is drawn,
// and the launch time is not cleared. This will be incorrectly used to calculate launch
// time for the next launched activity launched in the same windowing mode.
if (clearLaunchStartTime) {
final LaunchTimeTracker.Entry entry = mStackSupervisor
.getLaunchTimeTracker().getEntry(mStackSupervisor.getWindowingMode());
if (entry != null) {
entry.mLaunchStartTime = 0;
}
}
}
9.3 ASS.resumeFocusedStackTopActivityLocked
===========================================
`ActivityStackSupervisor.java`
boolean resumeFocusedStackTopActivityLocked() {
return resumeFocusedStackTopActivityLocked(null, null, null);
}
最后
分享一份NDK基础开发资料
分享内容包括不限于高级UI、性能优化、架构师课程、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter等全方面的Android进阶实践技术;希望能帮助到大家,也节省大家在网上搜索资料的时间来学习,也可以分享动态给身边好友一起学习!
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
ibleActivities
&& !mStackSupervisor.resumeFocusedStackTopActivityLocked()) {
// If there was nothing to resume, and we are not already restarting this process, but
// there is a visible activity that is hosted by the process... then make sure all
// visible activities are running, taking care of restarting this process.
mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
}
} finally {
mWindowManager.continueSurfaceLayout();
}
// TODO (b/67683350)
// When an app process is removed, activities from the process may be relaunched. In the
// case of forceStopPackageLocked the activities are finished before any window is drawn,
// and the launch time is not cleared. This will be incorrectly used to calculate launch
// time for the next launched activity launched in the same windowing mode.
if (clearLaunchStartTime) {
final LaunchTimeTracker.Entry entry = mStackSupervisor
.getLaunchTimeTracker().getEntry(mStackSupervisor.getWindowingMode());
if (entry != null) {
entry.mLaunchStartTime = 0;
}
}
}
9.3 ASS.resumeFocusedStackTopActivityLocked
===========================================
`ActivityStackSupervisor.java`
boolean resumeFocusedStackTopActivityLocked() {
return resumeFocusedStackTopActivityLocked(null, null, null);
}
最后
分享一份NDK基础开发资料
[外链图片转存中…(img-E6lG4KM6-1715678730506)]
分享内容包括不限于高级UI、性能优化、架构师课程、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter等全方面的Android进阶实践技术;希望能帮助到大家,也节省大家在网上搜索资料的时间来学习,也可以分享动态给身边好友一起学习!
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!