如何应对Android面试官 -> PKMS 安装与签名校验

Android PackageManagerService总结(二) PKMS启动过程 PackageManagerService(简称PKMS),是Android系统中核心服务之一,管理着所有与package相关的工作,常见的比如安装、卸载应用, 信息查询等工作 阅读详情

前言


image.png

本章主要围绕以上几个知识点进行讲解,最后会手写一个 权限申请框架;

PKMS


PackageManagerService 的作用:

  1. PackageManagerService(简称 PKMS),是 Android 系统中核心服务之一,负责应用程序的安装,卸载,信息查询,等工作;
  2. 解析AndroidNanifest.xml清单文件,解析清单文件中的所有节点信息;
  3. 扫描.apk文件,安装系统应用,安装本地应用等;
  4. 管理本地应用,主要有, 安装,卸载,应用信息查询 等;

PKMS 概述来说:Android 系统启动时,会启动(应用程序管理服务器 PKMS ),此服务负责扫描系统中特定的目录,寻找里面的APK格式的文件,并对这些文件进行解析,然后得到应用程序相关信息,最后完成应用程序的安装PKMS在安装应用过程中, 会全面解析应用程序的 AndroidManifest.xml 文件, 来得到 Activity, Service, BroadcastReceiver, ContextProvider 等信息, 在结合 PKMS 服务就可以在 Android OS 中正常的使用应用程序了,在 Android 系统中, 系统启动时由 SystemServer 启动 PKMS 服务, 启动该服务后会执行应用程序的安装过程;

PKMS 的角色位置,我们来看一张图

image.png

客户端可通过 Context.getPackageManager() 获得 ApplicationPackageManager 对象, 而 mPM 指向的是 Proxy 代理,当调用到 mPM. 方法后,将会调用到 IPackageManager 的 Proxy 代理方法,然后通过Binder 机制中的 mRemote 与服务端 PackageManagerService 通信 并调用到 PackageManagerService 的方法;

PKMS 启动过程分析


启动过程,依然从 SystemServer 的 run 看起,我们进入这个 run 方法的 startBootstrapServices() 方法,这个方法主要用来启动引导服务;

private void startBootstrapServices(@NonNull TimingsTraceAndSlog t) {
    // 第一步:创建安装器,并启动安装器
    Installer installer = mSystemServiceManager.startService(Installer.class);
    
    // 第二步:获取设置是否加密「例如设置了密码」
    String cryptState = VoldProperties.decrypt().orElse("");
    
    // 第三步:调用 PKMS 的 main 方法,实例化 PKMS
    mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
        domainVerificationService, mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF,
        mOnlyCore);
    
    // 第四步:如果设备没有加密,操作它,管理 A/B OAT dexopting
    if (!mOnlyCore) {
        boolean disableOtaDexopt = SystemProperties.getBoolean("config.disable_otadexopt",
                false);
        if (!disableOtaDexopt) {
            try {
                // 
                OtaDexoptService.main(mSystemContext, mPackageManagerService);
            } catch (Throwable e) {
                reportWtf("starting OtaDexOptService", e);
            } finally {
                Watchdog.getInstance().resumeWatchingCurrentThread("moveab");
                t.traceEnd();
            }
        }
    }
    
    // 第五步:如果设备没有加密,执行performDexOptUpdate 完成dex优化
    // 构造PackageDexOptimizer及DexManager类,处理dex优化;
    mPackageManagerService.updatePackagesIfNeeded();
    
    // 第六步:执行performStrim 完成磁盘优化
    mPackageManagerService.performFstrimIfNeeded();
    
    // 第七步:PKMS准备就绪
    mPackageManagerService.systemReady();
}

重点一在第五步,手机开机慢的主要原因:

手机开机,BootRoom 拉起BootLoader程序,BootLoader 会拉起 Linux 内核驱动,驱动会初始化init进程,init进程会创建zygote进程,zygote进程会fork出它的第大儿子 系统服务进程「system server」系统服务进程会初始化 PKMS,PKMS 在构造方法中 就会扫描手机上的所有应用,手机上应用越多,时间越长,扫描完之后 还会进行 dex 优化;

重点二在第三步,我们进入第三步的 main 方法看下:

public static PackageManagerService main(Context context, Installer installer,
        @NonNull DomainVerificationService domainVerificationService, boolean factoryTest,
        boolean onlyCore) {
    // 省略部分代码
    
    // 实例化 PackageManagerService
    PackageManagerService m = new PackageManagerService(injector, onlyCore, factoryTest,
        Build.FINGERPRINT, Build.IS_ENG, Build.IS_USERDEBUG, Build.VERSION.SDK_INT,
        Build.VERSION.INCREMENTAL);
    // 将 PMS 注册到 SystemServer 中
    ServiceManager.addService("package", m);
    // 
    final PackageManagerNative pmn = m.new PackageManagerNative();
    ServiceManager.addService("package_native", pmn);
}

这里主要是调用 PackageManagerService 的构造方法,进行实例化,并初始化相关信息,这里主要分为 5 个阶段;

public PackageManagerService(Injector injector, boolean onlyCore, boolean factoryTest,
        final String buildFingerprint, final boolean isEngBuild,
        final boolean isUserDebugBuild, final int sdkVersion, final String incrementalVersion) {
    // 省略部分代码
    
    // 阶段1 BOOT_PROGRESS_PMS_START
    EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,
        SystemClock.uptimeMillis());
    mMetrics = injector.getDisplayMetrics();
    mInstaller = injector.getInstaller();
    mPermissionManager = injector.getPermissionManagerServiceInternal();
    mSettings = injector.getSettings();
    // 这里的目的是:如果想安装系统应用,必须得到系统厂商的签名,这些 UID 是由 Linux 来管理的,系统应用在安装的时候,权限校验就能通过;
    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);
    // 构造PackageDexOptimizer及DexManager类,处理dex优化;
    mPackageDexOptimizer = injector.getPackageDexOptimizer();
    mDexManager = injector.getDexManager();
    // ART虚拟机管理服务
    mArtManagerService = injector.getArtManagerService();
    mMoveCallbacks = new MoveCallbacks(FgThread.get().getLooper());
    mViewCompiler = injector.getViewCompiler();
    // 权限变化监听器
    mProtectedPackages = new ProtectedPackages(mContext);
    mApexManager = injector.getApexManager();
}
  1. BOOT_PROGRESS_PMS_START,PKMS 的构造方法中进行;
  • mMetrics = new DisplayMetrics();初始化屏幕相关类;
  • mInstaller = installer;赋值安装器;
  • mPermissionManager = injector.getPermissionManagerServiceInternal();创建PermissionManager 进行权限管理;
  • 创建 settings 保存安装包信息;

这个 Settings 比较关键,我们进入这个 Settings 的构造方法看下;

