Android12系统源码分析-NativeTombstoneManager
The following article is from Hisense手机技术团队 Author 秋城
概述
Android12新增的system_server进程(LocalService)本地服务,用于管理native tombstones。
该服务在开机Systemerver初始化流程启动,添加到LocalService,然后启动一个ServiceThread线程用于(mHandler.post)处理本服务的业务。
NativeTombstoneManager的功能主要是:
监听
/data/tombstones
目录文件变动,解析为TombstoneFile对象保存,通知dropbox特定tombstones文件删除
特定tombstones文件检索
值得关注的是AMS对该服务的使用,也是Android11新增API:ActivityManager.java#getHistoricalProcessExitReasons()
软件架构如图:
图:NativeTombstoneManager类图
启动流程
图:NativeTombstoneManager服务启动时序图
服务比较简单,和其他SystemServer启动的服务一样,
frameworks/base/services/core/java/com/android/server/os/NativeTombstoneManagerService.java
public class NativeTombstoneManagerService extends SystemService {
private NativeTombstoneManager mManager;
@Override
public void onStart() {
mManager = new NativeTombstoneManager(getContext());
//仅添加本地服务,没有binder服务
LocalServices.addService(NativeTombstoneManager.class, mManager);
}
@Override
public void onBootPhase(int phase) {
if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
mManager.onSystemReady();
}
}
}
本服务也是SystemService工具类的子类,通过重写onStart、onBootPhase获得代码流程
在onStart中初始化真正的服务实现NativeTombstoneManager,实例化后添加到LocalServices
frameworks/base/services/core/java/com/android/server/os/NativeTombstoneManager.java
public final class NativeTombstoneManager {
NativeTombstoneManager(Context context) {
//启动handler线程,用于后续处理本服务的业务
final ServiceThread thread = new ServiceThread(TAG + ":tombstoneWatcher",
THREAD_PRIORITY_BACKGROUND, true /* allowIo */);
thread.start();
mHandler = thread.getThreadHandler();
//启动文件监听/data/tombstones
mWatcher = new TombstoneWatcher();
mWatcher.startWatching();
}
void onSystemReady() {
registerForUserRemoval();
registerForPackageRemoval();
// 开机阶段先扫描一次/data/tombstones目录
mHandler.post(() -> {
final File[] tombstoneFiles = TOMBSTONE_DIR.listFiles();
for (int i = 0; tombstoneFiles != null && i < tombstoneFiles.length; i++) {
if (tombstoneFiles[i].isFile()) {
handleTombstone(tombstoneFiles[i]);
开机流程有三个动作
启动handler线程,用于后续处理本服务的业务
TombstoneWatcher启动文件监听/data/tombstones
开机阶段先扫描一次/data/tombstones目录
看一下handleTombstone
frameworks/base/services/core/java/com/android/server/os/NativeTombstoneManager.java
private void handleTombstone(File path) {
final String filename = path.getName();
if (!filename.startsWith("tombstone_")) {
return;
}
if (filename.endsWith(".pb")) {
handleProtoTombstone(path);
BootReceiver.addTombstoneToDropBox(mContext, path, true);
} else {
BootReceiver.addTombstoneToDropBox(mContext, path, false);
如果是以pb结尾的原型文件,则handleProtoTombstone方法中为该文件生成TombstoneFile对象,并添加到数据结构
private final SparseArray<TombstoneFile> mTombstones;
并且,每个新生成的tombstone文件都会同步给dropbox
新文件的监听
frameworks/base/services/core/java/com/android/server/os/NativeTombstoneManager.java
class TombstoneWatcher extends FileObserver {
TombstoneWatcher() {
super(TOMBSTONE_DIR, FileObserver.CREATE | FileObserver.MOVED_TO);
}
@Override
public void onEvent(int event, @Nullable String path) {
mHandler.post(() -> {
handleTombstone(new File(TOMBSTONE_DIR, path));
});
内部类TombstoneWatcher,当目录/data/tombstones有文件生成时,回调到onEvent,然后通过handleTombstone方法做处理
AciivtyManager#getHistoricalProcessExitReasons
图:getHistoricalProcessExitReasons方法时序图
需要注意返回的数据结构的处理ApplicationExitInfo。
frameworks/base/services/core/java/com/android/server/os/NativeTombstoneManager.java
public void collectTombstones(ArrayList<ApplicationExitInfo> output, int callingUid, int pid,
int maxNum) {
CompletableFuture<Object> future = new CompletableFuture<>();
if (!UserHandle.isApp(callingUid)) {
return;
}
final int userId = UserHandle.getUserId(callingUid);
final int appId = UserHandle.getAppId(callingUid);
mHandler.post(() -> {
boolean appendedTombstones = false;
synchronized (mLock) {
final int tombstonesSize = mTombstones.size();
tombstoneIter:
//遍历所有已知tombstoe,
//如果userid和appid和reason匹配
//则返回请求的数量的tombstone
for (int i = 0; i < tombstonesSize; ++i) {
TombstoneFile tombstone = mTombstones.valueAt(i);
if (tombstone.matches(Optional.of(userId), Optional.of(appId))) {
if (pid != 0 && tombstone.mPid != pid) {
continue;
}
//reason判断
// Try to attach to an existing REASON_CRASH_NATIVE.
final int outputSize = output.size();
for (int j = 0; j < outputSize; ++j) {
ApplicationExitInfo exitInfo = output.get(j);
if (tombstone.matches(exitInfo)) {
exitInfo.setNativeTombstoneRetriever(tombstone.getPfdRetriever());
continue tombstoneIter;
}
}
//请求数量判断
if (output.size() < maxNum) {
appendedTombstones = true;
output.add(tombstone.toAppExitInfo());
}
}
}
}
//如果请求数量超过一个则按时间戳排序
if (appendedTombstones) {
Collections.sort(output, (lhs, rhs) -> {
// Reports should be ordered with newest reports first.
long diff = rhs.getTimestamp() - lhs.getTimestamp();
if (diff < 0) {
return -1;
} else if (diff == 0) {
return 0;
} else {
return 1;
}
});
}
future.complete(null);
});
try {
future.get();
遍历所有已知tombstoe,如果userid和appid和reason匹配则返回请求的数量的tombstone
如果数量超过一个则按时间戳排序
值得注意的是CompletableFuture,函数式编程,可参考:CompletableFuture基本用法
tombstone文件的清理
目前有两种场景会清理文件
主动调用接口删除,AppExitInfoTracker-->purge()
app被卸载时,registerForPackageRemoval-->purgePackage()-->purge()
clearHistoryProcessExitInfo
frameworks/base/services/core/java/com/android/server/am/AppExitInfoTracker.java
void clearHistoryProcessExitInfo(String packageName, int userId) {
NativeTombstoneManager tombstoneService = LocalServices.getService(
NativeTombstoneManager.class);
Optional<Integer> appId = Optional.empty();
if (TextUtils.isEmpty(packageName)) {
synchronized (mLock) {
removeByUserIdLocked(userId);
}
} else {
final int uid = mService.mPackageManagerInt.getPackageUid(packageName,
PackageManager.MATCH_ALL, userId);
appId = Optional.of(UserHandle.getAppId(uid));
synchronized (mLock) {
removePackageLocked(packageName, uid, true, userId);
}
}
tombstoneService.purge(Optional.of(userId), appId);
schedulePersistProcessExitInfo(true);
}
frameworks/base/services/core/java/com/android/server/os/NativeTombstoneManager.java
* Remove native tombstones matching a user and/or app.
public void purge(Optional<Integer> userId, Optional<Integer> appId) {
mHandler.post(() -> {
synchronized (mLock) {
for (int i = mTombstones.size() - 1; i >= 0; --i) {
TombstoneFile tombstone = mTombstones.valueAt(i);
if (tombstone.matches(userId, appId)) {
tombstone.purge();
mTombstones.removeAt(i);
----------------------------------------------------------------------
static class TombstoneFile {
public void purge() {
if (!mPurged) {
try {
Os.ftruncate(mPfd.getFileDescriptor(), 0);
} catch (ErrnoException ex) {
Slog.e(TAG, "Failed to truncate tombstone", ex);
}
mPurged = true;
purgePackage
frameworks/base/services/core/java/com/android/server/os/NativeTombstoneManager.java
private void registerForPackageRemoval() {
final IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED);
filter.addDataScheme("package");
mContext.registerReceiverForAllUsers(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
final int uid = intent.getIntExtra(Intent.EXTRA_UID, UserHandle.USER_NULL);
if (uid == UserHandle.USER_NULL) return;
final boolean allUsers = intent.getBooleanExtra(
Intent.EXTRA_REMOVED_FOR_ALL_USERS, false);
purgePackage(uid, allUsers);
}
}, filter, null, mHandler);
}
---------------------------------------------
private void purgePackage(int uid, boolean allUsers) {
final int appId = UserHandle.getAppId(uid);
Optional<Integer> userId;
if (allUsers) {
userId = Optional.empty();
} else {
userId = Optional.of(UserHandle.getUserId(uid));
}
purge(userId, Optional.of(appId));
}
private void purgeUser(int uid) {
purge(Optional.of(uid), Optional.empty());
}
服务启动时通过registerForPackageRemoval调用,开启对广播的监听:ACTION_PACKAGE_FULLY_REMOVED
当app卸载时,此处也删除其对应uid的tombstone文件
同这个包删除类似,还有用户删除时也会删对应的文件:
private void registerForUserRemoval() {
filter.addAction(Intent.ACTION_USER_REMOVED);
Android定制系统产品使用授权抽奖活动(每满100人抽奖一次),活动规则,加入星球查看,更多干货每天持续更新中,欢迎大家参与体验!