zoukankan      html  css  js  c++  java
  • Android12系统源码分析:NativeTombstoneManager

    Android12系统源码分析:NativeTombstoneManager

    概述

    android12新增的system_server进程(LocalService)本地服务,用于管理native tombstones。

    该服务在开机Systemerver初始化流程启动,添加到LocalService,然后启动一个ServiceThread线程用于(mHandler.post)处理本服务的业务。

    NativeTombstoneManager的功能主要是:

    • 监听/data/tombstones目录文件变动,解析为TombstoneFile对象保存,通知dropbox

    • 特定tombstones文件删除

    • 特定tombstones文件检索

    值得关注的是AMS对该服务的使用,也是Android11新增API: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());
        }
    
    

    f服务启动时registerForPackageRemoval调用,开启对广播的监听:ACTION_PACKAGE_FULLY_REMOVED

    当app卸载时,此处也删除其对应uid的tombstone文件

    同这个包删除类似,还有用户删除时也会删对应的文件:

        private void registerForUserRemoval() {
            filter.addAction(Intent.ACTION_USER_REMOVED);
    
    作者:秋城 | 博客:https://www.cnblogs.com/houser0323 | 转载请注明作者出处
  • 相关阅读:
    Yii 1 转载 数据库操作
    php的redis的pconnect
    微信第三方平台设置平台信息
    坑爹的python thread模块
    js爆布特效 jQuery Wookmark
    w3a Scan 插件结构的构想问题
    mac 下快捷键
    MUI学习03-滚动图(幻灯片)及菜单项(九宫格)
    MUI学习04-开关按钮
    MUI学习03-弹出菜单(弹出列表)
  • 原文地址:https://www.cnblogs.com/houser0323/p/15369142.html
Copyright © 2011-2022 走看看