fwrite

fwrite

好好生活
twitter
github
email

パッケージマネージャーサービス

PackageManagerService は SystemServer プロセスを通じて起動され、このサービスは システム内の特定のディレクトリをスキャンし、その中の APK 形式のファイルを探して解析(AppInfo に関連する情報を取得)し、最終的にインストールを完了します。
PKMS はアプリケーションのインストールプロセス中に APK 内の AndroidManifest.xml ファイルを解析(Android の 4 つの主要コンポーネントを解析)し、これらの解析された情報は Android システムに保存され、システムがいつでも利用できるようになります。

主な機能#

  • .apk ファイルをスキャンし、システムアプリローカルアプリをインストール
  • AndroidManifest.xml マニフェストファイルを解析し、4 つの主要コンポーネント、権限などの情報を分析し、PKMS に保存して照会を容易にする
  • ローカルアプリを管理し、インストールアンインストールAPK情報の照会などの機能を提供
  • アプリケーションの UID、GID を割り当てる

GID(グループ ID)を通じて権限管理を行い、特定のグループ内でのみ特定の機能を使用できるようにします。

使用#

Context#getPackageManager()メソッドを通じて PKMS サービスを取得できます。PackageManager は抽象クラスで、実際には ApplicationPackageManager です。

		
@Override
protected void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
		  
    PackageManager packageManager = this.getBaseContext().getPackageManager();
}

ServiceManager を通じて PKMS を取得#

ActivityThread は ServiceManager を通じて PKMS の IBinder を取得します。ここで
IPackageManager は AIDL を通じて自動生成されたクラスで、IPackageManager は asInterfaceを通じて Java プロキシクラスを取得し、そのプロキシクラスを通じて PKMS と通信します。

// ActivityThread.java
	  
@UnsupportedAppUsage
public static IPackageManager getPackageManager() {
    if (sPackageManager != null) {
        return sPackageManager;
    }
	          
    // 1.ServiceManagerのプロキシを取得
    // 2.プロキシを通じて「package」を渡してPKMSのハンドルを取得
    // 3.PKMSのプロキシを返す
    final IBinder b = ServiceManager.getService("package");
	          
    // AIDLのプロキシクラスを作成
    sPackageManager = IPackageManager.Stub.asInterface(b);
	          
    return sPackageManager;
}

SystemServer で PKMS を初期化#

SystemServer はブートストラップサービスを起動します(startBootstrapServices):PKMS はここで起動します。

// SystemServer.java

public static void main(String[] args) {
    new SystemServer().run();
}
	  
	  
private void run() {
    ... 省略部分

    try {
        startBootstrapServices(t);
        startCoreServices(t);
        startOtherServices(t);
    } /* 省略 catch */

    ... 省略部分

    // 永久にループします。
    Looper.loop();
	  
    throw new RuntimeException("メインスレッドループが予期せず終了しました");
}
	  
	  
private void startBootstrapServices(@NonNull TimingsTraceAndSlog t) 
    ... 

    // インストールサービス
    Installer installer = mSystemServiceManager.startService(Installer.class);

    mDisplayManagerService = mSystemServiceManager.startService(DisplayManagerService.class);
	  
	... 
	  
    try {
        ... watch dog

        // PackageManagerServiceの静的mainメソッドを呼び出す
        // @ mainを解析
        mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
                domainVerificationService, mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF,
                mOnlyCore);
    } ... watch dog
	  
    ... 
}

startBootstrapServices#

Installer サービスを起動し、その後このサービスを使用してすべてのアプリをインストールします。

// SystemServer.java

private void startBootstrapServices(@NonNull TimingsTraceAndSlog t) {
    ... 省略部分

    Installer installer = mSystemServiceManager.startService(Installer.class);

    ... 省略部分
}

VoldProperties#decryptはデバイスが暗号化されているかどうかを判断します(init.rcファイルの設定を読み取ります)。mOnlyCore = trueはコアプログラムのみを実行することを示します。

// SystemServer.java

private static final String ENCRYPTING_STATE = "trigger_restart_min_framework";

private void startBootstrapServices(@NonNull TimingsTraceAndSlog t) {
    ...

    // デバイスが暗号化されている場合は「コア」アプリのみを実行します。
    String cryptState = VoldProperties.decrypt().orElse("");

    if (ENCRYPTING_STATE.equals(cryptState)) {
        // コアプログラムのみを実行
        ... log msg

        mOnlyCore = true;
    } else if (ENCRYPTED_STATE.equals(cryptState)) {
        ... log msg

        mOnlyCore = true;
    }

    ...
}

PKMS#mainメソッドを呼び出して PKMS オブジェクトを作成します。

// SystemServer.java

private void startBootstrapServices(@NonNull TimingsTraceAndSlog t) {
    ... 省略部分

    try {
        ...

        PackageManagerService.main(mSystemContext, installer,
                domainVerificationService, 
                mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF,
                mOnlyCore);    // falseを渡すと仮定します
    } /* 省略 finally */
  
    ... 省略部分
}

デバイスが暗号化されていない場合、A/B OTA dexopting を実行します。OtaDexoptService#mainメソッド。

// SystemServer.java

private void startBootstrapServices(@NonNull TimingsTraceAndSlog t) {
    ... 

    if (!mOnlyCore) {
        boolean disableOtaDexopt = SystemProperties.getBoolean("config.disable_otadexopt",
                false);

        if (!disableOtaDexopt) {
            ... trace log
            try {
                ... watch dog
                    
                OtaDexoptService.main(mSystemContext, mPackageManagerService);
            } /*  catch、finally */
        }
    }

    ...
}

PKMS は SystemServer#startBootstrapServices関数で初期化操作を完了した後、startOtherServicesで後続の操作を行います(Dex 最適化、systemReady を完了します)。PKMS#performFstrimIfNeededを通じて dex 最適化を完了します。

// SystemServer.java

private void startOtherServices(@NonNull TimingsTraceAndSlog t) {

    ... 省略部分

    try {
        mPackageManagerService.performFstrimIfNeeded();
    } ...

    ... 省略部分
}

PKMS は準備が整ったらsystemReadyを呼び出し、デフォルトの権限を読み込みます

PKMS の分析#

PKMS main#

PackageManagerService#mainメソッドを通じて PackageManagerService オブジェクトを作成し、PKMS をpackagepackage_nativeを通じて ServiceManager に追加します。

// PackageManagerService.java

