作者安卓文件管理源码解析:秋城
概述Android12 新增安卓文件管理源码解析的 system_server 进程(LocalService)本地服务安卓文件管理源码解析,用于管理native tombstones。
该服务在开机 SystemServer 初始化流程启动,添加到 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;purgePackageframeworks/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);相关文章
本站已关闭游客评论,请登录或者注册后再评论吧~