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.util.Slog;
22 
23 import java.util.concurrent.locks.ReentrantLock;
24 
25 /**
26  * This is a unique class that is used as the PackageManager lock.  It can be targeted for lock
27  * injection, similar to {@link ActivityManagerGlobalLock}.
28  */
29 public class PackageManagerTracedLock implements AutoCloseable {
30     private static final String TAG = "PackageManagerTracedLock";
31     private static final boolean DEBUG = false;
32     private @NonNull final RawLock mLock;
33 
PackageManagerTracedLock(@ullable String lockName)34     public PackageManagerTracedLock(@Nullable String lockName) {
35         mLock = new RawLock(lockName);
36     }
37 
PackageManagerTracedLock()38     public PackageManagerTracedLock() {
39         this(null);
40     }
41 
42     /**
43      * Use this method to acquire the lock. Use it with try-with-resources to make sure the lock is
44      * released afterwards. Example usage:
45      * <pre>
46      * PackageManagerTracedLock myInstallLock = new PackageManagerTracedLock();
47      * try (PackageManagerTracedLock installLock = myInstallLock.acquireLock()) {
48      *     // do stuff under lock
49      * }
50      * </pre>
51      */
acquireLock()52     public PackageManagerTracedLock acquireLock() {
53         mLock.lock();
54         return this;
55     }
56 
57     /**
58      * Obtain the raw lock for fine control of lock state. Example usage:
59      * <pre>
60      * PackageManagerTracedLock myInstallLock = new PackageManagerTracedLock();
61      * PackageManagerTracedLock.RawLock rawLock = myInstallLock.getRawLock();
62      * rawLock.lock();
63      * // do stuff under lock
64      * rawLock.unlock();
65      * </pre>
66      */
getRawLock()67     public RawLock getRawLock() {
68         return mLock;
69     }
70 
71     /**
72      * Release the lock if it's held by the current thread.
73      * If you use {@link #acquireLock()} using try-with-resources, there's no need to call this
74      * method explicitly.
75      */
76     @Override
close()77     public void close() {
78         mLock.unlock();
79     }
80 
81     public static class RawLock extends ReentrantLock {
82         @Nullable private final String mLockName;
RawLock(@ullable String lockName)83         RawLock(@Nullable String lockName) {
84             mLockName = lockName;
85         }
86         @Override
lock()87         public void lock() {
88             super.lock();
89             if (DEBUG && mLockName != null) {
90                 Slog.i(TAG, "locked " + mLockName);
91             }
92         }
93 
94         @Override
unlock()95         public void unlock() {
96             super.unlock();
97             if (DEBUG && mLockName != null) {
98                 Slog.i(TAG, "unlocked " + mLockName);
99             }
100         }
101     }
102 }
103