Jimmy Chen

A Programmer

(原创)PackageManagerService启动流程分析(下)

  这里接着上一篇开始写,上一篇只是讲了在startBootstrapServices中启动PackageManagerService部分的代码,剩余的在startOtherServices中PackageManagerService相关设置操作没有分析到,这一篇接着分析下面遗留的问题:

  • mPackageManagerService.updatePackagesIfNeeded
  • mPackageManagerService.performFstrimIfNeeded
  • mPackageManagerService.systemReady
  • mPackageManagerService.waitForAppDataPrepared

一. mPackageManagerService.updatePackagesIfNeeded

public void updatePackagesIfNeeded() {
    enforceSystemOrRoot("Only the system can request package update");

    // 判断是否是FOTA升级
    boolean causeUpgrade = isUpgrade();

    // 判断是否是第一次开机或者恢复出厂设置或者FOTA到pre-N版本
    boolean causeFirstBoot = isFirstBoot() || mIsPreNUpgrade;

    // 判断是否有清除过Dalvik虚拟机的Cache
    boolean causePrunedCache = VMRuntime.didPruneDalvikCache();

    // 如果不存在上面三种情况,则直接返回,不需要执行更新Package
    if (!causeUpgrade && !causeFirstBoot && !causePrunedCache) {
        return;
    }

    List<PackageParser.Package> pkgs;
    synchronized (mPackages) {
        // 这里会按照Package的重要程度来给他们分配优先级
        // core app优先级最高,系统app次之,接着是被其他app以来的app,最后则是最近未被使用和剩余的app
        pkgs = PackageManagerServiceUtils.getPackagesForDexopt(mPackages.values(), this);
    }

    final long startTime = System.nanoTime();
    // 这里最后会调用到mInstaller.dexopt()方法,mInstaller会和Installd进行通信完成Dex优化升级
    final int[] stats = performDexOptUpgrade(pkgs, mIsPreNUpgrade /* showDialog */,
                getCompilerFilterForReason(causeFirstBoot ? REASON_FIRST_BOOT : REASON_BOOT),
                false /* bootComplete */);

    final int elapsedTimeSeconds =
            (int) TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - startTime);

    MetricsLogger.histogram(mContext, "opt_dialog_num_dexopted", stats[0]);
    MetricsLogger.histogram(mContext, "opt_dialog_num_skipped", stats[1]);
    MetricsLogger.histogram(mContext, "opt_dialog_num_failed", stats[2]);
    MetricsLogger.histogram(mContext, "opt_dialog_num_total", getOptimizablePackages().size());
    MetricsLogger.histogram(mContext, "opt_dialog_time_s", elapsedTimeSeconds);
}

  上面的代码首先判断是否需要对Package进行更新,如果需要更新的话会首先按照Package的重要程度给其赋予一个优先级,然后调用performDexOptUpgrade完成dex优化升级。

二.mPackageManagerService.performFstrimIfNeeded

public void performFstrimIfNeeded() {
    enforceSystemOrRoot("Only the system can request fstrim");

    try {
        // 获取MountService
        IStorageManager sm = PackageHelper.getStorageManager();
        if (sm != null) {
            boolean doTrim = false;
            // 获取执行FTRIM间隔,默认是3天,可以通过setting provider更改这个时间
            final long interval = android.provider.Settings.Global.getLong(
                    mContext.getContentResolver(),
                    android.provider.Settings.Global.FSTRIM_MANDATORY_INTERVAL,
                    DEFAULT_MANDATORY_FSTRIM_INTERVAL);
            if (interval > 0) {
                final long timeSinceLast = System.currentTimeMillis() - sm.lastMaintenance();
                // 上一次执行strim到现在超过三天,这需要执行FTRIM
                if (timeSinceLast > interval) {
                    doTrim = true;
                    Slog.w(TAG, "No disk maintenance in " + timeSinceLast
                            + "; running immediately");
                }
            }
            if (doTrim) {
                final boolean dexOptDialogShown;
                synchronized (mPackages) {
                    dexOptDialogShown = mDexOptDialogShown;
                }
                if (!isFirstBoot() && dexOptDialogShown) {
                    try {
                        // 显示一个带提示信息的窗口
                        ActivityManager.getService().showBootMessage(
                                mContext.getResources().getString(
                                        R.string.android_upgrading_fstrim), true);
                    } catch (RemoteException e) {
                    }
                }
                // 发送消息H_FSTRIM给handler,然后再向vold发送fstrim命令
                sm.runMaintenance();
            }
        } else {
            Slog.e(TAG, "storageManager service unavailable!");
        }
    } catch (RemoteException e) {
        // Can't happen; StorageManagerService is local
    }
}

  上面主要是执行磁盘清理工作,释放磁盘空间。