Settings(File dataDir, RuntimePermissionsPersistence runtimePermissionsPersistence,
        LegacyPermissionDataProvider permissionDataProvider,
        @NonNull DomainVerificationManagerInternal domainVerificationManager,
        @NonNull PackageManagerTracedLock lock)  {
    // 读取 dat/system/packages.xml 主要是为了读取系统应用并加载
    mSettingsFilename = new File(mSystemDir, "packages.xml");
    // 备份读取,为了加载过程中被打断之后可以继续加载 
    mBackupSettingsFilename = new File(mSystemDir, "packages-backup.xml");
    mPackageListFilename = new File(mSystemDir, "packages.list");
}

packages.xml中 存放着所有的系统权限 以及 安装在手机上的每一个应用程序信息。每次开机都会执行这个 PKMS 的构造方法,进行应用的安装处理,如果手机上安装的应用很多很多,开机时间也会相应的变长;

  1. EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START;扫描系统的 apk 应用;

这个阶段就是开始扫描系统的 apk 应用,

public PackageManagerService(Injector injector, boolean onlyCore, boolean factoryTest,
        final String buildFingerprint, final boolean isEngBuild,
        final boolean isUserDebugBuild, final int sdkVersion, final String incrementalVersion) {
    // 阶段2:扫描系统的 apk 应用     
    EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START,
        startTime);
    // 开始扫描
    for (int i = mDirsToScanAsSystem.size() - 1; i >= 0; i--) {
        final ScanPartition partition = mDirsToScanAsSystem.get(i);
        if (partition.getOverlayFolder() == null) {
            continue;
        }
        // 
        scanDirTracedLI(partition.getOverlayFolder(), systemParseFlags,
                systemScanFlags | partition.scanFlag, 0,
                packageParser, executorService);
    }
    // 扫描 framework 
    File frameworkDir = new File(Environment.getRootDirectory(), "framework");
    scanDirTracedLI(frameworkDir, systemParseFlags,
        systemScanFlags | SCAN_NO_DEX | SCAN_AS_PRIVILEGED, 0,
        packageParser, executorService);
    
    // 
    for (int i = 0, size = mDirsToScanAsSystem.size(); i < size; i++) {
        final ScanPartition partition = mDirsToScanAsSystem.get(i);
        if (partition.getPrivAppFolder() != null) {
            scanDirTracedLI(partition.getPrivAppFolder(), systemParseFlags,
                    systemScanFlags | SCAN_AS_PRIVILEGED | partition.scanFlag, 0,
                    packageParser, executorService);
        }
        scanDirTracedLI(partition.getAppFolder(), systemParseFlags,
                systemScanFlags | partition.scanFlag, 0,
                packageParser, executorService);
    }
}

扫描系统的应用,主要扫描下面几个目录的 apk:

private static int scanFlagForPartition(PackagePartitions.SystemPartition partition) {
    switch (partition.type) {
        // 
        case PackagePartitions.PARTITION_SYSTEM:
            return 0;
        // vendor/overlay
        case PackagePartitions.PARTITION_VENDOR:
            return SCAN_AS_VENDOR;
        // odm/overlay
        case PackagePartitions.PARTITION_ODM:
            return SCAN_AS_ODM;
        // oem/overlay
        case PackagePartitions.PARTITION_OEM:
            return SCAN_AS_OEM;
        // product/overlay
        case PackagePartitions.PARTITION_PRODUCT:
            return SCAN_AS_PRODUCT;
        // 
        case PackagePartitions.PARTITION_SYSTEM_EXT:
            return SCAN_AS_SYSTEM_EXT;
        default:
            throw new IllegalStateException("Unable to determine scan flag for "
                    + partition.getFolder());
    }
}
  1. BOOT_PROGRESS_PMS_DATA_SCAN_START,扫描data目录下的apk,这里主要是安装的第三方应用;
mAppInstallDir = new File(Environment.getDataDirectory(), "app");

if (!mOnlyCore) {
    EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
            SystemClock.uptimeMillis());
    scanDirTracedLI(mAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0,
            packageParser, executorService);
    // 移除通过OTA删除的更新系统应用程序的禁用package设置
    // 如果更新不再存在,则完全删除该应用。否则,撤消其系统权限       
    for (int i = possiblyDeletedUpdatedSystemApps.size() - 1; i >= 0; --i) {
        final String packageName = possiblyDeletedUpdatedSystemApps.get(i);
        final AndroidPackage pkg = mPackages.get(packageName);
        final String msg;

        // remove from the disabled system list; do this first so any future
        // scans of this package are performed without this state
        mSettings.removeDisabledSystemPackageLPw(packageName);
        // ...
    }
    
    // 确保期望在userdata分区上显示的所有系统应用程序实际显示
    // 如果从未出现过,需要回滚以恢复系统版本
    for (int i = 0; i < mExpectingBetter.size(); i++) {
        final String packageName = mExpectingBetter.keyAt(i);
        if (!mPackages.containsKey(packageName)) {
            final File scanFile = mExpectingBetter.valueAt(i);
            // ...
            mSettings.enableSystemPackageLPw(packageName);
            
            // 扫描 APK
            try {
                final AndroidPackage newPkg = scanPackageTracedLI(
                        scanFile, reparseFlags, rescanFlags, 0, null);
                // We rescanned a stub, add it to the list of stubbed system packages
                if (newPkg.isStub()) {
                    stubSystemApps.add(packageName);
                }
            } catch (PackageManagerException e) {
                Slog.e(TAG, "Failed to parse original system package: "
                        + e.getMessage());
            }
        }
    }
    // 解压缩并安装任何存根系统应用程序。必须最后执行此操作以确保替换或禁用所有存根
    installSystemStubPackages(stubSystemApps, scanFlags);
    // 获取storage manager包名
    mStorageManagerPackage = getStorageManagerPackageName();
    // 解决受保护的action过滤器。只允许setup wizard(开机向导)为这些action设置高优先级过滤器
    mSetupWizardPackage = getSetupWizardPackageNameImpl();
    // 更新客户端以确保持有正确的共享库路径
    updateAllSharedLibrariesLocked(null, null, Collections.unmodifiableMap(mPackages));
    // 读取并更新要保留的package的上次使用时间
    mPackageUsage.read(packageSettings);
    mCompilerStats.read();
}

处理 data 目录的应用信息,及时更新,祛除不必要的数据;

  1. BOOT_PROGRESS_PMS_SCAN_END OTA 升级后首次启动要清除不必要的缓存数据,权限等默认项更新后要清理相关数据,将阶段2 阶段3扫描后的数据更新到 packages.xml 文件中;
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,
        SystemClock.uptimeMillis());
  1. BOOT_PROGRESS_PMS_READY GC 内存回收
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY, SystemClock.uptimeMillis());
// PermissionController 主持 缺陷许可证的授予和角色管理,所以这是核心系统的一个关键部分。
mRequiredPermissionControllerPackage = getRequiredPermissionControllerLPr();
updateInstantAppInstallerLocked(null);
// 打开应用之后,及时回收处理
Runtime.getRuntime().gc();
// 上面的初始扫描在持有mPackage锁的同时对installd进行了多次调用
mInstaller.setWarnIfHeld(mPackages);