public static PackageManagerService main(Context context, Installer installer,
        @NonNull DomainVerificationService domainVerificationService, boolean factoryTest,
        boolean onlyCore) {

    // パッケージコンパイルに関連するシステムプロパティをチェック
    PackageManagerServiceCompilerMapping.checkProperties();

    ...

    Injector injector = new Injector(
            context, lock, installer, installLock, 
            new PackageAbiHelperImpl(),
            backgroundHandler,
            SYSTEM_PARTITIONS,
            (i, pm) -> new ComponentResolver(i.getUserManagerService(), pm.mPmInternal, lock),
            (i, pm) -> PermissionManagerService.create(context,
                    i.getSystemConfig().getAvailableFeatures()),
            (i, pm) -> new UserManagerService(context, pm,
                    new UserDataPreparer(installer, installLock, context, onlyCore),
                    lock),
            (i, pm) -> new Settings(Environment.getDataDirectory(),
                    RuntimePermissionsPersistence.createInstance(),
                    i.getPermissionManagerServiceInternal(),
                    domainVerificationService, lock),
            (i, pm) -> AppsFilter.create(pm.mPmInternal, i),
            (i, pm) -> (PlatformCompat) ServiceManager.getService("platform_compat"),
            (i, pm) -> SystemConfig.getInstance(),
            (i, pm) -> new PackageDexOptimizer(i.getInstaller(), i.getInstallLock(),
                    i.getContext(), "*dexopt*"),
            (i, pm) -> new DexManager(i.getContext(), pm, i.getPackageDexOptimizer(),
                    i.getInstaller(), i.getInstallLock()),
            (i, pm) -> new ArtManagerService(i.getContext(), pm, i.getInstaller(),
                    i.getInstallLock()),
            (i, pm) -> ApexManager.getInstance(),
            (i, pm) -> new ViewCompiler(i.getInstallLock(), i.getInstaller()),
            (i, pm) -> (IncrementalManager)
                    i.getContext().getSystemService(Context.INCREMENTAL_SERVICE),
            (i, pm) -> new DefaultAppProvider(() -> context.getSystemService(RoleManager.class),
                    () -> LocalServices.getService(UserManagerInternal.class)),
            (i, pm) -> new DisplayMetrics(),
            (i, pm) -> new PackageParser2(pm.mSeparateProcesses, pm.mOnlyCore,
                    i.getDisplayMetrics(), pm.mCacheDir,
                    pm.mPackageParserCallback) /* scanningCachingPackageParserProducer */,
            (i, pm) -> new PackageParser2(pm.mSeparateProcesses, pm.mOnlyCore,
                    i.getDisplayMetrics(), null,
                    pm.mPackageParserCallback) /* scanningPackageParserProducer */,
            (i, pm) -> new PackageParser2(pm.mSeparateProcesses, false, i.getDisplayMetrics(),
                    null, pm.mPackageParserCallback) /* preparingPackageParserProducer */,
            // ステージングマネージャがapexファイルを解析するためのパッケージパーサーの供給者を準備します
            (i, pm) -> new PackageInstallerService(
                    i.getContext(), pm, i::getScanningPackageParser),
            (i, pm, cn) -> new InstantAppResolverConnection(
                    i.getContext(), cn, Intent.ACTION_RESOLVE_INSTANT_APP_PACKAGE),
            (i, pm) -> new ModuleInfoProvider(i.getContext(), pm),
            (i, pm) -> LegacyPermissionManagerService.create(i.getContext()),
            (i, pm) -> domainVerificationService,
            (i, pm) -> {
                // apkのインストール、アンインストールを担当
                HandlerThread thread = new ServiceThread(TAG,
                        Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
                thread.start();
                return pm.new PackageHandler(thread.getLooper());
            },
            new DefaultSystemWrapper(),
            LocalServices::getService,
            context::getSystemService);

    // PackageMangerServiceのコンストラクタを呼び出す
    PackageManagerService m = new PackageManagerService(injector, onlyCore, factoryTest,
            Build.FINGERPRINT, Build.IS_ENG, Build.IS_USERDEBUG, Build.VERSION.SDK_INT,
            Build.VERSION.INCREMENTAL);

    ...

    // package、package_nativeを通じてServiceManagerに追加
    ServiceManager.addService("package", m);
    final PackageManagerNative pmn = m.new PackageManagerNative();
    ServiceManager.addService("package_native", pmn);
    return m;
}
// PackageManagerService.java

public static class Injector {

    @VisibleForTesting(visibility = Visibility.PRIVATE)
    interface Producer<T> {
        /** Produce an instance of type {@link T} */
        T produce(Injector injector, PackageManagerService packageManager);
    }

    ... 

    @VisibleForTesting(visibility = Visibility.PRIVATE)
    static class Singleton<T> {
        private final Producer<T> mProducer;
        private volatile T mInstance = null;

        Singleton(Producer<T> producer) {
            this.mProducer = producer;
        }

        T get(Injector injector, PackageManagerService packageManagerService) {
            if (mInstance == null) {
                mInstance = mProducer.produce(injector, packageManagerService);
            }
            return mInstance;
        }
    }

    private final Singleton<PermissionManagerServiceInternal> mPermissionManagerServiceProducer;
    private final Singleton<UserManagerService> mUserManagerProducer;
    private final Singleton<Settings> mSettingsProducer;
    private final Singleton<AppsFilter> mAppsFilterProducer;
    ...
    private final Singleton<DisplayMetrics> mDisplayMetricsProducer;

    Injector(Context context, PackageManagerTracedLock lock, Installer installer,
            Object installLock, PackageAbiHelper abiHelper,
            Handler backgroundHandler,
            List<ScanPartition> systemPartitions, 
            ...
            Producer<PermissionManagerServiceInternal> permissionManagerServiceProducer,
            Producer<UserManagerService> userManagerProducer,
            Producer<Settings> settingsProducer,
            Producer<DisplayMetrics> displayMetricsProducer,
            ) {

        ...

        mPermissionManagerServiceProducer = new Singleton<>(permissionManagerServiceProducer);
        mUserManagerProducer = new Singleton<>(userManagerProducer);
        mSettingsProducer = new Singleton<>(settingsProducer);

        ...

        mDisplayMetricsProducer = new Singleton<>(displayMetricsProducer);
    }

    public PermissionManagerServiceInternal getPermissionManagerServiceInternal() {
        return mPermissionManagerServiceProducer.get(this, mPackageManager);
    }

    public Context getContext() {
        return mContext;
    }

    public Settings getSettings() {
        return mSettingsProducer.get(this, mPackageManager);
    }

    public DisplayMetrics getDisplayMetrics() {
        return mDisplayMetricsProducer.get(this, mPackageManager);
    }

    ...

}

PKMS のコンストラクタ#

PackageManagerService のコンストラクタでは、PKMS が5 つの段階で構築されることがわかります(EventLog に記録されます)。

段階フラグ説明その他
BOOT_PROGRESS_PMS_START初期段階、Inject 内部クラスを通じてシングルトンのさまざまなサービス、オブジェクトを取得DisplayMetrics、Installer、mPermissionManager、mSettings、mPackageDexOptimizer
BOOT_PROGRESS_PMS_SYSTEM_SCAN_STARTシステムをスキャン
BOOT_PROGRESS_PMS_DATA_SCAN_STARTデータブロックをスキャン
BOOT_PROGRESS_PMS_SCAN_ENDスキャン終了
BOOT_PROGRESS_PMS_READY準備段階

PKMS は複数のスレッドを使用し、その中には注意すべき 2 つの重要なロックがあります。

ロック名説明補足
mPackages(小ロック)メモリ内のすべてのパッケージの詳細、状態、更新を保護するために使用mInstallLock を保持しているときに mPackages を取得することは安全です
mInstallLock(大ロック)すべての APK インストール時のロックを保護するために使用され、通常はアプリ APP の再ロードに関連します(単一スレッド、重い IO 操作に関与mPackages を取得する際にこのロックを取得すべきではありません

第一段階 - BOOT_PROGRESS_PMS_START#

第一段階の重点は Settings#readLPw メソッドで、/data/systemディレクトリ内のファイルを読み取ります。

BOOT_PROGRESS_PMS_STARTDisplayMetrics(解像度)、Installer(インストール)、PermissionManager(権限管理)、mSettings(インストール情報の保存、存在しないアプリの削除)、PackageDexOptimizer(Dex 最適化)などを取得します。詳細はコメントを参照してください。

// PackageManagerService.java

public PackageManagerService(Injector injector, boolean onlyCore, boolean factoryTest,final String buildFingerprint, final boolean isEngBuild,final boolean isUserDebugBuild, final int sdkVersion, final String incrementalVersion) {

    ...

    EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,
            SystemClock.uptimeMillis());


    mOnlyCore = onlyCore;
    mMetrics = injector.getDisplayMetrics();
    mInstaller = injector.getInstaller();
    mUserManager = injector.getUserManagerService(); // マルチユーザー管理
    // 権限管理サービス
    mPermissionManager = injector.getPermissionManagerServiceInternal();

    // 'data/system/'に関連するファイル
    // packages.xml
    // packages-backup.xml
    // packages.list
    // packages-stopped.xml
    // packages-stopped-backup.xmlファイル
    mSettings = injector.getSettings();

    ...

    // system、phone、log、nfc、bluetooth、shell、se、
    // networkstack、uwbなどのsharedUserLPwをmSettingsに追加
    mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,ApplicationInfo.FLAG_SYSTEM,ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
    mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID,
            ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
    mSettings.addSharedUserLPw("android.uid.log", LOG_UID,
            ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
    mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID,
            ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
    mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID,
            ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
    mSettings.addSharedUserLPw("android.uid.shell", SHELL_UID,
            ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
    mSettings.addSharedUserLPw("android.uid.se", SE_UID,
            ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
    mSettings.addSharedUserLPw("android.uid.networkstack", NETWORKSTACK_UID,
            ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
    mSettings.addSharedUserLPw("android.uid.uwb", UWB_UID,
            ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);

    ...

    // dex最適化を処理(DexOpt最適化)
    mPackageDexOptimizer = injector.getPackageDexOptimizer();
    mDexManager = injector.getDexManager();
    // Art仮想マシン管理
    mArtManagerService = injector.getArtManagerService();

    ...

    // /data/appフォルダを作成
    mAppInstallDir = new File(Environment.getDataDirectory(), "app");

    // APKインストール時に必要なロック、すべてのinstalledへのアクセスを保護
    // CHECKSTYLE:OFF IndentationCheck
    synchronized (mInstallLock) {
    // writer
    synchronized (mLock) {
        // PackageManager Threadを起動し、apkのインストール、アンインストールを担当
        mHandler = injector.getHandler();
        // プロセス記録Handler
        mProcessLoggingHandler = new ProcessLoggingHandler();
        
        // PackageManager Threadが10分間タイムアウトするかどうかを監視
        Watchdog.getInstance().addThread(mHandler, 
                                 // WATCHDOG_TIMEOUT => 10分
                                 WATCHDOG_TIMEOUT);
    
        ...
            
        // インストール関連のSELinuxポリシーを読み取る
        SELinuxMMAC.readInstallPolicy();
        
        // /data/system内のxmlファイルを読み取り、解析する
        mFirstBoot = !mSettings.readLPw(sUserManager.getUsers(false));
        
        t.traceEnd();
    }
    
    }
}

ここで mSettings.addSharedUserLPw メソッドは SharedUserId を Settings に追加します。一般的にプロセス間データは共有できませんが、共通の SharedUserId があればデータを共有できます

  • mPackageDexOptimizer は Dex の最適化ツールです。
  • mHandler はバックグラウンド ServiceThread のメッセージキューにバインドされ、PKMS はこれを通じて APK のコピーとインストールを駆動し、この Handler は WatchDog によって監視されます(過度な時間を費やさないように)。

PKMD は以下の重要なフォルダにアクセスします。

アクセスフォルダ
File(Environment.getDataDirectory(), “app”)/data/app
File(Environment.getDataDirectory(), “app-lib”)/data/app-lib

Settings の作成#

まず、Settings オブジェクトの由来を復習します:PKMS の Settings オブジェクトはPKMS#Injectクラスによって提供されます。

// PackageManager

public static class Injector {

    private final Singleton<Settings> mSettingsProducer;

    Injector(/* 省略パラメータ */) {
        ...
        mSettingsProducer = new Singleton<>(settingsProducer);
    }

    public Settings getSettings() {
        return mSettingsProducer.get(this, mPackageManager);
    }

}

public static PackageManagerService main(Context context, Installer installer,
        @NonNull DomainVerificationService domainVerificationService, boolean factoryTest,
        boolean onlyCore) {
    
    Injector injector = new Injector(
            context, lock, installer, installLock, new PackageAbiHelperImpl(),
            backgroundHandler,
            SYSTEM_PARTITIONS,
        ...
      
        (i, pm) -> new Settings(Environment.getDataDirectory(),  
                    RuntimePermissionsPersistence.createInstance(),
                    i.getPermissionManagerServiceInternal(),
                    domainVerificationService, 
                    lock),
    );
}

Settings クラスのコンストラクタは必要なファイルとフォルダを作成し、それらの権限を設定します。

// Settings.java

Settings(File dataDir,    //渡されたdataDirは/data
         RuntimePermissionsPersistence runtimePermissionsPersistence,
        LegacyPermissionDataProvider permissionDataProvider,
        @NonNull DomainVerificationManagerInternal domainVerificationManager,
        @NonNull PackageManagerTracedLock lock)  {

    ...

    // /data/systemディレクトリを作成
    mSystemDir = new File(dataDir, "system");//'/data/system'
    mSystemDir.mkdirs(); // /data/systemを作成
    // フォルダの権限 775
    FileUtils.setPermissions(mSystemDir.toString(),
            FileUtils.S_IRWXU|FileUtils.S_IRWXG
            |FileUtils.S_IROTH|FileUtils.S_IXOTH,
            -1, -1);

    // /data/system/packages.xmlを作成
    mSettingsFilename = new File(mSystemDir, "packages.xml");
    // /data/system/packages-backup.xmlを作成 
    mBackupSettingsFilename = new File(mSystemDir, "packages-backup.xml");
    // data/system/packages.listを作成
    mPackageListFilename = new File(mSystemDir, "packages.list");

    // chmod 0640を設定
    FileUtils.setPermissions(mPackageListFilename, 0640, SYSTEM_UID, PACKAGE_INFO_GID);

    final File kernelDir = new File("/config/sdcardfs");
    mKernelMappingFilename = kernelDir.exists() ? kernelDir : null;

    // 非推奨:移行に必要
    // data/system/packages-stopped.listを作成
    mStoppedPackagesFilename = new File(mSystemDir, "packages-stopped.xml");
    // data/system/packages-stopped-backup.listを作成
    mBackupStoppedPackagesFilename = new File(mSystemDir, "packages-stopped-backup.xml");

    ...

}

Settings - readLPw でパッケージファイルを読み取る#

mSettings#readLPw () 関数/data/systemディレクトリ内のファイルを読み取り、Settings オブジェクトに保存します。ファイルは以下のように分類されます(重要なものをいくつか挙げます)。

ファイル名説明その他
packages.xmlインストールされたアプリ情報PKMS がディレクトリファイルをスキャンした後にこのファイルが作成され、システムがインストール、アンインストール、更新などの操作を行うたびにこのファイルが更新されます。
packages-backup.xmlインストールされたアプリのバックアップ情報インストール中にシャットダウンすることを避けるため。
packages.listすべてのインストールされたアプリ情報(システム APP ではない)すべての非システム APK 情報を記述し、サードパーティアプリが変更されるとこのファイルが変更されます。
packages-stopped.xml強制停止されたアプリ情報ユーザー操作で特定のアプリを強制停止した場合、システムはそのアプリの関連情報をこのファイルに記録します。
packages-stopped-backup.xml強制停止されたアプリのバックアップ情報
**mSettings#readLPw ()** の機能:最初にpackages.xmlpackages-backup.xmlファイルをスキャンし、Linux で使用される UID に関連する関数は以下の通りです。
「package」タグreadPackageLPw関数を使用して、前回割り当てられた Linux UID を読み取ります。
「shared-user」タグreadSharedUserLPw関数を使用して、前回アプリが共有した shared ID を読み取ります。
// Settings.java

boolean readLPw(@NonNull List<UserInfo> users) {
    FileInputStream str = null;

    // packages-backup.xmlが存在する場合はバックアップIOストリームを取得
    if (mBackupSettingsFilename.exists()) {
        try {
            str = new FileInputStream(mBackupSettingsFilename);
            ...
        } /* 省略 catch */
    }

    try {
        if (str == null) {
            ...

            // バックアップがない場合はpackages.xmlを使用
            str = new FileInputStream(mSettingsFilename);
        }

        // xmlを解析
        final TypedXmlPullParser parser = Xml.resolvePullParser(str);
        int type;
        // xmlインデックス位置を調整
        while ((type = parser.next()) != XmlPullParser.START_TAG
                && type != XmlPullParser.END_DOCUMENT) {
            ;
        }
        // 解析形式を判断し、xml形式が正しいか確認
        if (type != XmlPullParser.START_TAG) {
            ... err log
            return false;
        }


        int outerDepth = parser.getDepth();
        // xmlの解析を開始
        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
                continue;
            }

            // ノード名を解析
            String tagName = parser.getName();
            if (tagName.equals("package")) {
                // 前回割り当てられたLinux UIDを読み取る
                readPackageLPw(parser, users);

            } else if (tagName.equals("permissions")) {
                mPermissions.readPermissions(parser);

            } else if (tagName.equals("permission-trees")) {
                mPermissions.readPermissionTrees(parser);

            } else if (tagName.equals("shared-user")) {
                // 前回アプリが共有したGIDを読み取る
                readSharedUserLPw(parser, users);

            } ... 省略部分 else if

            else {
                ... log

                XmlUtils.skipCurrentTag(parser);
            }
        }
        str.close();
    } /* 省略 catch、finally */ 

    ...

    return true;
}

readPackageLPw アプリに独立した Linux ID を割り当てる#

次に、私たちは「package」タグ内の 3 つの要素に注目します。

要素名機能補足
nameアプリのパッケージ名パッケージ名は必須です。
userIdLinux が前回このアプリに割り当てた 独立 UID
sharedUserIdこのアプリは 独立 UID を持たず、他のアプリと UID を共有します。このアプリをmPendingPackagesリストに追加した後に判断します。
// Setting.java

public static final String ATTR_NAME = "name";

private final WatchedArrayList<PackageSetting> mPendingPackages = new WatchedArrayList<>();

private void readPackageLPw(TypedXmlPullParser parser, List<UserInfo> users,
        ArrayMap<String, Long> originalFirstInstallTimes)
        throws XmlPullParserException, IOException {

    String name = null;
    int userId = 0;
    int sharedUserAppId = 0;

    try {
        // アプリパッケージ名
        name = parser.getAttributeValue(null, ATTR_NAME);

        ...

        userId = parser.getAttributeInt(null, "userId", 0);
        sharedUserAppId = parser.getAttributeInt(null, "sharedUserId", 0);

        if (name == null) {
            PackageManagerService.reportSettingsProblem(Log.WARN,
                    "エラー:パッケージマネージャ設定:<package>に名前がありません。位置:"
                            + parser.getPositionDescription());
        } else if (codePathStr == null) {
            ...

        } else if (userId > 0) {    // 独立IDが割り当てられている
            packageSetting = addPackageLPw(name.intern(), realName, new File(codePathStr),
                    legacyNativeLibraryPathStr, primaryCpuAbiString, secondaryCpuAbiString,
                    cpuAbiOverrideString, userId, versionCode, pkgFlags, pkgPrivateFlags,
                    null /* usesSdkLibraries */, null /* usesSdkLibraryVersions */,
                    null /* usesStaticLibraries */, null /* usesStaticLibraryVersions */,
                    null /* mimeGroups */, domainSetId);

            ...

        } else if (sharedUserAppId != 0) {    // 独立IDが割り当てられていない
            if (sharedUserAppId > 0) {

                // このアプリの情報を保存
                packageSetting = new PackageSetting(name.intern(), realName,
                        new File(codePathStr), legacyNativeLibraryPathStr,
                        primaryCpuAbiString, secondaryCpuAbiString, cpuAbiOverrideString,
                        versionCode, pkgFlags, pkgPrivateFlags, sharedUserAppId,
                        null /* usesSdkLibraries */,
                        null /* usesSdkLibrariesVersions */,
                        null /* usesStaticLibraries */,
                        null /* usesStaticLibraryVersions */,
                        null /* mimeGroups */, domainSetId);
                ...

                // `mPendingPackages`リストに追加
                mPendingPackages.add(packageSetting);
                ...
            } else {
                ...
            }
        } else {
            ...
        }
    } /* 省略 catch */
}

addPackageLPw関数:PKMS 内の 各アプリは PackageSetting オブジェクトとして存在し、パッケージ名をキーとした HashMap に保存されます。

// Setting.java

// すべてのアプリの情報を保存
final WatchedArrayMap<String, PackageSetting> mPackages;

private final AppIdSettingMap mAppIds;

PackageSetting addPackageLPw(String name, String realName, File codePath,
        String legacyNativeLibraryPathString, String primaryCpuAbiString,
        String secondaryCpuAbiString, String cpuAbiOverrideString, int uid, 
        ... /* 省略部分 */) {

    // nameを使用してPackageSettingを取得
    PackageSetting p = mPackages.get(name);
    if (p != null) {
        // uidを判断
        if (p.getAppId() == uid) {
            // 等しい場合は独立UIDが割り当てられていることを示します。
            return p;
        }
        PackageManagerService.reportSettingsProblem(Log.ERROR,
                "重複パッケージを追加しています。最初のものを保持します:" + name);
        return null;
    }
    p = new PackageSetting(name, realName, codePath, legacyNativeLibraryPathString,
            primaryCpuAbiString, secondaryCpuAbiString, cpuAbiOverrideString, 
            ... /* 省略部分 */);

    // このPackageSettingにUIDを設定
    p.setAppId(uid);

    // このIDをシステムに登録
    if (mAppIds.registerExistingAppId(uid, p, name)) {
        mPackages.put(name, p);
        return p;
    }
    return null;
}

registerExistingAppId関数:割り当てられたアプリはmNonSystemSettingsから null を取得します。

// Process.java

public static final int FIRST_APPLICATION_UID = 10000;

// ------------------------------------------------------------
// AppIdSettingMap.java

private final WatchedArrayList<SettingBase> mNonSystemSettings;

public boolean registerExistingAppId(int appId, SettingBase setting, Object name) {

    // FIRST_APPLICATION_UID以上は独立アプリを示します。
    if (appId >= Process.FIRST_APPLICATION_UID) {
        int size = mNonSystemSettings.size();
        final int index = appId - Process.FIRST_APPLICATION_UID;
        // インデックスが有効になるまで配列を埋めます。
        while (index >= size) {
            mNonSystemSettings.add(null);
            size++;
        }
        // すでに割り当てられている場合はnullを取得します。
        if (mNonSystemSettings.get(index) != null) {
            // 重複UID
           
            ...err msg
            return false;
        }
        mNonSystemSettings.set(index, setting);
    } else {
        // FIRST_APPLICATION_UID未満は共有アプリを示します。
        ...
    }
    return true;
}

readPackageLPw 共有 Linux ID をアプリに割り当てる#

次に、私たちは「shared-user」タグ内の 3 つの要素に注目します。

要素名機能補足
name共有 Linux ユーザーの名前を説明するために使用されます。
userId共有 Linux ユーザーの ID を説明します。
systemこの ID がシステム型、ユーザー型であることを示します。
// Setting.java

private void readSharedUserLPw(TypedXmlPullParser parser, List<UserInfo> users)
        throws XmlPullParserException, IOException {
    String name = null;
    int pkgFlags = 0;
    int pkgPrivateFlags = 0;
    SharedUserSetting su = null;
    {
        name = parser.getAttributeValue(null, ATTR_NAME);    
        int userId = parser.getAttributeInt(null, "userId", 0);
        if (parser.getAttributeBoolean(null, "system", false)) {
            pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
        }
        
        if (name == null) {
            ...
        } else if (userId == 0) {
            ...
        } else {
            if ((su = addSharedUserLPw(name.intern(), userId, pkgFlags, pkgPrivateFlags))
                    == null) 
                ...
            }
        }
    }

    ...
}

Setting#addSharedUserLPw 関数:SharedUserSettingを使用して共有アプリを説明します。ID を確認して問題がないことを確認した後、mSharedUsersリストに追加します。

// Setting.java

final WatchedArrayMap<String, SharedUserSetting> mSharedUsers 
            = new WatchedArrayMap<>();

SharedUserSetting addSharedUserLPw(String name, int uid, int pkgFlags, int pkgPrivateFlags) {
    SharedUserSetting s = mSharedUsers.get(name);
    if (s != null) {
        if (s.mAppId == uid) {
            return s;
        }
        ...err

        return null;
    }
    // 対応するオブジェクトを作成
    s = new SharedUserSetting(name, pkgFlags, pkgPrivateFlags);
    // IDを設定
    s.mAppId = uid;
    
    // 登録を試みる
    if (mAppIds.registerExistingAppId(uid, s, name)) {
        mSharedUsers.put(name, s);
        return s;
    }
    return null;
}

registerExistingAppId 関数:割り当てられたアプリはmNonSystemSettingsから null を取得します。

// Process.java

public static final int FIRST_APPLICATION_UID = 10000;

// ------------------------------------------------------------
// AppIdSettingMap.java

private final WatchedArrayList<SettingBase> mNonSystemSettings;

public boolean registerExistingAppId(int appId, SettingBase setting, Object name) {

    // FIRST_APPLICATION_UID以上は独立アプリを示します。
    if (appId >= Process.FIRST_APPLICATION_UID) {
        ...
    } else {
        // FIRST_APPLICATION_UID未満は共有アプリを示します。
        if (mSystemSettings.get(appId) != null) {
            ...err

            return false;
        }
        mSystemSettings.put(appId, setting);
    }
    return true;
}

readLPw関数に戻ります:上記の分析を経て、“shared-user”“package”の情報を取得し、次に共有アプリの ID を処理します。

// Settings.java

private final AppIdSettingMap mAppIds;

boolean readLPw(@NonNull List<UserInfo> users) {

    ...

    final int N = mPendingPackages.size();

    for (int i = 0; i < N; i++) {
        final PackageSetting p = mPendingPackages.get(i);
        final int sharedUserAppId = p.getSharedUserAppId();
        
        // 共有IDは必ず0より大きい
        if (sharedUserAppId <= 0) {
            continue;
        }
        final Object idObj = getSettingLPr(sharedUserAppId);
        if (idObj instanceof SharedUserSetting) {
            final SharedUserSetting sharedUser = (SharedUserSetting) idObj;
            addPackageSettingLPw(p, sharedUser);
        } else if (idObj != null) {
            ...
        } else {
            ...
        }
    }
    mPendingPackages.clear();

    return true;
}


public SettingBase getSettingLPr(int appId) {
    return mAppIds.getSetting(appId);
}

void addPackageSettingLPw(PackageSetting p, SharedUserSetting sharedUser) {
    mPackages.put(p.getPackageName(), p);
    
    // 共有アプリの場合はさらに判断が必要
    if (sharedUser != null) {
        SharedUserSetting existingSharedUserSetting = getSharedUserSettingLPr(p);

        if (existingSharedUserSetting != null && existingSharedUserSetting != sharedUser) {
            ...err msg

            sharedUser.removePackage(p);
        } else if (p.getAppId() != sharedUser.mAppId) {
            ...err msg

        }

        sharedUser.addPackage(p);
        p.setSharedUserAppId(sharedUser.mAppId);
        // 最終的なIDを決定
        p.setAppId(sharedUser.mAppId);
    }

    Object userIdPs = getSettingLPr(p.getAppId());
    if (sharedUser == null) {
        if (userIdPs != null && userIdPs != p) {
            mAppIds.replaceSetting(p.getAppId(), p);
        }
    } else {
        if (userIdPs != null && userIdPs != sharedUser) {
            mAppIds.replaceSetting(p.getAppId(), sharedUser);
        }
    }
}

第二段階 - BOOT_PROGRESS_PMS_SYSTEM_SCAN_START#

BOOT_PROGRESS_PMS_SYSTEM_SCAN_START:システムスキャン段階で、ディレクトリには(systemvendorproductodmoemなどのディレクトリ内のpriv-appappoverlay)が含まれ、このステップは2 つのロック内で実行されます
scanDirTracedLI メソッド:このメソッドは APK パッケージをスキャンし、渡されたパス内の APK ファイルをスキャンし、その後 scanDirTracedLI を分析します。

	  // PackageManagerService.java
	  
	  // キーはアプリパッケージ名、値はアプリパッケージ
	  final ArrayMap<String, PackageParser.Package> mPackages =
	          new ArrayMap<String, PackageParser.Package>();
	  
	  public PackageManagerService(Injector injector, boolean onlyCore, boolean factoryTest,
	          final String buildFingerprint, final boolean isEngBuild,
	          final boolean isUserDebugBuild, final int sdkVersion, final String incrementalVersion) {
	  
	      ...
	  
	      // CHECKSTYLE:OFF IndentationCheck
	      synchronized (mInstallLock) {
	      // writer
	      synchronized (mLock) {
	  
	          ...
	  
	          // 開始時間を記録
	          long startTime = SystemClock.uptimeMillis();
	          EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START,
	              startTime);
	  
	          // init.rcから環境変数BOOTCLASSPATH、
	          //                        SYSTEMSERVERCLASSPATHを取得
	          final String bootClassPath = 
	              System.getenv("BOOTCLASSPATH");
	  
	          final String systemServerClassPath = 
	              System.getenv("SYSTEMSERVERCLASSPATH");
	  
	  
	          // /system/frameworkディレクトリを取得
	          File frameworkDir = new File(Environment.getRootDirectory(), "framework");
	  
	          // 内部バージョンを取得
	          final VersionInfo ver = mSettings.getInternalVersion();
	  
	          // 更新が必要かどうかを判断
	          mIsUpgrade =
	              !buildFingerprint.equals(ver.fingerprint);
	  
	          // Android Mからのアップグレードバージョンでは、システムアプリの権限をインストール時に要求するのではなく、実行時に要求する必要があります。
	          mPromoteSystemApps =
	              mIsUpgrade && ver.sdkVersion <= Build.VERSION_CODES.LOLLIPOP_MR1;
	  
	          // Android Nからのアップグレードバージョンでは、初回起動時のようにパッケージ抽出を処理する必要があります。利用可能な解析データがないため。
	          mIsPreNUpgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.N;
	          mIsPreNMR1Upgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.N_MR1;
	          mIsPreQUpgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.Q;
	  
	          ...
	  
	          // パッケージ解析キャッシュを準備
	          mCacheDir = preparePackageParserCache(mIsEngBuild);
	  
	          // フラグを設定し、インストールファイルをスキャンする際にapkパスを変更しない
	          int scanFlags = SCAN_BOOTING | SCAN_INITIAL;
	  
	          // vendor/product/system_ext overlayパッケージを収集します。
	          for (int i = mDirsToScanAsSystem.size() - 1; i >= 0; i--) {
	              final ScanPartition partition = mDirsToScanAsSystem.get(i);
	              if (partition.getOverlayFolder() == null) {
	                  continue;
	              }
	              // overlayなどのフォルダ内のapkをスキャン
	              scanDirTracedLI(partition.getOverlayFolder(), systemParseFlags,
	                      systemScanFlags | partition.scanFlag, 0,
	                      packageParser, executorService);
	          }
	  
	          // frameworkフォルダ内のapkをスキャン
	          scanDirTracedLI(frameworkDir, systemParseFlags,
	              systemScanFlags | SCAN_NO_DEX | SCAN_AS_PRIVILEGED, 0,
	              packageParser, executorService);
	  
	          // インストールパッケージがandroidであるかどうかを判断
	          if (!mPackages.containsKey("android")) {
	              throw new IllegalStateException(
	                      "フレームワークパッケージの読み込みに失敗しました。警告をログで確認してください。");
	          }
	  
	          for (int i = 0, size = mDirsToScanAsSystem.size(); i < size; i++) {
	              final ScanPartition partition = mDirsToScanAsSystem.get(i);
	              if (partition.getPrivAppFolder() != null) {
	                  // priv-appフォルダをスキャン
	                  scanDirTracedLI(partition.getPrivAppFolder(), systemParseFlags,
	                          systemScanFlags | SCAN_AS_PRIVILEGED | partition.scanFlag, 0,
	                          packageParser, executorService);
	              }
	              // /system/appフォルダをスキャン
	              scanDirTracedLI(partition.getAppFolder(), systemParseFlags,
	                      systemScanFlags | partition.scanFlag, 0,
	                      packageParser, executorService);
	          }
	  
	          ...
	  
	          if (!mOnlyCore) {
	              // mPackagesを変更する前にこれを最初に行います。「より良いことを期待している」ケースのために
	              final int numPackages = mPackages.size();
	              for (int index = 0; index < numPackages; index++) {
	                  final AndroidPackage pkg = mPackages.valueAt(index);
	                  if (pkg.isStub()) {
	                      stubSystemApps.add(pkg.getPackageName());
	                  }
	              }
	  
	              // すべてのアプリを逆順でスキャンします。
	              for (int index = packageSettings.size() - 1; index >= 0; index--) {
	                  final PackageSetting ps = packageSettings.valueAt(index);
	  
	                  // パッケージにFLAG_SYSTEMがある場合は無視します。
	                  if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) {
	                      continue;
	                  }
	                  /*
	                   * パッケージがスキャンされている場合、消去されていません。
	                   */
	                  final AndroidPackage scannedPkg = mPackages.get(ps.name);
	                  if (scannedPkg != null) {
	  					//無効なパッケージリストにある場合、OTAを介して追加し、
	  					//その後削除します。
	                      if (mSettings.isDisabledSystemPackageLPr(ps.name)) {
	                          ...
	                          // システムアプリのPackageSettingをPKMSからmPackageから削除します。
	                          removePackageLI(scannedPkg, true);
	  
	                          // アップグレードパッケージのパスをmExpectingBetterリストに追加します。
	                          mExpectingBetter.put(ps.name, ps.getPath());
	                      }
	                      continue;
	                  }
	  
	                  if (!mSettings.isDisabledSystemPackageLPr(ps.name)) {
	                      logCriticalInfo(Log.WARN, "システムパッケージ " + ps.name
	                              + " はもはや存在しません。データが消去されます。");
	                      // システムAPPが存在しない場合、そのAPPのデータを削除します。
	                      removePackageDataLIF(ps, userIds, null, 0, false);
	                  } else {
	                      // まだ無効なシステムパッケージがありますが、削除されている可能性があります。
	                      // コードパスがまだ存在するかどうかを確認し、パッケージがまだ存在するかどうかを確認します。
	                      // 後者はOTAが同じコードパスを保持しますが、パッケージ名を変更する場合に発生する可能性があります。
	                      final PackageSetting disabledPs =
	                              mSettings.getDisabledSystemPkgLPr(ps.name);
	  
	                      if (disabledPs.getPath() == null || !disabledPs.getPath().exists()
	                              || disabledPs.pkg == null) {
	                          // このシステムアプリはisDisabledSystemPackageにあり、アップグレードパッケージが見つかりません。
	                          possiblyDeletedUpdatedSystemApps.add(ps.name);
	                      } else {
	                          // システムアプリは無効のままであるべきですが、データバージョンがスキャンできない場合に回復するために
	                          // 期待されるより良いものに追加します。
	                          mExpectingBetter.put(disabledPs.name, disabledPs.getPath());
	                      }
	                  }
	              }
	          }
	  
	          ...
	  
	      }
	  
	      }
	  }

