1 /*
2  * Copyright (C) 2023 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 android.car.builtin.keyguard;
18 
19 import static android.os.PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON;
20 import static android.os.PowerManager.WAKE_REASON_POWER_BUTTON;
21 
22 import android.annotation.NonNull;
23 import android.annotation.SystemApi;
24 import android.car.builtin.util.Slogf;
25 import android.content.ComponentName;
26 import android.content.Context;
27 import android.content.Intent;
28 import android.content.ServiceConnection;
29 import android.content.res.Resources;
30 import android.os.Handler;
31 import android.os.IBinder;
32 import android.os.PowerManager;
33 import android.os.RemoteException;
34 import android.os.UserHandle;
35 import android.util.Log;
36 
37 import com.android.internal.annotations.GuardedBy;
38 import com.android.internal.policy.IKeyguardDrawnCallback;
39 import com.android.internal.policy.IKeyguardService;
40 import com.android.internal.util.Preconditions;
41 
42 import java.io.PrintWriter;
43 import java.util.Arrays;
44 
45 /**
46  * Wrapper for KeyguardService
47  *
48  * Simplified version of com.android.server.policy.keyguard.KeyguardServiceDelegate. If something
49  * is not working, check for oversimplification from that class.
50  *
51  * @hide
52  */
53 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
54 public final class KeyguardServiceDelegate {
55     private static final String TAG = KeyguardServiceDelegate.class.getSimpleName();
56     private static final boolean DBG = Slogf.isLoggable(TAG, Log.DEBUG);
57 
58     private final KeyguardStateMonitor.StateCallback mStateCallback;
59     private final Object mLock = new Object();
60     private IKeyguardService mKeyguardService;
61     private KeyguardStateMonitor mKeyguardStateMonitor;
62     @GuardedBy("mLock")
63     private KeyguardLockedStateCallback mLockedStateCallback;
64     private Handler mHandler;
65     private int mUserId;
66     private int[] mDisplays;
67 
68     private final IKeyguardDrawnCallback.Stub mKeyguardShowDelegate =
69             new IKeyguardDrawnCallback.Stub() {
70                 @Override
71                 public void onDrawn() {
72                     if (DBG) {
73                         Slogf.v(TAG, "KeyguardShowDelegate.onDrawn userId=%d", mUserId);
74                     }
75                 }
76             };
77 
78     private final ServiceConnection mKeyguardConnection = new ServiceConnection() {
79         @Override
80         public void onServiceConnected(ComponentName name, IBinder service) {
81             if (DBG) {
82                 Slogf.d(TAG, "Keyguard connected for user %d", mUserId);
83             }
84             try {
85                 // replicated PhoneWindowManager order
86                 mKeyguardService = IKeyguardService.Stub.asInterface(service);
87                 mKeyguardService.onSystemReady();
88                 mKeyguardService.setCurrentUser(mUserId);
89                 mKeyguardStateMonitor = new KeyguardStateMonitor(mKeyguardService, mUserId,
90                         mStateCallback);
91 
92                 mKeyguardService.setSwitchingUser(false);
93                 mKeyguardService.onBootCompleted();
94                 mKeyguardService.onStartedWakingUp(PowerManager.WAKE_REASON_UNKNOWN, false);
95                 mKeyguardService.onFinishedWakingUp();
96                 mKeyguardService.onScreenTurningOn(mKeyguardShowDelegate);
97                 mKeyguardService.onScreenTurnedOn();
98             } catch (Exception e) {
99                 Slogf.e(TAG, e, "Can not start the keyguard");
100             }
101         }
102 
103         @Override
104         public void onServiceDisconnected(ComponentName name) {
105             if (DBG) {
106                 Slogf.d(TAG, "Keyguard disconnected for user %d", mUserId);
107             }
108             mKeyguardService = null;
109             mKeyguardStateMonitor = null;
110             // TODO(b/258238612): Enable once ActivityTaskManagerService APIs are ready
111             // mHandler.post(() -> {
112             //     try {
113             //         ActivityTaskManager.getService().setLockScreenShownForDisplays(
114             //                 /* showingKeyguard= */ true, /* showingAod= */ false, mDisplays);
115             //     } catch (RemoteException e) {
116             //     }
117             // });
118         }
119     };
120 
KeyguardServiceDelegate()121     public KeyguardServiceDelegate() {
122         mStateCallback = showing -> {
123             if (mHandler != null) {
124                 mHandler.post(() -> {
125                     synchronized (mLock) {
126                         if (mLockedStateCallback != null) {
127                             mLockedStateCallback.onKeyguardLockedStateChanged(showing);
128                         }
129                     }
130                 });
131             }
132         };
133     }
134 
135     /**
136      * Binds to the KeyguardService for a particular user and display(s).
137      */
bindService(Context context, UserHandle userHandle, int[] displays)138     public void bindService(Context context, UserHandle userHandle, int[] displays) {
139         if (DBG) {
140             Slogf.v(TAG, "bindService for user=%d, displays=%s", userHandle.getIdentifier(),
141                     Arrays.toString(displays));
142         }
143         mHandler = new Handler(context.getMainLooper());
144         mUserId = userHandle.getIdentifier();
145         mDisplays = displays;
146 
147         Intent intent = new Intent();
148         Resources resources = context.getApplicationContext().getResources();
149 
150         ComponentName keyguardComponent = ComponentName.unflattenFromString(
151                 resources.getString(com.android.internal.R.string.config_keyguardComponent));
152         intent.setComponent(keyguardComponent);
153 
154         if (!context.bindServiceAsUser(intent, mKeyguardConnection,
155                 Context.BIND_AUTO_CREATE, mHandler, userHandle)) {
156             Slogf.e(TAG, "Keyguard: can't bind to " + keyguardComponent);
157         } else {
158             if (DBG) {
159                 Slogf.v(TAG, "Keyguard started for user=%d", mUserId);
160             }
161         }
162     }
163 
164     /**
165      * Unbinds the currently bound KeyguardService.
166      */
stop(Context context)167     public void stop(Context context) {
168         try {
169             context.unbindService(mKeyguardConnection);
170         } catch (Exception e) {
171             Slogf.e(TAG, "Can't unbind the KeyguardService", e);
172         }
173     }
174 
175     /**
176      * Returns whether Keyguard is showing for this delegate. If Keyguard is not bound, return true
177      * to assume the most secure state.
178      */
isShowing()179     public boolean isShowing() {
180         if (mKeyguardStateMonitor == null) {
181             if (DBG) {
182                 Slogf.d(TAG, "mKeyguardStateMonitor null for user=%d - returning default", mUserId);
183             }
184             return true;
185         }
186         boolean showing = mKeyguardStateMonitor.isShowing();
187         if (DBG) {
188             Slogf.d(TAG, "isShowing=%b for user=%d", showing, mUserId);
189         }
190         return showing;
191     }
192 
193     /**
194      * Register a KeyguardLockedStateCallback for this delegate.
195      */
registerKeyguardLockedStateCallback( @onNull KeyguardLockedStateCallback callback)196     public void registerKeyguardLockedStateCallback(
197             @NonNull KeyguardLockedStateCallback callback) {
198         synchronized (mLock) {
199             Preconditions.checkState(mLockedStateCallback == null,
200                     "Keyguard locked state callback already registered");
201             mLockedStateCallback = callback;
202         }
203     }
204 
205     /**
206      * Unregister a KeyguardLockedStateCallback from this delegate.
207      */
unregisterKeyguardLockedStateCallback()208     public void unregisterKeyguardLockedStateCallback() {
209         synchronized (mLock) {
210             Preconditions.checkNotNull(mLockedStateCallback,
211                     "Keyguard locked state callback never registered");
212             mLockedStateCallback = null;
213         }
214     }
215 
216     /**
217      * Notify Keyguard of a display on event.
218      */
notifyDisplayOn()219     public void notifyDisplayOn() {
220         if (mKeyguardService == null) {
221             Slogf.w(TAG, "onDisplayOn - null KeyguardService");
222             return;
223         }
224         try {
225             if (DBG) {
226                 Slogf.v(TAG, "onDisplayOn");
227             }
228             mKeyguardService.onStartedWakingUp(
229                     WAKE_REASON_POWER_BUTTON, /* cameraGestureTriggered= */ false);
230             mKeyguardService.onScreenTurningOn(mKeyguardShowDelegate);
231             mKeyguardService.onScreenTurnedOn();
232             mKeyguardService.onFinishedWakingUp();
233         } catch (RemoteException e) {
234             Slogf.e(TAG, "RemoteException", e);
235         }
236     }
237 
238     /**
239      * Notify Keyguard of a display off event.
240      */
notifyDisplayOff()241     public void notifyDisplayOff() {
242         if (mKeyguardService == null) {
243             Slogf.w(TAG, "onDisplayOff - null KeyguardService");
244             return;
245         }
246         try {
247             if (DBG) {
248                 Slogf.v(TAG, "onDisplayOff");
249             }
250             // TODO(b/258238612): check that nothing is missed comparing to foreground user behavior
251             mKeyguardService.onStartedGoingToSleep(GO_TO_SLEEP_REASON_POWER_BUTTON);
252             mKeyguardService.onScreenTurningOff();
253             mKeyguardService.onScreenTurnedOff();
254             mKeyguardService.onFinishedGoingToSleep(GO_TO_SLEEP_REASON_POWER_BUTTON, false);
255         } catch (RemoteException e) {
256             Slogf.e(TAG, "RemoteException", e);
257         }
258     }
259 
260     /**
261      * Dump the KeyguardServiceDelegate state
262      */
dump(PrintWriter writer)263     public void dump(PrintWriter writer) {
264         writer.println("*KeyguardServiceDelegate*");
265         writer.println("Keyguard service connected = " + (mKeyguardService != null));
266         if (mKeyguardStateMonitor != null) {
267             mKeyguardStateMonitor.dump(writer);
268         }
269     }
270 
271     /**
272      * Callback interface that executes when the keyguard locked state changes.
273      */
274     public interface KeyguardLockedStateCallback {
275         /**
276          * Callback function that executes when the keyguard locked state changes.
277          */
onKeyguardLockedStateChanged(boolean isKeyguardLocked)278         void onKeyguardLockedStateChanged(boolean isKeyguardLocked);
279     }
280 }
281