APK 的扫描


PKMS的构造函数中调用了 scanDirTracedLI 方法 来扫描某个目录的 apk 文件;

private void scanDirTracedLI(File scanDir, final int parseFlags, int scanFlags,
        long currentTime, PackageParser2 packageParser, ExecutorService executorService) {
    try {
        scanDirLI(scanDir, parseFlags, scanFlags, currentTime, packageParser, executorService);
    } finally {
        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
    }
}

从这里执行 APK 的扫描操作,我们进入这个 scanDirLI 看下;

private void scanDirLI(File scanDir, int parseFlags, int scanFlags, long currentTime,
        PackageParser2 packageParser, ExecutorService executorService) {
    final File[] files = scanDir.listFiles();
    if (ArrayUtils.isEmpty(files)) {
        return;
    }

    ParallelPackageParser parallelPackageParser =
            new ParallelPackageParser(packageParser, executorService);

    int fileCount = 0;
    for (File file : files) {
        final boolean isPackage = (isApkFile(file) || file.isDirectory())
                && !PackageInstallerService.isStageName(file.getName());
        if (!isPackage) {
            // Ignore entries which are not packages
            continue;
        }
        // 收集apk文件 交给submit方法处理
        parallelPackageParser.submit(file, parseFlags);
        fileCount++;
    }
}

这里主要是 收集 apk 文件 交给 submit 方法处理;

public void submit(File scanFile, int parseFlags) {
    mExecutorService.submit(() -> {
        ParseResult pr = new ParseResult();
        try {
            pr.scanFile = scanFile;
            pr.parsedPackage = parsePackage(scanFile, parseFlags);
        } catch (Throwable e) {
            pr.throwable = e;
        } finally {
            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
        }
        try {
            mQueue.put(pr);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            mInterruptedInThread = Thread.currentThread().getName();
        }
    });
}

submit 把 PackageParser 封装好的信息交给 parsePackage 方法;

public ParsedPackage parsePackage(File packageFile, int flags, boolean useCaches)
        throws PackageParserException {
    if (useCaches && mCacher != null) {
        ParsedPackage parsed = mCacher.getCachedResult(packageFile, flags);
        if (parsed != null) {
            return parsed;
        }
    }

    long parseTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0;
    ParseInput input = mSharedResult.get().reset();
    // 解析 apk 文件
    ParseResult<ParsingPackage> result = parsingUtils.parsePackage(input, packageFile, flags);

    ParsedPackage parsed = (ParsedPackage) result.getResult().hideAsParsed();
    return parsed;
}

解析 apk 文件

public ParseResult<ParsingPackage> parsePackage(ParseInput input, File packageFile,
        int flags)
        throws PackageParserException {
    if (packageFile.isDirectory()) {
        return parseClusterPackage(input, packageFile, flags);
    } else {
        // 解析
        return parseMonolithicPackage(input, packageFile, flags);
    }
}

我们进入 parseMonolithicPackage 这个方法看下:

private ParseResult<ParsingPackage> parseMonolithicPackage(ParseInput input, File apkFile,
        int flags) throws PackageParserException {
    
    final SplitAssetLoader assetLoader = new DefaultSplitAssetLoader(lite, flags);
    try {
        // 通过 parseBaseApk 解析 apk 中的清单文件
        final ParseResult<ParsingPackage> result = parseBaseApk(input,
                apkFile,
                apkFile.getCanonicalPath(),
                assetLoader, flags);
        if (result.isError()) {
            return input.error(result);
        }

        return input.success(result.getResult()
                .setUse32BitAbi(lite.isUse32bitAbi()));
    } catch (IOException e) {
        return input.error(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
                "Failed to get path: " + apkFile, e);
    } finally {
        IoUtils.closeQuietly(assetLoader);
    }
}

通过 parseBaseApk 解析 apk 中的清单文件;

private ParseResult<ParsingPackage> parseBaseApk(ParseInput input, File apkFile,
        String codePath, SplitAssetLoader assetLoader, int flags)
        throws PackageParserException {
    final String apkPath = apkFile.getAbsolutePath();

    String volumeUuid = null;
    if (apkPath.startsWith(MNT_EXPAND)) {
        final int end = apkPath.indexOf('/', MNT_EXPAND.length());
        volumeUuid = apkPath.substring(MNT_EXPAND.length(), end);
    }

    if (DEBUG_JAR) Slog.d(TAG, "Scanning base APK: " + apkPath);

    final AssetManager assets = assetLoader.getBaseAssetManager();
    final int cookie = assets.findCookieForPath(apkPath);
    if (cookie == 0) {
        return input.error(INSTALL_PARSE_FAILED_BAD_MANIFEST,
                "Failed adding asset path: " + apkPath);
    }
    // 解析 apk 中的清单文件
    try (XmlResourceParser parser = assets.openXmlResourceParser(cookie,
            ANDROID_MANIFEST_FILENAME)) {
        final Resources res = new Resources(assets, mDisplayMetrics, null);
        // 获取应用的相关信息,并存储起来
        ParseResult<ParsingPackage> result = parseBaseApk(input, apkPath, codePath, res,
                parser, flags);
        if (result.isError()) {
            return input.error(result.getErrorCode(),
                    apkPath + " (at " + parser.getPositionDescription() + "): "
                            + result.getErrorMessage());
        }

        final ParsingPackage pkg = result.getResult();
        if (assets.containsAllocatedTable()) {
            final ParseResult<?> deferResult = input.deferError(
                    "Targeting R+ (version " + Build.VERSION_CODES.R + " and above) requires"
                            + " the resources.arsc of installed APKs to be stored uncompressed"
                            + " and aligned on a 4-byte boundary",
                    DeferredError.RESOURCES_ARSC_COMPRESSED);
            if (deferResult.isError()) {
                return input.error(INSTALL_PARSE_FAILED_RESOURCES_ARSC_COMPRESSED,
                        deferResult.getErrorMessage());
            }
        }

        ApkAssets apkAssets = assetLoader.getBaseApkAssets();
        boolean definesOverlayable = false;
        try {
            definesOverlayable = apkAssets.definesOverlayable();
        } catch (IOException ignored) {
            // Will fail if there's no packages in the ApkAssets, which can be treated as false
        }

        if (definesOverlayable) {
            SparseArray<String> packageNames = assets.getAssignedPackageIdentifiers();
            int size = packageNames.size();
            for (int index = 0; index < size; index++) {
                String packageName = packageNames.valueAt(index);
                Map<String, String> overlayableToActor = assets.getOverlayableMap(packageName);
                if (overlayableToActor != null && !overlayableToActor.isEmpty()) {
                    for (String overlayable : overlayableToActor.keySet()) {
                        pkg.addOverlayable(overlayable, overlayableToActor.get(overlayable));
                    }
                }
            }
        }

        pkg.setVolumeUuid(volumeUuid);

        if ((flags & PARSE_COLLECT_CERTIFICATES) != 0) {
            pkg.setSigningDetails(getSigningDetails(pkg, false));
        } else {
            pkg.setSigningDetails(SigningDetails.UNKNOWN);
        }

        return input.success(pkg);
    } catch (Exception e) {
        return input.error(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
                "Failed to read manifest from " + apkPath, e);
    }
}