システムフォルダのアップグレードアプリをスキャン#

現在の段階(BOOT_PROGRESS_PMS_SYSTEM_SCAN_START)では、主に/systemフォルダをスキャンします。このディレクトリ内のファイルはどのように配置されているか。
Android システムアーキテクチャはアプリケーション層、アプリケーションフレームワーク層、システム実行層、ハードウェア抽象層、カーネル層に分かれています。

system 内のフォルダ内容
appシステムアプリ
frameworkアプリケーションフレームワークの jar パッケージ
priv-app特権アプリ
lib動的 so ファイルを配置
fontsシステムフォント
mediaシステム音声

第二の目的はシステムファイルをスキャンして処理することです。処理の重点は ==OTA アップグレード ==で、システムはアップグレード可能なシステムアプリを DisabledSystemPackage としてマークします。状況は 3 つあります。
システム APP が更新される:removePackageLIを通じてシステムアプリの PackageSetting を PKMS から mPackage から削除し、mExpectingBetter リストに追加します
システム APP が削除される:removePackageDataLIFを通じてシステム APP データを削除します。
アップグレードパッケージがない:システムアプリが DisabledSystemPackage であるが、アップグレードパッケージが見つからない場合、システムアップグレードパッケージが
削除された可能性があります

第三段階 - BOOT_PROGRESS_PMS_DATA_SCAN_START#

