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