通过 XmlResourceParser parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME) 解析 apk 中的清单文件;

通过 parseBaseApk 获取应用的相关信息,并存储起来;

private ParseResult<ParsingPackage> parseBaseApk(ParseInput input, String apkPath,
        String codePath, Resources res, XmlResourceParser parser, int flags)
        throws XmlPullParserException, IOException {
    final String splitName;
    final String pkgName;

    ParseResult<Pair<String, String>> packageSplitResult =
            ApkLiteParseUtils.parsePackageSplitNames(input, parser);
    if (packageSplitResult.isError()) {
        return input.error(packageSplitResult);
    }

    Pair<String, String> packageSplit = packageSplitResult.getResult();
    pkgName = packageSplit.first;
    splitName = packageSplit.second;

    if (!TextUtils.isEmpty(splitName)) {
        return input.error(
                PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
                "Expected base APK, but found split " + splitName
        );
    }

    final TypedArray manifestArray = res.obtainAttributes(parser, R.styleable.AndroidManifest);
    try {
        final boolean isCoreApp =
                parser.getAttributeBooleanValue(null, "coreApp", false);
        // 获取清单文件中的标签 例如「application」「permission」「package」「manifest」
        final ParsingPackage pkg = mCallback.startParsingPackage(
                pkgName, apkPath, codePath, manifestArray, isCoreApp);
        // 获取application标签中的中的「activity」「service」「receiver」「provider」       
        final ParseResult<ParsingPackage> result =
                parseBaseApkTags(input, pkg, manifestArray, res, parser, flags);
        if (result.isError()) {
            return result;
        }

        return input.success(pkg);
    } finally {
        manifestArray.recycle();
    }
}

startParsingPackage 获取清单文件中的标签 例如「application」「permission」「package」「manifest」

parseBaseApkTags 获取application标签中的中的「activity」「service」「receiver」「provider」;

所以,静态广播是什么时候注册的?Activity的启动模式是在什么时候获取的呢? 答案就显而易见了;

开机的时候,在 PKMS 的构造方法中 会扫描所有的 apk,包括系统 apk 和应用 apk,并解析它们的清单文件,获取到 receiver 的时候就会注册,获取到 activity 的时候 一并获取了 launchMode;

扫描外部apk直接通过接口,获取 Package 对象,PackageParserCompat.parsePackage(context, apk, PackageParser.PARSE_MUST_BE_APK);

安装 APK


用户点击 xxx.apk 文件进行安装,从「开始安装」到「完成安装」到过程;这里分为两个步骤,一个是复制流程,一个是安装流程;

复制流程

点击xxx.apk执行onClick事件,通过Intent 发起startActivity 跳转到 PackageInstallerActivity 这个界面,这个界面是以 Dialog 形式展示,存在「安装」和「取消」事件,进入「安装」事件看下;

从 PackageInstallerActivity 的 bindUI 发起流程,会调用 startInstall 方法进行整个的安装流程;

private void bindUi() {
    mAlert.setIcon(mAppSnippet.icon);
    mAlert.setTitle(mAppSnippet.label);
    mAlert.setView(R.layout.install_content_view);
    mAlert.setButton(DialogInterface.BUTTON_POSITIVE, getString(R.string.install),
            (ignored, ignored2) -> {
                if (mOk.isEnabled()) {
                    if (mSessionId != -1) {
                        mInstaller.setPermissionsResult(mSessionId, true);
                        finish();
                    } else {
                        // 开始安装
                        startInstall();
                    }
                }
            }, null);
    mAlert.setButton(DialogInterface.BUTTON_NEGATIVE, getString(R.string.cancel),
            (ignored, ignored2) -> {
                // Cancel and finish
                setResult(RESULT_CANCELED);
                if (mSessionId != -1) {
                    mInstaller.setPermissionsResult(mSessionId, false);
                }
                finish();
            }, null);
    setupAlert();

    mOk = mAlert.getButton(DialogInterface.BUTTON_POSITIVE);
    mOk.setEnabled(false);

    if (!mOk.isInTouchMode()) {
        mAlert.getButton(DialogInterface.BUTTON_NEGATIVE).requestFocus();
    }
}

调用 startInstall 发起安装

private void startInstall() {
    // Start subactivity to actually install the application
    Intent newIntent = new Intent();
    newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO,
            mPkgInfo.applicationInfo);
    newIntent.setData(mPackageURI);
    newIntent.setClass(this, InstallInstalling.class);
    String installerPackageName = getIntent().getStringExtra(
            Intent.EXTRA_INSTALLER_PACKAGE_NAME);
    if (mOriginatingURI != null) {
        newIntent.putExtra(Intent.EXTRA_ORIGINATING_URI, mOriginatingURI);
    }
    if (mReferrerURI != null) {
        newIntent.putExtra(Intent.EXTRA_REFERRER, mReferrerURI);
    }
    if (mOriginatingUid != PackageInstaller.SessionParams.UID_UNKNOWN) {
        newIntent.putExtra(Intent.EXTRA_ORIGINATING_UID, mOriginatingUid);
    }
    if (installerPackageName != null) {
        newIntent.putExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME,
                installerPackageName);
    }
    if (getIntent().getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false)) {
        newIntent.putExtra(Intent.EXTRA_RETURN_RESULT, true);
    }
    newIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
    if (mLocalLOGV) Log.i(TAG, "downloaded app uri=" + mPackageURI);
    startActivity(newIntent);
    finish();
}

跳转到 安装中 InstallInstalling.class 界面,在 onResume 执行安装逻辑

protected void onResume() {
    super.onResume();

    // This is the first onResume in a single life of the activity
    if (mInstallingTask == null) {
        PackageInstaller installer = getPackageManager().getPackageInstaller();
        PackageInstaller.SessionInfo sessionInfo = installer.getSessionInfo(mSessionId);

        if (sessionInfo != null && !sessionInfo.isActive()) {
            mInstallingTask = new InstallingAsyncTask();
            // 执行 execute 方法进行安装
            mInstallingTask.execute();
        } else {
            // we will receive a broadcast when the install is finished
            mCancelButton.setEnabled(false);
            setFinishOnTouchOutside(false);
        }
    }
}

