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