• 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.content.pm.PackageManager.UNINSTALL_REASON_UNKNOWN;
20 import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
21 import static android.os.incremental.IncrementalManager.isIncrementalPath;
22 import static android.os.storage.StorageManager.FLAG_STORAGE_CE;
23 import static android.os.storage.StorageManager.FLAG_STORAGE_DE;
24 import static android.os.storage.StorageManager.FLAG_STORAGE_EXTERNAL;
25 
26 import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL;
27 import static com.android.server.pm.PackageManagerService.DEBUG_REMOVE;
28 import static com.android.server.pm.PackageManagerService.RANDOM_DIR_PREFIX;
29 import static com.android.server.pm.PackageManagerService.TAG;
30 
31 import android.annotation.NonNull;
32 import android.content.pm.PackageManager;
33 import android.os.Trace;
34 import android.os.UserHandle;
35 import android.os.incremental.IncrementalManager;
36 import android.util.Log;
37 import android.util.Slog;
38 import android.util.SparseBooleanArray;
39 
40 import com.android.internal.annotations.GuardedBy;
41 import com.android.internal.util.ArrayUtils;
42 import com.android.server.pm.parsing.PackageCacher;
43 import com.android.server.pm.parsing.pkg.AndroidPackage;
44 import com.android.server.pm.parsing.pkg.PackageImpl;
45 import com.android.server.pm.permission.PermissionManagerServiceInternal;
46 import com.android.server.pm.pkg.PackageStateInternal;
47 import com.android.server.pm.pkg.component.ParsedInstrumentation;
48 
49 import java.io.File;
50 import java.util.Collections;
51 import java.util.List;
52 
53 /**
54  * Removes a package from internal data structures, deletes it data directories if requested,
55  * and clears its app profiles
56  */
57 final class RemovePackageHelper {
58     private final PackageManagerService mPm;
59     private final IncrementalManager mIncrementalManager;
60     private final Installer mInstaller;
61     private final UserManagerInternal mUserManagerInternal;
62     private final PermissionManagerServiceInternal mPermissionManager;
63     private final SharedLibrariesImpl mSharedLibraries;
64     private final AppDataHelper mAppDataHelper;
65 
66     // TODO(b/198166813): remove PMS dependency
RemovePackageHelper(PackageManagerService pm, AppDataHelper appDataHelper)67     RemovePackageHelper(PackageManagerService pm, AppDataHelper appDataHelper) {
68         mPm = pm;
69         mIncrementalManager = mPm.mInjector.getIncrementalManager();
70         mInstaller = mPm.mInjector.getInstaller();
71         mUserManagerInternal = mPm.mInjector.getUserManagerInternal();
72         mPermissionManager = mPm.mInjector.getPermissionManagerServiceInternal();
73         mSharedLibraries = mPm.mInjector.getSharedLibrariesImpl();
74         mAppDataHelper = appDataHelper;
75     }
76 
RemovePackageHelper(PackageManagerService pm)77     RemovePackageHelper(PackageManagerService pm) {
78         this(pm, new AppDataHelper(pm));
79     }
80 
81     @GuardedBy("mPm.mInstallLock")
removeCodePathLI(File codePath)82     public void removeCodePathLI(File codePath) {
83         if (codePath.isDirectory()) {
84             final File codePathParent = codePath.getParentFile();
85             final boolean needRemoveParent = codePathParent.getName().startsWith(RANDOM_DIR_PREFIX);
86             try {
87                 final boolean isIncremental = (mIncrementalManager != null && isIncrementalPath(
88                         codePath.getAbsolutePath()));
89                 if (isIncremental) {
90                     if (needRemoveParent) {
91                         mIncrementalManager.rmPackageDir(codePathParent);
92                     } else {
93                         mIncrementalManager.rmPackageDir(codePath);
94                     }
95                 }
96 
97                 final String packageName = codePath.getName();
98                 mInstaller.rmPackageDir(packageName, codePath.getAbsolutePath());
99                 if (needRemoveParent) {
100                     mInstaller.rmPackageDir(packageName, codePathParent.getAbsolutePath());
101                     removeCachedResult(codePathParent);
102                 }
103             } catch (Installer.InstallerException e) {
104                 Slog.w(TAG, "Failed to remove code path", e);
105             }
106         } else {
107             codePath.delete();
108         }
109     }
110 
removeCachedResult(@onNull File codePath)111     private void removeCachedResult(@NonNull File codePath) {
112         if (mPm.getCacheDir() == null) {
113             return;
114         }
115 
116         final PackageCacher cacher = new PackageCacher(mPm.getCacheDir());
117         // Find and delete the cached result belong to the given codePath.
118         cacher.cleanCachedResult(codePath);
119     }
120 
removePackageLI(AndroidPackage pkg, boolean chatty)121     public void removePackageLI(AndroidPackage pkg, boolean chatty) {
122         // Remove the parent package setting
123         PackageStateInternal ps = mPm.snapshotComputer()
124                 .getPackageStateInternal(pkg.getPackageName());
125         if (ps != null) {
126             removePackageLI(ps.getPackageName(), chatty);
127         } else if (DEBUG_REMOVE && chatty) {
128             Log.d(TAG, "Not removing package " + pkg.getPackageName() + "; mExtras == null");
129         }
130     }
131 
removePackageLI(String packageName, boolean chatty)132     private void removePackageLI(String packageName, boolean chatty) {
133         if (DEBUG_INSTALL) {
134             if (chatty) {
135                 Log.d(TAG, "Removing package " + packageName);
136             }
137         }
138 
139         // writer
140         synchronized (mPm.mLock) {
141             final AndroidPackage removedPackage = mPm.mPackages.remove(packageName);
142             if (removedPackage != null) {
143                 cleanPackageDataStructuresLILPw(removedPackage, chatty);
144             }
145         }
146     }
147 
cleanPackageDataStructuresLILPw(AndroidPackage pkg, boolean chatty)148     private void cleanPackageDataStructuresLILPw(AndroidPackage pkg, boolean chatty) {
149         mPm.mComponentResolver.removeAllComponents(pkg, chatty);
150         mPermissionManager.onPackageRemoved(pkg);
151         mPm.getPackageProperty().removeAllProperties(pkg);
152 
153         final int instrumentationSize = ArrayUtils.size(pkg.getInstrumentations());
154         StringBuilder r = null;
155         int i;
156         for (i = 0; i < instrumentationSize; i++) {
157             ParsedInstrumentation a = pkg.getInstrumentations().get(i);
158             mPm.getInstrumentation().remove(a.getComponentName());
159             if (DEBUG_REMOVE && chatty) {
160                 if (r == null) {
161                     r = new StringBuilder(256);
162                 } else {
163                     r.append(' ');
164                 }
165                 r.append(a.getName());
166             }
167         }
168         if (r != null) {
169             if (DEBUG_REMOVE) Log.d(TAG, "  Instrumentation: " + r);
170         }
171 
172         r = null;
173         if (pkg.isSystem()) {
174             // Only system apps can hold shared libraries.
175             final int libraryNamesSize = pkg.getLibraryNames().size();
176             for (i = 0; i < libraryNamesSize; i++) {
177                 String name = pkg.getLibraryNames().get(i);
178                 if (mSharedLibraries.removeSharedLibraryLPw(name, 0)) {
179                     if (DEBUG_REMOVE && chatty) {
180                         if (r == null) {
181                             r = new StringBuilder(256);
182                         } else {
183                             r.append(' ');
184                         }
185                         r.append(name);
186                     }
187                 }
188             }
189         }
190 
191         r = null;
192 
193         // Any package can hold SDK or static shared libraries.
194         if (pkg.getSdkLibName() != null) {
195             if (mSharedLibraries.removeSharedLibraryLPw(
196                     pkg.getSdkLibName(), pkg.getSdkLibVersionMajor())) {
197                 if (DEBUG_REMOVE && chatty) {
198                     if (r == null) {
199                         r = new StringBuilder(256);
200                     } else {
201                         r.append(' ');
202                     }
203                     r.append(pkg.getSdkLibName());
204                 }
205             }
206         }
207         if (pkg.getStaticSharedLibName() != null) {
208             if (mSharedLibraries.removeSharedLibraryLPw(pkg.getStaticSharedLibName(),
209                     pkg.getStaticSharedLibVersion())) {
210                 if (DEBUG_REMOVE && chatty) {
211                     if (r == null) {
212                         r = new StringBuilder(256);
213                     } else {
214                         r.append(' ');
215                     }
216                     r.append(pkg.getStaticSharedLibName());
217                 }
218             }
219         }
220 
221         if (r != null) {
222             if (DEBUG_REMOVE) Log.d(TAG, "  Libraries: " + r);
223         }
224     }
225 
226     /*
227      * This method deletes the package from internal data structures. If the DELETE_KEEP_DATA
228      * flag is not set, the data directory is removed as well.
229      * make sure this flag is set for partially installed apps. If not its meaningless to
230      * delete a partially installed application.
231      */
removePackageDataLIF(final PackageSetting deletedPs, @NonNull int[] allUserHandles, PackageRemovedInfo outInfo, int flags, boolean writeSettings)232     public void removePackageDataLIF(final PackageSetting deletedPs, @NonNull int[] allUserHandles,
233             PackageRemovedInfo outInfo, int flags, boolean writeSettings) {
234         String packageName = deletedPs.getPackageName();
235         if (DEBUG_REMOVE) Slog.d(TAG, "removePackageDataLI: " + deletedPs);
236         // Retrieve object to delete permissions for shared user later on
237         final AndroidPackage deletedPkg = deletedPs.getPkg();
238         if (outInfo != null) {
239             outInfo.mRemovedPackage = packageName;
240             outInfo.mInstallerPackageName = deletedPs.getInstallSource().installerPackageName;
241             outInfo.mIsStaticSharedLib = deletedPkg != null
242                     && deletedPkg.getStaticSharedLibName() != null;
243             outInfo.populateUsers(deletedPs.queryInstalledUsers(
244                     mUserManagerInternal.getUserIds(), true), deletedPs);
245             outInfo.mIsExternal = deletedPs.isExternalStorage();
246         }
247 
248         removePackageLI(deletedPs.getPackageName(), (flags & PackageManager.DELETE_CHATTY) != 0);
249 
250         if ((flags & PackageManager.DELETE_KEEP_DATA) == 0) {
251             final AndroidPackage resolvedPkg;
252             if (deletedPkg != null) {
253                 resolvedPkg = deletedPkg;
254             } else {
255                 // We don't have a parsed package when it lives on an ejected
256                 // adopted storage device, so fake something together
257                 resolvedPkg = PackageImpl.buildFakeForDeletion(deletedPs.getPackageName(),
258                         deletedPs.getVolumeUuid());
259             }
260             mAppDataHelper.destroyAppDataLIF(resolvedPkg, UserHandle.USER_ALL,
261                     FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL);
262             mAppDataHelper.destroyAppProfilesLIF(resolvedPkg);
263             if (outInfo != null) {
264                 outInfo.mDataRemoved = true;
265             }
266         }
267 
268         int removedAppId = -1;
269 
270         // writer
271         boolean installedStateChanged = false;
272         if ((flags & PackageManager.DELETE_KEEP_DATA) == 0) {
273             final SparseBooleanArray changedUsers = new SparseBooleanArray();
274             synchronized (mPm.mLock) {
275                 mPm.mDomainVerificationManager.clearPackage(deletedPs.getPackageName());
276                 mPm.mSettings.getKeySetManagerService().removeAppKeySetDataLPw(packageName);
277                 final Computer snapshot = mPm.snapshotComputer();
278                 mPm.mAppsFilter.removePackage(snapshot,
279                         snapshot.getPackageStateInternal(packageName), false /* isReplace */);
280                 removedAppId = mPm.mSettings.removePackageLPw(packageName);
281                 if (outInfo != null) {
282                     outInfo.mRemovedAppId = removedAppId;
283                 }
284                 if (!mPm.mSettings.isDisabledSystemPackageLPr(packageName)) {
285                     // If we don't have a disabled system package to reinstall, the package is
286                     // really gone and its permission state should be removed.
287                     SharedUserSetting sus = mPm.mSettings.getSharedUserSettingLPr(deletedPs);
288                     List<AndroidPackage> sharedUserPkgs =
289                             sus != null ? sus.getPackages() : Collections.emptyList();
290                     mPermissionManager.onPackageUninstalled(packageName, deletedPs.getAppId(),
291                             deletedPkg, sharedUserPkgs, UserHandle.USER_ALL);
292                     // After permissions are handled, check if the shared user can be migrated
293                     if (sus != null) {
294                         mPm.mSettings.checkAndConvertSharedUserSettingsLPw(sus);
295                     }
296                 }
297                 mPm.clearPackagePreferredActivitiesLPw(
298                         deletedPs.getPackageName(), changedUsers, UserHandle.USER_ALL);
299 
300                 mPm.mSettings.removeRenamedPackageLPw(deletedPs.getRealName());
301             }
302             if (changedUsers.size() > 0) {
303                 final PreferredActivityHelper preferredActivityHelper =
304                         new PreferredActivityHelper(mPm);
305                 preferredActivityHelper.updateDefaultHomeNotLocked(mPm.snapshotComputer(),
306                         changedUsers);
307                 mPm.postPreferredActivityChangedBroadcast(UserHandle.USER_ALL);
308             }
309         }
310         // make sure to preserve per-user disabled state if this removal was just
311         // a downgrade of a system app to the factory package
312         if (outInfo != null && outInfo.mOrigUsers != null) {
313             if (DEBUG_REMOVE) {
314                 Slog.d(TAG, "Propagating install state across downgrade");
315             }
316             for (int userId : allUserHandles) {
317                 final boolean installed = ArrayUtils.contains(outInfo.mOrigUsers, userId);
318                 if (DEBUG_REMOVE) {
319                     Slog.d(TAG, "    user " + userId + " => " + installed);
320                 }
321                 if (installed != deletedPs.getInstalled(userId)) {
322                     installedStateChanged = true;
323                 }
324                 deletedPs.setInstalled(installed, userId);
325                 if (installed) {
326                     deletedPs.setUninstallReason(UNINSTALL_REASON_UNKNOWN, userId);
327                 }
328             }
329         }
330         synchronized (mPm.mLock) {
331             // can downgrade to reader
332             if (writeSettings) {
333                 // Save settings now
334                 mPm.writeSettingsLPrTEMP();
335             }
336             if (installedStateChanged) {
337                 mPm.mSettings.writeKernelMappingLPr(deletedPs);
338             }
339         }
340 
341         if (removedAppId != -1) {
342             // A user ID was deleted here. Go through all users and remove it from KeyStore.
343             final int appIdToRemove = removedAppId;
344             mPm.mInjector.getBackgroundHandler().post(() -> {
345                 try {
346                     Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER,
347                             "clearKeystoreData:" + appIdToRemove);
348                     mAppDataHelper.clearKeystoreData(UserHandle.USER_ALL, appIdToRemove);
349                 } finally {
350                     Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
351                 }
352             });
353         }
354     }
355 }
356