mInstallingTask.execute(); 执行 execute 方法进行安装;这里是一个 AsyncTask,要处理 doInBackground 和 onPostExecute

private final class InstallingAsyncTask extends AsyncTask<Void, Void,
        PackageInstaller.Session> {
    volatile boolean isDone;

    @Override
    protected PackageInstaller.Session doInBackground(Void... params) {
        PackageInstaller.Session session;
        try {
            session = getPackageManager().getPackageInstaller().openSession(mSessionId);
        } catch (IOException e) {
            synchronized (this) {
                isDone = true;
                notifyAll();
            }
            return null;
        }

        session.setStagingProgress(0);

        try {
            File file = new File(mPackageURI.getPath());

            try (InputStream in = new FileInputStream(file)) {
                long sizeBytes = file.length();
                try (OutputStream out = session
                        .openWrite("PackageInstaller", 0, sizeBytes)) {
                    byte[] buffer = new byte[1024 * 1024];
                    while (true) {
                        int numRead = in.read(buffer);

                        if (numRead == -1) {
                            session.fsync(out);
                            break;
                        }

                        if (isCancelled()) {
                            session.close();
                            break;
                        }

                        out.write(buffer, 0, numRead);
                        if (sizeBytes > 0) {
                            float fraction = ((float) numRead / (float) sizeBytes);
                            session.addProgress(fraction);
                        }
                    }
                }
            }

            return session;
        } catch (IOException | SecurityException e) {
            Log.e(LOG_TAG, "Could not write package", e);

            session.close();

            return null;
        } finally {
            synchronized (this) {
                isDone = true;
                notifyAll();
            }
        }
    }

    @Override
    protected void onPostExecute(PackageInstaller.Session session) {
        if (session != null) {
            Intent broadcastIntent = new Intent(BROADCAST_ACTION);
            broadcastIntent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
            broadcastIntent.setPackage(getPackageName());
            broadcastIntent.putExtra(EventResultPersister.EXTRA_ID, mInstallId);

            PendingIntent pendingIntent = PendingIntent.getBroadcast(
                    InstallInstalling.this,
                    mInstallId,
                    broadcastIntent,
                    PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);

            session.commit(pendingIntent.getIntentSender());
            mCancelButton.setEnabled(false);
            setFinishOnTouchOutside(false);
        } else {
            getPackageManager().getPackageInstaller().abandonSession(mSessionId);

            if (!isCancelled()) {
                launchFailure(PackageInstaller.STATUS_FAILURE,
                        PackageManager.INSTALL_FAILED_INVALID_APK, null);
            }
        }
    }
}

doInBackground方法中:通过IO流 将apk文件写入session中;

onPostExecute方法中:通过 session.commit 方法,跨进程操作,将 session 交给 PKMS,最终走到 PKMS 的 installStage 方法;

void installStage(InstallParams params) {
    final Message msg = mHandler.obtainMessage(INIT_COPY);
    params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params));
    msg.obj = params;

    Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installStage",
            System.identityHashCode(msg.obj));
    Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
            System.identityHashCode(msg.obj));

    mHandler.sendMessage(msg);
}

msg.what == INIT_COPY; handleMessage 的这个 case 我们进入看下:

class PackageHandler extends Handler {
    
    void doHandleMessage(Message msg) {
        
        switch (msg.what) {
            case INIT_COPY: {
                HandlerParams params = (HandlerParams) msg.obj;
                if (params != null) {
                    params.startCopy();
                }
                break;
            }
        }
    }
}

INIT_COPY 中最终执行的是 HandlerParams 的 startCopy 方法,将 apk 复制到 /data/app 目录下;

最终走到 PKMS 的 handleStartCopy() 方法 和 handleReturnCode 方法;

public void handleStartCopy() {
    if ((installFlags & PackageManager.INSTALL_APEX) != 0) {
        mRet = INSTALL_SUCCEEDED;
        return;
    }
    PackageInfoLite pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
            mPackageLite, origin.resolvedPath, installFlags, packageAbiOverride);

    // For staged session, there is a delay between its verification and install. Device
    // state can change within this delay and hence we need to re-verify certain conditions.
    boolean isStaged = (installFlags & INSTALL_STAGED) != 0;
    if (isStaged) {
        mRet = verifyReplacingVersionCode(
                pkgLite, requiredInstalledVersionCode, installFlags);
        if (mRet != INSTALL_SUCCEEDED) {
            return;
        }
    }

    mRet = overrideInstallLocation(pkgLite);
}

主要是为了创建 InstallArgs,在 handleReturnCode 中执行 copyApk 方法;

void handleReturnCode() {
    processPendingInstall();
}

private void processPendingInstall() {
    // 这里创建的是 FileInstallArgs
    InstallArgs args = createInstallArgs(this);
    if (mRet == PackageManager.INSTALL_SUCCEEDED) {
        mRet = args.copyApk();
    }
    if (mRet == PackageManager.INSTALL_SUCCEEDED) {
        F2fsUtils.releaseCompressedBlocks(
                mContext.getContentResolver(), new File(args.getCodePath()));
    }
    if (mParentInstallParams != null) {
        mParentInstallParams.tryProcessInstallRequest(args, mRet);
    } else {
        PackageInstalledInfo res = createPackageInstalledInfo(mRet);
        processInstallRequestsAsync(
                res.returnCode == PackageManager.INSTALL_SUCCEEDED,
                Collections.singletonList(new InstallRequest(args, res)));
    }
}

handleReturnCode 执行到 args.copyApk() 的时候,才真正的将 apk 文件复制到了 /data/app 目录下;

int copyApk() {
    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyApk");
    try {
        return doCopyApk();
    } finally {
        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
    }
}

private int doCopyApk() {
    if (origin.staged) {
        if (DEBUG_INSTALL) Slog.d(TAG, origin.file + " already staged; skipping copy");
        codeFile = origin.file;
        return PackageManager.INSTALL_SUCCEEDED;
    }

    try {
        final boolean isEphemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
        final File tempDir =
                mInstallerService.allocateStageDirLegacy(volumeUuid, isEphemeral);
        codeFile = tempDir;
    } catch (IOException e) {
        Slog.w(TAG, "Failed to create copy file: " + e);
        return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
    }

    int ret = PackageManagerServiceUtils.copyPackage(
            origin.file.getAbsolutePath(), codeFile);
    if (ret != PackageManager.INSTALL_SUCCEEDED) {
        Slog.e(TAG, "Failed to copy package");
        return ret;
    }

    final boolean isIncremental = isIncrementalPath(codeFile.getAbsolutePath());
    final File libraryRoot = new File(codeFile, LIB_DIR_NAME);
    NativeLibraryHelper.Handle handle = null;
    try {
        handle = NativeLibraryHelper.Handle.create(codeFile);
        ret = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot,
                abiOverride, isIncremental);
    } catch (IOException e) {
        Slog.e(TAG, "Copying native libraries failed", e);
        ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
    } finally {
        IoUtils.closeQuietly(handle);
    }

    return ret;
}

