天天看點

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()

軟體架構如圖:

Android12系統源碼分析:NativeTombstoneManager

圖:NativeTombstoneManager類圖

啟動流程

Android12系統源碼分析: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

Android12系統源碼分析:NativeTombstoneManager

圖: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);