TrustAgentService.java revision 65c09b10ca73d369e836074eeba38e01cd4c05b6
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.util.Log; 34import android.util.Slog; 35 36/** 37 * A service that notifies the system about whether it believes the environment of the device 38 * to be trusted. 39 * 40 * <p>Trust agents may only be provided by the platform.</p> 41 * 42 * <p>To extend this class, you must declare the service in your manifest file with 43 * the {@link android.Manifest.permission#BIND_TRUST_AGENT} permission 44 * and include an intent filter with the {@link #SERVICE_INTERFACE} action. For example:</p> 45 * <pre> 46 * <service android:name=".TrustAgent" 47 * android:label="@string/service_name" 48 * android:permission="android.permission.BIND_TRUST_AGENT"> 49 * <intent-filter> 50 * <action android:name="android.service.trust.TrustAgentService" /> 51 * </intent-filter> 52 * <meta-data android:name="android.service.trust.trustagent" 53 * android:value="@xml/trust_agent" /> 54 * </service></pre> 55 * 56 * <p>The associated meta-data file can specify an activity that is accessible through Settings 57 * and should allow configuring the trust agent, as defined in 58 * {@link android.R.styleable#TrustAgent}. For example:</p> 59 * 60 * <pre> 61 * <trust-agent xmlns:android="http://schemas.android.com/apk/res/android" 62 * android:settingsActivity=".TrustAgentSettings" /></pre> 63 * 64 * @hide 65 */ 66@SystemApi 67public class TrustAgentService extends Service { 68 private final String TAG = TrustAgentService.class.getSimpleName() + 69 "[" + getClass().getSimpleName() + "]"; 70 private static final boolean DEBUG = false; 71 72 /** 73 * The {@link Intent} that must be declared as handled by the service. 74 */ 75 @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION) 76 public static final String SERVICE_INTERFACE 77 = "android.service.trust.TrustAgentService"; 78 79 /** 80 * The name of the {@code meta-data} tag pointing to additional configuration of the trust 81 * agent. 82 */ 83 public static final String TRUST_AGENT_META_DATA = "android.service.trust.trustagent"; 84 85 /** 86 * A white list of features that the given trust agent should support when otherwise disabled 87 * by device policy. 88 */ 89 public static final String KEY_FEATURES = "trust_agent_features"; 90 91 private static final int MSG_UNLOCK_ATTEMPT = 1; 92 private static final int MSG_SET_TRUST_AGENT_FEATURES_ENABLED = 2; 93 94 private ITrustAgentServiceCallback mCallback; 95 96 private Runnable mPendingGrantTrustTask; 97 98 private boolean mManagingTrust; 99 100 // Lock used to access mPendingGrantTrustTask and mCallback. 101 private final Object mLock = new Object(); 102 103 private Handler mHandler = new Handler() { 104 public void handleMessage(android.os.Message msg) { 105 switch (msg.what) { 106 case MSG_UNLOCK_ATTEMPT: 107 onUnlockAttempt(msg.arg1 != 0); 108 break; 109 case MSG_SET_TRUST_AGENT_FEATURES_ENABLED: 110 Bundle features = msg.peekData(); 111 IBinder token = (IBinder) msg.obj; 112 boolean result = onSetTrustAgentFeaturesEnabled(features); 113 try { 114 synchronized (mLock) { 115 mCallback.onSetTrustAgentFeaturesEnabledCompleted(result, token); 116 } 117 } catch (RemoteException e) { 118 onError("calling onSetTrustAgentFeaturesEnabledCompleted()"); 119 } 120 break; 121 } 122 } 123 }; 124 125 @Override 126 public void onCreate() { 127 super.onCreate(); 128 ComponentName component = new ComponentName(this, getClass()); 129 try { 130 ServiceInfo serviceInfo = getPackageManager().getServiceInfo(component, 0 /* flags */); 131 if (!Manifest.permission.BIND_TRUST_AGENT.equals(serviceInfo.permission)) { 132 throw new IllegalStateException(component.flattenToShortString() 133 + " is not declared with the permission " 134 + "\"" + Manifest.permission.BIND_TRUST_AGENT + "\""); 135 } 136 } catch (PackageManager.NameNotFoundException e) { 137 Log.e(TAG, "Can't get ServiceInfo for " + component.toShortString()); 138 } 139 } 140 141 /** 142 * Called when the user attempted to authenticate on the device. 143 * 144 * @param successful true if the attempt succeeded 145 */ 146 public void onUnlockAttempt(boolean successful) { 147 } 148 149 private void onError(String msg) { 150 Slog.v(TAG, "Remote exception while " + msg); 151 } 152 153 /** 154 * Called when device policy wants to restrict features in the TrustAgent in response to 155 * {@link DevicePolicyManager#setTrustAgentFeaturesEnabled(ComponentName, ComponentName, java.util.List) }. 156 * TrustAgents that support this feature should overload this method and return 'true'. 157 * 158 * The list of options can be obtained by calling 159 * options.getStringArrayList({@link #KEY_FEATURES}). Presence of a feature string in the list 160 * means it should be enabled ("white-listed"). Absence of the feature means it should be 161 * disabled. An empty list means all features should be disabled. 162 * 163 * This function is only called if {@link DevicePolicyManager#KEYGUARD_DISABLE_TRUST_AGENTS} is 164 * set. 165 * 166 * @param options Option feature bundle. 167 * @return true if the {@link TrustAgentService} supports this feature. 168 */ 169 public boolean onSetTrustAgentFeaturesEnabled(Bundle options) { 170 return false; 171 } 172 173 /** 174 * Call to grant trust on the device. 175 * 176 * @param message describes why the device is trusted, e.g. "Trusted by location". 177 * @param durationMs amount of time in milliseconds to keep the device in a trusted state. Trust 178 * for this agent will automatically be revoked when the timeout expires. 179 * @param initiatedByUser indicates that the user has explicitly initiated an action that proves 180 * the user is about to use the device. 181 * @throws IllegalStateException if the agent is not currently managing trust. 182 */ 183 public final void grantTrust( 184 final CharSequence message, final long durationMs, final boolean initiatedByUser) { 185 synchronized (mLock) { 186 if (!mManagingTrust) { 187 throw new IllegalStateException("Cannot grant trust if agent is not managing trust." 188 + " Call setManagingTrust(true) first."); 189 } 190 if (mCallback != null) { 191 try { 192 mCallback.grantTrust(message.toString(), durationMs, initiatedByUser); 193 } catch (RemoteException e) { 194 onError("calling enableTrust()"); 195 } 196 } else { 197 // Remember trust has been granted so we can effectively grant it once the service 198 // is bound. 199 mPendingGrantTrustTask = new Runnable() { 200 @Override 201 public void run() { 202 grantTrust(message, durationMs, initiatedByUser); 203 } 204 }; 205 } 206 } 207 } 208 209 /** 210 * Call to revoke trust on the device. 211 */ 212 public final void revokeTrust() { 213 synchronized (mLock) { 214 if (mPendingGrantTrustTask != null) { 215 mPendingGrantTrustTask = null; 216 } 217 if (mCallback != null) { 218 try { 219 mCallback.revokeTrust(); 220 } catch (RemoteException e) { 221 onError("calling revokeTrust()"); 222 } 223 } 224 } 225 } 226 227 /** 228 * Call to notify the system if the agent is ready to manage trust. 229 * 230 * This property is not persistent across recreating the service and defaults to false. 231 * Therefore this method is typically called when initializing the agent in {@link #onCreate}. 232 * 233 * @param managingTrust indicates if the agent would like to manage trust. 234 */ 235 public final void setManagingTrust(boolean managingTrust) { 236 synchronized (mLock) { 237 if (mManagingTrust != managingTrust) { 238 mManagingTrust = managingTrust; 239 if (mCallback != null) { 240 try { 241 mCallback.setManagingTrust(managingTrust); 242 } catch (RemoteException e) { 243 onError("calling setManagingTrust()"); 244 } 245 } 246 } 247 } 248 } 249 250 @Override 251 public final IBinder onBind(Intent intent) { 252 if (DEBUG) Slog.v(TAG, "onBind() intent = " + intent); 253 return new TrustAgentServiceWrapper(); 254 } 255 256 private final class TrustAgentServiceWrapper extends ITrustAgentService.Stub { 257 @Override 258 public void onUnlockAttempt(boolean successful) { 259 mHandler.obtainMessage(MSG_UNLOCK_ATTEMPT, successful ? 1 : 0, 0) 260 .sendToTarget(); 261 } 262 263 @Override 264 public void setCallback(ITrustAgentServiceCallback callback) { 265 synchronized (mLock) { 266 mCallback = callback; 267 // The managingTrust property is false implicitly on the server-side, so we only 268 // need to set it here if the agent has decided to manage trust. 269 if (mManagingTrust) { 270 try { 271 mCallback.setManagingTrust(mManagingTrust); 272 } catch (RemoteException e ) { 273 onError("calling setManagingTrust()"); 274 } 275 } 276 if (mPendingGrantTrustTask != null) { 277 mPendingGrantTrustTask.run(); 278 mPendingGrantTrustTask = null; 279 } 280 } 281 } 282 283 @Override 284 public void setTrustAgentFeaturesEnabled(Bundle features, IBinder token) { 285 Message msg = mHandler.obtainMessage(MSG_SET_TRUST_AGENT_FEATURES_ENABLED, token); 286 msg.setData(features); 287 msg.sendToTarget(); 288 } 289 } 290 291} 292