通过 IO 流 执行 copy 操作;这也就能解释为什么 apk 安装包可以删除的原因了;

扫描流程大致可以理解为:

  1. 在 PackageParser 扫描完一个 APK 后,此时系统已经根据该 APK 中 AndroidManifest.xml,创建了一个完整的 Package 对象;
  2. 扫描APK,解析AndroidManifest.xml文件,得到清单文件各个标签内容;
  3. 解析清单文件的信息由 Package 保存,从该类的成员变量可看出,和 Android 四大组件相关
    的信息分别由 activites、receivers、providers、services 保存,由于一个 APK 可声明多个组件,因此 activites 和 receivers 等均声明为 ArrayList;

安装流程

安装流程也是有 PKMS 发起的,它发起的起点就是 handleReturnCode 的回调中调用了processPendingInstall 方法

void handleReturnCode() {
    processPendingInstall();
}

private void processPendingInstall() {
    InstallArgs args = createInstallArgs(this);
    if (mRet == PackageManager.INSTALL_SUCCEEDED) {
        mRet = args.copyApk();
    }
    if (mRet == PackageManager.INSTALL_SUCCEEDED) {
        F2fsUtils.releaseCompressedBlocks(
                mContext.getContentResolver(), new File(args.getCodePath()));
    }
    if (mParentInstallParams != null) {
        mParentInstallParams.tryProcessInstallRequest(args, mRet);
    } else {
        PackageInstalledInfo res = createPackageInstalledInfo(mRet);
        // 执行安装逻辑
        processInstallRequestsAsync(
                res.returnCode == PackageManager.INSTALL_SUCCEEDED,
                Collections.singletonList(new InstallRequest(args, res)));
    }
}

通过调用 processInstallRequestsAsync 执行安装逻辑

private void processInstallRequestsAsync(boolean success,
        List<InstallRequest> installRequests) {
    
    mHandler.post(() -> {
        // 省略部分代码
        if (success) {
            // 省略部分代码
            synchronized (mInstallLock) {
                installPackagesTracedLI(apkInstallRequests);
            }
        }
    })    
}

这里直接调用 installPackagesTracedLI 进行安装;

private void installPackagesTracedLI(List<InstallRequest> requests) {
    try {
        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackages");
        installPackagesLI(requests);
    } finally {
        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
    }
}

这里直接调用 installPackagesLI 方法进行 apk 扫描以及安装

private void installPackagesLI(List<InstallRequest> requests) {
    //
    // 省略部分代码
    final ScanResult result = scanPackageTracedLI(
        prepareResult.packageToScan, prepareResult.parseFlags,
        prepareResult.scanFlags, System.currentTimeMillis(),
        request.args.user, request.args.abiOverride);
    
    // 构建安装请求,然后调用 executePostCommitSteps 进行安装
    CommitRequest commitRequest = null;
    synchronized (mLock) {
        Map<String, ReconciledPackage> reconciledPackages;
        try {
            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "reconcilePackages");
            reconciledPackages = reconcilePackagesLocked(
                    reconcileRequest, mSettings.getKeySetManagerService(), mInjector);
        } catch (ReconcileFailure e) {
            for (InstallRequest request : requests) {
                request.installResult.setError("Reconciliation failed...", e);
            }
            return;
        } finally {
            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
        }
        try {
            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "commitPackages");
            commitRequest = new CommitRequest(reconciledPackages,
                    mUserManager.getUserIds());
            commitPackagesLocked(commitRequest);
            success = true;
        } finally {
            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
        }
    }
    executePostCommitSteps(commitRequest);
}

构建安装请求,然后调用 executePostCommitSteps 进行安装;

private void executePostCommitSteps(CommitRequest commitRequest) {
    // 省略部分代码
    final ArraySet<IncrementalStorage> incrementalStorages = new ArraySet<>();
    for (ReconciledPackage reconciledPkg : commitRequest.reconciledPackages.values()) {
        final boolean instantApp = ((reconciledPkg.scanResult.request.scanFlags
                        & PackageManagerService.SCAN_AS_INSTANT_APP) != 0);
        final AndroidPackage pkg = reconciledPkg.pkgSetting.pkg;
        final String packageName = pkg.getPackageName();
        final String codePath = pkg.getPath();
        final boolean onIncremental = mIncrementalManager != null
                && isIncrementalPath(codePath);
        if (onIncremental) {
            IncrementalStorage storage = mIncrementalManager.openStorage(codePath);
            if (storage == null) {
                throw new IllegalArgumentException(
                        "Install: null storage for incremental package " + packageName);
            }
            incrementalStorages.add(storage);
        }
        prepareAppDataAfterInstallLIF(pkg);
        
        // 省略部分代码
    }
    
    // 省略部分代码
}

这里调用 prepareAppDataAfterInstallLIF 最终调用到 prepareAppDataLeaf 中的 batch.createAppData

private @NonNull CompletableFuture<?> prepareAppDataLeaf(@NonNull Installer.Batch batch,
        @NonNull AndroidPackage pkg, int userId, int flags) {
    return batch.createAppData(volumeUuid, packageName, userId, flags, appId, seInfo,
        targetSdkVersion).whenComplete((ceDataInode, e) -> {
            
            if (e != null) {
                
                destroyAppDataLeafLIF(pkg, userId, flags);
                try {
                    ceDataInode = mInstaller.createAppData(volumeUuid, packageName, userId,
                            flags, appId, seInfo, pkg.getTargetSdkVersion());
                    
                } catch (InstallerException e2) {
                    
                }
            } else if (e != null) {
               
            }
            if (mIsUpgrade || mFirstBoot || (userId != UserHandle.USER_SYSTEM)) {
                mArtManagerService.prepareAppProfiles(pkg, userId,
                    /* updateReferenceProfileContent= */ false);
            }

            if ((flags & StorageManager.FLAG_STORAGE_CE) != 0 && ceDataInode != -1) {
                synchronized (mLock) {
                    if (ps != null) {
                        ps.setCeDataInode(ceDataInode, userId);
                    }
                }
            }
            
            prepareAppDataContentsLeafLIF(pkg, ps, userId, flags);
        });
}

Batch 的 createAppData 最终调用到的是其 execute 方法;

public synchronized void execute(@NonNull Installer installer) throws InstallerException {
    if (mExecuted) throw new IllegalStateException();
    mExecuted = true;

    final int size = mArgs.size();
    for (int i = 0; i < size; i += CREATE_APP_DATA_BATCH_SIZE) {
        final CreateAppDataArgs[] args = new CreateAppDataArgs[Math.min(size - i,
                CREATE_APP_DATA_BATCH_SIZE)];
        for (int j = 0; j < args.length; j++) {
            args[j] = mArgs.get(i + j);
        }
        final CreateAppDataResult[] results = installer.createAppDataBatched(args);
        for (int j = 0; j < args.length; j++) {
            final CreateAppDataResult result = results[j];
            final CompletableFuture<Long> future = mFutures.get(i + j);
            if (result.exceptionCode == 0) {
                future.complete(result.ceDataInode);
            } else {
                future.completeExceptionally(
                        new InstallerException(result.exceptionMessage));
            }
        }
    }
}