BOOT_PROGRESS_PMS_DATA_SCAN_START:主に/dataフォルダをスキャンします。
スキャン処理、更新/dataディレクトリのアプリ情報(不要なデータも即座に削除されます)。
前のステップで残された possiblyDeletedUpdatedSystemApps リストを処理します。

  • mPackage からパッケージを取得できない場合、その APP を削除します。
  • パッケージを取得できるがシステム APP でない場合、以下のことを行います。
    • システム権限を削除します。
    • パッケージを削除します。
    • パッケージパスの APK を再スキャンします。
      mExpectingBetter リストをスキャンします。
    • システム APP のアップグレードパッケージのパスを取得し、以下のことを行います。
    • システム APP が存在するディレクトリに基づいてスキャン解析パラメータを設定します。
    • PackageName をmSetting#mPackagesに設定します(removeDisabledSystemPackageLPw メソッド)。
    • mExpectingBetter リストをクリアします。
// PackageManagerService.java

private final File mAppInstallDir;

public PackageManagerService(Injector injector, boolean onlyCore, boolean factoryTest,
        final String buildFingerprint, final boolean isEngBuild,
        final boolean isUserDebugBuild, final int sdkVersion, final String incrementalVersion) {

    ...
   
    // /data/appフォルダを取得
    mAppInstallDir = new File(Environment.getDataDirectory(), "app");
    
     // CHECKSTYLE:OFF IndentationCheck
    synchronized (mInstallLock) {
    // writer
    synchronized (mLock) {
        
        ...
            
        if (!mOnlyCore) {
            EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
                    SystemClock.uptimeMillis());
            
            // /data/appフォルダをスキャン
            scanDirTracedLI(mAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0,
                    packageParser, executorService);
        }
        
        // パーサーストリームを閉じる(パッケージxmlの解析ストリーム)
        packageParser.close();
        
        // Executorのすべてのタスクを閉じる
        List<Runnable> unfinishedTasks = executorService.shutdownNow();
        if (!unfinishedTasks.isEmpty()) {
            throw new IllegalStateException("すべてのタスクが終了する前に閉じられました:" + unfinishedTasks);
        }
        
        
        if (!mOnlyCore) {    
            // 2.前のステップで残されたAPPパッケージをスキャン(逆順)

            for (int i = possiblyDeletedUpdatedSystemApps.size() - 1; i >= 0; --i) {
                final String packageName = possiblyDeletedUpdatedSystemApps.get(i);
                final AndroidPackage pkg = mPackages.get(packageName);
                final String msg;
                
                // 無効なシステムリスト(mDisabledSystemPackage)から削除します。
                mSettings.removeDisabledSystemPackageLPw(packageName);
                
                if (pkg == null) {
                    // アップグレードパッケージを見つけるはずですが、見つかりませんでした(このAPPを削除します)。
                    msg = "更新されたシステムパッケージ " + packageName
                            + " はもはや存在しません。データを削除します。";
                    // (実際にはすぐに削除されるわけではありません)
                } else {
                    
                    // pkgを取得できた場合、APPがData区に存在することを示し、
                    // システムAPPではないため、システム権限を削除します。
                    msg = "更新されたシステムパッケージ " + packageName
                            + " はもはや存在しません。データを再スキャンします。";
                    // 以下、削除して再スキャンします。
                    removePackageLI(pkg, true);    // 削除
                    try {
                        final File codePath = new File(pkg.getPath());
                        // 再スキャン
                        scanPackageTracedLI(codePath, 0, scanFlags, 0, null);
                    } catch (PackageManagerException e) {
                        Slog.e(TAG, "更新されたシステムパッケージの解析に失敗しました:" + e.getMessage());
                    }
                }
               
                // もしパッケージ設定がまだ存在する場合[つまり、以前にスキャンされてシステムに知られている]
                // しかし、Pkgが存在しない場合[つまり、/dataをスキャンする際にエラーが発生した場合]
                // パッケージデータを完全に削除します。
                final PackageSetting ps = mSettings.getPackageLPr(packageName);
                if (ps != null && mPackages.get(packageName) == null) {
                    // データ内のエラーが発生したパッケージデータを削除します。
                    removePackageDataLIF(ps, userIds, null, 0, false);
                }
                logCriticalInfo(Log.WARN, msg);

            }

            // 3. mExpectingBetterリストをスキャン
            for (int i = 0; i < mExpectingBetter.size(); i++) {
                final String packageName = mExpectingBetter.keyAt(i);
                if (!mPackages.containsKey(packageName)) {
                    // システムAPPのアップグレードパッケージのパスを取得します。
                    final File scanFile = mExpectingBetter.valueAt(i);

                    for (int i1 = mDirsToScanAsSystem.size() - 1; i1 >= 0; i1--) {
                        final ScanPartition partition = mDirsToScanAsSystem.get(i1);
                        // システムAPPが存在するディレクトリに基づいてスキャン解析パラメータを設定します。
                        if (partition.containsPrivApp(scanFile)) {
                            reparseFlags = systemParseFlags;
                            // スキャンパラメータを設定します。
                            rescanFlags = systemScanFlags | SCAN_AS_PRIVILEGED | partition.scanFlag;
                            break;
                        }
                        if (partition.containsApp(scanFile)) {
                            reparseFlags = systemParseFlags;
                            rescanFlags = systemScanFlags | partition.scanFlag;
                            break;
                        }
                    }
                    if (rescanFlags == 0) {
                        Slog.e(TAG, "予期しないフォールバックパスを無視しています " + scanFile);
                        continue;
                    }

                  //PackageNameに対応するパッケージ設定データ(PackagesSetting)
                  //をmSettingのmPackagesに追加します。
                    mSettings.enableSystemPackageLPw(packageName);

                    try {
                        // システムAPPのアップグレードパッケージをスキャンします。
                        final AndroidPackage newPkg = scanPackageTracedLI(
                                scanFile, reparseFlags, rescanFlags, 0, null);
                        // スタブを再スキャンしました。スタブされたシステムパッケージのリストに追加します。
                        if (newPkg.isStub()) {
                            stubSystemApps.add(packageName);
                        }
                    } /* 省略 catch */
                }
            }

          //ルートシステムアプリを解凍&インストールします。
          //この操作は最後に実行され、すべてのスタブが置き換えられるか無効にされることを確認します。
          // スタブ(stub)
            installSystemStubPackages(stubSystemApps, scanFlags);

            ...
        }
        
        
        // アップグレードリストをクリアします。
        mExpectingBetter.clear();
        
        // ストレージ管理パッケージ名を取得します。
        mStorageManagerPackage = getStorageManagerPackageName();
        
        // 保護アクションフィルタを解決します。これらのアクションに対してセットアップウィザードのみが最高権限のフィルタを持つことを許可します。
        mSetupWizardPackage = getSetupWizardPackageNameImpl();
        
        ...
        
        // 保持するパッケージの最終使用時間を読み取り、更新します。
        mPackageUsage.read(packageSettings);
        mCompilerStats.read();

    }
}

