| /* |
| * Copyright (C) 2021 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.server.pm; |
| |
| import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK; |
| import static android.content.pm.PackageManager.INSTALL_FAILED_PROCESS_NOT_DEFINED; |
| import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES; |
| import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; |
| |
| import static com.android.server.pm.PackageManagerService.DEBUG_ABI_SELECTION; |
| import static com.android.server.pm.PackageManagerService.DEBUG_PACKAGE_SCANNING; |
| import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME; |
| import static com.android.server.pm.PackageManagerService.SCAN_AS_APEX; |
| import static com.android.server.pm.PackageManagerService.SCAN_AS_FULL_APP; |
| import static com.android.server.pm.PackageManagerService.SCAN_AS_INSTANT_APP; |
| import static com.android.server.pm.PackageManagerService.SCAN_AS_ODM; |
| import static com.android.server.pm.PackageManagerService.SCAN_AS_OEM; |
| import static com.android.server.pm.PackageManagerService.SCAN_AS_PRIVILEGED; |
| import static com.android.server.pm.PackageManagerService.SCAN_AS_PRODUCT; |
| import static com.android.server.pm.PackageManagerService.SCAN_AS_STOPPED_SYSTEM_APP; |
| import static com.android.server.pm.PackageManagerService.SCAN_AS_SYSTEM; |
| import static com.android.server.pm.PackageManagerService.SCAN_AS_SYSTEM_EXT; |
| import static com.android.server.pm.PackageManagerService.SCAN_AS_VENDOR; |
| import static com.android.server.pm.PackageManagerService.SCAN_AS_VIRTUAL_PRELOAD; |
| import static com.android.server.pm.PackageManagerService.SCAN_BOOTING; |
| import static com.android.server.pm.PackageManagerService.SCAN_FIRST_BOOT_OR_UPGRADE; |
| import static com.android.server.pm.PackageManagerService.SCAN_MOVE; |
| import static com.android.server.pm.PackageManagerService.SCAN_NEW_INSTALL; |
| import static com.android.server.pm.PackageManagerService.SCAN_NO_DEX; |
| import static com.android.server.pm.PackageManagerService.SCAN_UPDATE_TIME; |
| import static com.android.server.pm.PackageManagerService.TAG; |
| import static com.android.server.pm.PackageManagerServiceUtils.compareSignatures; |
| import static com.android.server.pm.PackageManagerServiceUtils.compressedFileExists; |
| import static com.android.server.pm.PackageManagerServiceUtils.deriveAbiOverride; |
| import static com.android.server.pm.PackageManagerServiceUtils.getLastModifiedTime; |
| |
| import android.annotation.NonNull; |
| import android.annotation.Nullable; |
| import android.content.pm.ApplicationInfo; |
| import android.content.pm.PackageManager; |
| import android.content.pm.SharedLibraryInfo; |
| import android.content.pm.SigningDetails; |
| import android.content.pm.parsing.result.ParseResult; |
| import android.content.pm.parsing.result.ParseTypeImpl; |
| import android.os.Build; |
| import android.os.Environment; |
| import android.os.Process; |
| import android.os.SystemProperties; |
| import android.os.Trace; |
| import android.os.UserHandle; |
| import android.text.TextUtils; |
| import android.util.ArrayMap; |
| import android.util.ArraySet; |
| import android.util.Log; |
| import android.util.Pair; |
| import android.util.Slog; |
| import android.util.apk.ApkSignatureVerifier; |
| import android.util.jar.StrictJarFile; |
| |
| import com.android.internal.annotations.GuardedBy; |
| import com.android.internal.annotations.VisibleForTesting; |
| import com.android.internal.util.ArrayUtils; |
| import com.android.server.SystemConfig; |
| import com.android.server.pm.parsing.PackageInfoUtils; |
| import com.android.server.pm.parsing.library.PackageBackwardCompatibility; |
| import com.android.server.pm.parsing.pkg.AndroidPackageUtils; |
| import com.android.server.pm.parsing.pkg.ParsedPackage; |
| import com.android.server.pm.pkg.AndroidPackage; |
| import com.android.server.pm.pkg.PackageStateUtils; |
| import com.android.server.pm.pkg.component.ComponentMutateUtils; |
| import com.android.server.pm.pkg.component.ParsedActivity; |
| import com.android.server.pm.pkg.component.ParsedMainComponent; |
| import com.android.server.pm.pkg.component.ParsedProcess; |
| import com.android.server.pm.pkg.component.ParsedProvider; |
| import com.android.server.pm.pkg.component.ParsedService; |
| import com.android.server.pm.pkg.parsing.ParsingPackageUtils; |
| import com.android.server.utils.WatchedArraySet; |
| |
| import dalvik.system.VMRuntime; |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Objects; |
| import java.util.UUID; |
| |
| /** |
| * Helper class that handles package scanning logic |
| */ |
| final class ScanPackageUtils { |
| /** |
| * Just scans the package without any side effects. |
| * |
| * @param injector injector for acquiring dependencies |
| * @param request Information about the package to be scanned |
| * @param isUnderFactoryTest Whether or not the device is under factory test |
| * @param currentTime The current time, in millis |
| * @return The results of the scan |
| */ |
| @GuardedBy("mPm.mInstallLock") |
| @VisibleForTesting |
| @NonNull |
| public static ScanResult scanPackageOnlyLI(@NonNull ScanRequest request, |
| PackageManagerServiceInjector injector, |
| boolean isUnderFactoryTest, long currentTime) |
| throws PackageManagerException { |
| final PackageAbiHelper packageAbiHelper = injector.getAbiHelper(); |
| ParsedPackage parsedPackage = request.mParsedPackage; |
| PackageSetting pkgSetting = request.mPkgSetting; |
| final PackageSetting disabledPkgSetting = request.mDisabledPkgSetting; |
| final PackageSetting originalPkgSetting = request.mOriginalPkgSetting; |
| final @ParsingPackageUtils.ParseFlags int parseFlags = request.mParseFlags; |
| final @PackageManagerService.ScanFlags int scanFlags = request.mScanFlags; |
| final String realPkgName = request.mRealPkgName; |
| final SharedUserSetting oldSharedUserSetting = request.mOldSharedUserSetting; |
| final SharedUserSetting sharedUserSetting = request.mSharedUserSetting; |
| final UserHandle user = request.mUser; |
| final boolean isPlatformPackage = request.mIsPlatformPackage; |
| |
| List<String> changedAbiCodePath = null; |
| |
| if (DEBUG_PACKAGE_SCANNING) { |
| if ((parseFlags & ParsingPackageUtils.PARSE_CHATTY) != 0) { |
| Log.d(TAG, "Scanning package " + parsedPackage.getPackageName()); |
| } |
| } |
| |
| // Initialize package source and resource directories |
| final File destCodeFile = new File(parsedPackage.getPath()); |
| |
| // We keep references to the derived CPU Abis from settings in oder to reuse |
| // them in the case where we're not upgrading or booting for the first time. |
| String primaryCpuAbiFromSettings = null; |
| String secondaryCpuAbiFromSettings = null; |
| boolean needToDeriveAbi = (scanFlags & SCAN_FIRST_BOOT_OR_UPGRADE) != 0; |
| if (!needToDeriveAbi) { |
| if (pkgSetting != null) { |
| // TODO(b/154610922): if it is not first boot or upgrade, we should directly use |
| // API info from existing package setting. However, stub packages currently do not |
| // preserve ABI info, thus the special condition check here. Remove the special |
| // check after we fix the stub generation. |
| if (pkgSetting.getPkg() != null && pkgSetting.getPkg().isStub()) { |
| needToDeriveAbi = true; |
| } else { |
| primaryCpuAbiFromSettings = pkgSetting.getPrimaryCpuAbiLegacy(); |
| secondaryCpuAbiFromSettings = pkgSetting.getSecondaryCpuAbiLegacy(); |
| } |
| } else { |
| // Re-scanning a system package after uninstalling updates; need to derive ABI |
| needToDeriveAbi = true; |
| } |
| } |
| |
| if (pkgSetting != null && oldSharedUserSetting != sharedUserSetting) { |
| PackageManagerService.reportSettingsProblem(Log.WARN, |
| "Package " + parsedPackage.getPackageName() + " shared user changed from " |
| + (oldSharedUserSetting != null |
| ? oldSharedUserSetting.name : "<nothing>") |
| + " to " |
| + (sharedUserSetting != null ? sharedUserSetting.name : "<nothing>") |
| + "; replacing with new"); |
| pkgSetting = null; |
| } |
| |
| String[] usesSdkLibraries = null; |
| if (!parsedPackage.getUsesSdkLibraries().isEmpty()) { |
| usesSdkLibraries = new String[parsedPackage.getUsesSdkLibraries().size()]; |
| parsedPackage.getUsesSdkLibraries().toArray(usesSdkLibraries); |
| } |
| |
| String[] usesStaticLibraries = null; |
| if (!parsedPackage.getUsesStaticLibraries().isEmpty()) { |
| usesStaticLibraries = new String[parsedPackage.getUsesStaticLibraries().size()]; |
| parsedPackage.getUsesStaticLibraries().toArray(usesStaticLibraries); |
| } |
| |
| final UUID newDomainSetId = injector.getDomainVerificationManagerInternal().generateNewId(); |
| |
| // TODO(b/135203078): Remove appInfoFlag usage in favor of individually assigned booleans |
| // to avoid adding something that's unsupported due to lack of state, since it's called |
| // with null. |
| final boolean createNewPackage = (pkgSetting == null); |
| if (createNewPackage) { |
| final boolean instantApp = (scanFlags & SCAN_AS_INSTANT_APP) != 0; |
| final boolean virtualPreload = (scanFlags & SCAN_AS_VIRTUAL_PRELOAD) != 0; |
| final boolean isStoppedSystemApp = (scanFlags & SCAN_AS_STOPPED_SYSTEM_APP) != 0; |
| |
| // Flags contain system values stored in the server variant of AndroidPackage, |
| // and so the server-side PackageInfoUtils is still called, even without a |
| // PackageSetting to pass in. |
| int pkgFlags = PackageInfoUtils.appInfoFlags(parsedPackage, null); |
| int pkgPrivateFlags = PackageInfoUtils.appInfoPrivateFlags(parsedPackage, null); |
| |
| // REMOVE SharedUserSetting from method; update in a separate call |
| pkgSetting = Settings.createNewSetting(parsedPackage.getPackageName(), |
| originalPkgSetting, disabledPkgSetting, realPkgName, sharedUserSetting, |
| destCodeFile, parsedPackage.getNativeLibraryRootDir(), |
| AndroidPackageUtils.getRawPrimaryCpuAbi(parsedPackage), |
| AndroidPackageUtils.getRawSecondaryCpuAbi(parsedPackage), |
| parsedPackage.getLongVersionCode(), pkgFlags, pkgPrivateFlags, user, |
| true /*allowInstall*/, instantApp, virtualPreload, isStoppedSystemApp, |
| UserManagerService.getInstance(), usesSdkLibraries, |
| parsedPackage.getUsesSdkLibrariesVersionsMajor(), usesStaticLibraries, |
| parsedPackage.getUsesStaticLibrariesVersions(), parsedPackage.getMimeGroups(), |
| newDomainSetId); |
| } else { |
| // make a deep copy to avoid modifying any existing system state. |
| pkgSetting = new PackageSetting(pkgSetting); |
| pkgSetting.setPkg(parsedPackage); |
| |
| // REMOVE SharedUserSetting from method; update in a separate call. |
| // |
| // TODO(narayan): This update is bogus. nativeLibraryDir & primaryCpuAbi, |
| // secondaryCpuAbi are not known at this point so we always update them |
| // to null here, only to reset them at a later point. |
| Settings.updatePackageSetting(pkgSetting, disabledPkgSetting, oldSharedUserSetting, |
| sharedUserSetting, destCodeFile, parsedPackage.getNativeLibraryDir(), |
| pkgSetting.getPrimaryCpuAbi(), |
| pkgSetting.getSecondaryCpuAbi(), |
| PackageInfoUtils.appInfoFlags(parsedPackage, pkgSetting), |
| PackageInfoUtils.appInfoPrivateFlags(parsedPackage, pkgSetting), |
| UserManagerService.getInstance(), |
| usesSdkLibraries, parsedPackage.getUsesSdkLibrariesVersionsMajor(), |
| usesStaticLibraries, parsedPackage.getUsesStaticLibrariesVersions(), |
| parsedPackage.getMimeGroups(), newDomainSetId); |
| } |
| if (createNewPackage && originalPkgSetting != null) { |
| // This is the initial transition from the original package, so, |
| // fix up the new package's name now. We must do this after looking |
| // up the package under its new name, so getPackageLP takes care of |
| // fiddling things correctly. |
| parsedPackage.setPackageName(originalPkgSetting.getPackageName()); |
| |
| // File a report about this. |
| String msg = "New package " + pkgSetting.getRealName() |
| + " renamed to replace old package " + pkgSetting.getPackageName(); |
| PackageManagerService.reportSettingsProblem(Log.WARN, msg); |
| } |
| |
| final int userId = (user == null ? UserHandle.USER_SYSTEM : user.getIdentifier()); |
| // for existing packages, change the install state; but, only if it's explicitly specified |
| if (!createNewPackage) { |
| final boolean instantApp = (scanFlags & SCAN_AS_INSTANT_APP) != 0; |
| final boolean fullApp = (scanFlags & SCAN_AS_FULL_APP) != 0; |
| setInstantAppForUser(injector, pkgSetting, userId, instantApp, fullApp); |
| } |
| // TODO(patb): see if we can do away with disabled check here. |
| if (disabledPkgSetting != null |
| || (0 != (scanFlags & SCAN_NEW_INSTALL) |
| && pkgSetting != null && pkgSetting.isSystem())) { |
| pkgSetting.getPkgState().setUpdatedSystemApp(true); |
| } |
| |
| pkgSetting.getTransientState().setSeInfo(SELinuxMMAC.getSeInfo(pkgSetting, parsedPackage, |
| sharedUserSetting, injector.getCompatibility())); |
| |
| if (pkgSetting.isSystem()) { |
| configurePackageComponents(parsedPackage); |
| } |
| |
| final String cpuAbiOverride = deriveAbiOverride(request.mCpuAbiOverride); |
| final boolean isSystemApp = pkgSetting.isSystem(); |
| final boolean isUpdatedSystemApp = pkgSetting.isUpdatedSystemApp(); |
| |
| final File appLib32InstallDir = getAppLib32InstallDir(); |
| if ((scanFlags & SCAN_NEW_INSTALL) == 0) { |
| if (needToDeriveAbi) { |
| Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "derivePackageAbi"); |
| final Pair<PackageAbiHelper.Abis, PackageAbiHelper.NativeLibraryPaths> derivedAbi = |
| packageAbiHelper.derivePackageAbi(parsedPackage, isSystemApp, |
| isUpdatedSystemApp, cpuAbiOverride, appLib32InstallDir); |
| derivedAbi.first.applyTo(parsedPackage); |
| derivedAbi.second.applyTo(parsedPackage); |
| Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); |
| |
| // Some system apps still use directory structure for native libraries |
| // in which case we might end up not detecting abi solely based on apk |
| // structure. Try to detect abi based on directory structure. |
| |
| String pkgRawPrimaryCpuAbi = AndroidPackageUtils.getRawPrimaryCpuAbi(parsedPackage); |
| if (isSystemApp && !isUpdatedSystemApp && pkgRawPrimaryCpuAbi == null) { |
| final PackageAbiHelper.Abis abis = packageAbiHelper.getBundledAppAbis( |
| parsedPackage); |
| abis.applyTo(parsedPackage); |
| abis.applyTo(pkgSetting); |
| final PackageAbiHelper.NativeLibraryPaths nativeLibraryPaths = |
| packageAbiHelper.deriveNativeLibraryPaths(parsedPackage, isSystemApp, |
| isUpdatedSystemApp, appLib32InstallDir); |
| nativeLibraryPaths.applyTo(parsedPackage); |
| } |
| } else { |
| // This is not a first boot or an upgrade, don't bother deriving the |
| // ABI during the scan. Instead, trust the value that was stored in the |
| // package setting. |
| parsedPackage.setPrimaryCpuAbi(primaryCpuAbiFromSettings) |
| .setSecondaryCpuAbi(secondaryCpuAbiFromSettings); |
| |
| final PackageAbiHelper.NativeLibraryPaths nativeLibraryPaths = |
| packageAbiHelper.deriveNativeLibraryPaths(parsedPackage, isSystemApp, |
| isUpdatedSystemApp, appLib32InstallDir); |
| nativeLibraryPaths.applyTo(parsedPackage); |
| |
| if (DEBUG_ABI_SELECTION) { |
| Slog.i(TAG, "Using ABIS and native lib paths from settings : " |
| + parsedPackage.getPackageName() + " " |
| + AndroidPackageUtils.getRawPrimaryCpuAbi(parsedPackage) |
| + ", " |
| + AndroidPackageUtils.getRawSecondaryCpuAbi(parsedPackage)); |
| } |
| } |
| } else { |
| if ((scanFlags & SCAN_MOVE) != 0) { |
| // We haven't run dex-opt for this move (since we've moved the compiled output too) |
| // but we already have this packages package info in the PackageSetting. We just |
| // use that and derive the native library path based on the new code path. |
| parsedPackage.setPrimaryCpuAbi(pkgSetting.getPrimaryCpuAbiLegacy()) |
| .setSecondaryCpuAbi(pkgSetting.getSecondaryCpuAbiLegacy()); |
| } |
| |
| // Set native library paths again. For moves, the path will be updated based on the |
| // ABIs we've determined above. For non-moves, the path will be updated based on the |
| // ABIs we determined during compilation, but the path will depend on the final |
| // package path (after the rename away from the stage path). |
| final PackageAbiHelper.NativeLibraryPaths nativeLibraryPaths = |
| packageAbiHelper.deriveNativeLibraryPaths(parsedPackage, isSystemApp, |
| isUpdatedSystemApp, appLib32InstallDir); |
| nativeLibraryPaths.applyTo(parsedPackage); |
| } |
| |
| // This is a special case for the "system" package, where the ABI is |
| // dictated by the zygote configuration (and init.rc). We should keep track |
| // of this ABI so that we can deal with "normal" applications that run under |
| // the same UID correctly. |
| if (isPlatformPackage) { |
| parsedPackage.setPrimaryCpuAbi(VMRuntime.getRuntime().is64Bit() |
| ? Build.SUPPORTED_64_BIT_ABIS[0] : Build.SUPPORTED_32_BIT_ABIS[0]); |
| } |
| |
| // If there's a mismatch between the abi-override in the package setting |
| // and the abiOverride specified for the install. Warn about this because we |
| // would've already compiled the app without taking the package setting into |
| // account. |
| if ((scanFlags & SCAN_NO_DEX) == 0 && (scanFlags & SCAN_NEW_INSTALL) != 0) { |
| if (cpuAbiOverride == null) { |
| Slog.w(TAG, "Ignoring persisted ABI override for package " |
| + parsedPackage.getPackageName()); |
| } |
| } |
| |
| pkgSetting.setPrimaryCpuAbi(AndroidPackageUtils.getRawPrimaryCpuAbi(parsedPackage)) |
| .setSecondaryCpuAbi(AndroidPackageUtils.getRawSecondaryCpuAbi(parsedPackage)) |
| .setCpuAbiOverride(cpuAbiOverride); |
| |
| if (DEBUG_ABI_SELECTION) { |
| Slog.d(TAG, "Resolved nativeLibraryRoot for " + parsedPackage.getPackageName() |
| + " to root=" + parsedPackage.getNativeLibraryRootDir() |
| + ", to dir=" + parsedPackage.getNativeLibraryDir() |
| + ", isa=" + parsedPackage.isNativeLibraryRootRequiresIsa()); |
| } |
| |
| // Push the derived path down into PackageSettings so we know what to |
| // clean up at uninstall time. |
| pkgSetting.setLegacyNativeLibraryPath(parsedPackage.getNativeLibraryRootDir()); |
| |
| if (DEBUG_ABI_SELECTION) { |
| Log.d(TAG, "Abis for package[" + parsedPackage.getPackageName() + "] are" |
| + " primary=" + pkgSetting.getPrimaryCpuAbiLegacy() |
| + " secondary=" + pkgSetting.getSecondaryCpuAbiLegacy() |
| + " abiOverride=" + pkgSetting.getCpuAbiOverride()); |
| } |
| |
| if ((scanFlags & SCAN_BOOTING) == 0 && oldSharedUserSetting != null) { |
| // We don't do this here during boot because we can do it all |
| // at once after scanning all existing packages. |
| // |
| // We also do this *before* we perform dexopt on this package, so that |
| // we can avoid redundant dexopts, and also to make sure we've got the |
| // code and package path correct. |
| changedAbiCodePath = applyAdjustedAbiToSharedUser(oldSharedUserSetting, |
| parsedPackage, packageAbiHelper.getAdjustedAbiForSharedUser( |
| oldSharedUserSetting.getPackageStates(), parsedPackage)); |
| } |
| |
| parsedPackage.setFactoryTest(isUnderFactoryTest && parsedPackage.getRequestedPermissions() |
| .contains(android.Manifest.permission.FACTORY_TEST)); |
| |
| if (isSystemApp) { |
| pkgSetting.setIsOrphaned(true); |
| } |
| |
| // Take care of first install / last update times. |
| final long scanFileTime = getLastModifiedTime(parsedPackage); |
| final long existingFirstInstallTime = userId == UserHandle.USER_ALL |
| ? PackageStateUtils.getEarliestFirstInstallTime(pkgSetting.getUserStates()) |
| : pkgSetting.readUserState(userId).getFirstInstallTimeMillis(); |
| if (currentTime != 0) { |
| if (existingFirstInstallTime == 0) { |
| pkgSetting.setFirstInstallTime(currentTime, userId) |
| .setLastUpdateTime(currentTime); |
| } else if ((scanFlags & SCAN_UPDATE_TIME) != 0) { |
| pkgSetting.setLastUpdateTime(currentTime); |
| } |
| } else if (existingFirstInstallTime == 0) { |
| // We need *something*. Take time stamp of the file. |
| pkgSetting.setFirstInstallTime(scanFileTime, userId) |
| .setLastUpdateTime(scanFileTime); |
| } else if ((parseFlags & ParsingPackageUtils.PARSE_IS_SYSTEM_DIR) != 0) { |
| if (scanFileTime != pkgSetting.getLastModifiedTime()) { |
| // A package on the system image has changed; consider this |
| // to be an update. |
| pkgSetting.setLastUpdateTime(scanFileTime); |
| } |
| } |
| pkgSetting.setLastModifiedTime(scanFileTime); |
| // TODO(b/135203078): Remove, move to constructor |
| pkgSetting.setPkg(parsedPackage) |
| .setFlags(PackageInfoUtils.appInfoFlags(parsedPackage, pkgSetting)) |
| .setPrivateFlags(PackageInfoUtils.appInfoPrivateFlags(parsedPackage, pkgSetting)); |
| if (parsedPackage.getLongVersionCode() != pkgSetting.getVersionCode()) { |
| pkgSetting.setLongVersionCode(parsedPackage.getLongVersionCode()); |
| } |
| // Update volume if needed |
| final String volumeUuid = parsedPackage.getVolumeUuid(); |
| if (!Objects.equals(volumeUuid, pkgSetting.getVolumeUuid())) { |
| Slog.i(PackageManagerService.TAG, |
| "Update" + (pkgSetting.isSystem() ? " system" : "") |
| + " package " + parsedPackage.getPackageName() |
| + " volume from " + pkgSetting.getVolumeUuid() |
| + " to " + volumeUuid); |
| pkgSetting.setVolumeUuid(volumeUuid); |
| } |
| |
| SharedLibraryInfo sdkLibraryInfo = null; |
| if (!TextUtils.isEmpty(parsedPackage.getSdkLibraryName())) { |
| sdkLibraryInfo = AndroidPackageUtils.createSharedLibraryForSdk(parsedPackage); |
| } |
| SharedLibraryInfo staticSharedLibraryInfo = null; |
| if (!TextUtils.isEmpty(parsedPackage.getStaticSharedLibraryName())) { |
| staticSharedLibraryInfo = |
| AndroidPackageUtils.createSharedLibraryForStatic(parsedPackage); |
| } |
| List<SharedLibraryInfo> dynamicSharedLibraryInfos = null; |
| if (!ArrayUtils.isEmpty(parsedPackage.getLibraryNames())) { |
| dynamicSharedLibraryInfos = new ArrayList<>(parsedPackage.getLibraryNames().size()); |
| for (String name : parsedPackage.getLibraryNames()) { |
| dynamicSharedLibraryInfos.add( |
| AndroidPackageUtils.createSharedLibraryForDynamic(parsedPackage, name)); |
| } |
| } |
| |
| return new ScanResult(request, pkgSetting, changedAbiCodePath, |
| !createNewPackage /* existingSettingCopied */, |
| Process.INVALID_UID /* previousAppId */ , sdkLibraryInfo, |
| staticSharedLibraryInfo, dynamicSharedLibraryInfos); |
| } |
| |
| /** |
| * Returns the actual scan flags depending upon the state of the other settings. |
| * <p>Updated system applications will not have the following flags set |
| * by default and need to be adjusted after the fact: |
| * <ul> |
| * <li>{@link PackageManagerService.SCAN_AS_SYSTEM}</li> |
| * <li>{@link PackageManagerService.SCAN_AS_PRIVILEGED}</li> |
| * <li>{@link PackageManagerService.SCAN_AS_OEM}</li> |
| * <li>{@link PackageManagerService.SCAN_AS_VENDOR}</li> |
| * <li>{@link PackageManagerService.SCAN_AS_PRODUCT}</li> |
| * <li>{@link PackageManagerService.SCAN_AS_SYSTEM_EXT}</li> |
| * <li>{@link PackageManagerService.SCAN_AS_INSTANT_APP}</li> |
| * <li>{@link PackageManagerService.SCAN_AS_VIRTUAL_PRELOAD}</li> |
| * <li>{@link PackageManagerService.SCAN_AS_ODM}</li> |
| * </ul> |
| */ |
| public static @PackageManagerService.ScanFlags int adjustScanFlagsWithPackageSetting( |
| @PackageManagerService.ScanFlags int scanFlags, |
| PackageSetting pkgSetting, PackageSetting disabledPkgSetting, UserHandle user) { |
| |
| // TODO(patb): Do away entirely with disabledPkgSetting here. PkgSetting will always contain |
| // the correct isSystem value now that we don't disable system packages before scan. |
| final PackageSetting systemPkgSetting = |
| (scanFlags & SCAN_NEW_INSTALL) != 0 && disabledPkgSetting == null |
| && pkgSetting != null && pkgSetting.isSystem() |
| ? pkgSetting |
| : disabledPkgSetting; |
| if (systemPkgSetting != null) { |
| // updated system application, must at least have SCAN_AS_SYSTEM |
| scanFlags |= SCAN_AS_SYSTEM; |
| if ((systemPkgSetting.getPrivateFlags() |
| & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) { |
| scanFlags |= SCAN_AS_PRIVILEGED; |
| } |
| if ((systemPkgSetting.getPrivateFlags() |
| & ApplicationInfo.PRIVATE_FLAG_OEM) != 0) { |
| scanFlags |= SCAN_AS_OEM; |
| } |
| if ((systemPkgSetting.getPrivateFlags() |
| & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0) { |
| scanFlags |= SCAN_AS_VENDOR; |
| } |
| if ((systemPkgSetting.getPrivateFlags() |
| & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0) { |
| scanFlags |= SCAN_AS_PRODUCT; |
| } |
| if ((systemPkgSetting.getPrivateFlags() |
| & ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT) != 0) { |
| scanFlags |= SCAN_AS_SYSTEM_EXT; |
| } |
| if ((systemPkgSetting.getPrivateFlags() |
| & ApplicationInfo.PRIVATE_FLAG_ODM) != 0) { |
| scanFlags |= SCAN_AS_ODM; |
| } |
| } |
| if (pkgSetting != null) { |
| final int userId = ((user == null) ? 0 : user.getIdentifier()); |
| if (pkgSetting.getInstantApp(userId)) { |
| scanFlags |= SCAN_AS_INSTANT_APP; |
| } |
| if (pkgSetting.getVirtualPreload(userId)) { |
| scanFlags |= SCAN_AS_VIRTUAL_PRELOAD; |
| } |
| } |
| |
| return scanFlags; |
| } |
| |
| /** |
| * Enforces code policy for the package. This ensures that if an APK has |
| * declared hasCode="true" in its manifest that the APK actually contains |
| * code. |
| * |
| * @throws PackageManagerException If bytecode could not be found when it should exist |
| */ |
| public static void assertCodePolicy(AndroidPackage pkg) |
| throws PackageManagerException { |
| final boolean shouldHaveCode = pkg.isDeclaredHavingCode(); |
| if (shouldHaveCode && !apkHasCode(pkg.getBaseApkPath())) { |
| throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, |
| "Package " + pkg.getBaseApkPath() + " code is missing"); |
| } |
| |
| if (!ArrayUtils.isEmpty(pkg.getSplitCodePaths())) { |
| for (int i = 0; i < pkg.getSplitCodePaths().length; i++) { |
| final boolean splitShouldHaveCode = |
| (pkg.getSplitFlags()[i] & ApplicationInfo.FLAG_HAS_CODE) != 0; |
| if (splitShouldHaveCode && !apkHasCode(pkg.getSplitCodePaths()[i])) { |
| throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, |
| "Package " + pkg.getSplitCodePaths()[i] + " code is missing"); |
| } |
| } |
| } |
| } |
| |
| public static void assertStaticSharedLibraryIsValid(AndroidPackage pkg, |
| @PackageManagerService.ScanFlags int scanFlags) throws PackageManagerException { |
| // Static shared libraries should have at least O target SDK |
| if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.O) { |
| throw PackageManagerException.ofInternalError( |
| "Packages declaring static-shared libs must target O SDK or higher", |
| PackageManagerException.INTERNAL_ERROR_STATIC_SHARED_LIB_LOW_SDK); |
| } |
| |
| // Package declaring static a shared lib cannot be instant apps |
| if ((scanFlags & SCAN_AS_INSTANT_APP) != 0) { |
| throw PackageManagerException.ofInternalError( |
| "Packages declaring static-shared libs cannot be instant apps", |
| PackageManagerException.INTERNAL_ERROR_STATIC_SHARED_LIB_INSTANT); |
| } |
| |
| // Package declaring static a shared lib cannot be renamed since the package |
| // name is synthetic and apps can't code around package manager internals. |
| if (!ArrayUtils.isEmpty(pkg.getOriginalPackages())) { |
| throw PackageManagerException.ofInternalError( |
| "Packages declaring static-shared libs cannot be renamed", |
| PackageManagerException.INTERNAL_ERROR_STATIC_SHARED_LIB_RENAMED); |
| } |
| |
| // Package declaring static a shared lib cannot declare dynamic libs |
| if (!ArrayUtils.isEmpty(pkg.getLibraryNames())) { |
| throw PackageManagerException.ofInternalError( |
| "Packages declaring static-shared libs cannot declare dynamic libs", |
| PackageManagerException.INTERNAL_ERROR_STATIC_SHARED_LIB_DYNAMIC); |
| } |
| |
| // Package declaring static a shared lib cannot declare shared users |
| if (pkg.getSharedUserId() != null) { |
| throw PackageManagerException.ofInternalError( |
| "Packages declaring static-shared libs cannot declare shared users", |
| PackageManagerException.INTERNAL_ERROR_STATIC_SHARED_LIB_SHARED_USER); |
| } |
| |
| // Static shared libs cannot declare activities |
| if (!pkg.getActivities().isEmpty()) { |
| throw PackageManagerException.ofInternalError( |
| "Static shared libs cannot declare activities", |
| PackageManagerException.INTERNAL_ERROR_STATIC_SHARED_LIB_ACTIVITY); |
| } |
| |
| // Static shared libs cannot declare services |
| if (!pkg.getServices().isEmpty()) { |
| throw PackageManagerException.ofInternalError( |
| "Static shared libs cannot declare services", |
| PackageManagerException.INTERNAL_ERROR_STATIC_SHARED_LIB_SERVICE); |
| } |
| |
| // Static shared libs cannot declare providers |
| if (!pkg.getProviders().isEmpty()) { |
| throw PackageManagerException.ofInternalError( |
| "Static shared libs cannot declare content providers", |
| PackageManagerException.INTERNAL_ERROR_STATIC_SHARED_LIB_CONTENT_PROVIDER); |
| } |
| |
| // Static shared libs cannot declare receivers |
| if (!pkg.getReceivers().isEmpty()) { |
| throw PackageManagerException.ofInternalError( |
| "Static shared libs cannot declare broadcast receivers", |
| PackageManagerException.INTERNAL_ERROR_STATIC_SHARED_LIB_BROADCAST_RECEIVER); |
| } |
| |
| // Static shared libs cannot declare permission groups |
| if (!pkg.getPermissionGroups().isEmpty()) { |
| throw PackageManagerException.ofInternalError( |
| "Static shared libs cannot declare permission groups", |
| PackageManagerException.INTERNAL_ERROR_STATIC_SHARED_LIB_PERMISSION_GROUP); |
| } |
| |
| // Static shared libs cannot declare attributions |
| if (!pkg.getAttributions().isEmpty()) { |
| throw PackageManagerException.ofInternalError( |
| "Static shared libs cannot declare features", |
| PackageManagerException.INTERNAL_ERROR_STATIC_SHARED_LIB_FEATURE); |
| } |
| |
| // Static shared libs cannot declare permissions |
| if (!pkg.getPermissions().isEmpty()) { |
| throw PackageManagerException.ofInternalError( |
| "Static shared libs cannot declare permissions", |
| PackageManagerException.INTERNAL_ERROR_STATIC_SHARED_LIB_PERMISSION); |
| } |
| |
| // Static shared libs cannot declare protected broadcasts |
| if (!pkg.getProtectedBroadcasts().isEmpty()) { |
| throw PackageManagerException.ofInternalError( |
| "Static shared libs cannot declare protected broadcasts", |
| PackageManagerException.INTERNAL_ERROR_STATIC_SHARED_LIB_PROTECTED_BROADCAST); |
| } |
| |
| // Static shared libs cannot be overlay targets |
| if (pkg.getOverlayTarget() != null) { |
| throw PackageManagerException.ofInternalError( |
| "Static shared libs cannot be overlay targets", |
| PackageManagerException.INTERNAL_ERROR_STATIC_SHARED_LIB_OVERLAY_TARGETS); |
| } |
| } |
| |
| public static void assertProcessesAreValid(AndroidPackage pkg) throws PackageManagerException { |
| final Map<String, ParsedProcess> procs = pkg.getProcesses(); |
| if (!procs.isEmpty()) { |
| if (!procs.containsKey(pkg.getProcessName())) { |
| throw new PackageManagerException( |
| INSTALL_FAILED_PROCESS_NOT_DEFINED, |
| "Can't install because application tag's process attribute " |
| + pkg.getProcessName() |
| + " (in package " + pkg.getPackageName() |
| + ") is not included in the <processes> list"); |
| } |
| assertPackageProcesses(pkg, pkg.getActivities(), procs, "activity"); |
| assertPackageProcesses(pkg, pkg.getServices(), procs, "service"); |
| assertPackageProcesses(pkg, pkg.getReceivers(), procs, "receiver"); |
| assertPackageProcesses(pkg, pkg.getProviders(), procs, "provider"); |
| } |
| } |
| |
| private static <T extends ParsedMainComponent> void assertPackageProcesses(AndroidPackage pkg, |
| List<T> components, Map<String, ParsedProcess> procs, String compName) |
| throws PackageManagerException { |
| if (components == null) { |
| return; |
| } |
| for (int i = components.size() - 1; i >= 0; i--) { |
| final ParsedMainComponent component = components.get(i); |
| if (!procs.containsKey(component.getProcessName())) { |
| throw new PackageManagerException( |
| INSTALL_FAILED_PROCESS_NOT_DEFINED, |
| "Can't install because " + compName + " " + component.getClassName() |
| + "'s process attribute " + component.getProcessName() |
| + " (in package " + pkg.getPackageName() |
| + ") is not included in the <processes> list"); |
| } |
| } |
| } |
| |
| public static void assertMinSignatureSchemeIsValid(AndroidPackage pkg, |
| @ParsingPackageUtils.ParseFlags int parseFlags) throws PackageManagerException { |
| int minSignatureSchemeVersion = |
| ApkSignatureVerifier.getMinimumSignatureSchemeVersionForTargetSdk( |
| pkg.getTargetSdkVersion()); |
| if (pkg.getSigningDetails().getSignatureSchemeVersion() |
| < minSignatureSchemeVersion) { |
| throw new PackageManagerException(INSTALL_PARSE_FAILED_NO_CERTIFICATES, |
| "No signature found in package of version " + minSignatureSchemeVersion |
| + " or newer for package " + pkg.getPackageName()); |
| } |
| } |
| |
| /** |
| * Returns the "real" name of the package. |
| * <p>This may differ from the package's actual name if the application has already |
| * been installed under one of this package's original names. |
| */ |
| public static @Nullable String getRealPackageName(@NonNull AndroidPackage pkg, |
| @Nullable String renamedPkgName, boolean isSystemApp) { |
| if (isPackageRenamed(pkg, renamedPkgName)) { |
| return AndroidPackageUtils.getRealPackageOrNull(pkg, isSystemApp); |
| } |
| return null; |
| } |
| |
| /** Returns {@code true} if the package has been renamed. Otherwise, {@code false}. */ |
| public static boolean isPackageRenamed(@NonNull AndroidPackage pkg, |
| @Nullable String renamedPkgName) { |
| return pkg.getOriginalPackages().contains(renamedPkgName); |
| } |
| |
| /** |
| * Renames the package if it was installed under a different name. |
| * <p>When we've already installed the package under an original name, update |
| * the new package so we can continue to have the old name. |
| */ |
| public static void ensurePackageRenamed(@NonNull ParsedPackage parsedPackage, |
| @NonNull String renamedPackageName) { |
| if (!parsedPackage.getOriginalPackages().contains(renamedPackageName) |
| || parsedPackage.getPackageName().equals(renamedPackageName)) { |
| return; |
| } |
| parsedPackage.setPackageName(renamedPackageName); |
| } |
| |
| /** |
| * Returns {@code true} if the given file contains code. Otherwise {@code false}. |
| */ |
| public static boolean apkHasCode(String fileName) { |
| StrictJarFile jarFile = null; |
| try { |
| jarFile = new StrictJarFile(fileName, |
| false /*verify*/, false /*signatureSchemeRollbackProtectionsEnforced*/); |
| return jarFile.findEntry("classes.dex") != null; |
| } catch (IOException ignore) { |
| } finally { |
| try { |
| if (jarFile != null) { |
| jarFile.close(); |
| } |
| } catch (IOException ignore) { |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Sets the enabled state of components configured through {@link SystemConfig}. |
| * This modifies the {@link PackageSetting} object. |
| * |
| * TODO(b/135203078): Move this to package parsing |
| **/ |
| public static void configurePackageComponents(AndroidPackage pkg) { |
| final ArrayMap<String, Boolean> componentsEnabledStates = SystemConfig.getInstance() |
| .getComponentsEnabledStates(pkg.getPackageName()); |
| if (componentsEnabledStates == null) { |
| return; |
| } |
| |
| for (int i = ArrayUtils.size(pkg.getActivities()) - 1; i >= 0; i--) { |
| final ParsedActivity component = pkg.getActivities().get(i); |
| final Boolean enabled = componentsEnabledStates.get(component.getName()); |
| if (enabled != null) { |
| ComponentMutateUtils.setEnabled(component, enabled); |
| } |
| } |
| |
| for (int i = ArrayUtils.size(pkg.getReceivers()) - 1; i >= 0; i--) { |
| final ParsedActivity component = pkg.getReceivers().get(i); |
| final Boolean enabled = componentsEnabledStates.get(component.getName()); |
| if (enabled != null) { |
| ComponentMutateUtils.setEnabled(component, enabled); |
| } |
| } |
| |
| for (int i = ArrayUtils.size(pkg.getProviders()) - 1; i >= 0; i--) { |
| final ParsedProvider component = pkg.getProviders().get(i); |
| final Boolean enabled = componentsEnabledStates.get(component.getName()); |
| if (enabled != null) { |
| ComponentMutateUtils.setEnabled(component, enabled); |
| } |
| } |
| |
| for (int i = ArrayUtils.size(pkg.getServices()) - 1; i >= 0; i--) { |
| final ParsedService component = pkg.getServices().get(i); |
| final Boolean enabled = componentsEnabledStates.get(component.getName()); |
| if (enabled != null) { |
| ComponentMutateUtils.setEnabled(component, enabled); |
| } |
| } |
| } |
| |
| public static int getVendorPartitionVersion() { |
| final String version = SystemProperties.get("ro.vndk.version"); |
| if (!version.isEmpty()) { |
| try { |
| return Integer.parseInt(version); |
| } catch (NumberFormatException ignore) { |
| if (ArrayUtils.contains(Build.VERSION.ACTIVE_CODENAMES, version)) { |
| return Build.VERSION_CODES.CUR_DEVELOPMENT; |
| } |
| } |
| } |
| return Build.VERSION_CODES.P; |
| } |
| |
| /** |
| * Applies policy to the parsed package based upon the given policy flags. |
| * Ensures the package is in a good state. |
| * <p> |
| * Implementation detail: This method must NOT have any side effect. It would |
| * ideally be static, but, it requires locks to read system state. |
| */ |
| public static void applyPolicy(ParsedPackage parsedPackage, |
| final @PackageManagerService.ScanFlags int scanFlags, |
| @Nullable AndroidPackage platformPkg, boolean isUpdatedSystemApp) { |
| // TODO: In the real APIs, an updated system app is always a system app, but that may not |
| // hold true during scan because PMS doesn't propagate the SCAN_AS_SYSTEM flag for the data |
| // directory. This tries to emulate that behavior by using either the flag or the boolean, |
| // but this logic is fragile. Specifically, it may affect the PackageBackwardCompatibility |
| // checker, which switches branches based on whether an app is a system app. When install |
| // is refactored, the scan policy flags should not be read this late and instead passed |
| // around in the PackageSetting or a temporary object which infers these values early, so |
| // that all further consumers agree on their values. |
| boolean isSystemApp = isUpdatedSystemApp; |
| if ((scanFlags & SCAN_AS_SYSTEM) != 0) { |
| isSystemApp = true; |
| parsedPackage.setSystem(true); |
| // TODO(b/135203078): Can this be done in PackageParser? Or just inferred when the flag |
| // is set during parse. |
| if (parsedPackage.isDirectBootAware()) { |
| parsedPackage.setAllComponentsDirectBootAware(true); |
| } |
| if (compressedFileExists(parsedPackage.getPath())) { |
| parsedPackage.setStub(true); |
| } |
| } else { |
| parsedPackage |
| // Non system apps cannot mark any broadcast as protected |
| .clearProtectedBroadcasts() |
| // non system apps can't be flagged as core |
| .setCoreApp(false) |
| // clear flags not applicable to regular apps |
| .setPersistent(false) |
| .setDefaultToDeviceProtectedStorage(false) |
| .setDirectBootAware(false) |
| // non system apps can't have permission priority |
| .capPermissionPriorities(); |
| } |
| if ((scanFlags & SCAN_AS_PRIVILEGED) == 0) { |
| parsedPackage |
| .markNotActivitiesAsNotExportedIfSingleUser(); |
| } |
| |
| parsedPackage.setApex((scanFlags & SCAN_AS_APEX) != 0); |
| |
| parsedPackage.setPrivileged((scanFlags & SCAN_AS_PRIVILEGED) != 0) |
| .setOem((scanFlags & SCAN_AS_OEM) != 0) |
| .setVendor((scanFlags & SCAN_AS_VENDOR) != 0) |
| .setProduct((scanFlags & SCAN_AS_PRODUCT) != 0) |
| .setSystemExt((scanFlags & SCAN_AS_SYSTEM_EXT) != 0) |
| .setOdm((scanFlags & SCAN_AS_ODM) != 0); |
| |
| // Check if the package is signed with the same key as the platform package. |
| parsedPackage.setSignedWithPlatformKey( |
| (PLATFORM_PACKAGE_NAME.equals(parsedPackage.getPackageName()) |
| || (platformPkg != null && compareSignatures( |
| platformPkg.getSigningDetails().getSignatures(), |
| parsedPackage.getSigningDetails().getSignatures() |
| ) == PackageManager.SIGNATURE_MATCH)) |
| ); |
| |
| if (!isSystemApp) { |
| // Only system apps can use these features. |
| parsedPackage.clearOriginalPackages() |
| .clearAdoptPermissions(); |
| } |
| |
| PackageBackwardCompatibility.modifySharedLibraries(parsedPackage, isSystemApp, |
| isUpdatedSystemApp); |
| } |
| |
| /** |
| * Applies the adjusted ABI calculated by |
| * {@link PackageAbiHelper#getAdjustedAbiForSharedUser(ArraySet, AndroidPackage)} to all |
| * relevant packages and settings. |
| * @param sharedUserSetting The {@code SharedUserSetting} to adjust |
| * @param scannedPackage the package being scanned or null |
| * @param adjustedAbi the adjusted ABI calculated by {@link PackageAbiHelper} |
| * @return the list of code paths that belong to packages that had their ABIs adjusted. |
| */ |
| public static List<String> applyAdjustedAbiToSharedUser(SharedUserSetting sharedUserSetting, |
| ParsedPackage scannedPackage, String adjustedAbi) { |
| if (scannedPackage != null) { |
| scannedPackage.setPrimaryCpuAbi(adjustedAbi); |
| } |
| List<String> changedAbiCodePath = null; |
| final WatchedArraySet<PackageSetting> sharedUserPackageSettings = |
| sharedUserSetting.getPackageSettings(); |
| for (int i = 0; i < sharedUserPackageSettings.size(); i++) { |
| PackageSetting ps = sharedUserPackageSettings.valueAt(i); |
| if (scannedPackage == null |
| || !scannedPackage.getPackageName().equals(ps.getPackageName())) { |
| if (ps.getPrimaryCpuAbiLegacy() != null) { |
| continue; |
| } |
| |
| ps.setPrimaryCpuAbi(adjustedAbi); |
| ps.onChanged(); |
| if (ps.getPkg() != null) { |
| if (!TextUtils.equals(adjustedAbi, |
| AndroidPackageUtils.getRawPrimaryCpuAbi(ps.getPkg()))) { |
| if (DEBUG_ABI_SELECTION) { |
| Slog.i(TAG, |
| "Adjusting ABI for " + ps.getPackageName() + " to " |
| + adjustedAbi + " (scannedPackage=" |
| + (scannedPackage != null ? scannedPackage : "null") |
| + ")"); |
| } |
| if (changedAbiCodePath == null) { |
| changedAbiCodePath = new ArrayList<>(); |
| } |
| changedAbiCodePath.add(ps.getPathString()); |
| } |
| } |
| } |
| } |
| return changedAbiCodePath; |
| } |
| |
| public static void collectCertificatesLI(PackageSetting ps, ParsedPackage parsedPackage, |
| Settings.VersionInfo settingsVersionForPackage, boolean forceCollect, |
| boolean skipVerify, boolean isPreNMR1Upgrade) |
| throws PackageManagerException { |
| // When upgrading from pre-N MR1, verify the package time stamp using the package |
| // directory and not the APK file. |
| final long lastModifiedTime = isPreNMR1Upgrade |
| ? new File(parsedPackage.getPath()).lastModified() |
| : getLastModifiedTime(parsedPackage); |
| if (ps != null && !forceCollect |
| && ps.getPathString().equals(parsedPackage.getPath()) |
| && ps.getLastModifiedTime() == lastModifiedTime |
| && !ReconcilePackageUtils.isCompatSignatureUpdateNeeded(settingsVersionForPackage) |
| && !ReconcilePackageUtils.isRecoverSignatureUpdateNeeded( |
| settingsVersionForPackage)) { |
| if (ps.getSigningDetails().getSignatures() != null |
| && ps.getSigningDetails().getSignatures().length != 0 |
| && ps.getSigningDetails().getSignatureSchemeVersion() |
| != SigningDetails.SignatureSchemeVersion.UNKNOWN) { |
| // Optimization: reuse the existing cached signing data |
| // if the package appears to be unchanged. |
| parsedPackage.setSigningDetails( |
| new SigningDetails(ps.getSigningDetails())); |
| return; |
| } |
| |
| Slog.w(TAG, "PackageSetting for " + ps.getPackageName() |
| + " is missing signatures. Collecting certs again to recover them."); |
| } else { |
| Slog.i(TAG, parsedPackage.getPath() + " changed; collecting certs" |
| + (forceCollect ? " (forced)" : "")); |
| } |
| |
| try { |
| Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates"); |
| final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing(); |
| final ParseResult<SigningDetails> result = ParsingPackageUtils.getSigningDetails( |
| input, parsedPackage, skipVerify); |
| if (result.isError()) { |
| throw new PackageManagerException( |
| result.getErrorCode(), result.getErrorMessage(), result.getException()); |
| } |
| parsedPackage.setSigningDetails(result.getResult()); |
| } finally { |
| Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); |
| } |
| } |
| |
| public static void setInstantAppForUser(PackageManagerServiceInjector injector, |
| PackageSetting pkgSetting, int userId, boolean instantApp, boolean fullApp) { |
| // no state specified; do nothing |
| if (!instantApp && !fullApp) { |
| return; |
| } |
| if (userId != UserHandle.USER_ALL) { |
| if (instantApp && !pkgSetting.getInstantApp(userId)) { |
| pkgSetting.setInstantApp(true /*instantApp*/, userId); |
| } else if (fullApp && pkgSetting.getInstantApp(userId)) { |
| pkgSetting.setInstantApp(false /*instantApp*/, userId); |
| } |
| } else { |
| for (int currentUserId : injector.getUserManagerInternal().getUserIds()) { |
| if (instantApp && !pkgSetting.getInstantApp(currentUserId)) { |
| pkgSetting.setInstantApp(true /*instantApp*/, currentUserId); |
| } else if (fullApp && pkgSetting.getInstantApp(currentUserId)) { |
| pkgSetting.setInstantApp(false /*instantApp*/, currentUserId); |
| } |
| } |
| } |
| } |
| |
| /** Directory where installed application's 32-bit native libraries are copied. */ |
| public static File getAppLib32InstallDir() { |
| return new File(Environment.getDataDirectory(), "app-lib"); |
| } |
| } |