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.PowerExemptionManager.REASON_PACKAGE_REPLACED;
20 import static android.os.PowerExemptionManager.TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
21 
22 import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
23 
24 import android.annotation.NonNull;
25 import android.app.ActivityManagerInternal;
26 import android.app.BroadcastOptions;
27 import android.content.Intent;
28 import android.os.Bundle;
29 import android.os.PowerExemptionManager;
30 import android.util.SparseArray;
31 import android.util.SparseIntArray;
32 
33 import com.android.internal.util.ArrayUtils;
34 import com.android.server.LocalServices;
35 
36 final class PackageRemovedInfo {
37     final PackageSender mPackageSender;
38     String mRemovedPackage;
39     String mInstallerPackageName;
40     int mUid = -1;
41     int mRemovedAppId = -1;
42     int[] mOrigUsers;
43     int[] mRemovedUsers = null;
44     int[] mBroadcastUsers = null;
45     int[] mInstantUserIds = null;
46     SparseIntArray mInstallReasons;
47     SparseIntArray mUninstallReasons;
48     boolean mIsRemovedPackageSystemUpdate = false;
49     boolean mIsUpdate;
50     boolean mDataRemoved;
51     boolean mRemovedForAllUsers;
52     boolean mIsStaticSharedLib;
53     boolean mIsExternal;
54     long mRemovedPackageVersionCode;
55     // a two dimensional array mapping userId to the set of appIds that can receive notice
56     // of package changes
57     SparseArray<int[]> mBroadcastAllowList;
58     // Clean up resources deleted packages.
59     InstallArgs mArgs = null;
60     private static final int[] EMPTY_INT_ARRAY = new int[0];
61 
PackageRemovedInfo(PackageSender packageSender)62     PackageRemovedInfo(PackageSender packageSender) {
63         mPackageSender = packageSender;
64     }
65 
sendPackageRemovedBroadcasts(boolean killApp, boolean removedBySystem)66     void sendPackageRemovedBroadcasts(boolean killApp, boolean removedBySystem) {
67         sendPackageRemovedBroadcastInternal(killApp, removedBySystem);
68     }
69 
sendSystemPackageUpdatedBroadcasts()70     void sendSystemPackageUpdatedBroadcasts() {
71         if (mIsRemovedPackageSystemUpdate) {
72             sendSystemPackageUpdatedBroadcastsInternal();
73         }
74     }
75 
sendSystemPackageUpdatedBroadcastsInternal()76     private void sendSystemPackageUpdatedBroadcastsInternal() {
77         Bundle extras = new Bundle(2);
78         extras.putInt(Intent.EXTRA_UID, mRemovedAppId >= 0 ? mRemovedAppId : mUid);
79         extras.putBoolean(Intent.EXTRA_REPLACING, true);
80         mPackageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, mRemovedPackage, extras,
81                 0, null /*targetPackage*/, null, null, null, mBroadcastAllowList, null);
82         if (mInstallerPackageName != null) {
83             mPackageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
84                     mRemovedPackage, extras, 0 /*flags*/,
85                     mInstallerPackageName, null, null, null, null /* broadcastAllowList */,
86                     null);
87             mPackageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
88                     mRemovedPackage, extras, 0 /*flags*/,
89                     mInstallerPackageName, null, null, null, null /* broadcastAllowList */,
90                     null);
91         }
92         mPackageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, mRemovedPackage,
93                 extras, 0, null /*targetPackage*/, null, null, null, mBroadcastAllowList, null);
94         mPackageSender.sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, null, null, 0,
95                 mRemovedPackage, null, null, null, null /* broadcastAllowList */,
96                 getTemporaryAppAllowlistBroadcastOptions(REASON_PACKAGE_REPLACED).toBundle());
97     }
98 
getTemporaryAppAllowlistBroadcastOptions( @owerExemptionManager.ReasonCode int reasonCode)99     private static @NonNull BroadcastOptions getTemporaryAppAllowlistBroadcastOptions(
100             @PowerExemptionManager.ReasonCode int reasonCode) {
101         long duration = 10_000;
102         final ActivityManagerInternal amInternal =
103                 LocalServices.getService(ActivityManagerInternal.class);
104         if (amInternal != null) {
105             duration = amInternal.getBootTimeTempAllowListDuration();
106         }
107         final BroadcastOptions bOptions = BroadcastOptions.makeBasic();
108         bOptions.setTemporaryAppAllowlist(duration,
109                 TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
110                 reasonCode, "");
111         return bOptions;
112     }
113 
sendPackageRemovedBroadcastInternal(boolean killApp, boolean removedBySystem)114     private void sendPackageRemovedBroadcastInternal(boolean killApp, boolean removedBySystem) {
115         Bundle extras = new Bundle();
116         final int removedUid = mRemovedAppId >= 0  ? mRemovedAppId : mUid;
117         extras.putInt(Intent.EXTRA_UID, removedUid);
118         extras.putBoolean(Intent.EXTRA_DATA_REMOVED, mDataRemoved);
119         extras.putBoolean(Intent.EXTRA_SYSTEM_UPDATE_UNINSTALL, mIsRemovedPackageSystemUpdate);
120         extras.putBoolean(Intent.EXTRA_DONT_KILL_APP, !killApp);
121         extras.putBoolean(Intent.EXTRA_USER_INITIATED, !removedBySystem);
122         final boolean isReplace = mIsUpdate || mIsRemovedPackageSystemUpdate;
123         if (isReplace) {
124             extras.putBoolean(Intent.EXTRA_REPLACING, true);
125         }
126         extras.putBoolean(Intent.EXTRA_REMOVED_FOR_ALL_USERS, mRemovedForAllUsers);
127 
128         // Send PACKAGE_REMOVED broadcast to the respective installer.
129         if (mRemovedPackage != null && mInstallerPackageName != null) {
130             mPackageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED,
131                     mRemovedPackage, extras, 0 /*flags*/,
132                     mInstallerPackageName, null, mBroadcastUsers, mInstantUserIds, null, null);
133         }
134         if (mIsStaticSharedLib) {
135             // When uninstalling static shared libraries, only the package's installer needs to be
136             // sent a PACKAGE_REMOVED broadcast. There are no other intended recipients.
137             return;
138         }
139         if (mRemovedPackage != null) {
140             mPackageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED,
141                     mRemovedPackage, extras, 0, null /*targetPackage*/, null,
142                     mBroadcastUsers, mInstantUserIds, mBroadcastAllowList, null);
143             mPackageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED_INTERNAL,
144                     mRemovedPackage, extras, 0 /*flags*/, PLATFORM_PACKAGE_NAME,
145                     null /*finishedReceiver*/, mBroadcastUsers, mInstantUserIds,
146                     mBroadcastAllowList, null /*bOptions*/);
147             if (mDataRemoved && !mIsRemovedPackageSystemUpdate) {
148                 mPackageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_FULLY_REMOVED,
149                         mRemovedPackage, extras, Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND, null,
150                         null, mBroadcastUsers, mInstantUserIds, mBroadcastAllowList, null);
151                 mPackageSender.notifyPackageRemoved(mRemovedPackage, removedUid);
152             }
153         }
154         if (mRemovedAppId >= 0) {
155             // If a system app's updates are uninstalled the UID is not actually removed. Some
156             // services need to know the package name affected.
157             if (isReplace) {
158                 extras.putString(Intent.EXTRA_PACKAGE_NAME, mRemovedPackage);
159             }
160 
161             mPackageSender.sendPackageBroadcast(Intent.ACTION_UID_REMOVED,
162                     null, extras, Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND,
163                     null, null, mBroadcastUsers, mInstantUserIds, mBroadcastAllowList, null);
164         }
165     }
166 
populateUsers(int[] userIds, PackageSetting deletedPackageSetting)167     public void populateUsers(int[] userIds, PackageSetting deletedPackageSetting) {
168         mRemovedUsers = userIds;
169         if (mRemovedUsers == null) {
170             mBroadcastUsers = null;
171             return;
172         }
173 
174         mBroadcastUsers = EMPTY_INT_ARRAY;
175         mInstantUserIds = EMPTY_INT_ARRAY;
176         for (int i = userIds.length - 1; i >= 0; --i) {
177             final int userId = userIds[i];
178             if (deletedPackageSetting.getInstantApp(userId)) {
179                 mInstantUserIds = ArrayUtils.appendInt(mInstantUserIds, userId);
180             } else {
181                 mBroadcastUsers = ArrayUtils.appendInt(mBroadcastUsers, userId);
182             }
183         }
184     }
185 }
186