scanDirTracedLI - data ディレクトリの内容を分析#

/dataフォルダはデータパーティションとして機能し、主に 2 つの目的があります。
すべてのユーザーの個人データを保存します。
すべてのユーザーの設定ファイルを保存します。
次に、/data ディレクトリ内のサブディレクトリがどのようなデータを保存しているかを見てみましょう。

/data 下のディレクトリ意味
appこのデバイスにインストールされた APP アプリを保存します。
dataすべてのインストールされた APP データを保存します。システム APP データも含まれます。
app-privateAPP のプライベートストレージ
app-libすべての APP の JNI Lib を保存します。
systemシステム設定ファイルを保存します。
anrANR が発生したときにシステムが生成するtraces.textファイルを保存します。

第四段階 - BOOT_PROGRESS_PMS_SCAN_END#

BOOT_PROGRESS_PMS_SCAN_END 段階アップグレード後の初回起動時、不要なキャッシュデータ、権限をクリアし、package.xmlファイルを更新します(packages.xml はすべての APP の情報を保存するために使用されます)。
SDK バージョンが変更され、権限が再更新されます。
OTA アップグレード後の初回起動時、不要なキャッシュをクリアします。
OTA の英語のフルネームはOver-the-Air Technologyで、携帯電話がモバイルネットワークを介して携帯電話のシステムやアプリケーションを管理する技術です。
権限の更新が完了した後、関連データをクリアします。
mSetting の内容を通じて package.xml ファイルを保存し更新し、今後 PKMS が作成されると新しい Setting が読み込まれます。

