1 /*
2  * Copyright (C) 2012 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.wm;
18 
19 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
20 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
21 
22 import android.app.admin.DevicePolicyCache;
23 import android.app.admin.DevicePolicyManager;
24 import android.content.Context;
25 import android.os.Handler;
26 import android.os.IBinder;
27 import android.os.Process;
28 import android.os.UserHandle;
29 import android.os.UserManagerInternal;
30 
31 import com.android.internal.annotations.VisibleForTesting;
32 import com.android.server.LocalServices;
33 import com.android.server.policy.WindowManagerPolicy;
34 import com.android.server.utils.UserTokenWatcher;
35 import com.android.server.wm.LockTaskController.LockTaskToken;
36 
37 class KeyguardDisableHandler {
38     private static final String TAG = TAG_WITH_CLASS_NAME ? "KeyguardDisableHandler" : TAG_WM;
39 
40     private final UserTokenWatcher mAppTokenWatcher;
41     private final UserTokenWatcher mSystemTokenWatcher;
42 
43     private int mCurrentUser = UserHandle.USER_SYSTEM;
44     private Injector mInjector;
45 
46     @VisibleForTesting
KeyguardDisableHandler(Injector injector, Handler handler)47     KeyguardDisableHandler(Injector injector, Handler handler) {
48         mInjector = injector;
49         mAppTokenWatcher = new UserTokenWatcher(mCallback, handler, TAG);
50         mSystemTokenWatcher = new UserTokenWatcher(mCallback, handler, TAG);
51     }
52 
setCurrentUser(int user)53     public void setCurrentUser(int user) {
54         synchronized (this) {
55             mCurrentUser = user;
56             updateKeyguardEnabledLocked(UserHandle.USER_ALL);
57         }
58     }
59 
updateKeyguardEnabled(int userId)60     void updateKeyguardEnabled(int userId) {
61         synchronized (this) {
62             updateKeyguardEnabledLocked(userId);
63         }
64     }
65 
updateKeyguardEnabledLocked(int userId)66     private void updateKeyguardEnabledLocked(int userId) {
67         if (mCurrentUser == userId || userId == UserHandle.USER_ALL) {
68             mInjector.enableKeyguard(shouldKeyguardBeEnabled(mCurrentUser));
69         }
70     }
71 
disableKeyguard(IBinder token, String tag, int callingUid, int userId)72     void disableKeyguard(IBinder token, String tag, int callingUid, int userId) {
73         UserTokenWatcher watcherForCaller = watcherForCallingUid(token, callingUid);
74         watcherForCaller.acquire(token, tag, mInjector.getProfileParentId(userId));
75     }
76 
reenableKeyguard(IBinder token, int callingUid, int userId)77     void reenableKeyguard(IBinder token, int callingUid, int userId) {
78         UserTokenWatcher watcherForCaller = watcherForCallingUid(token, callingUid);
79         watcherForCaller.release(token, mInjector.getProfileParentId(userId));
80     }
81 
watcherForCallingUid(IBinder token, int callingUid)82     private UserTokenWatcher watcherForCallingUid(IBinder token, int callingUid) {
83         if (Process.isApplicationUid(callingUid)) {
84             return mAppTokenWatcher;
85         } else if (callingUid == Process.SYSTEM_UID && token instanceof LockTaskToken) {
86             // We allow the lock task token here as a legacy case, because it enforces its own
87             // security guarantees.
88             // NOTE: DO NOT add new usages of this API in system server. It is deprecated and
89             // easily misused.
90             return mSystemTokenWatcher;
91         } else {
92             throw new UnsupportedOperationException("Only apps can use the KeyguardLock API");
93         }
94     }
95 
shouldKeyguardBeEnabled(int userId)96     private boolean shouldKeyguardBeEnabled(int userId) {
97         final boolean dpmRequiresPassword = mInjector.dpmRequiresPassword(mCurrentUser);
98         final boolean keyguardSecure = mInjector.isKeyguardSecure(mCurrentUser);
99 
100         final boolean allowedFromApps = !dpmRequiresPassword && !keyguardSecure;
101         // The system can disable the keyguard for lock task mode even if the keyguard is secure,
102         // because it enforces its own security guarantees.
103         final boolean allowedFromSystem = !dpmRequiresPassword;
104 
105         final boolean shouldBeDisabled = allowedFromApps && mAppTokenWatcher.isAcquired(userId)
106                         || allowedFromSystem && mSystemTokenWatcher.isAcquired(userId);
107         return !shouldBeDisabled;
108     }
109 
110     // Callback happens on mHandler thread.
111     private final UserTokenWatcher.Callback mCallback = new UserTokenWatcher.Callback() {
112         @Override
113         public void acquired(int userId) {
114             updateKeyguardEnabled(userId);
115         }
116 
117         @Override
118         public void released(int userId) {
119             updateKeyguardEnabled(userId);
120         }
121     };
122 
create(Context context, WindowManagerPolicy policy, Handler handler)123     static KeyguardDisableHandler create(Context context, WindowManagerPolicy policy,
124             Handler handler) {
125         final UserManagerInternal userManager = LocalServices.getService(UserManagerInternal.class);
126         return new KeyguardDisableHandler(new Injector() {
127             @Override
128             public boolean dpmRequiresPassword(int userId) {
129                 return DevicePolicyCache.getInstance().getPasswordQuality(userId)
130                         != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
131             }
132 
133             @Override
134             public boolean isKeyguardSecure(int userId) {
135                 return policy.isKeyguardSecure(userId);
136             }
137 
138             @Override
139             public int getProfileParentId(int userId) {
140                 return userManager.getProfileParentId(userId);
141             }
142 
143             @Override
144             public void enableKeyguard(boolean enabled) {
145                 policy.enableKeyguard(enabled);
146             }
147         }, handler);
148     }
149 
150     interface Injector {
151         boolean dpmRequiresPassword(int userId);
152 
153         boolean isKeyguardSecure(int userId);
154 
155         int getProfileParentId(int userId);
156 
157         void enableKeyguard(boolean enabled);
158     }
159 }
160