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.devicelockcontroller; 18 19 import android.app.Service; 20 import android.app.admin.DevicePolicyManager; 21 import android.content.Intent; 22 import android.content.pm.PackageManager; 23 import android.devicelock.ParcelableException; 24 import android.os.Bundle; 25 import android.os.IBinder; 26 import android.os.RemoteCallback; 27 28 import androidx.annotation.NonNull; 29 import androidx.annotation.Nullable; 30 31 import com.android.devicelockcontroller.policy.DevicePolicyController; 32 import com.android.devicelockcontroller.policy.DeviceStateController; 33 import com.android.devicelockcontroller.policy.FinalizationController; 34 import com.android.devicelockcontroller.policy.PolicyObjectsProvider; 35 import com.android.devicelockcontroller.stats.StatsLogger; 36 import com.android.devicelockcontroller.stats.StatsLoggerProvider; 37 import com.android.devicelockcontroller.storage.GlobalParametersClient; 38 import com.android.devicelockcontroller.storage.SetupParametersClient; 39 import com.android.devicelockcontroller.util.LogUtil; 40 41 import com.google.common.util.concurrent.FutureCallback; 42 import com.google.common.util.concurrent.Futures; 43 import com.google.common.util.concurrent.ListenableFuture; 44 import com.google.common.util.concurrent.MoreExecutors; 45 46 import java.util.List; 47 import java.util.Objects; 48 49 /** 50 * Device Lock Controller Service. This is hosted in an APK and is bound 51 * by the Device Lock System Service. 52 */ 53 public final class DeviceLockControllerService extends Service { 54 private static final String TAG = "DeviceLockControllerService"; 55 private DeviceStateController mDeviceStateController; 56 private DevicePolicyController mPolicyController; 57 private FinalizationController mFinalizationController; 58 private PackageManager mPackageManager; 59 private StatsLogger mStatsLogger; 60 61 private final IDeviceLockControllerService.Stub mBinder = 62 new IDeviceLockControllerService.Stub() { 63 @Override 64 public void lockDevice(RemoteCallback remoteCallback) { 65 logKioskAppRequest(); 66 ListenableFuture<Void> lockDeviceFuture = mDeviceStateController.lockDevice(); 67 Futures.addCallback(lockDeviceFuture, 68 remoteCallbackWrapper(remoteCallback), 69 MoreExecutors.directExecutor()); 70 Futures.addCallback(lockDeviceFuture, 71 logLockUnlockDeviceCallback(/* isLockDevice = */ true), 72 MoreExecutors.directExecutor()); 73 } 74 75 @Override 76 public void unlockDevice(RemoteCallback remoteCallback) { 77 logKioskAppRequest(); 78 ListenableFuture<Void> unlockDeviceFuture = 79 mDeviceStateController.unlockDevice(); 80 Futures.addCallback(unlockDeviceFuture, 81 remoteCallbackWrapper(remoteCallback), 82 MoreExecutors.directExecutor()); 83 Futures.addCallback(unlockDeviceFuture, 84 logLockUnlockDeviceCallback(/* isLockDevice = */ false), 85 MoreExecutors.directExecutor()); 86 } 87 88 @Override 89 public void isDeviceLocked(RemoteCallback remoteCallback) { 90 logKioskAppRequest(); 91 Futures.addCallback(mDeviceStateController.isLocked(), 92 remoteCallbackWrapper(remoteCallback, KEY_RESULT), 93 MoreExecutors.directExecutor()); 94 } 95 96 @Override 97 public void getDeviceIdentifier(RemoteCallback remoteCallback) { 98 logKioskAppRequest(); 99 Futures.addCallback( 100 GlobalParametersClient.getInstance().getRegisteredDeviceId(), 101 remoteCallbackWrapper(remoteCallback, KEY_RESULT), 102 MoreExecutors.directExecutor()); 103 } 104 105 @Override 106 public void clearDeviceRestrictions(RemoteCallback remoteCallback) { 107 logKioskAppRequest(); 108 Futures.addCallback( 109 Futures.transformAsync(mDeviceStateController.clearDevice(), 110 unused -> mFinalizationController.notifyRestrictionsCleared(), 111 MoreExecutors.directExecutor()), 112 remoteCallbackWrapper(remoteCallback), 113 MoreExecutors.directExecutor()); 114 } 115 116 @Override 117 public void onUserSwitching(RemoteCallback remoteCallback) { 118 Futures.addCallback( 119 Futures.transformAsync(mPolicyController.enforceCurrentPolicies(), 120 // Force read from disk in case it progressed on the other user 121 unused -> mFinalizationController.enforceDiskState( 122 /* force= */ true), 123 MoreExecutors.directExecutor()), 124 remoteCallbackWrapper(remoteCallback), 125 MoreExecutors.directExecutor()); 126 } 127 128 @Override 129 public void onUserUnlocked(RemoteCallback remoteCallback) { 130 DevicePolicyManager dpm = getSystemService(DevicePolicyManager.class); 131 Objects.requireNonNull(dpm).setUserControlDisabledPackages( 132 /* admin= */ null, 133 List.of(getPackageName())); 134 Futures.addCallback(mPolicyController.onUserUnlocked(), 135 remoteCallbackWrapper(remoteCallback), 136 MoreExecutors.directExecutor()); 137 } 138 139 @Override 140 public void onUserSetupCompleted(RemoteCallback remoteCallback) { 141 Futures.addCallback(mPolicyController.onUserSetupCompleted(), 142 remoteCallbackWrapper(remoteCallback), 143 MoreExecutors.directExecutor()); 144 } 145 146 @Override 147 public void onAppCrashed(boolean isKiosk, RemoteCallback remoteCallback) { 148 Futures.addCallback(mPolicyController.onAppCrashed(isKiosk), 149 remoteCallbackWrapper(remoteCallback), 150 MoreExecutors.directExecutor()); 151 } 152 153 private void logKioskAppRequest() { 154 Futures.addCallback(SetupParametersClient.getInstance().getKioskPackage(), 155 new FutureCallback<>() { 156 @Override 157 public void onSuccess(String result) { 158 try { 159 final int uid = mPackageManager.getPackageUid( 160 result, /* flags= */ 0); 161 mStatsLogger.logKioskAppRequest(uid); 162 } catch (PackageManager.NameNotFoundException e) { 163 LogUtil.e(TAG, "Kiosk App package name not found", e); 164 } 165 } 166 167 @Override 168 public void onFailure(Throwable t) { 169 LogUtil.e(TAG, "Failed to get Kiosk app package name", t); 170 } 171 }, 172 MoreExecutors.directExecutor()); 173 174 } 175 }; 176 177 @NonNull remoteCallbackWrapper(RemoteCallback remoteCallback, @Nullable final String key)178 private static FutureCallback<Object> remoteCallbackWrapper(RemoteCallback remoteCallback, 179 @Nullable final String key) { 180 return new FutureCallback<>() { 181 @Override 182 public void onSuccess(Object result) { 183 sendResult(key, remoteCallback, result); 184 } 185 186 @Override 187 public void onFailure(Throwable t) { 188 LogUtil.e(TAG, "Failed to perform the request", t); 189 sendFailure(t, remoteCallback); 190 } 191 }; 192 } 193 194 @NonNull 195 private static FutureCallback<Object> remoteCallbackWrapper(RemoteCallback remoteCallback) { 196 return remoteCallbackWrapper(remoteCallback, /* key= */ null); 197 } 198 199 /** 200 * Send result to caller. 201 * 202 * @param key Key to use in bundle for result. null if no result is needed 203 * @param remoteCallback remote callback used to send the result. 204 * @param result Value to return in bundle. 205 */ 206 private static void sendResult(@Nullable String key, RemoteCallback remoteCallback, 207 Object result) { 208 final Bundle bundle = new Bundle(); 209 if (key != null) { 210 if (result instanceof Boolean) { 211 bundle.putBoolean(key, (Boolean) result); 212 } else if (result instanceof String) { 213 bundle.putString(key, (String) result); 214 } 215 } 216 remoteCallback.sendResult(bundle); 217 } 218 219 private static void sendFailure(Throwable t, RemoteCallback remoteCallback) { 220 final Bundle bundle = new Bundle(); 221 bundle.putParcelable(IDeviceLockControllerService.KEY_PARCELABLE_EXCEPTION, 222 new ParcelableException(t instanceof Exception ? (Exception) t : new Exception(t))); 223 remoteCallback.sendResult(bundle); 224 } 225 226 private FutureCallback<Void> logLockUnlockDeviceCallback(boolean isLockDevice) { 227 return new FutureCallback<Void>() { 228 @Override 229 public void onSuccess(Void result) { 230 if (isLockDevice) { 231 mStatsLogger.logSuccessfulLockingDevice(); 232 } else { 233 mStatsLogger.logSuccessfulUnlockingDevice(); 234 } 235 } 236 237 @Override 238 public void onFailure(Throwable t) { 239 Futures.addCallback(mDeviceStateController.getDeviceState(), 240 new FutureCallback<Integer>() { 241 @Override 242 public void onSuccess(Integer result) { 243 int deviceStatePostCommand; 244 switch (result) { 245 case DeviceStateController.DeviceState.UNLOCKED -> 246 deviceStatePostCommand = 247 StatsLogger.DeviceStateStats.UNLOCKED; 248 case DeviceStateController.DeviceState.LOCKED -> 249 deviceStatePostCommand = 250 StatsLogger.DeviceStateStats.LOCKED; 251 case DeviceStateController.DeviceState.CLEARED -> 252 deviceStatePostCommand = 253 StatsLogger.DeviceStateStats.CLEARED; 254 case DeviceStateController.DeviceState.UNDEFINED -> 255 deviceStatePostCommand = 256 StatsLogger.DeviceStateStats.UNDEFINED; 257 default -> deviceStatePostCommand = 258 StatsLogger.DeviceStateStats.UNDEFINED; 259 } 260 if (isLockDevice) { 261 mStatsLogger.logLockDeviceFailure(deviceStatePostCommand); 262 } else { 263 mStatsLogger.logUnlockDeviceFailure(deviceStatePostCommand); 264 } 265 } 266 267 // We don't expect this to be reached 268 @Override 269 public void onFailure(Throwable t) { 270 LogUtil.e(TAG, "Failed to get device State", t); 271 throw new RuntimeException(t); 272 } 273 }, MoreExecutors.directExecutor()); 274 } 275 }; 276 } 277 278 @Override 279 public void onCreate() { 280 LogUtil.d(TAG, "onCreate"); 281 282 final PolicyObjectsProvider policyObjects = (PolicyObjectsProvider) getApplication(); 283 final StatsLoggerProvider statsLoggerProvider = (StatsLoggerProvider) getApplication(); 284 mDeviceStateController = policyObjects.getDeviceStateController(); 285 mPolicyController = policyObjects.getPolicyController(); 286 mFinalizationController = policyObjects.getFinalizationController(); 287 mPackageManager = getPackageManager(); 288 mStatsLogger = statsLoggerProvider.getStatsLogger(); 289 } 290 291 @Override 292 public IBinder onBind(Intent intent) { 293 return mBinder; 294 } 295 } 296