// PackageManagerService.java

public PackageManagerService(Injector injector, boolean onlyCore, boolean factoryTest,
        final String buildFingerprint, final boolean isEngBuild,
        final boolean isUserDebugBuild, final int sdkVersion, final String incrementalVersion) {

    ... 
  
     // CHECKSTYLE:OFF IndentationCheck
    synchronized (mInstallLock) {
    // writer
    synchronized (mLock) {
        
        ...

        // 第四段階に入ります。
        EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,
                SystemClock.uptimeMillis());

        // 権限のリセット
        mPermissionManager.onStorageVolumeMounted(
                StorageManager.UUID_PRIVATE_INTERNAL, mIsUpgrade);
        ver.sdkVersion = mSdkVersion;

        // 初回起動またはpre-Mからのアップグレードであり、正常に起動している場合、ユーザー定義のデフォルトの優先アプリを初期化する必要があります。
        if (!mOnlyCore && (mPromoteSystemApps || mFirstBoot)) {
            for (UserInfo user : mInjector.getUserManagerInternal().getUsers(true)) {
                mSettings.applyDefaultPreferredAppsLPw(user.id);
            }
        }
        
      //起動中にシステムユーザーのストレージスペースを準備します。
      //SettingsProviderやSystemUIはユーザーの起動を待つことができません。
        final int storageFlags;
        if (StorageManager.isFileEncryptedNativeOrEmulated()) {
            storageFlags = StorageManager.FLAG_STORAGE_DE;
        } else {
            storageFlags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE;
        }
        
        ...
        
        // OTAアップグレードが成功した後の初回起動時、不要なキャッシュをクリアしますが、アプリケーションの設定ファイルはクリアしません。
        if (mIsUpgrade && !mOnlyCore) {
            Slog.i(TAG, "ビルドフィンガープリントが変更されました。コードキャッシュをクリアします。");
            for (int i = 0; i < packageSettings.size(); i++) {
                final PackageSetting ps = packageSettings.valueAt(i);
                if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, ps.volumeUuid)) {
                    // この時点でアプリは起動しないため、フリーズする必要はありません。
                    clearAppDataLIF(ps.pkg, UserHandle.USER_ALL,
                            FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL
                                    | Installer.FLAG_CLEAR_CODE_CACHE_ONLY
                                    | Installer.FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES);
                }
            }
            ver.fingerprint = Build.FINGERPRINT;
        }
        
        // Launcherでアイコンを隠します(Android-Q以前の非システムアプリ)。
        if (!mOnlyCore && mIsPreQUpgrade) {
            Slog.i(TAG, "すべての既存アプリをホワイトリストに追加し、アイコンを隠します。");
            int size = packageSettings.size();
            for (int i = 0; i < size; i++) {
                final PackageSetting ps = packageSettings.valueAt(i);
                if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0) {
                    continue;
                }
                ps.disableComponentLPw(PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME,
                        UserHandle.USER_SYSTEM);
            }
        }
        // 権限や他のデフォルトが更新された後にのみクリアします。
        mPromoteSystemApps = false;
        
        // すべての変更はスキャン中に完了します。
        ver.databaseVersion = Settings.CURRENT_DATABASE_VERSION;
        
        // package.xmlを更新します。
        t.traceBegin("設定を書き込みます");
        writeSettingsLPrTEMP();
        t.traceEnd();

        ...

    }
        
    }
}

