• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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