通过 installer.createAppDataBatched(args) 方法进行 app 的创建;

public @NonNull CreateAppDataResult[] createAppDataBatched(@NonNull CreateAppDataArgs[] args)
        throws InstallerException {
    if (!checkBeforeRemote()) {
        final CreateAppDataResult[] results = new CreateAppDataResult[args.length];
        Arrays.fill(results, buildPlaceholderCreateAppDataResult());
        return results;
    }
    try {
        // 进入 linux 底层的安装逻辑
        return mInstalld.createAppDataBatched(args);
    } catch (Exception e) {
        throw InstallerException.from(e);
    }
}

最终 mInstalld.createAppDataBatched(args); 进入 linux 底层的安装逻辑,底层的安装逻辑我也不太清楚,只能到这里了;

权限扫描


PKMS 的构造方法中会调用到 SystemConfig systemConfig = SystemConfig.getInstance(); 方法,此方法会执行权限的扫描/system/etc/permissions

image.png

SytestemConfig 的构造方法中 会执行权限的读取操作;

image.png

readPermissions 和扫描到的AndroidManifest文件中声明的权限会和这里进行一个匹配,匹配上了给予权限;

image.png
好了,本章的讲解就到这里吧,静默安装和权限申请框架我们放在了下一章;

下一章预告


PMS 权限管理

欢迎三连


来都来了,点个关注点个赞吧,你的支持是我最大的动力~~

Android Framework之Pkms详解 system 用户并没有访问应用程序目录的权限,但是 Installd 服务是以 root 用户启动的,可以访问 /data/data/ 下的目录,Installd 需要完成一些创建应用数据的任务。Installer 服务是 Android 提供的用于安装的服务,Installer 持有 Installd 守护进程对应的 Binder 服务的代理对象,本质上是通过 Binder 通信调用底层的 Installd 服务真正完成 APK 文件格式的优化和转换、建立相关的数据目录、删除文件、安装应用等工作。 阅读详情

相关推荐

面试:Android 签名校验机制 v1、v2、v3

2. 对MAINFEST.MF整个文件做一次算法(数据摘要+Base64编码),存放到CERT.SF文件的头属性中,在对MAINFEST.MF文件中各个属性块做一次算法(数据摘要+Base64编码),存放到一个属性块中。:由于开发商可能通过使用相同的package name来混淆替换已经安装的程序,以此保证签名不同的包不被替换。2. 保证信息传输的完成性:签名对于包中的每个文件进行处理,以此确保包中内容不被替换。3. 对CERT.SF文件做签名,内容存档到CERT.RSA中。

王温暖的博客 3151

Android---PKMS核心分析1

Android 系统启动时,会启动应用程序管理服务KPMS,此服务负责扫描系统中特定的目录,寻找里面的 APK 格式文件,并对这些文件进行解析,然后得到应用程序相关信息,最后完成应用程序的安装。PKMS 在安装应用过程中,会全面解析应用程序的 AndroidManifest.xml 文件,来得到 Activity,Service,BroadcastReceiver,ContextProvider 等信息,在结合 PKMS 服务就可以在 OS 中正常的使用应用程序了。

qq_44950283的博客 2176

Android 进阶——系统启动 之PKMS和Laucher应用启动详解(十三)

系统启动 之PKMS和Laucher应用启动详解

最美不过,心中有梦,身旁有你! 3049

android程序中证书签名校验的方法

android程序中证书签名校验的方法一 2013-02-26 09:56:22| 分类: android逆向技巧 |举报 |字号 订阅 (1)、将证书进行base64编码,并将编码后的字符串保存在程序中; (2)、将证书签名(MD5或SHA1值)进行对称算法加密(比如:DES),然后将加密后的结果和对称算法密钥放在一起,再使用证书的private key 对其加密,将加密后的...

阿弥陀佛 609

PackageManagerService的启动过程——Android 12(一)

PackageManagerService(简称PKMS)的官方解释:随时随地跟踪所有的APKs。主要职责分为: 启动过程中扫描App所有安装目录,解析其中的Apk将相关信息加载到PKMS的数据结构中,同时同步到/data/system/packages.xml中;注册APK信息和其四大组件到PKMS中。 负责App的安装和卸载。 对外提供接口查询App相关信息。

lvyaer_1122的博客 1844

Android系统服务PKMS(PackageManagerService)

1、概述 PKMS全称PackageManagerService,是Android核心服务之一,主要负责功能如下: 解析AndroidManifest.xml,主要有AndroidManifest中节点信息的解析和提炼。 扫描本地文件,主要针对apk,系统应用、本地安装应用等。 管理本地apk,包括安装、删除等。 2、核心源码 /frameworks/base/core/java/android/app/ApplicationPackageManager.java /frameworks/.

ming15920的博客 1468

数据中心机房设备标签规范建议

机房的维护工作中,标识管理是极其重要的一部分,从基本的线缆上跳接信息的标识,到设备、机柜标识规范的实施,不同程度的体现了标识管理的重要作用。本规范适用于机房主设备、线缆、机柜(含PDU插排)、仪器仪表、动力配套设备(各类空调、消防设备、配电柜、UPS等设备)、网络口、电源插座口的标签、标识规定。动力设备的设备编号、设备名称、生产厂商及厂商技术支持热线、设备型号、设备序列号、设备使用部门、设备责任人、设备启用时间及设备保修年限、条形码。各类标签、标识可根据设备和机柜的尺寸、大小进行调整。

有地气的强弱电小圈子 3524

android开发浅谈之PackageManagerService(pkms)

本文基于Android10.0 主要从以下几个方面着手: PKMS启动 PKMS安装APK PKMS卸载APK PKMS启动 这里我简单的将其分为以下几个步骤: 1.SystemServer通过PKMS的main方法启动PKMS 2.PKMS构造方法中初始化Settings 3.扫描各个系统目录下APP相关信息 1.SystemServer通过PKMS的main方法启动PKMS PKMS启动是在SystemServer.startBootstrapServices: mPackageManagerSer

hfreeman2008的专栏 2718

2022-04-06 RK3566 上调试百兆以太网卡YT8512C 调试记录

