1 /*
2  * Copyright (C) 2022 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.devicelock;
18 
19 import static android.app.AppOpsManager.OPSTR_SYSTEM_EXEMPT_FROM_HIBERNATION;
20 import static android.app.role.RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP;
21 import static android.content.IntentFilter.SYSTEM_HIGH_PRIORITY;
22 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
23 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
24 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
25 import static android.content.pm.PackageManager.DONT_KILL_APP;
26 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
27 import static android.devicelock.DeviceId.DEVICE_ID_TYPE_IMEI;
28 import static android.devicelock.DeviceId.DEVICE_ID_TYPE_MEID;
29 import static android.provider.Settings.Secure.USER_SETUP_COMPLETE;
30 
31 import android.Manifest;
32 import android.Manifest.permission;
33 import android.annotation.NonNull;
34 import android.annotation.Nullable;
35 import android.app.AppOpsManager;
36 import android.app.role.RoleManager;
37 import android.content.BroadcastReceiver;
38 import android.content.ComponentName;
39 import android.content.ContentResolver;
40 import android.content.Context;
41 import android.content.Intent;
42 import android.content.IntentFilter;
43 import android.content.ServiceConnection;
44 import android.content.pm.PackageManager;
45 import android.content.pm.PackageManager.NameNotFoundException;
46 import android.content.pm.ServiceInfo;
47 import android.database.ContentObserver;
48 import android.devicelock.DeviceId.DeviceIdType;
49 import android.devicelock.DeviceLockManager;
50 import android.devicelock.IDeviceLockService;
51 import android.devicelock.IGetDeviceIdCallback;
52 import android.devicelock.IGetKioskAppsCallback;
53 import android.devicelock.IIsDeviceLockedCallback;
54 import android.devicelock.ILockUnlockDeviceCallback;
55 import android.devicelock.ParcelableException;
56 import android.net.NetworkPolicyManager;
57 import android.net.Uri;
58 import android.os.Binder;
59 import android.os.Bundle;
60 import android.os.Environment;
61 import android.os.IBinder;
62 import android.os.OutcomeReceiver;
63 import android.os.PowerExemptionManager;
64 import android.os.RemoteCallback;
65 import android.os.RemoteException;
66 import android.os.UserHandle;
67 import android.os.UserManager;
68 import android.provider.Settings;
69 import android.telephony.TelephonyManager;
70 import android.text.TextUtils;
71 import android.util.ArrayMap;
72 import android.util.Slog;
73 
74 import com.android.internal.annotations.GuardedBy;
75 import com.android.internal.annotations.VisibleForTesting;
76 
77 import java.io.File;
78 import java.lang.reflect.InvocationTargetException;
79 import java.util.ArrayList;
80 import java.util.List;
81 import java.util.concurrent.ExecutorService;
82 import java.util.concurrent.Executors;
83 
84 /**
85  * Implementation of {@link android.devicelock.IDeviceLockService} binder service.
86  */
87 final class DeviceLockServiceImpl extends IDeviceLockService.Stub {
88     private static final String TAG = "DeviceLockServiceImpl";
89 
90     // Keep this in sync with NetworkPolicyManager#POLICY_NONE.
91     private static final int POLICY_NONE = 0x0;
92     //Keep this in sync with NetworkPolicyManager#POLICY_ALLOW_METERED_BACKGROUND.
93     private static final int POLICY_ALLOW_METERED_BACKGROUND = 0x4;
94     private static final String ACTION_DEVICE_LOCK_KEEPALIVE =
95             "com.android.devicelock.action.KEEPALIVE";
96 
97     // Workaround for timeout while adding the kiosk app as role holder for financing.
98     private static final int MAX_ADD_ROLE_HOLDER_TRIES = 4;
99 
100     private final Context mContext;
101     private final ExecutorService mExecutorService;
102 
103     private final RoleManager mRoleManager;
104     private final TelephonyManager mTelephonyManager;
105     private final AppOpsManager mAppOpsManager;
106     private final UserManager mUserManager;
107 
108     // Map user id -> DeviceLockControllerConnector
109     @GuardedBy("this")
110     private final ArrayMap<Integer, DeviceLockControllerConnector> mDeviceLockControllerConnectors;
111 
112     private final DeviceLockControllerConnectorStub mDeviceLockControllerConnectorStub =
113             new DeviceLockControllerConnectorStub();
114 
115     private final DeviceLockControllerPackageUtils mPackageUtils;
116 
117     private final ServiceInfo mServiceInfo;
118 
119     // Map user id -> ServiceConnection for kiosk keepalive.
120     private final ArrayMap<Integer, KeepaliveServiceConnection> mKioskKeepaliveServiceConnections;
121 
122     // Map user id -> ServiceConnection for controller keepalive.
123     private final ArrayMap<Integer, KeepaliveServiceConnection>
124             mControllerKeepaliveServiceConnections;
125 
126     private final DeviceLockPersistentStore mPersistentStore;
127 
128     // The following string constants should be a SystemApi on AppOpsManager.
129     @VisibleForTesting
130     static final String OPSTR_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION =
131             "android:system_exempt_from_activity_bg_start_restriction";
132     @VisibleForTesting
133     static final String OPSTR_SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS =
134             "android:system_exempt_from_dismissible_notifications";
135     @VisibleForTesting
136     static final String OPSTR_SYSTEM_EXEMPT_FROM_POWER_RESTRICTIONS =
137             "android:system_exempt_from_power_restrictions";
138 
139     // Stopgap: this receiver should be replaced by an API on DeviceLockManager.
140     private final class DeviceLockClearReceiver extends BroadcastReceiver {
141         static final String ACTION_CLEAR = "com.android.devicelock.intent.action.CLEAR";
142         static final int CLEAR_SUCCEEDED = 0;
143         static final int CLEAR_FAILED = 1;
144 
145         @Override
onReceive(Context context, Intent intent)146         public void onReceive(Context context, Intent intent) {
147             Slog.i(TAG, "Received request to clear device");
148 
149             // This receiver should be the only one.
150             // The result will still be sent to the 'resultReceiver' of 'sendOrderedBroadcast'.
151             abortBroadcast();
152 
153             final UserHandle userHandle = getSendingUser();
154 
155             final PendingResult pendingResult = goAsync();
156 
157             getDeviceLockControllerConnector(userHandle).clearDeviceRestrictions(
158                     new OutcomeReceiver<>() {
159 
160                         private void setResult(int resultCode) {
161                             pendingResult.setResultCode(resultCode);
162 
163                             pendingResult.finish();
164                         }
165 
166                         @Override
167                         public void onResult(Void ignored) {
168                             Slog.i(TAG, "Device cleared ");
169 
170                             setResult(DeviceLockClearReceiver.CLEAR_SUCCEEDED);
171                         }
172 
173                         @Override
174                         public void onError(Exception ex) {
175                             Slog.e(TAG, "Exception clearing device: ", ex);
176 
177                             setResult(DeviceLockClearReceiver.CLEAR_FAILED);
178                         }
179                     });
180         }
181     }
182 
183     // Last supported device id type
184     private static final @DeviceIdType int LAST_DEVICE_ID_TYPE = DEVICE_ID_TYPE_MEID;
185 
186     @VisibleForTesting
187     static final String MANAGE_DEVICE_LOCK_SERVICE_FROM_CONTROLLER =
188             "com.android.devicelockcontroller.permission."
189                     + "MANAGE_DEVICE_LOCK_SERVICE_FROM_CONTROLLER";
190 
191     @NonNull
getDeviceLockControllerConnector(UserHandle userHandle)192     private DeviceLockControllerConnector getDeviceLockControllerConnector(UserHandle userHandle) {
193         synchronized (this) {
194             final int userId = userHandle.getIdentifier();
195             DeviceLockControllerConnector deviceLockControllerConnector =
196                     mDeviceLockControllerConnectors.get(userId);
197             if (deviceLockControllerConnector == null) {
198                 if (isDlcPackageEnabledForUser(userHandle)) {
199                     final ComponentName componentName = new ComponentName(mServiceInfo.packageName,
200                             mServiceInfo.name);
201                     deviceLockControllerConnector = new DeviceLockControllerConnectorImpl(mContext,
202                             componentName, userHandle);
203                 } else {
204                     deviceLockControllerConnector = mDeviceLockControllerConnectorStub;
205                 }
206                 mDeviceLockControllerConnectors.put(userId, deviceLockControllerConnector);
207             }
208             return deviceLockControllerConnector;
209         }
210     }
211 
212     @NonNull
getDeviceLockControllerConnector()213     private DeviceLockControllerConnector getDeviceLockControllerConnector() {
214         final UserHandle userHandle = Binder.getCallingUserHandle();
215         return getDeviceLockControllerConnector(userHandle);
216     }
217 
DeviceLockServiceImpl(@onNull Context context)218     DeviceLockServiceImpl(@NonNull Context context) {
219         this(context, context.getSystemService(TelephonyManager.class),
220                 Executors.newCachedThreadPool(),
221                 Environment.getDataDirectory());
222     }
223 
224     @VisibleForTesting
DeviceLockServiceImpl(@onNull Context context, TelephonyManager telephonyManager, ExecutorService executorService, File dataDirectory)225     DeviceLockServiceImpl(@NonNull Context context, TelephonyManager telephonyManager,
226             ExecutorService executorService, File dataDirectory) {
227         mContext = context;
228         mTelephonyManager = telephonyManager;
229         mExecutorService = executorService;
230 
231         mRoleManager = context.getSystemService(RoleManager.class);
232         mAppOpsManager = context.getSystemService(AppOpsManager.class);
233         mUserManager = context.getSystemService(UserManager.class);
234 
235         mDeviceLockControllerConnectors = new ArrayMap<>();
236 
237         mKioskKeepaliveServiceConnections = new ArrayMap<>();
238         mControllerKeepaliveServiceConnections = new ArrayMap<>();
239 
240         mPackageUtils = new DeviceLockControllerPackageUtils(context);
241 
242         mPersistentStore = new DeviceLockPersistentStore(executorService, dataDirectory);
243 
244         final StringBuilder errorMessage = new StringBuilder();
245         mServiceInfo = mPackageUtils.findService(errorMessage);
246 
247         if (mServiceInfo == null) {
248             throw new RuntimeException(errorMessage.toString());
249         }
250 
251         enableDlcIfNeeded(UserHandle.SYSTEM);
252 
253         final IntentFilter intentFilter = new IntentFilter(DeviceLockClearReceiver.ACTION_CLEAR);
254         // Run before any eventual app receiver (there should be none).
255         intentFilter.setPriority(SYSTEM_HIGH_PRIORITY);
256         context.registerReceiverForAllUsers(new DeviceLockClearReceiver(), intentFilter,
257                 Manifest.permission.MANAGE_DEVICE_LOCK_STATE, null /* scheduler */,
258                 Context.RECEIVER_EXPORTED);
259     }
260 
261     /**
262      * Enable DLC for user if it should be enabled.
263      * <p>
264      * Note that this is separate from {@link #disableDlcIfNeeded} because we always want to enable
265      * if the device is not finalized but we generally do not want to disable immediately if
266      * the device is finalized in case we still need to do some clean up. See
267      * {@link #disableDlcIfNeeded}.
268      *
269      * @param userHandle user to enable for
270      */
enableDlcIfNeeded(@onNull UserHandle userHandle)271     private void enableDlcIfNeeded(@NonNull UserHandle userHandle) {
272         mPersistentStore.readFinalizedState(
273                 isFinalized -> {
274                     if (!isFinalized || !canDlcBeDisabledForFinalizedUser(userHandle)) {
275                         setDeviceLockControllerPackageEnabledState(userHandle, true);
276                     }
277                 },
278                 mContext.getMainExecutor());
279     }
280 
281     /**
282      * Disable DLC for user if it should be disabled.
283      * <p>
284      * We only want to do this for newly created users or previously provisioned users that have
285      * run their clean-up logic and told us to disable them with {@link #setDeviceFinalized}.
286      * Otherwise, we risk disabling before all the roles, permissions, etc. have been removed.
287      *
288      * @param userHandle user to disable for
289      */
disableDlcIfNeeded(@onNull UserHandle userHandle)290     private void disableDlcIfNeeded(@NonNull UserHandle userHandle) {
291         mPersistentStore.readFinalizedState(
292                 isFinalized -> {
293                     if (isFinalized && canDlcBeDisabledForFinalizedUser(userHandle)) {
294                         setDeviceLockControllerPackageEnabledState(userHandle, false);
295                     }
296                 },
297                 mContext.getMainExecutor());
298     }
299 
300     /**
301      * Whether the DLC on a given user can be disabled safely at this point assuming the user
302      * has been finalized (i.e. the DLC has done its clean-up logic on finalization).
303      *
304      * @param userHandle user handle to check
305      * @return true if it can be disabled, false otherwise
306      */
canDlcBeDisabledForFinalizedUser(UserHandle userHandle)307     private boolean canDlcBeDisabledForFinalizedUser(UserHandle userHandle) {
308         if (!userHandle.isSystem()) {
309             return true;
310         }
311         // If the user is system, we can only disable it if all other users have finished
312         // finalizing since the system user DLC process hosts services that DLC processes in other
313         // users need to complete finalization (e.g. global parameters).
314         boolean allNonSystemUsersFinalized = true;
315         final long identity = Binder.clearCallingIdentity();
316         List<UserHandle> users = mUserManager.getUserHandles(/* excludeDying= */ true);
317         for (int i = 0; i < users.size(); i++) {
318             UserHandle user = users.get(i);
319             if (user.isSystem()) {
320                 continue;
321             }
322             if (isDlcPackageEnabledForUser(user)) {
323                 Slog.d(TAG, "Cannot disable DLC for system user. User " + user + " "
324                         + "is not finalized.");
325                 allNonSystemUsersFinalized = false;
326                 break;
327             }
328         }
329         Binder.restoreCallingIdentity(identity);
330         return allNonSystemUsersFinalized;
331     }
332 
isDlcPackageEnabledForUser(UserHandle userHandle)333     private boolean isDlcPackageEnabledForUser(UserHandle userHandle) {
334         final String controllerPackageName = mServiceInfo.packageName;
335         Context controllerContext;
336         try {
337             controllerContext = mContext.createPackageContextAsUser(controllerPackageName,
338                     0 /* flags */, userHandle);
339         } catch (NameNotFoundException e) {
340             Slog.e(TAG, "Cannot create package context for: " + userHandle, e);
341             return false;
342         }
343         final PackageManager controllerPackageManager = controllerContext.getPackageManager();
344         final int enabledState =
345                 controllerPackageManager.getApplicationEnabledSetting(controllerPackageName);
346         return (enabledState != COMPONENT_ENABLED_STATE_DISABLED
347                 && enabledState != COMPONENT_ENABLED_STATE_DISABLED_USER);
348     }
349 
setDeviceLockControllerPackageEnabledState(UserHandle userHandle, boolean enabled)350     private void setDeviceLockControllerPackageEnabledState(UserHandle userHandle,
351             boolean enabled) {
352         final String controllerPackageName = mServiceInfo.packageName;
353 
354         Context controllerContext;
355         try {
356             controllerContext = mContext.createPackageContextAsUser(controllerPackageName,
357                     0 /* flags */, userHandle);
358         } catch (NameNotFoundException e) {
359             Slog.e(TAG, "Cannot create package context for: " + userHandle, e);
360 
361             return;
362         }
363 
364         final PackageManager controllerPackageManager = controllerContext.getPackageManager();
365 
366         final int enableState =
367                 enabled ? COMPONENT_ENABLED_STATE_DEFAULT : COMPONENT_ENABLED_STATE_DISABLED;
368         // We cannot check if user control is disabled since
369         // DevicePolicyManager.getUserControlDisabledPackages() acts on the calling user.
370         // Additionally, we would have to catch SecurityException anyways to avoid TOCTOU bugs
371         // since checking and setting is not atomic.
372         try {
373             controllerPackageManager.setApplicationEnabledSetting(controllerPackageName,
374                     enableState, enabled ? DONT_KILL_APP : 0);
375         } catch (SecurityException ex) {
376             // This exception is thrown when Device Lock Controller has already enabled
377             // package protection for itself. This is an expected behaviour.
378             // Note: the exception description thrown by
379             // PackageManager.setApplicationEnabledSetting() is somehow misleading because it says
380             // that a protected package cannot be disabled (but we're actually trying to enable it).
381         }
382         synchronized (this) {
383             // Refresh connector
384             mDeviceLockControllerConnectors.put(userHandle.getIdentifier(), null);
385             getDeviceLockControllerConnector(userHandle);
386         }
387     }
388 
onUserAdded(@onNull UserHandle userHandle)389     void onUserAdded(@NonNull UserHandle userHandle) {
390         // New users do not have any provisioning to clean up and can be disabled immediately
391         disableDlcIfNeeded(userHandle);
392     }
393 
onUserSwitching(@onNull UserHandle userHandle)394     void onUserSwitching(@NonNull UserHandle userHandle) {
395         enableDlcIfNeeded(userHandle);
396         getDeviceLockControllerConnector(userHandle).onUserSwitching(new OutcomeReceiver<>() {
397             @Override
398             public void onResult(Void ignored) {
399                 Slog.i(TAG, "User switching reported for: " + userHandle);
400             }
401 
402             @Override
403             public void onError(Exception ex) {
404                 Slog.e(TAG, "Exception reporting user switching for: " + userHandle, ex);
405             }
406         });
407     }
408 
onUserUnlocked(@onNull Context userContext, @NonNull UserHandle userHandle)409     void onUserUnlocked(@NonNull Context userContext, @NonNull UserHandle userHandle) {
410         enableDlcIfNeeded(userHandle);
411         mExecutorService.execute(() -> {
412             getDeviceLockControllerConnector(userHandle).onUserUnlocked(new OutcomeReceiver<>() {
413                 @Override
414                 public void onResult(Void ignored) {
415                     Slog.i(TAG, "User unlocked reported for: " + userHandle);
416                 }
417 
418                 @Override
419                 public void onError(Exception ex) {
420                     Slog.e(TAG, "Exception reporting user unlocked for: " + userHandle, ex);
421                 }
422             });
423             // TODO(b/312521897): Add unit tests for this flow
424             registerUserSetupCompleteListener(userContext, userHandle);
425         });
426     }
427 
registerUserSetupCompleteListener(Context userContext, UserHandle userHandle)428     private void registerUserSetupCompleteListener(Context userContext, UserHandle userHandle) {
429         final ContentResolver contentResolver = userContext.getContentResolver();
430         Uri setupCompleteUri = Settings.Secure.getUriFor(USER_SETUP_COMPLETE);
431         contentResolver.registerContentObserver(setupCompleteUri,
432                 false /* notifyForDescendants */, new ContentObserver(null /* handler */) {
433                     @Override
434                     public void onChange(boolean selfChange, @Nullable Uri uri) {
435                         if (setupCompleteUri.equals(uri)
436                                 && Settings.Secure.getInt(
437                                 contentResolver, USER_SETUP_COMPLETE, 0) != 0) {
438                             onUserSetupCompleted(userHandle);
439                         }
440                     }
441                 });
442     }
443 
onUserSetupCompleted(UserHandle userHandle)444     void onUserSetupCompleted(UserHandle userHandle) {
445         getDeviceLockControllerConnector(userHandle).onUserSetupCompleted(new OutcomeReceiver<>() {
446             @Override
447             public void onResult(Void ignored) {
448                 Slog.i(TAG, "User set up complete reported for: " + userHandle);
449             }
450 
451             @Override
452             public void onError(Exception ex) {
453                 Slog.e(TAG, "Exception reporting user setup complete for: " + userHandle, ex);
454             }
455         });
456     }
457 
checkCallerPermission()458     private boolean checkCallerPermission() {
459         return mContext.checkCallingOrSelfPermission(Manifest.permission.MANAGE_DEVICE_LOCK_STATE)
460                 == PERMISSION_GRANTED;
461     }
462 
reportDeviceLockedUnlocked(@onNull ILockUnlockDeviceCallback callback, @Nullable Exception exception)463     private void reportDeviceLockedUnlocked(@NonNull ILockUnlockDeviceCallback callback,
464             @Nullable Exception exception) {
465         try {
466             if (exception == null) {
467                 callback.onDeviceLockedUnlocked();
468             } else {
469                 callback.onError(getParcelableException(exception));
470             }
471         } catch (RemoteException e) {
472             Slog.e(TAG, "Unable to send result to the callback", e);
473         }
474     }
475 
getLockUnlockOutcomeReceiver( @onNull ILockUnlockDeviceCallback callback, @NonNull String successMessage)476     private OutcomeReceiver<Void, Exception> getLockUnlockOutcomeReceiver(
477             @NonNull ILockUnlockDeviceCallback callback, @NonNull String successMessage) {
478         return new OutcomeReceiver<>() {
479             @Override
480             public void onResult(Void ignored) {
481                 Slog.i(TAG, successMessage);
482                 reportDeviceLockedUnlocked(callback, /* exception= */ null);
483             }
484 
485             @Override
486             public void onError(Exception ex) {
487                 Slog.e(TAG, "Exception: ", ex);
488                 reportDeviceLockedUnlocked(callback, ex);
489             }
490         };
491     }
492 
493     private ParcelableException getParcelableException(Exception exception) {
494         return exception instanceof ParcelableException ? (ParcelableException) exception
495                 : new ParcelableException(exception);
496     }
497 
498     @Override
499     public void lockDevice(@NonNull ILockUnlockDeviceCallback callback) {
500         if (!checkCallerPermission()) {
501             try {
502                 callback.onError(new ParcelableException(new SecurityException()));
503             } catch (RemoteException e) {
504                 Slog.e(TAG, "lockDevice() - Unable to send error to the callback", e);
505             }
506             return;
507         }
508 
509         getDeviceLockControllerConnector().lockDevice(
510                 getLockUnlockOutcomeReceiver(callback, "Device locked"));
511     }
512 
513     @Override
514     public void unlockDevice(@NonNull ILockUnlockDeviceCallback callback) {
515         if (!checkCallerPermission()) {
516             try {
517                 callback.onError(new ParcelableException(new SecurityException()));
518             } catch (RemoteException e) {
519                 Slog.e(TAG, "unlockDevice() - Unable to send error to the callback", e);
520             }
521             return;
522         }
523 
524         getDeviceLockControllerConnector().unlockDevice(
525                 getLockUnlockOutcomeReceiver(callback, "Device unlocked"));
526     }
527 
528     @Override
529     public void isDeviceLocked(@NonNull IIsDeviceLockedCallback callback) {
530         if (!checkCallerPermission()) {
531             try {
532                 callback.onError(new ParcelableException(new SecurityException()));
533             } catch (RemoteException e) {
534                 Slog.e(TAG, "isDeviceLocked() - Unable to send error to the callback", e);
535             }
536             return;
537         }
538 
539         getDeviceLockControllerConnector().isDeviceLocked(new OutcomeReceiver<>() {
540             @Override
541             public void onResult(Boolean isLocked) {
542                 Slog.i(TAG, isLocked ? "Device is locked" : "Device is not locked");
543                 try {
544                     callback.onIsDeviceLocked(isLocked);
545                 } catch (RemoteException e) {
546                     Slog.e(TAG, "isDeviceLocked() - Unable to send result to the " + "callback", e);
547                 }
548             }
549 
550             @Override
551             public void onError(Exception ex) {
552                 Slog.e(TAG, "isDeviceLocked exception: ", ex);
553                 try {
554                     callback.onError(getParcelableException(ex));
555                 } catch (RemoteException e) {
556                     Slog.e(TAG, "isDeviceLocked() - Unable to send error to the " + "callback", e);
557                 }
558             }
559         });
560     }
561 
562     private boolean hasGsm() {
563         return mContext.getPackageManager().hasSystemFeature(
564                 PackageManager.FEATURE_TELEPHONY_GSM);
565     }
566 
567     private boolean hasCdma() {
568         return mContext.getPackageManager().hasSystemFeature(
569                 PackageManager.FEATURE_TELEPHONY_CDMA);
570     }
571 
572     @VisibleForTesting
573     void getDeviceId(@NonNull IGetDeviceIdCallback callback, int deviceIdTypeBitmap) {
574         try {
575             if (deviceIdTypeBitmap < 0 || deviceIdTypeBitmap >= (1 << (LAST_DEVICE_ID_TYPE + 1))) {
576                 callback.onError(new ParcelableException("Invalid device type"));
577                 return;
578             }
579         } catch (RemoteException e) {
580             Slog.e(TAG, "getDeviceId() - Unable to send result to the callback", e);
581         }
582 
583         int activeModemCount = mTelephonyManager.getActiveModemCount();
584         List<String> imeiList = new ArrayList<String>();
585         List<String> meidList = new ArrayList<String>();
586 
587         if (hasGsm() && ((deviceIdTypeBitmap & (1 << DEVICE_ID_TYPE_IMEI)) != 0)) {
588             for (int i = 0; i < activeModemCount; i++) {
589                 String imei = mTelephonyManager.getImei(i);
590                 if (!TextUtils.isEmpty(imei)) {
591                     imeiList.add(imei);
592                 }
593             }
594         }
595 
596         if (hasCdma() && ((deviceIdTypeBitmap & (1 << DEVICE_ID_TYPE_MEID)) != 0)) {
597             for (int i = 0; i < activeModemCount; i++) {
598                 String meid = mTelephonyManager.getMeid(i);
599                 if (!TextUtils.isEmpty(meid)) {
600                     meidList.add(meid);
601                 }
602             }
603         }
604 
605         getDeviceLockControllerConnector().getDeviceId(new OutcomeReceiver<>() {
606             @Override
607             public void onResult(String deviceId) {
608                 Slog.i(TAG, "Get Device ID ");
609                 try {
610                     if (meidList.contains(deviceId)) {
611                         callback.onDeviceIdReceived(DEVICE_ID_TYPE_MEID, deviceId);
612                         return;
613                     }
614                     if (imeiList.contains(deviceId)) {
615                         callback.onDeviceIdReceived(DEVICE_ID_TYPE_IMEI, deviceId);
616                         return;
617                     }
618                     // When a device ID is returned from DLC App, but none of the IDs got from
619                     // TelephonyManager matches that device ID.
620                     //
621                     // TODO(b/270392813): Send the device ID back to the callback with
622                     //  UNSPECIFIED device ID type.
623                     callback.onError(new ParcelableException("Unable to get device id"));
624                 } catch (RemoteException e) {
625                     Slog.e(TAG, "getDeviceId() - Unable to send result to the callback", e);
626                 }
627             }
628 
629             @Override
630             public void onError(Exception ex) {
631                 Slog.e(TAG, "Exception: ", ex);
632                 try {
633                     callback.onError(getParcelableException(ex));
634                 } catch (RemoteException e) {
635                     Slog.e(TAG,
636                             "getDeviceId() - " + "Unable to send error to" + " the " + "callback",
637                             e);
638                 }
639             }
640         });
641     }
642 
643     @Override
644     public void getDeviceId(@NonNull IGetDeviceIdCallback callback) {
645         if (!checkCallerPermission()) {
646             try {
647                 callback.onError(new ParcelableException(new SecurityException()));
648             } catch (RemoteException e) {
649                 Slog.e(TAG, "getDeviceId() - Unable to send error to the callback", e);
650             }
651             return;
652         }
653 
654         final StringBuilder errorBuilder = new StringBuilder();
655 
656         final long identity = Binder.clearCallingIdentity();
657         final int deviceIdTypeBitmap = mPackageUtils.getDeviceIdTypeBitmap(errorBuilder);
658         Binder.restoreCallingIdentity(identity);
659 
660         if (deviceIdTypeBitmap < 0) {
661             Slog.e(TAG, "getDeviceId: " + errorBuilder);
662         }
663 
664         getDeviceId(callback, deviceIdTypeBitmap);
665     }
666 
667     @Override
668     public void getKioskApps(@NonNull IGetKioskAppsCallback callback) {
669         // Caller is not necessarily a kiosk app, and no particular permission enforcing is needed.
670 
671         final ArrayMap kioskApps = new ArrayMap<Integer, String>();
672 
673         final UserHandle userHandle = Binder.getCallingUserHandle();
674         final long identity = Binder.clearCallingIdentity();
675         try {
676             List<String> roleHolders = mRoleManager.getRoleHoldersAsUser(
677                     RoleManager.ROLE_FINANCED_DEVICE_KIOSK, userHandle);
678 
679             if (!roleHolders.isEmpty()) {
680                 kioskApps.put(DeviceLockManager.DEVICE_LOCK_ROLE_FINANCING, roleHolders.get(0));
681             }
682 
683             callback.onKioskAppsReceived(kioskApps);
684         } catch (RemoteException e) {
685             Slog.e(TAG, "getKioskApps() - Unable to send result to the callback", e);
686         } finally {
687             Binder.restoreCallingIdentity(identity);
688         }
689     }
690 
691     // For calls from Controller to System Service.
692 
693     private void reportErrorToCaller(@NonNull RemoteCallback remoteCallback) {
694         final Bundle result = new Bundle();
695         result.putBoolean(KEY_REMOTE_CALLBACK_RESULT, false);
696         remoteCallback.sendResult(result);
697     }
698 
699     private boolean checkDeviceLockControllerPermission(@NonNull RemoteCallback remoteCallback) {
700         if (mContext.checkCallingOrSelfPermission(MANAGE_DEVICE_LOCK_SERVICE_FROM_CONTROLLER)
701                 != PERMISSION_GRANTED) {
702             reportErrorToCaller(remoteCallback);
703             return false;
704         }
705 
706         return true;
707     }
708 
709     private void reportResult(boolean accepted, long identity,
710             @NonNull RemoteCallback remoteCallback) {
711         Binder.restoreCallingIdentity(identity);
712 
713         final Bundle result = new Bundle();
714         result.putBoolean(KEY_REMOTE_CALLBACK_RESULT, accepted);
715         remoteCallback.sendResult(result);
716     }
717 
718     private void addFinancedDeviceKioskRoleInternal(@NonNull String packageName,
719             @NonNull RemoteCallback remoteCallback, @NonNull UserHandle userHandle, long identity,
720             int remainingTries) {
721         mRoleManager.addRoleHolderAsUser(RoleManager.ROLE_FINANCED_DEVICE_KIOSK, packageName,
722                 MANAGE_HOLDERS_FLAG_DONT_KILL_APP, userHandle, mContext.getMainExecutor(),
723                 accepted -> {
724                     if (accepted || remainingTries == 1) {
725                         reportResult(accepted, identity, remoteCallback);
726                     } else {
727                         final int retryNumber = MAX_ADD_ROLE_HOLDER_TRIES - remainingTries + 1;
728                         Slog.w(TAG, "Retrying adding financed device role to kiosk app (retry "
729                                 + retryNumber + ")");
730                         addFinancedDeviceKioskRoleInternal(packageName, remoteCallback, userHandle,
731                                 identity, remainingTries - 1);
732                     }
733                 });
734     }
735 
736     @Override
737     public void addFinancedDeviceKioskRole(@NonNull String packageName,
738             @NonNull RemoteCallback remoteCallback) {
739         if (!checkDeviceLockControllerPermission(remoteCallback)) {
740             return;
741         }
742 
743         final UserHandle userHandle = Binder.getCallingUserHandle();
744         final long identity = Binder.clearCallingIdentity();
745 
746         addFinancedDeviceKioskRoleInternal(packageName, remoteCallback, userHandle, identity,
747                 MAX_ADD_ROLE_HOLDER_TRIES);
748 
749         Binder.restoreCallingIdentity(identity);
750     }
751 
752     @Override
753     public void removeFinancedDeviceKioskRole(@NonNull String packageName,
754             @NonNull RemoteCallback remoteCallback) {
755         if (!checkDeviceLockControllerPermission(remoteCallback)) {
756             return;
757         }
758 
759         final UserHandle userHandle = Binder.getCallingUserHandle();
760         final long identity = Binder.clearCallingIdentity();
761 
762         // Clear the FLAG_PERMISSION_GRANTED_BY_ROLE flag from POST_NOTIFICATIONS for the kiosk app
763         // before removing the ROLE_FINANCED_DEVICE_KIOSK role, to prevent the app from being
764         // killed.
765         final PackageManager packageManager = mContext.getPackageManager();
766         packageManager.updatePermissionFlags(permission.POST_NOTIFICATIONS, packageName,
767                 PackageManager.FLAG_PERMISSION_GRANTED_BY_ROLE, /* flagValues= */ 0, userHandle);
768 
769         mRoleManager.removeRoleHolderAsUser(RoleManager.ROLE_FINANCED_DEVICE_KIOSK, packageName,
770                 MANAGE_HOLDERS_FLAG_DONT_KILL_APP, userHandle, mContext.getMainExecutor(),
771                 accepted -> reportResult(accepted, identity, remoteCallback));
772 
773         Binder.restoreCallingIdentity(identity);
774     }
775 
776     /**
777      * @param uid         The uid whose AppOps mode needs to change.
778      * @param packageName The name of the package whose AppOp mode needs to change.
779      * @param appOps      A list of appOps to change
780      * @param allowed     If true, the mode would be set to {@link AppOpsManager#MODE_ALLOWED};
781      *                    false,
782      *                    the mode would be set to {@link AppOpsManager#MODE_DEFAULT}.
783      * @return a boolean value indicates whether the app ops modes have been changed to the
784      * requested value.
785      */
786     private boolean setAppOpsModes(int uid, String packageName, String[] appOps, boolean allowed) {
787         final int mode = allowed ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_DEFAULT;
788 
789         long identity = Binder.clearCallingIdentity();
790         for (String appOp : appOps) {
791             mAppOpsManager.setMode(appOp, uid, packageName, mode);
792         }
793         Binder.restoreCallingIdentity(identity);
794         return true;
795     }
796 
797     /**
798      * Set the exemption state for activity background start restriction for the calling uid.
799      * Caller must hold the {@link MANAGE_DEVICE_LOCK_SERVICE_FROM_CONTROLLER} permission.
800      *
801      * @param exempt if true, the calling uid will be set to exempt from activity background start
802      *               restriction; false, the exemption state will be set to default.
803      */
804     @Override
805     public void setCallerExemptFromActivityBgStartRestrictionState(boolean exempt,
806             @NonNull RemoteCallback remoteCallback) {
807         if (!checkDeviceLockControllerPermission(remoteCallback)) {
808             return;
809         }
810         Bundle result = new Bundle();
811         result.putBoolean(KEY_REMOTE_CALLBACK_RESULT,
812                 setAppOpsModes(Binder.getCallingUid(), mServiceInfo.packageName,
813                         new String[]{OPSTR_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION},
814                         exempt));
815         remoteCallback.sendResult(result);
816     }
817 
818     /**
819      * Set whether the caller is allowed to send undismissible notifications.
820      *
821      * @param allowed true if the caller can send undismissible notifications, false otherwise
822      */
823     @Override
824     public void setCallerAllowedToSendUndismissibleNotifications(boolean allowed,
825             @NonNull RemoteCallback remoteCallback) {
826         if (!checkDeviceLockControllerPermission(remoteCallback)) {
827             return;
828         }
829         Bundle result = new Bundle();
830         result.putBoolean(KEY_REMOTE_CALLBACK_RESULT,
831                 setAppOpsModes(Binder.getCallingUid(), mServiceInfo.packageName,
832                         new String[]{OPSTR_SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS}, allowed));
833         remoteCallback.sendResult(result);
834     }
835 
836     /**
837      * @param uid   The uid whose network policy needs to change.
838      * @param allow whether to allow background data usage in metered data mode.
839      * @return a boolean value indicates whether the policy change is a success.
840      */
841     private boolean setNetworkPolicyForUid(int uid, boolean allow) {
842         boolean result;
843         long caller = Binder.clearCallingIdentity();
844         try {
845             // TODO(b/319266027): Figure out a long term solution instead of using reflection here.
846             NetworkPolicyManager networkPolicyManager = mContext.getSystemService(
847                     NetworkPolicyManager.class);
848             NetworkPolicyManager.class.getDeclaredMethod("setUidPolicy", Integer.TYPE,
849                     Integer.TYPE).invoke(networkPolicyManager, uid,
850                     allow ? POLICY_ALLOW_METERED_BACKGROUND : POLICY_NONE);
851             result = true;
852         } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
853             Slog.e(TAG, "Failed to exempt data usage for given uid: " + uid, e);
854             result = false;
855         }
856         Binder.restoreCallingIdentity(caller);
857         return result;
858     }
859 
860     private boolean setPowerExemptionForPackage(String packageName, boolean allow) {
861         boolean result;
862         long caller = Binder.clearCallingIdentity();
863         try {
864             // TODO(b/321539640): Figure out a long term solution instead of using reflection here.
865             PowerExemptionManager powerExemptionManager = mContext.getSystemService(
866                     PowerExemptionManager.class);
867             String methodName = allow ? "addToPermanentAllowList" : "removeFromPermanentAllowList";
868             PowerExemptionManager.class.getDeclaredMethod(methodName, String.class).invoke(
869                     powerExemptionManager, packageName);
870             result = true;
871         } catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {
872             Slog.e(TAG, "Failed to exempt power usage for given package: " + packageName, e);
873             result = false;
874         }
875         Binder.restoreCallingIdentity(caller);
876         return result;
877     }
878 
879     /**
880      * Set the exemption state for app restrictions(e.g. hibernation, battery and data usage
881      * restriction) for the given uid
882      * Caller must hold the {@link MANAGE_DEVICE_LOCK_SERVICE_FROM_CONTROLLER} permission.
883      *
884      * @param exempt if true, the given uid will be set to exempt from hibernation, battery and data
885      *               usage restriction; false, the exemption state will be set to default.
886      */
887     @Override
888     public void setUidExemptFromRestrictionsState(int uid, boolean exempt,
889             @NonNull RemoteCallback remoteCallback) {
890         if (!checkDeviceLockControllerPermission(remoteCallback)) {
891             return;
892         }
893         boolean setAppOpsResult = false;
894         boolean setPowerExemptionResult = false;
895 
896         String[] packageNames = mContext.getPackageManager().getPackagesForUid(uid);
897         if (packageNames == null || packageNames.length < 1) {
898             Slog.e(TAG, "Can not find package name for given uid: " + uid);
899         } else {
900             setAppOpsResult = setAppOpsModes(uid, packageNames[0],
901                     new String[]{OPSTR_SYSTEM_EXEMPT_FROM_HIBERNATION,
902                             OPSTR_SYSTEM_EXEMPT_FROM_POWER_RESTRICTIONS}, exempt);
903             setPowerExemptionResult = setPowerExemptionForPackage(packageNames[0], exempt);
904         }
905         boolean setNetworkPolicyResult = setNetworkPolicyForUid(uid, exempt);
906         Bundle result = new Bundle();
907         result.putBoolean(KEY_REMOTE_CALLBACK_RESULT,
908                 setAppOpsResult && setPowerExemptionResult && setNetworkPolicyResult);
909         remoteCallback.sendResult(result);
910     }
911 
912     private class KeepaliveServiceConnection implements ServiceConnection {
913         final boolean mIsKiosk;
914         final String mPackageName;
915         final UserHandle mUserHandle;
916 
917         final Intent mService;
918 
919         KeepaliveServiceConnection(boolean isKiosk, String packageName, UserHandle userHandle) {
920             super();
921             mIsKiosk = isKiosk;
922             mPackageName = packageName;
923             mUserHandle = userHandle;
924             mService = new Intent(ACTION_DEVICE_LOCK_KEEPALIVE).setPackage(packageName);
925         }
926 
927         private boolean bind() {
928             return mContext.bindServiceAsUser(mService, this, Context.BIND_AUTO_CREATE,
929                     mUserHandle);
930         }
931 
932         private boolean rebind() {
933             mContext.unbindService(this);
934             boolean bound = bind();
935 
936             if (bound) {
937                 getDeviceLockControllerConnector(mUserHandle).onAppCrashed(mIsKiosk,
938                         new OutcomeReceiver<>() {
939                             @Override
940                             public void onResult(Void result) {
941                                 Slog.i(TAG,
942                                         "Notified controller about " + mPackageName + " crash");
943                             }
944 
945                             @Override
946                             public void onError(Exception ex) {
947                                 Slog.e(TAG, "On " + mPackageName + " crashed error: ", ex);
948                             }
949                         });
950             }
951 
952             return bound;
953         }
954 
955         @Override
956         public void onServiceConnected(ComponentName name, IBinder service) {
957             Slog.i(TAG, mPackageName + " keepalive successful for user " + mUserHandle);
958         }
959 
960         @Override
961         public void onServiceDisconnected(ComponentName name) {
962             if (rebind()) {
963                 Slog.i(TAG,
964                         "onServiceDisconnected rebind successful for " + mPackageName + " user "
965                                 + mUserHandle);
966             } else {
967                 Slog.e(TAG, "onServiceDisconnected rebind failed for " + mPackageName + " user "
968                         + mUserHandle);
969             }
970         }
971 
972         @Override
973         public void onBindingDied(ComponentName name) {
974             ServiceConnection.super.onBindingDied(name);
975             if (rebind()) {
976                 Slog.i(TAG, "onBindingDied rebind successful for " + mPackageName + " user "
977                         + mUserHandle);
978             } else {
979                 Slog.e(TAG,
980                         "onBindingDied rebind failed for " + mPackageName + " user "
981                                 + mUserHandle);
982             }
983         }
984     }
985 
986     @Override
987     public void enableKioskKeepalive(String packageName, @NonNull RemoteCallback remoteCallback) {
988         enableKeepalive(true /* forKiosk */, packageName, remoteCallback);
989     }
990 
991     @Override
992     public void disableKioskKeepalive(@NonNull RemoteCallback remoteCallback) {
993         disableKeepalive(true /* forKiosk */, remoteCallback);
994     }
995 
996     @Override
997     public void enableControllerKeepalive(@NonNull RemoteCallback remoteCallback) {
998         enableKeepalive(false /* forKiosk */, mServiceInfo.packageName, remoteCallback);
999     }
1000 
1001     @Override
1002     public void disableControllerKeepalive(@NonNull RemoteCallback remoteCallback) {
1003         disableKeepalive(false /* forKiosk */, remoteCallback);
1004     }
1005 
1006     private void enableKeepalive(boolean forKiosk, String packageName,
1007             @NonNull RemoteCallback remoteCallback) {
1008         final UserHandle controllerUserHandle = Binder.getCallingUserHandle();
1009         final int controllerUserId = controllerUserHandle.getIdentifier();
1010         boolean keepaliveEnabled = false;
1011         final ArrayMap<Integer, KeepaliveServiceConnection> keepaliveServiceConnections =
1012                 forKiosk ? mKioskKeepaliveServiceConnections
1013                         : mControllerKeepaliveServiceConnections;
1014 
1015         synchronized (this) {
1016             if (keepaliveServiceConnections.get(controllerUserId) == null) {
1017                 final KeepaliveServiceConnection serviceConnection =
1018                         new KeepaliveServiceConnection(
1019                                 forKiosk, packageName, controllerUserHandle);
1020                 final long identity = Binder.clearCallingIdentity();
1021                 if (serviceConnection.bind()) {
1022                     keepaliveServiceConnections.put(controllerUserId, serviceConnection);
1023                     keepaliveEnabled = true;
1024                 } else {
1025                     Slog.w(TAG, "enableKeepalive: failed to bind to keepalive service "
1026                             + " for package: " + packageName + " user:" + controllerUserHandle);
1027                     mContext.unbindService(serviceConnection);
1028                 }
1029                 Binder.restoreCallingIdentity(identity);
1030             } else {
1031                 // Consider success if we already have an entry for this user id.
1032                 keepaliveEnabled = true;
1033             }
1034         }
1035 
1036         final Bundle result = new Bundle();
1037         result.putBoolean(KEY_REMOTE_CALLBACK_RESULT, keepaliveEnabled);
1038         remoteCallback.sendResult(result);
1039     }
1040 
1041     private void disableKeepalive(boolean isKiosk, @NonNull RemoteCallback remoteCallback) {
1042         final UserHandle controllerUserHandle = Binder.getCallingUserHandle();
1043         final int controllerUserId = controllerUserHandle.getIdentifier();
1044         final KeepaliveServiceConnection serviceConnection;
1045         final ArrayMap<Integer, KeepaliveServiceConnection> keepaliveServiceConnections =
1046                 isKiosk ? mKioskKeepaliveServiceConnections
1047                         : mControllerKeepaliveServiceConnections;
1048 
1049         synchronized (this) {
1050             serviceConnection = keepaliveServiceConnections.remove(controllerUserId);
1051         }
1052 
1053         if (serviceConnection != null) {
1054             final long identity = Binder.clearCallingIdentity();
1055             mContext.unbindService(serviceConnection);
1056             Binder.restoreCallingIdentity(identity);
1057         } else {
1058             final String target = isKiosk ? "kiosk" : "controller";
1059             Slog.e(TAG,
1060                     "disableKeepalive: Service connection to " + target
1061                             + " not found for user: "
1062                             + controllerUserHandle);
1063         }
1064 
1065         final Bundle result = new Bundle();
1066         result.putBoolean(KEY_REMOTE_CALLBACK_RESULT, serviceConnection != null);
1067         remoteCallback.sendResult(result);
1068     }
1069 
1070     @Override
1071     public void setDeviceFinalized(boolean finalized, @NonNull RemoteCallback remoteCallback) {
1072         mPersistentStore.scheduleWrite(finalized);
1073         UserHandle user = getCallingUserHandle();
1074         if (canDlcBeDisabledForFinalizedUser(user)) {
1075             setDeviceLockControllerPackageEnabledState(user, false);
1076             Slog.d(TAG, "Device finalized for user " + user + ". Disabling DLC.");
1077         }
1078 
1079         final Bundle result = new Bundle();
1080         result.putBoolean(KEY_REMOTE_CALLBACK_RESULT, true);
1081         remoteCallback.sendResult(result);
1082     }
1083 
1084     @Override
1085     public void setPostNotificationsSystemFixed(boolean systemFixed,
1086             @NonNull RemoteCallback remoteCallback) {
1087         final UserHandle userHandle = Binder.getCallingUserHandle();
1088         final PackageManager packageManager = mContext.getPackageManager();
1089         final int permissionFlags = PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
1090         final int newFlagValues = systemFixed ? permissionFlags : 0;
1091         final long identity = Binder.clearCallingIdentity();
1092         // Make sure permission hasn't been revoked.
1093         packageManager.grantRuntimePermission(mServiceInfo.packageName,
1094                 permission.POST_NOTIFICATIONS, userHandle);
1095         packageManager.updatePermissionFlags(permission.POST_NOTIFICATIONS,
1096                 mServiceInfo.packageName, permissionFlags, newFlagValues,
1097                 userHandle);
1098         Binder.restoreCallingIdentity(identity);
1099 
1100         final Bundle result = new Bundle();
1101         result.putBoolean(KEY_REMOTE_CALLBACK_RESULT, true);
1102         remoteCallback.sendResult(result);
1103     }
1104 }
1105