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