blob: c762fd3f9648be01ba0af9be253145d4f051db49 [file] [log] [blame]
/*
* 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.os.PowerExemptionManager.REASON_PACKAGE_REPLACED;
import static android.os.PowerExemptionManager.TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
import android.annotation.NonNull;
import android.app.ActivityManagerInternal;
import android.app.BroadcastOptions;
import android.content.Intent;
import android.os.Bundle;
import android.os.PowerExemptionManager;
import android.util.SparseArray;
import android.util.SparseIntArray;
import com.android.internal.util.ArrayUtils;
import com.android.server.LocalServices;
final class PackageRemovedInfo {
final PackageSender mPackageSender;
String mRemovedPackage;
String mInstallerPackageName;
int mUid = -1;
int mRemovedAppId = -1;
int[] mOrigUsers;
int[] mRemovedUsers = null;
int[] mBroadcastUsers = null;
int[] mInstantUserIds = null;
SparseIntArray mInstallReasons;
SparseIntArray mUninstallReasons;
boolean mIsRemovedPackageSystemUpdate = false;
boolean mIsUpdate;
boolean mDataRemoved;
boolean mRemovedForAllUsers;
boolean mIsStaticSharedLib;
boolean mIsExternal;
long mRemovedPackageVersionCode;
// a two dimensional array mapping userId to the set of appIds that can receive notice
// of package changes
SparseArray<int[]> mBroadcastAllowList;
// Clean up resources deleted packages.
InstallArgs mArgs = null;
private static final int[] EMPTY_INT_ARRAY = new int[0];
PackageRemovedInfo(PackageSender packageSender) {
mPackageSender = packageSender;
}
void sendPackageRemovedBroadcasts(boolean killApp, boolean removedBySystem) {
sendPackageRemovedBroadcastInternal(killApp, removedBySystem);
}
void sendSystemPackageUpdatedBroadcasts() {
if (mIsRemovedPackageSystemUpdate) {
sendSystemPackageUpdatedBroadcastsInternal();
}
}
private void sendSystemPackageUpdatedBroadcastsInternal() {
Bundle extras = new Bundle(2);
extras.putInt(Intent.EXTRA_UID, mRemovedAppId >= 0 ? mRemovedAppId : mUid);
extras.putBoolean(Intent.EXTRA_REPLACING, true);
mPackageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, mRemovedPackage, extras,
0, null /*targetPackage*/, null, null, null, mBroadcastAllowList, null);
if (mInstallerPackageName != null) {
mPackageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
mRemovedPackage, extras, 0 /*flags*/,
mInstallerPackageName, null, null, null, null /* broadcastAllowList */,
null);
mPackageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
mRemovedPackage, extras, 0 /*flags*/,
mInstallerPackageName, null, null, null, null /* broadcastAllowList */,
null);
}
mPackageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, mRemovedPackage,
extras, 0, null /*targetPackage*/, null, null, null, mBroadcastAllowList, null);
mPackageSender.sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, null, null, 0,
mRemovedPackage, null, null, null, null /* broadcastAllowList */,
getTemporaryAppAllowlistBroadcastOptions(REASON_PACKAGE_REPLACED).toBundle());
}
private static @NonNull BroadcastOptions getTemporaryAppAllowlistBroadcastOptions(
@PowerExemptionManager.ReasonCode int reasonCode) {
long duration = 10_000;
final ActivityManagerInternal amInternal =
LocalServices.getService(ActivityManagerInternal.class);
if (amInternal != null) {
duration = amInternal.getBootTimeTempAllowListDuration();
}
final BroadcastOptions bOptions = BroadcastOptions.makeBasic();
bOptions.setTemporaryAppAllowlist(duration,
TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
reasonCode, "");
return bOptions;
}
private void sendPackageRemovedBroadcastInternal(boolean killApp, boolean removedBySystem) {
Bundle extras = new Bundle();
final int removedUid = mRemovedAppId >= 0 ? mRemovedAppId : mUid;
extras.putInt(Intent.EXTRA_UID, removedUid);
extras.putBoolean(Intent.EXTRA_DATA_REMOVED, mDataRemoved);
extras.putBoolean(Intent.EXTRA_SYSTEM_UPDATE_UNINSTALL, mIsRemovedPackageSystemUpdate);
extras.putBoolean(Intent.EXTRA_DONT_KILL_APP, !killApp);
extras.putBoolean(Intent.EXTRA_USER_INITIATED, !removedBySystem);
final boolean isReplace = mIsUpdate || mIsRemovedPackageSystemUpdate;
if (isReplace) {
extras.putBoolean(Intent.EXTRA_REPLACING, true);
}
extras.putBoolean(Intent.EXTRA_REMOVED_FOR_ALL_USERS, mRemovedForAllUsers);
// Send PACKAGE_REMOVED broadcast to the respective installer.
if (mRemovedPackage != null && mInstallerPackageName != null) {
mPackageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED,
mRemovedPackage, extras, 0 /*flags*/,
mInstallerPackageName, null, mBroadcastUsers, mInstantUserIds, null, null);
}
if (mIsStaticSharedLib) {
// When uninstalling static shared libraries, only the package's installer needs to be
// sent a PACKAGE_REMOVED broadcast. There are no other intended recipients.
return;
}
if (mRemovedPackage != null) {
mPackageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED,
mRemovedPackage, extras, 0, null /*targetPackage*/, null,
mBroadcastUsers, mInstantUserIds, mBroadcastAllowList, null);
mPackageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED_INTERNAL,
mRemovedPackage, extras, 0 /*flags*/, PLATFORM_PACKAGE_NAME,
null /*finishedReceiver*/, mBroadcastUsers, mInstantUserIds,
mBroadcastAllowList, null /*bOptions*/);
if (mDataRemoved && !mIsRemovedPackageSystemUpdate) {
mPackageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_FULLY_REMOVED,
mRemovedPackage, extras, Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND, null,
null, mBroadcastUsers, mInstantUserIds, mBroadcastAllowList, null);
mPackageSender.notifyPackageRemoved(mRemovedPackage, removedUid);
}
}
if (mRemovedAppId >= 0) {
// If a system app's updates are uninstalled the UID is not actually removed. Some
// services need to know the package name affected.
if (isReplace) {
extras.putString(Intent.EXTRA_PACKAGE_NAME, mRemovedPackage);
}
mPackageSender.sendPackageBroadcast(Intent.ACTION_UID_REMOVED,
null, extras, Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND,
null, null, mBroadcastUsers, mInstantUserIds, mBroadcastAllowList, null);
}
}
public void populateUsers(int[] userIds, PackageSetting deletedPackageSetting) {
mRemovedUsers = userIds;
if (mRemovedUsers == null) {
mBroadcastUsers = null;
return;
}
mBroadcastUsers = EMPTY_INT_ARRAY;
mInstantUserIds = EMPTY_INT_ARRAY;
for (int i = userIds.length - 1; i >= 0; --i) {
final int userId = userIds[i];
if (deletedPackageSetting.getInstantApp(userId)) {
mInstantUserIds = ArrayUtils.appendInt(mInstantUserIds, userId);
} else {
mBroadcastUsers = ArrayUtils.appendInt(mBroadcastUsers, userId);
}
}
}
}