三.mPackageManagerService.systemReady

public void systemReady() {
    enforceSystemOrRoot("Only the system can claim the system is ready");

    mSystemReady = true;
    // 获取PackageManagerService的ContentResolver
    final ContentResolver resolver = mContext.getContentResolver();
    ContentObserver co = new ContentObserver(mHandler) {
        @Override
        public void onChange(boolean selfChange) {
            mEphemeralAppsDisabled =
                    (Global.getInt(resolver, Global.ENABLE_EPHEMERAL_FEATURE, 1) == 0) ||
                            (Secure.getInt(resolver, Secure.INSTANT_APPS_ENABLED, 1) == 0);
        }
    };
    mContext.getContentResolver().registerContentObserver(android.provider.Settings.Global
                    .getUriFor(Global.ENABLE_EPHEMERAL_FEATURE),
            false, co, UserHandle.USER_SYSTEM);
    mContext.getContentResolver().registerContentObserver(android.provider.Settings.Global
                    .getUriFor(Secure.INSTANT_APPS_ENABLED), false, co, UserHandle.USER_SYSTEM);
    co.onChange(true);

    // 禁用运营商的app
    CarrierAppUtils.disableCarrierAppsUntilPrivileged(mContext.getOpPackageName(), this,
            mContext.getContentResolver(), UserHandle.USER_SYSTEM);

    // 系统处于ready时,读取系统的兼容性设置
    boolean compatibilityModeEnabled = android.provider.Settings.Global.getInt(
            mContext.getContentResolver(),
            android.provider.Settings.Global.COMPATIBILITY_MODE, 1) == 1;
    // 设置PackageParser是否启用兼容性设置
    PackageParser.setCompatibilityModeEnabled(compatibilityModeEnabled);
    if (DEBUG_SETTINGS) {
        Log.d(TAG, "compatibility mode:" + compatibilityModeEnabled);
    }

    int[] grantPermissionsUserIds = EMPTY_INT_ARRAY;

    synchronized (mPackages) {
        // 检查Preferred Activity是否有更新
        ArrayList<PreferredActivity> removed = new ArrayList<PreferredActivity>();
        for (int i=0; i < mSettings.mPreferredActivities.size(); i++) {
            PreferredIntentResolver pir = mSettings.mPreferredActivities.valueAt(i);
            removed.clear();
            for (PreferredActivity pa : pir.filterSet()) {
                if (mActivities.mActivities.get(pa.mPref.mComponent) == null) {
                    removed.add(pa);
                }
            }
            if (removed.size() > 0) {
                for (int r=0; r < removed.size(); r++) {
                    PreferredActivity pa = removed.get(r);
                    Slog.w(TAG, "Removing dangling preferred activity: "
                            + pa.mPref.mComponent);
                    pir.removeFilter(pa);
                }
                mSettings.writePackageRestrictionsLPr(
                        mSettings.mPreferredActivities.keyAt(i));
            }
        }

        for (int userId : UserManagerService.getInstance().getUserIds()) {
            if (!mSettings.areDefaultRuntimePermissionsGrantedLPr(userId)) {
                grantPermissionsUserIds = ArrayUtils.appendInt(
                        grantPermissionsUserIds, userId);
            }
        }
    }
    // 多用户服务
    sUserManager.systemReady();

    // 升级所有以获取到的默认权限
    for (int userId : grantPermissionsUserIds) {
        mDefaultPermissionPolicy.grantDefaultPermissions(userId);
    }

    // 此处调取前面获取默认权限失败时抛出的异常
    if (grantPermissionsUserIds == EMPTY_INT_ARRAY) {
        mDefaultPermissionPolicy.scheduleReadDefaultPermissionExceptions();
    }

    // 处理所有等待系统就绪的消息
    if (mPostSystemReadyMessages != null) {
        for (Message msg : mPostSystemReadyMessages) {
            msg.sendToTarget();
        }
        mPostSystemReadyMessages = null;
    }

    // 观察外部存储设备
    final StorageManager storage = mContext.getSystemService(StorageManager.class);
    storage.registerListener(mStorageListener);

    mInstallerService.systemReady();
    mPackageDexOptimizer.systemReady();

    // Storage相关处理,暂不分析
    StorageManagerInternal StorageManagerInternal = LocalServices.getService(
            StorageManagerInternal.class);
    StorageManagerInternal.addExternalStoragePolicy(
            new StorageManagerInternal.ExternalStorageMountPolicy() {
        @Override
        public int getMountMode(int uid, String packageName) {
            if (Process.isIsolated(uid)) {
                return Zygote.MOUNT_EXTERNAL_NONE;
            }
            if (checkUidPermission(WRITE_MEDIA_STORAGE, uid) == PERMISSION_GRANTED) {
                return Zygote.MOUNT_EXTERNAL_DEFAULT;
            }
            if (checkUidPermission(READ_EXTERNAL_STORAGE, uid) == PERMISSION_DENIED) {
                return Zygote.MOUNT_EXTERNAL_DEFAULT;
            }
            if (checkUidPermission(WRITE_EXTERNAL_STORAGE, uid) == PERMISSION_DENIED) {
                return Zygote.MOUNT_EXTERNAL_READ;
            }
            return Zygote.MOUNT_EXTERNAL_WRITE;
        }

        @Override
        public boolean hasExternalStorage(int uid, String packageName) {
            return true;
        }
    });

    // 清除过期的userid和app
    sUserManager.reconcileUsers(StorageManager.UUID_PRIVATE_INTERNAL);
    reconcileApps(StorageManager.UUID_PRIVATE_INTERNAL);

    if (mPrivappPermissionsViolations != null) {
        Slog.wtf(TAG,"Signature|privileged permissions not in "
                + "privapp-permissions whitelist: " + mPrivappPermissionsViolations);
        mPrivappPermissionsViolations = null;
    }
}

  这一部分主要是当PKMS准备就绪是,更新一些Package的信息、默认权限的获取以及通知在等待PKMS就绪的主件。下面接着分析最后一个方法调用。

四.mPackageManagerService.waitForAppDataPrepared

public void waitForAppDataPrepared() {
    if (mPrepareAppDataFuture == null) {
        return;
    }
    ConcurrentUtils.waitForFutureNoInterrupt(mPrepareAppDataFuture, "wait for prepareAppData");
    mPrepareAppDataFuture = null;
}

public static <T> T waitForFutureNoInterrupt(Future<T> future, String description) {
    try {
        return future.get();
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
        throw new IllegalStateException(description + " interrupted");
    } catch (ExecutionException e) {
        throw new RuntimeException(description + " failed", e);
    }
}

&emps; 上面一段代码看是获取特定的feature的。

  这一篇就到这里啦,简简单单看了下PKMS初始化之后所作的事情。感觉处理第一个函数对package的信息进行更新和第二个函数对存储空间进行回收外并没有做特别多的事情。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d 博主赞过: