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