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 android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.annotation.SpecialUsers.CanBeALL; 22 import android.annotation.UserIdInt; 23 import android.content.pm.Flags; 24 import android.content.pm.PackageManager; 25 26 import dalvik.system.CloseGuard; 27 28 import java.util.concurrent.atomic.AtomicBoolean; 29 30 /** 31 * Class that freezes and kills the given package upon creation, and 32 * unfreezes it upon closing. This is typically used when doing surgery on 33 * app code/data to prevent the app from running while you're working. 34 */ 35 final class PackageFreezer implements AutoCloseable { 36 @Nullable private InstallRequest mInstallRequest; 37 38 private final String mPackageName; 39 40 private final AtomicBoolean mClosed = new AtomicBoolean(); 41 private final CloseGuard mCloseGuard = CloseGuard.get(); 42 43 @NonNull 44 private final PackageManagerService mPm; 45 46 /** 47 * Create and return a stub freezer that doesn't actually do anything, 48 * typically used when someone requested 49 * {@link PackageManager#INSTALL_DONT_KILL_APP} or 50 * {@link PackageManager#DELETE_DONT_KILL_APP}. 51 */ 52 PackageFreezer(PackageManagerService pm, @Nullable InstallRequest request)53 PackageFreezer(PackageManagerService pm, @Nullable InstallRequest request) { 54 mPm = pm; 55 mPackageName = null; 56 mClosed.set(true); 57 mCloseGuard.open("close"); 58 mInstallRequest = request; 59 // We only focus on the install Freeze metrics now 60 if (mInstallRequest != null) { 61 mInstallRequest.onFreezeStarted(); 62 } 63 } 64 PackageFreezer(String packageName, @CanBeALL @UserIdInt int userId, String killReason, PackageManagerService pm, int exitInfoReason, @Nullable InstallRequest request)65 PackageFreezer(String packageName, @CanBeALL @UserIdInt int userId, String killReason, 66 PackageManagerService pm, int exitInfoReason, @Nullable InstallRequest request) { 67 this(packageName, userId, killReason, pm, exitInfoReason, request, false); 68 } 69 PackageFreezer(String packageName, @CanBeALL @UserIdInt int userId, String killReason, PackageManagerService pm, int exitInfoReason, @Nullable InstallRequest request, boolean waitAppKilled)70 PackageFreezer(String packageName, @CanBeALL @UserIdInt int userId, String killReason, 71 PackageManagerService pm, int exitInfoReason, @Nullable InstallRequest request, 72 boolean waitAppKilled) { 73 mPm = pm; 74 mPackageName = packageName; 75 mInstallRequest = request; 76 final PackageSetting ps; 77 // We only focus on the install Freeze metrics now 78 if (mInstallRequest != null) { 79 mInstallRequest.onFreezeStarted(); 80 } 81 synchronized (mPm.mLock) { 82 final int refCounts = mPm.mFrozenPackages 83 .getOrDefault(mPackageName, 0 /* defaultValue */) + 1; 84 mPm.mFrozenPackages.put(mPackageName, refCounts); 85 ps = mPm.mSettings.getPackageLPr(mPackageName); 86 } 87 if (ps != null) { 88 if (waitAppKilled && Flags.waitApplicationKilled()) { 89 mPm.killApplicationSync(ps.getPackageName(), ps.getAppId(), userId, killReason, 90 exitInfoReason); 91 } else { 92 mPm.killApplication(ps.getPackageName(), ps.getAppId(), userId, killReason, 93 exitInfoReason); 94 } 95 } 96 mCloseGuard.open("close"); 97 } 98 99 @Override finalize()100 protected void finalize() throws Throwable { 101 try { 102 mCloseGuard.warnIfOpen(); 103 close(); 104 } finally { 105 super.finalize(); 106 } 107 } 108 109 @Override close()110 public void close() { 111 mCloseGuard.close(); 112 if (mClosed.compareAndSet(false, true)) { 113 synchronized (mPm.mLock) { 114 final int refCounts = mPm.mFrozenPackages 115 .getOrDefault(mPackageName, 0 /* defaultValue */) - 1; 116 if (refCounts > 0) { 117 mPm.mFrozenPackages.put(mPackageName, refCounts); 118 } else { 119 mPm.mFrozenPackages.remove(mPackageName); 120 } 121 } 122 } 123 // We only focus on the install Freeze metrics now 124 if (mInstallRequest != null) { 125 mInstallRequest.onFreezeCompleted(); 126 mInstallRequest = null; 127 } 128 } 129 } 130