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