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