一、原理图 二、dts &gmac1_clkin{ clock-frequency = <50000000>; status = "okay"; }; &gmac1 { phy-mode = "rmii"; clock_in_out = "input"; snps,reset-gpio = <&gpio4 RK_PC2 GPIO_ACTIVE_LOW>; snps,reset-active-low; sn...

海月汐辰 1万+

基于STM32F427的模拟SSI协议绝对式编码器位置反馈通信

基于STM32F427的模拟SSI协议绝对式编码器位置反馈通信

xeke997的博客 6064

最常见的Android签名校验

将Signature对象转化为MD5字符串的方法

m0_47587308的博客 2103

RH850从0搭建Autosar开发环境【3X】- Davinci Configurator之BswM模块配置详解(上)

RH850从0搭建Autosar开发环境【3X】- Davinci Configurator之BswM模块配置详解(上)

weixin_42412049的博客 736

android framework-PackageManagerService(PKMS)包管理服务

PKMS

知识共享,你我皆是知识的搬运工 946

使用 MATLAB/Simulink 构建一个分布式光伏-储能联合系统在配电网中的协同控制模型

本文介绍了使用MATLAB/Simulink构建分布式光伏-储能联合系统协同控制模型的方法。该系统包含光伏发电、储能、负荷和控制器等模块,通过协同控制实现能量优化管理。建模过程详细说明了从创建项目、搭建组件到实现控制策略的步骤,包括光伏特性模拟、储能参数设置和负荷需求建模。重点设计了协同控制器算法,实时调节电力分配,并展示了系统运行指标和经济效益分析。该方法为多能互补系统在配电网中的应用提供了技术验证,未来可进一步优化控制算法和场景适应性。

MHD0815的博客 309

WPF实战项目十七(客户端):数据等待加载弹框动画

1、在Common文件夹下新建文件夹Events,新建扩展类UpdateLoadingEvent。2、新建一个静态扩展类DialogExtensions来编写注册和推送等待消息弹框方法。3、在ViewModel中添加实现类NavigationViewModel。5、在View文件夹下新建用户控件ProgressView.xmal。4、在主窗体MainView.xmal中给弹窗界面命名。6、在MainView.xmal.cs中注册消息。

yigu4011的博客 2346

Android验证apk签名

1.验证apk签名 打开待查看的apk,将其中META-INF文件夹解压出来,得到其中的CERT.RSA文件 $ keytool -printcert -file META-INF/CERT.RSA 2.apk打签名 jarsigner -verbose -keystore [keystorePath] -signedjar [apkOut] [apkIn] [

zhengjuqiang的博客 2820

知识图谱中的 Ontology(本体论)

1980年,本体论(Ontology)哲学概念“本体”被引入到人工智能领域用来刻画知识。本体概念模型、明确、形式化、共享。本体是实体存在形式的描述,往往表示为一组概念定义和概念之间的层级关系,本体框架形式树状结构,通常被用来为知识图谱定义schema。如人、公司、车等都可以在具体场景下称为本体。Ontology是(特定领域)信息组织的一种形式,是领域知识规范的抽象和描述,是表达、共享、重用知识的方法。Ontology。

全网粉丝30W+,优快云、稀土掘金人工智能领域签约作者,人工智能、大模型、Python 爬虫,商务合作,请私信沟通。 2028

【Android】【Framework】PKMS

PKMS(AOSP4.4.2)主要负责Android系统中应用程序的安装与管理。其启动过程包括SystemServer调用PKMS扫描系统目录中的APK文件,解析AndroidManifest.xml获取应用信息,并为应用分配Linux用户ID和组ID。DEX文件作为Dalvik虚拟机的可执行格式,在应用安装时由Java字节码转换生成,经过优化后由系统加载执行。PKMS通过ServiceManager注册为系统服务,管理/data/app等目录的应用安装,并维护应用的权限与用户ID信息。相关技术涉及多DEX

qiushan_的博客 616

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

PKMS源码解析

PKMS指PackageManagerService服务本身以及PackageManagerService服务运作时使用到的各种其他系统服务;是Android系统中的核心服务之一,负责应用程序的安装、卸载以及信息查询等工作;1.解析AndroidManifest.xml文件,解析清单文件中的所有节点信息; 2.扫描.apk文件,安装系统应用、本地应用等; 3.管理本地应用,主要有安装、卸载、应用信息查询等; 客户端通过拿到ApplicationPackageManager对象,通过binder进行跨进程通信

故不积跬步无以至千里 1431

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

PackageManagerService介绍----基于Android Q

1.PKMS功能概述 PackageManagerService是系统的核心服务之一,负责系统中Package的管理,应用程序的安装、卸载、信息查询等。 2.类继承结构图 IPackageManager:接口类,定义了服务端和客户端通信的函数以及Stub(从Binder派生并实现IPackageManager接口),在编译过程中由IPackageManager.aidl文件生成。 PackageManagerService: 继承 IPackageManager.stub,具体实现功能类,是

hanhan1016的专栏 4380

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

Android逆向-基础与实践 (五) 签名校验

是开发者在数据传送时采用的一种校正数据的一种方式常见的校验有:签名校验(最常见)、dexcrc校验、apk完整性校验、路径文件校验等通过对 Apk 进行签名,开发者可以证明对 Apk 的所有权和控制权,可用于安装和更新其应用。而在 Android 设备上的安装 Apk ,如果是一个没有被签名的 Apk,则会被拒绝安装。在安装 Apk 的时候,软件包管理器也会验证 Apk 是否已经被正确签名,并且通过签名证书和数据摘要验证是否合法没有被篡改。只有确认安全无篡改的情况下,才允许安装在设备上。

shuwangyong的专栏 2399

Android PackageManagerService总结(四) APK安装流程

管理本地apk,主要包括安装、删除 本篇文章重点介绍一下apk安装流程

u012514113的专栏 6463

Android Framework中关于PKMS的调用方式简述

PKMS指PackageManagerService服务本身以及PackageManagerService服务运作时使用到的各种其他系统服务;是Android系统中的核心服务之一,负责应用程序的安装、卸载以及信息查询等工作;如果想要成为架构师或想突破20~30K薪资范畴,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。

m0_64365896的博客 274

Android Fk:PKMS(1)-PackageManagerService的Binder架构及初始化

Android Fk:PKMS(1)-PackageManagerService的Binder架构及初始化一、PKMS的概述及其Binder架构1. PKMS的基本功能:  PackageManagerService是Android的核心服务,负责系统中的Package的管理,应用的安装,卸载,信息查询等。   手机平台的Android代码PKMS为了优化或者新功能更改了很多,本文主要基于Andr

TaylorPotter的博客 3528

PKMS权限管理简单分析

拉起应用授权的系统应用原来是在 PackageInstall.apk中,android11后更改到PermissionControll.apk,这里注意看是否google原生的还是其他平台的。android 11及以上源码。主要涉及到的activity为。保存权限到手机的位置。

孙国庆的博客 663
上一篇: Jetpack Compose -> 重组的性能风险和优化
下一篇: 如何应对Android面试官 -> PKMS 权限管理
老A说
博客等级 码龄14年 1181粉丝 85原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值