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 127 /** 128 * Class containing raw data for a given configuration request. 129 */ 130 private static final class ConfigurationData { 131 final IBinder token; 132 final List<PersistableBundle> options; 133 ConfigurationData(List<PersistableBundle> opts, IBinder t) { 134 options = opts; 135 token = t; 136 } 137 } 138 139 private ITrustAgentServiceCallback mCallback; 140 141 private Runnable mPendingGrantTrustTask; 142 143 private boolean mManagingTrust; 144 145 // Lock used to access mPendingGrantTrustTask and mCallback. 146 private final Object mLock = new Object(); 147 148 private Handler mHandler = new Handler() { 149 public void handleMessage(android.os.Message msg) { 150 switch (msg.what) { 151 case MSG_UNLOCK_ATTEMPT: 152 onUnlockAttempt(msg.arg1 != 0); 153 break; 154 case MSG_CONFIGURE: 155 ConfigurationData data = (ConfigurationData) msg.obj; 156 boolean result = onConfigure(data.options); 157 if (data.token != null) { 158 try { 159 synchronized (mLock) { 160 mCallback.onConfigureCompleted(result, data.token); 161 } 162 } catch (RemoteException e) { 163 onError("calling onSetTrustAgentFeaturesEnabledCompleted()"); 164 } 165 } 166 break; 167 case MSG_TRUST_TIMEOUT: 168 onTrustTimeout(); 169 break; 170 case MSG_DEVICE_LOCKED: 171 onDeviceLocked(); 172 break; 173 case MSG_DEVICE_UNLOCKED: 174 onDeviceUnlocked(); 175 break; 176 } 177 } 178 }; 179 180 @Override 181 public void onCreate() { 182 super.onCreate(); 183 ComponentName component = new ComponentName(this, getClass()); 184 try { 185 ServiceInfo serviceInfo = getPackageManager().getServiceInfo(component, 0 /* flags */); 186 if (!Manifest.permission.BIND_TRUST_AGENT.equals(serviceInfo.permission)) { 187 throw new IllegalStateException(component.flattenToShortString() 188 + " is not declared with the permission " 189 + "\"" + Manifest.permission.BIND_TRUST_AGENT + "\""); 190 } 191 } catch (PackageManager.NameNotFoundException e) { 192 Log.e(TAG, "Can't get ServiceInfo for " + component.toShortString()); 193 } 194 } 195 196 /** 197 * Called after the user attempts to authenticate in keyguard with their device credentials, 198 * such as pin, pattern or password. 199 * 200 * @param successful true if the user successfully completed the challenge. 201 */ 202 public void onUnlockAttempt(boolean successful) { 203 } 204 205 /** 206 * Called when the timeout provided by the agent expires. Note that this may be called earlier 207 * than requested by the agent if the trust timeout is adjusted by the system or 208 * {@link DevicePolicyManager}. The agent is expected to re-evaluate the trust state and only 209 * call {@link #grantTrust(CharSequence, long, boolean)} if the trust state should be 210 * continued. 211 */ 212 public void onTrustTimeout() { 213 } 214 215 /** 216 * Called when the device enters a state where a PIN, pattern or 217 * password must be entered to unlock it. 218 */ 219 public void onDeviceLocked() { 220 } 221 222 /** 223 * Called when the device leaves a state where a PIN, pattern or 224 * password must be entered to unlock it. 225 */ 226 public void onDeviceUnlocked() { 227 } 228 229 private void onError(String msg) { 230 Slog.v(TAG, "Remote exception while " + msg); 231 } 232 233 /** 234 * Called when device policy admin wants to enable specific options for agent in response to 235 * {@link DevicePolicyManager#setKeyguardDisabledFeatures(ComponentName, int)} and 236 * {@link DevicePolicyManager#setTrustAgentConfiguration(ComponentName, ComponentName, 237 * PersistableBundle)}. 238 * <p>Agents that support configuration options should overload this method and return 'true'. 239 * 240 * @param options The aggregated list of options or an empty list if no restrictions apply. 241 * @return true if the {@link TrustAgentService} supports configuration options. 242 */ 243 public boolean onConfigure(List<PersistableBundle> options) { 244 return false; 245 } 246 247 /** 248 * Call to grant trust on the device. 249 * 250 * @param message describes why the device is trusted, e.g. "Trusted by location". 251 * @param durationMs amount of time in milliseconds to keep the device in a trusted state. 252 * Trust for this agent will automatically be revoked when the timeout expires unless 253 * extended by a subsequent call to this function. The timeout is measured from the 254 * invocation of this function as dictated by {@link SystemClock#elapsedRealtime())}. 255 * For security reasons, the value should be no larger than necessary. 256 * The value may be adjusted by the system as necessary to comply with a policy controlled 257 * by the system or {@link DevicePolicyManager} restrictions. See {@link #onTrustTimeout()} 258 * for determining when trust expires. 259 * @param initiatedByUser this is a hint to the system that trust is being granted as the 260 * direct result of user action - such as solving a security challenge. The hint is used 261 * by the system to optimize the experience. Behavior may vary by device and release, so 262 * one should only set this parameter if it meets the above criteria rather than relying on 263 * the behavior of any particular device or release. Corresponds to 264 * {@link #FLAG_GRANT_TRUST_INITIATED_BY_USER}. 265 * @throws IllegalStateException if the agent is not currently managing trust. 266 * 267 * @deprecated use {@link #grantTrust(CharSequence, long, int)} instead. 268 */ 269 @Deprecated 270 public final void grantTrust( 271 final CharSequence message, final long durationMs, final boolean initiatedByUser) { 272 grantTrust(message, durationMs, initiatedByUser ? FLAG_GRANT_TRUST_INITIATED_BY_USER : 0); 273 } 274 275 /** 276 * Call to grant trust on the device. 277 * 278 * @param message describes why the device is trusted, e.g. "Trusted by location". 279 * @param durationMs amount of time in milliseconds to keep the device in a trusted state. 280 * Trust for this agent will automatically be revoked when the timeout expires unless 281 * extended by a subsequent call to this function. The timeout is measured from the 282 * invocation of this function as dictated by {@link SystemClock#elapsedRealtime())}. 283 * For security reasons, the value should be no larger than necessary. 284 * The value may be adjusted by the system as necessary to comply with a policy controlled 285 * by the system or {@link DevicePolicyManager} restrictions. See {@link #onTrustTimeout()} 286 * for determining when trust expires. 287 * @param flags TBDocumented 288 * @throws IllegalStateException if the agent is not currently managing trust. 289 */ 290 public final void grantTrust( 291 final CharSequence message, final long durationMs, @GrantTrustFlags final int flags) { 292 synchronized (mLock) { 293 if (!mManagingTrust) { 294 throw new IllegalStateException("Cannot grant trust if agent is not managing trust." 295 + " Call setManagingTrust(true) first."); 296 } 297 if (mCallback != null) { 298 try { 299 mCallback.grantTrust(message.toString(), durationMs, flags); 300 } catch (RemoteException e) { 301 onError("calling enableTrust()"); 302 } 303 } else { 304 // Remember trust has been granted so we can effectively grant it once the service 305 // is bound. 306 mPendingGrantTrustTask = new Runnable() { 307 @Override 308 public void run() { 309 grantTrust(message, durationMs, flags); 310 } 311 }; 312 } 313 } 314 } 315 316 /** 317 * Call to revoke trust on the device. 318 */ 319 public final void revokeTrust() { 320 synchronized (mLock) { 321 if (mPendingGrantTrustTask != null) { 322 mPendingGrantTrustTask = null; 323 } 324 if (mCallback != null) { 325 try { 326 mCallback.revokeTrust(); 327 } catch (RemoteException e) { 328 onError("calling revokeTrust()"); 329 } 330 } 331 } 332 } 333 334 /** 335 * Call to notify the system if the agent is ready to manage trust. 336 * 337 * This property is not persistent across recreating the service and defaults to false. 338 * Therefore this method is typically called when initializing the agent in {@link #onCreate}. 339 * 340 * @param managingTrust indicates if the agent would like to manage trust. 341 */ 342 public final void setManagingTrust(boolean managingTrust) { 343 synchronized (mLock) { 344 if (mManagingTrust != managingTrust) { 345 mManagingTrust = managingTrust; 346 if (mCallback != null) { 347 try { 348 mCallback.setManagingTrust(managingTrust); 349 } catch (RemoteException e) { 350 onError("calling setManagingTrust()"); 351 } 352 } 353 } 354 } 355 } 356 357 @Override 358 public final IBinder onBind(Intent intent) { 359 if (DEBUG) Slog.v(TAG, "onBind() intent = " + intent); 360 return new TrustAgentServiceWrapper(); 361 } 362 363 private final class TrustAgentServiceWrapper extends ITrustAgentService.Stub { 364 @Override /* Binder API */ 365 public void onUnlockAttempt(boolean successful) { 366 mHandler.obtainMessage(MSG_UNLOCK_ATTEMPT, successful ? 1 : 0, 0).sendToTarget(); 367 } 368 369 @Override /* Binder API */ 370 public void onTrustTimeout() { 371 mHandler.sendEmptyMessage(MSG_TRUST_TIMEOUT); 372 } 373 374 @Override /* Binder API */ 375 public void onConfigure(List<PersistableBundle> args, IBinder token) { 376 mHandler.obtainMessage(MSG_CONFIGURE, new ConfigurationData(args, token)) 377 .sendToTarget(); 378 } 379 380 @Override 381 public void onDeviceLocked() throws RemoteException { 382 mHandler.obtainMessage(MSG_DEVICE_LOCKED).sendToTarget(); 383 } 384 385 @Override 386 public void onDeviceUnlocked() throws RemoteException { 387 mHandler.obtainMessage(MSG_DEVICE_UNLOCKED).sendToTarget(); 388 } 389 390 @Override /* Binder API */ 391 public void setCallback(ITrustAgentServiceCallback callback) { 392 synchronized (mLock) { 393 mCallback = callback; 394 // The managingTrust property is false implicitly on the server-side, so we only 395 // need to set it here if the agent has decided to manage trust. 396 if (mManagingTrust) { 397 try { 398 mCallback.setManagingTrust(mManagingTrust); 399 } catch (RemoteException e ) { 400 onError("calling setManagingTrust()"); 401 } 402 } 403 if (mPendingGrantTrustTask != null) { 404 mPendingGrantTrustTask.run(); 405 mPendingGrantTrustTask = null; 406 } 407 } 408 } 409 } 410 411} 412