TrustAgentService.java revision 327323d2b337077433fe02438a79cc98e91799e3
1/** 2 * Copyright (C) 2014 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 17package android.service.trust; 18 19import android.Manifest; 20import android.annotation.IntDef; 21import android.annotation.SdkConstant; 22import android.annotation.SystemApi; 23import android.app.Service; 24import android.app.admin.DevicePolicyManager; 25import android.content.ComponentName; 26import android.content.Intent; 27import android.content.pm.PackageManager; 28import android.content.pm.ServiceInfo; 29import android.os.Handler; 30import android.os.IBinder; 31import android.os.PersistableBundle; 32import android.os.RemoteException; 33import android.util.Log; 34import android.util.Slog; 35 36import java.lang.annotation.Retention; 37import java.lang.annotation.RetentionPolicy; 38import java.util.List; 39 40/** 41 * A service that notifies the system about whether it believes the environment of the device 42 * to be trusted. 43 * 44 * <p>Trust agents may only be provided by the platform. It is expected that there is only 45 * one trust agent installed on the platform. In the event there is more than one, 46 * either trust agent can enable trust. 47 * </p> 48 * 49 * <p>To extend this class, you must declare the service in your manifest file with 50 * the {@link android.Manifest.permission#BIND_TRUST_AGENT} permission 51 * and include an intent filter with the {@link #SERVICE_INTERFACE} action. For example:</p> 52 * <pre> 53 * <service android:name=".TrustAgent" 54 * android:label="@string/service_name" 55 * android:permission="android.permission.BIND_TRUST_AGENT"> 56 * <intent-filter> 57 * <action android:name="android.service.trust.TrustAgentService" /> 58 * </intent-filter> 59 * <meta-data android:name="android.service.trust.trustagent" 60 * android:value="@xml/trust_agent" /> 61 * </service></pre> 62 * 63 * <p>The associated meta-data file can specify an activity that is accessible through Settings 64 * and should allow configuring the trust agent, as defined in 65 * {@link android.R.styleable#TrustAgent}. For example:</p> 66 * 67 * <pre> 68 * <trust-agent xmlns:android="http://schemas.android.com/apk/res/android" 69 * android:settingsActivity=".TrustAgentSettings" /></pre> 70 * 71 * @hide 72 */ 73@SystemApi 74public class TrustAgentService extends Service { 75 76 private final String TAG = TrustAgentService.class.getSimpleName() + 77 "[" + getClass().getSimpleName() + "]"; 78 private static final boolean DEBUG = false; 79 80 /** 81 * The {@link Intent} that must be declared as handled by the service. 82 */ 83 @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION) 84 public static final String SERVICE_INTERFACE 85 = "android.service.trust.TrustAgentService"; 86 87 /** 88 * The name of the {@code meta-data} tag pointing to additional configuration of the trust 89 * agent. 90 */ 91 public static final String TRUST_AGENT_META_DATA = "android.service.trust.trustagent"; 92 93 94 /** 95 * Flag for {@link #grantTrust(CharSequence, long, int)} indicating that trust is being granted 96 * as the direct result of user action - such as solving a security challenge. The hint is used 97 * by the system to optimize the experience. Behavior may vary by device and release, so 98 * one should only set this parameter if it meets the above criteria rather than relying on 99 * the behavior of any particular device or release. 100 */ 101 public static final int FLAG_GRANT_TRUST_INITIATED_BY_USER = 1 << 0; 102 103 /** 104 * Flag for {@link #grantTrust(CharSequence, long, int)} indicating that the agent would like 105 * to dismiss the keyguard. When using this flag, the {@code TrustAgentService} must ensure 106 * it is only set in response to a direct user action with the expectation of dismissing the 107 * keyguard. 108 */ 109 public static final int FLAG_GRANT_TRUST_DISMISS_KEYGUARD = 1 << 1; 110 111 /** @hide */ 112 @Retention(RetentionPolicy.SOURCE) 113 @IntDef(flag = true, 114 value = { 115 FLAG_GRANT_TRUST_INITIATED_BY_USER, 116 FLAG_GRANT_TRUST_DISMISS_KEYGUARD, 117 }) 118 public @interface GrantTrustFlags {} 119 120 121 private static final int MSG_UNLOCK_ATTEMPT = 1; 122 private static final int MSG_CONFIGURE = 2; 123 private static final int MSG_TRUST_TIMEOUT = 3; 124 private static final int MSG_DEVICE_LOCKED = 4; 125 private static final int MSG_DEVICE_UNLOCKED = 5; 126 private static final int MSG_UNLOCK_LOCKOUT = 6; 127 128 /** 129 * Class containing raw data for a given configuration request. 130 */ 131 private static final class ConfigurationData { 132 final IBinder token; 133 final List<PersistableBundle> options; 134 ConfigurationData(List<PersistableBundle> opts, IBinder t) { 135 options = opts; 136 token = t; 137 } 138 } 139 140 private ITrustAgentServiceCallback mCallback; 141 142 private Runnable mPendingGrantTrustTask; 143 144 private boolean mManagingTrust; 145 146 // Lock used to access mPendingGrantTrustTask and mCallback. 147 private final Object mLock = new Object(); 148 149 private Handler mHandler = new Handler() { 150 public void handleMessage(android.os.Message msg) { 151 switch (msg.what) { 152 case MSG_UNLOCK_ATTEMPT: 153 onUnlockAttempt(msg.arg1 != 0); 154 break; 155 case MSG_UNLOCK_LOCKOUT: 156 onDeviceUnlockLockout(msg.arg1); 157 break; 158 case MSG_CONFIGURE: 159 ConfigurationData data = (ConfigurationData) msg.obj; 160 boolean result = onConfigure(data.options); 161 if (data.token != null) { 162 try { 163 synchronized (mLock) { 164 mCallback.onConfigureCompleted(result, data.token); 165 } 166 } catch (RemoteException e) { 167 onError("calling onSetTrustAgentFeaturesEnabledCompleted()"); 168 } 169 } 170 break; 171 case MSG_TRUST_TIMEOUT: 172 onTrustTimeout(); 173 break; 174 case MSG_DEVICE_LOCKED: 175 onDeviceLocked(); 176 break; 177 case MSG_DEVICE_UNLOCKED: 178 onDeviceUnlocked(); 179 break; 180 } 181 } 182 }; 183 184 @Override 185 public void onCreate() { 186 super.onCreate(); 187 ComponentName component = new ComponentName(this, getClass()); 188 try { 189 ServiceInfo serviceInfo = getPackageManager().getServiceInfo(component, 0 /* flags */); 190 if (!Manifest.permission.BIND_TRUST_AGENT.equals(serviceInfo.permission)) { 191 throw new IllegalStateException(component.flattenToShortString() 192 + " is not declared with the permission " 193 + "\"" + Manifest.permission.BIND_TRUST_AGENT + "\""); 194 } 195 } catch (PackageManager.NameNotFoundException e) { 196 Log.e(TAG, "Can't get ServiceInfo for " + component.toShortString()); 197 } 198 } 199 200 /** 201 * Called after the user attempts to authenticate in keyguard with their device credentials, 202 * such as pin, pattern or password. 203 * 204 * @param successful true if the user successfully completed the challenge. 205 */ 206 public void onUnlockAttempt(boolean successful) { 207 } 208 209 /** 210 * Called when the timeout provided by the agent expires. Note that this may be called earlier 211 * than requested by the agent if the trust timeout is adjusted by the system or 212 * {@link DevicePolicyManager}. The agent is expected to re-evaluate the trust state and only 213 * call {@link #grantTrust(CharSequence, long, boolean)} if the trust state should be 214 * continued. 215 */ 216 public void onTrustTimeout() { 217 } 218 219 /** 220 * Called when the device enters a state where a PIN, pattern or 221 * password must be entered to unlock it. 222 */ 223 public void onDeviceLocked() { 224 } 225 226 /** 227 * Called when the device leaves a state where a PIN, pattern or 228 * password must be entered to unlock it. 229 */ 230 public void onDeviceUnlocked() { 231 } 232 233 /** 234 * Called when the device enters a temporary unlock lockout. 235 * 236 * <p>This occurs when the user has consecutively failed to unlock the device too many times, 237 * and must wait until a timeout has passed to perform another attempt. The user may then only 238 * use strong authentication mechanisms (PIN, pattern or password) to unlock the device. 239 * Calls to {@link #grantTrust(CharSequence, long, int)} will be ignored until the user has 240 * unlocked the device and {@link #onDeviceUnlocked()} is called. 241 * 242 * @param timeoutMs The amount of time, in milliseconds, that needs to elapse before the user 243 * can attempt to unlock the device again. 244 */ 245 public void onDeviceUnlockLockout(long timeoutMs) { 246 } 247 248 private void onError(String msg) { 249 Slog.v(TAG, "Remote exception while " + msg); 250 } 251 252 /** 253 * Called when device policy admin wants to enable specific options for agent in response to 254 * {@link DevicePolicyManager#setKeyguardDisabledFeatures(ComponentName, int)} and 255 * {@link DevicePolicyManager#setTrustAgentConfiguration(ComponentName, ComponentName, 256 * PersistableBundle)}. 257 * <p>Agents that support configuration options should overload this method and return 'true'. 258 * 259 * @param options The aggregated list of options or an empty list if no restrictions apply. 260 * @return true if the {@link TrustAgentService} supports configuration options. 261 */ 262 public boolean onConfigure(List<PersistableBundle> options) { 263 return false; 264 } 265 266 /** 267 * Call to grant trust on the device. 268 * 269 * @param message describes why the device is trusted, e.g. "Trusted by location". 270 * @param durationMs amount of time in milliseconds to keep the device in a trusted state. 271 * Trust for this agent will automatically be revoked when the timeout expires unless 272 * extended by a subsequent call to this function. The timeout is measured from the 273 * invocation of this function as dictated by {@link SystemClock#elapsedRealtime())}. 274 * For security reasons, the value should be no larger than necessary. 275 * The value may be adjusted by the system as necessary to comply with a policy controlled 276 * by the system or {@link DevicePolicyManager} restrictions. See {@link #onTrustTimeout()} 277 * for determining when trust expires. 278 * @param initiatedByUser this is a hint to the system that trust is being granted as the 279 * direct result of user action - such as solving a security challenge. The hint is used 280 * by the system to optimize the experience. Behavior may vary by device and release, so 281 * one should only set this parameter if it meets the above criteria rather than relying on 282 * the behavior of any particular device or release. Corresponds to 283 * {@link #FLAG_GRANT_TRUST_INITIATED_BY_USER}. 284 * @throws IllegalStateException if the agent is not currently managing trust. 285 * 286 * @deprecated use {@link #grantTrust(CharSequence, long, int)} instead. 287 */ 288 @Deprecated 289 public final void grantTrust( 290 final CharSequence message, final long durationMs, final boolean initiatedByUser) { 291 grantTrust(message, durationMs, initiatedByUser ? FLAG_GRANT_TRUST_INITIATED_BY_USER : 0); 292 } 293 294 /** 295 * Call to grant trust on the device. 296 * 297 * @param message describes why the device is trusted, e.g. "Trusted by location". 298 * @param durationMs amount of time in milliseconds to keep the device in a trusted state. 299 * Trust for this agent will automatically be revoked when the timeout expires unless 300 * extended by a subsequent call to this function. The timeout is measured from the 301 * invocation of this function as dictated by {@link SystemClock#elapsedRealtime())}. 302 * For security reasons, the value should be no larger than necessary. 303 * The value may be adjusted by the system as necessary to comply with a policy controlled 304 * by the system or {@link DevicePolicyManager} restrictions. See {@link #onTrustTimeout()} 305 * for determining when trust expires. 306 * @param flags TBDocumented 307 * @throws IllegalStateException if the agent is not currently managing trust. 308 */ 309 public final void grantTrust( 310 final CharSequence message, final long durationMs, @GrantTrustFlags final int flags) { 311 synchronized (mLock) { 312 if (!mManagingTrust) { 313 throw new IllegalStateException("Cannot grant trust if agent is not managing trust." 314 + " Call setManagingTrust(true) first."); 315 } 316 if (mCallback != null) { 317 try { 318 mCallback.grantTrust(message.toString(), durationMs, flags); 319 } catch (RemoteException e) { 320 onError("calling enableTrust()"); 321 } 322 } else { 323 // Remember trust has been granted so we can effectively grant it once the service 324 // is bound. 325 mPendingGrantTrustTask = new Runnable() { 326 @Override 327 public void run() { 328 grantTrust(message, durationMs, flags); 329 } 330 }; 331 } 332 } 333 } 334 335 /** 336 * Call to revoke trust on the device. 337 */ 338 public final void revokeTrust() { 339 synchronized (mLock) { 340 if (mPendingGrantTrustTask != null) { 341 mPendingGrantTrustTask = null; 342 } 343 if (mCallback != null) { 344 try { 345 mCallback.revokeTrust(); 346 } catch (RemoteException e) { 347 onError("calling revokeTrust()"); 348 } 349 } 350 } 351 } 352 353 /** 354 * Call to notify the system if the agent is ready to manage trust. 355 * 356 * This property is not persistent across recreating the service and defaults to false. 357 * Therefore this method is typically called when initializing the agent in {@link #onCreate}. 358 * 359 * @param managingTrust indicates if the agent would like to manage trust. 360 */ 361 public final void setManagingTrust(boolean managingTrust) { 362 synchronized (mLock) { 363 if (mManagingTrust != managingTrust) { 364 mManagingTrust = managingTrust; 365 if (mCallback != null) { 366 try { 367 mCallback.setManagingTrust(managingTrust); 368 } catch (RemoteException e) { 369 onError("calling setManagingTrust()"); 370 } 371 } 372 } 373 } 374 } 375 376 @Override 377 public final IBinder onBind(Intent intent) { 378 if (DEBUG) Slog.v(TAG, "onBind() intent = " + intent); 379 return new TrustAgentServiceWrapper(); 380 } 381 382 private final class TrustAgentServiceWrapper extends ITrustAgentService.Stub { 383 @Override /* Binder API */ 384 public void onUnlockAttempt(boolean successful) { 385 mHandler.obtainMessage(MSG_UNLOCK_ATTEMPT, successful ? 1 : 0, 0).sendToTarget(); 386 } 387 388 @Override 389 public void onUnlockLockout(int timeoutMs) { 390 mHandler.obtainMessage(MSG_UNLOCK_LOCKOUT, timeoutMs, 0).sendToTarget(); 391 } 392 393 @Override /* Binder API */ 394 public void onTrustTimeout() { 395 mHandler.sendEmptyMessage(MSG_TRUST_TIMEOUT); 396 } 397 398 @Override /* Binder API */ 399 public void onConfigure(List<PersistableBundle> args, IBinder token) { 400 mHandler.obtainMessage(MSG_CONFIGURE, new ConfigurationData(args, token)) 401 .sendToTarget(); 402 } 403 404 @Override 405 public void onDeviceLocked() throws RemoteException { 406 mHandler.obtainMessage(MSG_DEVICE_LOCKED).sendToTarget(); 407 } 408 409 @Override 410 public void onDeviceUnlocked() throws RemoteException { 411 mHandler.obtainMessage(MSG_DEVICE_UNLOCKED).sendToTarget(); 412 } 413 414 @Override /* Binder API */ 415 public void setCallback(ITrustAgentServiceCallback callback) { 416 synchronized (mLock) { 417 mCallback = callback; 418 // The managingTrust property is false implicitly on the server-side, so we only 419 // need to set it here if the agent has decided to manage trust. 420 if (mManagingTrust) { 421 try { 422 mCallback.setManagingTrust(mManagingTrust); 423 } catch (RemoteException e ) { 424 onError("calling setManagingTrust()"); 425 } 426 } 427 if (mPendingGrantTrustTask != null) { 428 mPendingGrantTrustTask.run(); 429 mPendingGrantTrustTask = null; 430 } 431 } 432 } 433 } 434 435} 436