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