1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.pm; 18 19 import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; 20 21 import static com.android.internal.util.FrameworkStatsLog.BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_DATA_APP_AVG_SCAN_TIME; 22 import static com.android.internal.util.FrameworkStatsLog.BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_SYSTEM_APP_AVG_SCAN_TIME; 23 import static com.android.server.pm.PackageManagerService.SCAN_AS_APK_IN_APEX; 24 import static com.android.server.pm.PackageManagerService.SCAN_AS_PRIVILEGED; 25 import static com.android.server.pm.PackageManagerService.SCAN_AS_SYSTEM; 26 import static com.android.server.pm.PackageManagerService.SCAN_BOOTING; 27 import static com.android.server.pm.PackageManagerService.SCAN_DROP_CACHE; 28 import static com.android.server.pm.PackageManagerService.SCAN_FIRST_BOOT_OR_UPGRADE; 29 import static com.android.server.pm.PackageManagerService.SCAN_INITIAL; 30 import static com.android.server.pm.PackageManagerService.SCAN_NO_DEX; 31 import static com.android.server.pm.PackageManagerService.SCAN_REQUIRE_KNOWN; 32 import static com.android.server.pm.PackageManagerService.SYSTEM_PARTITIONS; 33 import static com.android.server.pm.PackageManagerService.TAG; 34 import static com.android.server.pm.pkg.parsing.ParsingPackageUtils.PARSE_APK_IN_APEX; 35 36 import android.annotation.NonNull; 37 import android.annotation.Nullable; 38 import android.content.pm.parsing.ApkLiteParseUtils; 39 import android.os.Environment; 40 import android.os.SystemClock; 41 import android.os.Trace; 42 import android.util.ArrayMap; 43 import android.util.EventLog; 44 import android.util.Slog; 45 46 import com.android.internal.annotations.GuardedBy; 47 import com.android.internal.content.om.OverlayConfig; 48 import com.android.internal.util.FrameworkStatsLog; 49 import com.android.server.EventLogTags; 50 import com.android.server.pm.parsing.PackageCacher; 51 import com.android.server.pm.parsing.PackageParser2; 52 import com.android.server.pm.parsing.pkg.AndroidPackage; 53 import com.android.server.pm.pkg.parsing.ParsingPackageUtils; 54 import com.android.server.utils.WatchedArrayMap; 55 56 import java.io.File; 57 import java.util.ArrayList; 58 import java.util.List; 59 import java.util.concurrent.ExecutorService; 60 61 /** 62 * Part of PackageManagerService that handles init and system packages. This class still needs 63 * further cleanup and eventually all the installation/scanning related logic will go to another 64 * class. 65 */ 66 final class InitAppsHelper { 67 private final PackageManagerService mPm; 68 private final List<ScanPartition> mDirsToScanAsSystem; 69 private final int mScanFlags; 70 private final int mSystemParseFlags; 71 private final int mSystemScanFlags; 72 private final InstallPackageHelper mInstallPackageHelper; 73 private final ApexManager mApexManager; 74 private final ExecutorService mExecutorService; 75 /* Tracks how long system scan took */ 76 private long mSystemScanTime; 77 /* Track of the number of cached system apps */ 78 private int mCachedSystemApps; 79 /* Track of the number of system apps */ 80 private int mSystemPackagesCount; 81 private final boolean mIsDeviceUpgrading; 82 private final boolean mIsOnlyCoreApps; 83 private final List<ScanPartition> mSystemPartitions; 84 85 /** 86 * Tracks new system packages [received in an OTA] that we expect to 87 * find updated user-installed versions. Keys are package name, values 88 * are package location. 89 */ 90 private final ArrayMap<String, File> mExpectingBetter = new ArrayMap<>(); 91 /* Tracks of any system packages that no longer exist that needs to be pruned. */ 92 private final List<String> mPossiblyDeletedUpdatedSystemApps = new ArrayList<>(); 93 // Tracks of stub packages that must either be replaced with full versions in the /data 94 // partition or be disabled. 95 private final List<String> mStubSystemApps = new ArrayList<>(); 96 97 // TODO(b/198166813): remove PMS dependency InitAppsHelper(PackageManagerService pm, ApexManager apexManager, InstallPackageHelper installPackageHelper, List<ScanPartition> systemPartitions)98 InitAppsHelper(PackageManagerService pm, ApexManager apexManager, 99 InstallPackageHelper installPackageHelper, 100 List<ScanPartition> systemPartitions) { 101 mPm = pm; 102 mApexManager = apexManager; 103 mInstallPackageHelper = installPackageHelper; 104 mSystemPartitions = systemPartitions; 105 mDirsToScanAsSystem = getSystemScanPartitions(); 106 mIsDeviceUpgrading = mPm.isDeviceUpgrading(); 107 mIsOnlyCoreApps = mPm.isOnlyCoreApps(); 108 // Set flag to monitor and not change apk file paths when scanning install directories. 109 int scanFlags = SCAN_BOOTING | SCAN_INITIAL; 110 if (mIsDeviceUpgrading || mPm.isFirstBoot()) { 111 mScanFlags = scanFlags | SCAN_FIRST_BOOT_OR_UPGRADE; 112 } else { 113 mScanFlags = scanFlags; 114 } 115 mSystemParseFlags = mPm.getDefParseFlags() | ParsingPackageUtils.PARSE_IS_SYSTEM_DIR; 116 mSystemScanFlags = mScanFlags | SCAN_AS_SYSTEM; 117 mExecutorService = ParallelPackageParser.makeExecutorService(); 118 } 119 getFrameworkResApkSplitFiles()120 private List<File> getFrameworkResApkSplitFiles() { 121 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanFrameworkResApkSplits"); 122 try { 123 final List<File> splits = new ArrayList<>(); 124 final List<ApexManager.ActiveApexInfo> activeApexInfos = 125 mPm.mApexManager.getActiveApexInfos(); 126 for (int i = 0; i < activeApexInfos.size(); i++) { 127 ApexManager.ActiveApexInfo apexInfo = activeApexInfos.get(i); 128 File splitsFolder = new File(apexInfo.apexDirectory, "etc/splits"); 129 if (splitsFolder.isDirectory()) { 130 for (File file : splitsFolder.listFiles()) { 131 if (ApkLiteParseUtils.isApkFile(file)) { 132 splits.add(file); 133 } 134 } 135 } 136 } 137 return splits; 138 } finally { 139 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); 140 } 141 } 142 getSystemScanPartitions()143 private List<ScanPartition> getSystemScanPartitions() { 144 final List<ScanPartition> scanPartitions = new ArrayList<>(); 145 scanPartitions.addAll(mSystemPartitions); 146 scanPartitions.addAll(getApexScanPartitions()); 147 Slog.d(TAG, "Directories scanned as system partitions: " + scanPartitions); 148 return scanPartitions; 149 } 150 getApexScanPartitions()151 private List<ScanPartition> getApexScanPartitions() { 152 final List<ScanPartition> scanPartitions = new ArrayList<>(); 153 final List<ApexManager.ActiveApexInfo> activeApexInfos = mApexManager.getActiveApexInfos(); 154 for (int i = 0; i < activeApexInfos.size(); i++) { 155 final ScanPartition scanPartition = resolveApexToScanPartition(activeApexInfos.get(i)); 156 if (scanPartition != null) { 157 scanPartitions.add(scanPartition); 158 } 159 } 160 return scanPartitions; 161 } 162 resolveApexToScanPartition( ApexManager.ActiveApexInfo apexInfo)163 private static @Nullable ScanPartition resolveApexToScanPartition( 164 ApexManager.ActiveApexInfo apexInfo) { 165 for (int i = 0, size = SYSTEM_PARTITIONS.size(); i < size; i++) { 166 ScanPartition sp = SYSTEM_PARTITIONS.get(i); 167 if (apexInfo.preInstalledApexPath.getAbsolutePath().equals( 168 sp.getFolder().getAbsolutePath()) 169 || apexInfo.preInstalledApexPath.getAbsolutePath().startsWith( 170 sp.getFolder().getAbsolutePath() + File.separator)) { 171 int flags = SCAN_AS_APK_IN_APEX; 172 if (apexInfo.activeApexChanged) { 173 flags |= SCAN_DROP_CACHE; 174 } 175 return new ScanPartition(apexInfo.apexDirectory, sp, flags); 176 } 177 } 178 return null; 179 } 180 181 /** 182 * Install apps from system dirs. 183 */ 184 @GuardedBy({"mPm.mInstallLock", "mPm.mLock"}) initSystemApps(PackageParser2 packageParser, WatchedArrayMap<String, PackageSetting> packageSettings, int[] userIds, long startTime)185 public OverlayConfig initSystemApps(PackageParser2 packageParser, 186 WatchedArrayMap<String, PackageSetting> packageSettings, 187 int[] userIds, long startTime) { 188 // Prepare apex package info before scanning APKs, this information is needed when 189 // scanning apk in apex. 190 mApexManager.scanApexPackagesTraced(packageParser, mExecutorService); 191 192 scanSystemDirs(packageParser, mExecutorService); 193 // Parse overlay configuration files to set default enable state, mutability, and 194 // priority of system overlays. 195 final ArrayMap<String, File> apkInApexPreInstalledPaths = new ArrayMap<>(); 196 for (ApexManager.ActiveApexInfo apexInfo : mApexManager.getActiveApexInfos()) { 197 for (String packageName : mApexManager.getApksInApex(apexInfo.apexModuleName)) { 198 apkInApexPreInstalledPaths.put(packageName, apexInfo.preInstalledApexPath); 199 } 200 } 201 final OverlayConfig overlayConfig = OverlayConfig.initializeSystemInstance( 202 consumer -> mPm.forEachPackage(mPm.snapshotComputer(), 203 pkg -> consumer.accept(pkg, pkg.isSystem(), 204 apkInApexPreInstalledPaths.get(pkg.getPackageName())))); 205 206 if (!mIsOnlyCoreApps) { 207 // do this first before mucking with mPackages for the "expecting better" case 208 updateStubSystemAppsList(mStubSystemApps); 209 mInstallPackageHelper.prepareSystemPackageCleanUp(packageSettings, 210 mPossiblyDeletedUpdatedSystemApps, mExpectingBetter, userIds); 211 } 212 213 logSystemAppsScanningTime(startTime); 214 return overlayConfig; 215 } 216 217 @GuardedBy({"mPm.mInstallLock", "mPm.mLock"}) logSystemAppsScanningTime(long startTime)218 private void logSystemAppsScanningTime(long startTime) { 219 mCachedSystemApps = PackageCacher.sCachedPackageReadCount.get(); 220 221 // Remove any shared userIDs that have no associated packages 222 mPm.mSettings.pruneSharedUsersLPw(); 223 mSystemScanTime = SystemClock.uptimeMillis() - startTime; 224 mSystemPackagesCount = mPm.mPackages.size(); 225 Slog.i(TAG, "Finished scanning system apps. Time: " + mSystemScanTime 226 + " ms, packageCount: " + mSystemPackagesCount 227 + " , timePerPackage: " 228 + (mSystemPackagesCount == 0 ? 0 : mSystemScanTime / mSystemPackagesCount) 229 + " , cached: " + mCachedSystemApps); 230 if (mIsDeviceUpgrading && mSystemPackagesCount > 0) { 231 //CHECKSTYLE:OFF IndentationCheck 232 FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED, 233 BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_SYSTEM_APP_AVG_SCAN_TIME, 234 mSystemScanTime / mSystemPackagesCount); 235 //CHECKSTYLE:ON IndentationCheck 236 } 237 } 238 239 /** 240 * Install apps/updates from data dir and fix system apps that are affected. 241 */ 242 @GuardedBy({"mPm.mInstallLock", "mPm.mLock"}) initNonSystemApps(PackageParser2 packageParser, @NonNull int[] userIds, long startTime)243 public void initNonSystemApps(PackageParser2 packageParser, @NonNull int[] userIds, 244 long startTime) { 245 if (!mIsOnlyCoreApps) { 246 EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START, 247 SystemClock.uptimeMillis()); 248 scanDirTracedLI(mPm.getAppInstallDir(), /* frameworkSplits= */ null, 0, 249 mScanFlags | SCAN_REQUIRE_KNOWN, 250 packageParser, mExecutorService); 251 } 252 253 List<Runnable> unfinishedTasks = mExecutorService.shutdownNow(); 254 if (!unfinishedTasks.isEmpty()) { 255 throw new IllegalStateException("Not all tasks finished before calling close: " 256 + unfinishedTasks); 257 } 258 if (!mIsOnlyCoreApps) { 259 fixSystemPackages(userIds); 260 logNonSystemAppScanningTime(startTime); 261 } 262 mExpectingBetter.clear(); 263 mPm.mSettings.pruneRenamedPackagesLPw(); 264 } 265 266 /** 267 * Clean up system packages now that some system package updates have been installed from 268 * the data dir. Also install system stub packages as the last step. 269 */ 270 @GuardedBy({"mPm.mInstallLock", "mPm.mLock"}) fixSystemPackages(@onNull int[] userIds)271 private void fixSystemPackages(@NonNull int[] userIds) { 272 mInstallPackageHelper.cleanupDisabledPackageSettings(mPossiblyDeletedUpdatedSystemApps, 273 userIds, mScanFlags); 274 mInstallPackageHelper.checkExistingBetterPackages(mExpectingBetter, 275 mStubSystemApps, mSystemScanFlags, mSystemParseFlags); 276 277 // Uncompress and install any stubbed system applications. 278 // This must be done last to ensure all stubs are replaced or disabled. 279 mInstallPackageHelper.installSystemStubPackages(mStubSystemApps, mScanFlags); 280 } 281 282 @GuardedBy({"mPm.mInstallLock", "mPm.mLock"}) logNonSystemAppScanningTime(long startTime)283 private void logNonSystemAppScanningTime(long startTime) { 284 final int cachedNonSystemApps = PackageCacher.sCachedPackageReadCount.get() 285 - mCachedSystemApps; 286 287 final long dataScanTime = SystemClock.uptimeMillis() - mSystemScanTime - startTime; 288 final int dataPackagesCount = mPm.mPackages.size() - mSystemPackagesCount; 289 Slog.i(TAG, "Finished scanning non-system apps. Time: " + dataScanTime 290 + " ms, packageCount: " + dataPackagesCount 291 + " , timePerPackage: " 292 + (dataPackagesCount == 0 ? 0 : dataScanTime / dataPackagesCount) 293 + " , cached: " + cachedNonSystemApps); 294 if (mIsDeviceUpgrading && dataPackagesCount > 0) { 295 //CHECKSTYLE:OFF IndentationCheck 296 FrameworkStatsLog.write( 297 FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED, 298 BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_DATA_APP_AVG_SCAN_TIME, 299 dataScanTime / dataPackagesCount); 300 //CHECKSTYLE:OFF IndentationCheck 301 } 302 } 303 304 /** 305 * First part of init dir scanning 306 */ 307 @GuardedBy({"mPm.mInstallLock", "mPm.mLock"}) scanSystemDirs(PackageParser2 packageParser, ExecutorService executorService)308 private void scanSystemDirs(PackageParser2 packageParser, ExecutorService executorService) { 309 File frameworkDir = new File(Environment.getRootDirectory(), "framework"); 310 311 // Collect vendor/product/system_ext overlay packages. (Do this before scanning 312 // any apps.) 313 // For security and version matching reason, only consider overlay packages if they 314 // reside in the right directory. 315 for (int i = mDirsToScanAsSystem.size() - 1; i >= 0; i--) { 316 final ScanPartition partition = mDirsToScanAsSystem.get(i); 317 if (partition.getOverlayFolder() == null) { 318 continue; 319 } 320 scanDirTracedLI(partition.getOverlayFolder(), /* frameworkSplits= */ null, 321 mSystemParseFlags, mSystemScanFlags | partition.scanFlag, 322 packageParser, executorService); 323 } 324 325 scanDirTracedLI(frameworkDir, null, 326 mSystemParseFlags, 327 mSystemScanFlags | SCAN_NO_DEX | SCAN_AS_PRIVILEGED, 328 packageParser, executorService); 329 if (!mPm.mPackages.containsKey("android")) { 330 throw new IllegalStateException( 331 "Failed to load frameworks package; check log for warnings"); 332 } 333 334 for (int i = 0, size = mDirsToScanAsSystem.size(); i < size; i++) { 335 final ScanPartition partition = mDirsToScanAsSystem.get(i); 336 if (partition.getPrivAppFolder() != null) { 337 scanDirTracedLI(partition.getPrivAppFolder(), /* frameworkSplits= */ null, 338 mSystemParseFlags, 339 mSystemScanFlags | SCAN_AS_PRIVILEGED | partition.scanFlag, 340 packageParser, executorService); 341 } 342 scanDirTracedLI(partition.getAppFolder(), /* frameworkSplits= */ null, 343 mSystemParseFlags, mSystemScanFlags | partition.scanFlag, 344 packageParser, executorService); 345 } 346 } 347 348 @GuardedBy("mPm.mLock") updateStubSystemAppsList(List<String> stubSystemApps)349 private void updateStubSystemAppsList(List<String> stubSystemApps) { 350 final int numPackages = mPm.mPackages.size(); 351 for (int index = 0; index < numPackages; index++) { 352 final AndroidPackage pkg = mPm.mPackages.valueAt(index); 353 if (pkg.isStub()) { 354 stubSystemApps.add(pkg.getPackageName()); 355 } 356 } 357 } 358 359 @GuardedBy({"mPm.mInstallLock", "mPm.mLock"}) scanDirTracedLI(File scanDir, List<File> frameworkSplits, int parseFlags, int scanFlags, PackageParser2 packageParser, ExecutorService executorService)360 private void scanDirTracedLI(File scanDir, List<File> frameworkSplits, 361 int parseFlags, int scanFlags, 362 PackageParser2 packageParser, ExecutorService executorService) { 363 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir [" + scanDir.getAbsolutePath() + "]"); 364 try { 365 if ((scanFlags & SCAN_AS_APK_IN_APEX) != 0) { 366 // when scanning apk in apexes, we want to check the maxSdkVersion 367 parseFlags |= PARSE_APK_IN_APEX; 368 } 369 mInstallPackageHelper.installPackagesFromDir(scanDir, frameworkSplits, parseFlags, 370 scanFlags, packageParser, executorService); 371 } finally { 372 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); 373 } 374 } 375 isExpectingBetter(String packageName)376 public boolean isExpectingBetter(String packageName) { 377 return mExpectingBetter.containsKey(packageName); 378 } 379 getDirsToScanAsSystem()380 public List<ScanPartition> getDirsToScanAsSystem() { 381 return mDirsToScanAsSystem; 382 } 383 } 384