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