第五段階 - BOOT_PROGRESS_PMS_READY#

BOOT_PROGRESS_PMS_READY:PKMS の最終段階です。
PackageInstallerService はインストールセッションサービスを管理し、各インストールプロセスでセッション ID が割り当てられます
GC を要求してメモリを回収します。

// PackageManagerService.java
public PackageManagerService(Injector injector, boolean onlyCore, boolean factoryTest,
        final String buildFingerprint, final boolean isEngBuild,
        final boolean isUserDebugBuild, final int sdkVersion, final String incrementalVersion) {

    ...
    
     // CHECKSTYLE:OFF IndentationCheck
    synchronized (mInstallLock) {
    // writer
    synchronized (mLock) {
        
        ...
             
    EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY,
                SystemClock.uptimeMillis());
        
        ... 
        
        // PermissionControllerはシステムコアであり、デフォルトで同意し、権限を管理します。
        mRequiredPermissionControllerPackage = getRequiredPermissionControllerLPr();
        
        ... 省略部分
        
        // インストーラーサービスを取得します。
        mInstallerService = mInjector.getPackageInstallerService();
        
        ...
        
      // dexファイルの使用法を読み取り、更新します。
      // PM initが終了したときにこの操作を実行し、すべてのパッケージがデータディレクトリを調整できるようにします。
      // 検証可能なファイルを構築し、メモリキャッシュを構築します。
      // ファイルを使用することは非常に小さいため、他のアクティビティと比較して、読み込みと検証に多くの時間がかかります。
        final Map<Integer, List<PackageInfo>> userPackages = new HashMap<>();
        for (int userId : userIds) {
            userPackages.put(userId, getInstalledPackages(/*flags*/ 0, userId).getList());
        }
        mDexManager.load(userPackages);
        if (mIsUpgrade) {
            FrameworkStatsLog.write(
                    FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED,
                    BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_INIT_TIME,
                    SystemClock.uptimeMillis() - startTime);
        }

        // 属性が再構成された後、ライブコンピュータを再構成します。
        mLiveComputer = createLiveComputer();

    }
        
    }
    
    ...
    
    // アプリのzipを開いた後、すべてを更新し、GCを要求します。
    VMRuntime.getRuntime().requestConcurrentGC();
    
    mInstaller.setWarnIfHeld(mLock);
    
    ...
}
読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。