blob: 9d7ffad5052e90e11292eca64b9981a50486b348 [file] [log] [blame]
Adrian Roosff2144c2014-03-28 13:02:19 +01001/**
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
Adrian Rooscb9fbc32014-05-16 23:55:56 +020019import android.Manifest;
Adrian Roos94e15a52015-04-16 12:23:18 -070020import android.annotation.IntDef;
Adrian Roosff2144c2014-03-28 13:02:19 +010021import android.annotation.SdkConstant;
Adrian Roosa06d5ca2014-07-28 15:14:21 +020022import android.annotation.SystemApi;
Adrian Roosff2144c2014-03-28 13:02:19 +010023import android.app.Service;
Jim Miller604e7552014-07-18 19:00:02 -070024import android.app.admin.DevicePolicyManager;
Adrian Rooscb9fbc32014-05-16 23:55:56 +020025import android.content.ComponentName;
Adrian Roosff2144c2014-03-28 13:02:19 +010026import android.content.Intent;
Adrian Rooscb9fbc32014-05-16 23:55:56 +020027import android.content.pm.PackageManager;
28import android.content.pm.ServiceInfo;
Adrian Roosff2144c2014-03-28 13:02:19 +010029import android.os.Handler;
30import android.os.IBinder;
Jim Millere303bf42014-08-26 17:12:29 -070031import android.os.PersistableBundle;
Adrian Roosff2144c2014-03-28 13:02:19 +010032import android.os.RemoteException;
Adrian Rooscb9fbc32014-05-16 23:55:56 +020033import android.util.Log;
Adrian Roosff2144c2014-03-28 13:02:19 +010034import android.util.Slog;
35
Adrian Roos94e15a52015-04-16 12:23:18 -070036import java.lang.annotation.Retention;
37import java.lang.annotation.RetentionPolicy;
Jim Millere303bf42014-08-26 17:12:29 -070038import java.util.List;
39
Adrian Roosff2144c2014-03-28 13:02:19 +010040/**
41 * A service that notifies the system about whether it believes the environment of the device
42 * to be trusted.
43 *
Jim Millerd4efaac2014-08-14 18:02:45 -070044 * <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>
Adrian Roos18ea8932014-05-28 14:53:06 +020048 *
Adrian Roosff2144c2014-03-28 13:02:19 +010049 * <p>To extend this class, you must declare the service in your manifest file with
Adrian Roos7e03dfc2014-05-16 16:06:28 +020050 * the {@link android.Manifest.permission#BIND_TRUST_AGENT} permission
Adrian Roosff2144c2014-03-28 13:02:19 +010051 * and include an intent filter with the {@link #SERVICE_INTERFACE} action. For example:</p>
52 * <pre>
53 * &lt;service android:name=".TrustAgent"
54 * android:label="&#64;string/service_name"
Adrian Roos7e03dfc2014-05-16 16:06:28 +020055 * android:permission="android.permission.BIND_TRUST_AGENT">
Adrian Roosff2144c2014-03-28 13:02:19 +010056 * &lt;intent-filter>
57 * &lt;action android:name="android.service.trust.TrustAgentService" />
58 * &lt;/intent-filter>
59 * &lt;meta-data android:name="android.service.trust.trustagent"
60 * android:value="&#64;xml/trust_agent" />
61 * &lt;/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>
Adrian Roos7e03dfc2014-05-16 16:06:28 +020068 * &lt;trust-agent xmlns:android="http://schemas.android.com/apk/res/android"
Adrian Roosff2144c2014-03-28 13:02:19 +010069 * android:settingsActivity=".TrustAgentSettings" /></pre>
Adrian Roosa06d5ca2014-07-28 15:14:21 +020070 *
71 * @hide
Adrian Roosff2144c2014-03-28 13:02:19 +010072 */
Adrian Roosa06d5ca2014-07-28 15:14:21 +020073@SystemApi
Adrian Roosff2144c2014-03-28 13:02:19 +010074public class TrustAgentService extends Service {
Adrian Roos94e15a52015-04-16 12:23:18 -070075
Adrian Roosff2144c2014-03-28 13:02:19 +010076 private final String TAG = TrustAgentService.class.getSimpleName() +
77 "[" + getClass().getSimpleName() + "]";
Adrian Roos7861c662014-07-25 15:37:28 +020078 private static final boolean DEBUG = false;
79
Adrian Roosff2144c2014-03-28 13:02:19 +010080 /**
81 * The {@link Intent} that must be declared as handled by the service.
82 */
83 @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
84 public static final String SERVICE_INTERFACE
85 = "android.service.trust.TrustAgentService";
86
87 /**
88 * The name of the {@code meta-data} tag pointing to additional configuration of the trust
89 * agent.
90 */
91 public static final String TRUST_AGENT_META_DATA = "android.service.trust.trustagent";
92
Adrian Roos94e15a52015-04-16 12:23:18 -070093
94 /**
95 * Flag for {@link #grantTrust(CharSequence, long, int)} indicating that trust is being granted
96 * as the direct result of user action - such as solving a security challenge. The hint is used
97 * by the system to optimize the experience. Behavior may vary by device and release, so
98 * one should only set this parameter if it meets the above criteria rather than relying on
99 * the behavior of any particular device or release.
100 */
101 public static final int FLAG_GRANT_TRUST_INITIATED_BY_USER = 1 << 0;
102
103 /**
104 * Flag for {@link #grantTrust(CharSequence, long, int)} indicating that the agent would like
105 * to dismiss the keyguard. When using this flag, the {@code TrustAgentService} must ensure
106 * it is only set in response to a direct user action with the expectation of dismissing the
107 * keyguard.
108 */
109 public static final int FLAG_GRANT_TRUST_DISMISS_KEYGUARD = 1 << 1;
110
111 /** @hide */
112 @Retention(RetentionPolicy.SOURCE)
113 @IntDef(flag = true,
114 value = {
115 FLAG_GRANT_TRUST_INITIATED_BY_USER,
116 FLAG_GRANT_TRUST_DISMISS_KEYGUARD,
117 })
118 public @interface GrantTrustFlags {}
119
120
Adrian Roosff2144c2014-03-28 13:02:19 +0100121 private static final int MSG_UNLOCK_ATTEMPT = 1;
Jim Millere303bf42014-08-26 17:12:29 -0700122 private static final int MSG_CONFIGURE = 2;
Jim Millerd4efaac2014-08-14 18:02:45 -0700123 private static final int MSG_TRUST_TIMEOUT = 3;
Adrian Roos481a6df2014-11-20 19:48:56 +0100124 private static final int MSG_DEVICE_LOCKED = 4;
125 private static final int MSG_DEVICE_UNLOCKED = 5;
Adrian Roosff2144c2014-03-28 13:02:19 +0100126
Jim Millere303bf42014-08-26 17:12:29 -0700127 /**
Jim Millere303bf42014-08-26 17:12:29 -0700128 * Class containing raw data for a given configuration request.
129 */
130 private static final class ConfigurationData {
131 final IBinder token;
132 final List<PersistableBundle> options;
133 ConfigurationData(List<PersistableBundle> opts, IBinder t) {
134 options = opts;
135 token = t;
136 }
137 }
138
Adrian Roosff2144c2014-03-28 13:02:19 +0100139 private ITrustAgentServiceCallback mCallback;
140
Jay Civelli4f227772014-06-11 15:41:31 -0700141 private Runnable mPendingGrantTrustTask;
142
Adrian Roos7861c662014-07-25 15:37:28 +0200143 private boolean mManagingTrust;
144
Jay Civelli4f227772014-06-11 15:41:31 -0700145 // Lock used to access mPendingGrantTrustTask and mCallback.
146 private final Object mLock = new Object();
147
Adrian Roosff2144c2014-03-28 13:02:19 +0100148 private Handler mHandler = new Handler() {
149 public void handleMessage(android.os.Message msg) {
150 switch (msg.what) {
151 case MSG_UNLOCK_ATTEMPT:
152 onUnlockAttempt(msg.arg1 != 0);
153 break;
Jim Millere303bf42014-08-26 17:12:29 -0700154 case MSG_CONFIGURE:
155 ConfigurationData data = (ConfigurationData) msg.obj;
Jim Miller0814d412014-11-06 18:40:15 -0800156 boolean result = onConfigure(data.options);
Adrian Roosa43fd032015-03-09 19:10:15 +0100157 if (data.token != null) {
158 try {
159 synchronized (mLock) {
160 mCallback.onConfigureCompleted(result, data.token);
161 }
162 } catch (RemoteException e) {
163 onError("calling onSetTrustAgentFeaturesEnabledCompleted()");
Adrian Roos8f211582014-07-29 15:09:57 +0200164 }
Adrian Roos8f211582014-07-29 15:09:57 +0200165 }
166 break;
Jim Millerd4efaac2014-08-14 18:02:45 -0700167 case MSG_TRUST_TIMEOUT:
168 onTrustTimeout();
169 break;
Adrian Roos481a6df2014-11-20 19:48:56 +0100170 case MSG_DEVICE_LOCKED:
171 onDeviceLocked();
172 break;
173 case MSG_DEVICE_UNLOCKED:
174 onDeviceUnlocked();
175 break;
Adrian Roosff2144c2014-03-28 13:02:19 +0100176 }
Adrian Roos8f211582014-07-29 15:09:57 +0200177 }
Adrian Roosff2144c2014-03-28 13:02:19 +0100178 };
179
Adrian Rooscb9fbc32014-05-16 23:55:56 +0200180 @Override
181 public void onCreate() {
182 super.onCreate();
183 ComponentName component = new ComponentName(this, getClass());
184 try {
185 ServiceInfo serviceInfo = getPackageManager().getServiceInfo(component, 0 /* flags */);
186 if (!Manifest.permission.BIND_TRUST_AGENT.equals(serviceInfo.permission)) {
187 throw new IllegalStateException(component.flattenToShortString()
188 + " is not declared with the permission "
189 + "\"" + Manifest.permission.BIND_TRUST_AGENT + "\"");
190 }
191 } catch (PackageManager.NameNotFoundException e) {
192 Log.e(TAG, "Can't get ServiceInfo for " + component.toShortString());
193 }
194 }
195
Adrian Roosff2144c2014-03-28 13:02:19 +0100196 /**
Jim Millerd4efaac2014-08-14 18:02:45 -0700197 * Called after the user attempts to authenticate in keyguard with their device credentials,
198 * such as pin, pattern or password.
Adrian Roosff2144c2014-03-28 13:02:19 +0100199 *
Jim Millerd4efaac2014-08-14 18:02:45 -0700200 * @param successful true if the user successfully completed the challenge.
Adrian Roosff2144c2014-03-28 13:02:19 +0100201 */
Adrian Roos7e03dfc2014-05-16 16:06:28 +0200202 public void onUnlockAttempt(boolean successful) {
Adrian Roosff2144c2014-03-28 13:02:19 +0100203 }
204
Jim Millerd4efaac2014-08-14 18:02:45 -0700205 /**
206 * Called when the timeout provided by the agent expires. Note that this may be called earlier
207 * than requested by the agent if the trust timeout is adjusted by the system or
208 * {@link DevicePolicyManager}. The agent is expected to re-evaluate the trust state and only
209 * call {@link #grantTrust(CharSequence, long, boolean)} if the trust state should be
210 * continued.
211 */
212 public void onTrustTimeout() {
213 }
214
Adrian Roos481a6df2014-11-20 19:48:56 +0100215 /**
216 * Called when the device enters a state where a PIN, pattern or
217 * password must be entered to unlock it.
218 */
219 public void onDeviceLocked() {
220 }
221
222 /**
223 * Called when the device leaves a state where a PIN, pattern or
224 * password must be entered to unlock it.
225 */
226 public void onDeviceUnlocked() {
227 }
228
Adrian Roosff2144c2014-03-28 13:02:19 +0100229 private void onError(String msg) {
230 Slog.v(TAG, "Remote exception while " + msg);
231 }
232
233 /**
Jim Millere303bf42014-08-26 17:12:29 -0700234 * Called when device policy admin wants to enable specific options for agent in response to
235 * {@link DevicePolicyManager#setKeyguardDisabledFeatures(ComponentName, int)} and
236 * {@link DevicePolicyManager#setTrustAgentConfiguration(ComponentName, ComponentName,
237 * PersistableBundle)}.
238 * <p>Agents that support configuration options should overload this method and return 'true'.
Jim Miller604e7552014-07-18 19:00:02 -0700239 *
Adrian Roosa43fd032015-03-09 19:10:15 +0100240 * @param options The aggregated list of options or an empty list if no restrictions apply.
Jim Millere303bf42014-08-26 17:12:29 -0700241 * @return true if the {@link TrustAgentService} supports configuration options.
Jim Miller604e7552014-07-18 19:00:02 -0700242 */
Jim Miller0814d412014-11-06 18:40:15 -0800243 public boolean onConfigure(List<PersistableBundle> options) {
Jim Miller604e7552014-07-18 19:00:02 -0700244 return false;
245 }
246
247 /**
Adrian Roos7e03dfc2014-05-16 16:06:28 +0200248 * Call to grant trust on the device.
Adrian Roosff2144c2014-03-28 13:02:19 +0100249 *
250 * @param message describes why the device is trusted, e.g. "Trusted by location".
Jim Millerd4efaac2014-08-14 18:02:45 -0700251 * @param durationMs amount of time in milliseconds to keep the device in a trusted state.
252 * Trust for this agent will automatically be revoked when the timeout expires unless
253 * extended by a subsequent call to this function. The timeout is measured from the
254 * invocation of this function as dictated by {@link SystemClock#elapsedRealtime())}.
255 * For security reasons, the value should be no larger than necessary.
256 * The value may be adjusted by the system as necessary to comply with a policy controlled
257 * by the system or {@link DevicePolicyManager} restrictions. See {@link #onTrustTimeout()}
258 * for determining when trust expires.
259 * @param initiatedByUser this is a hint to the system that trust is being granted as the
260 * direct result of user action - such as solving a security challenge. The hint is used
261 * by the system to optimize the experience. Behavior may vary by device and release, so
262 * one should only set this parameter if it meets the above criteria rather than relying on
Adrian Roos94e15a52015-04-16 12:23:18 -0700263 * the behavior of any particular device or release. Corresponds to
264 * {@link #FLAG_GRANT_TRUST_INITIATED_BY_USER}.
265 * @throws IllegalStateException if the agent is not currently managing trust.
266 *
267 * @deprecated use {@link #grantTrust(CharSequence, long, int)} instead.
268 */
269 @Deprecated
270 public final void grantTrust(
271 final CharSequence message, final long durationMs, final boolean initiatedByUser) {
272 grantTrust(message, durationMs, initiatedByUser ? FLAG_GRANT_TRUST_INITIATED_BY_USER : 0);
273 }
274
275 /**
276 * Call to grant trust on the device.
277 *
278 * @param message describes why the device is trusted, e.g. "Trusted by location".
279 * @param durationMs amount of time in milliseconds to keep the device in a trusted state.
280 * Trust for this agent will automatically be revoked when the timeout expires unless
281 * extended by a subsequent call to this function. The timeout is measured from the
282 * invocation of this function as dictated by {@link SystemClock#elapsedRealtime())}.
283 * For security reasons, the value should be no larger than necessary.
284 * The value may be adjusted by the system as necessary to comply with a policy controlled
285 * by the system or {@link DevicePolicyManager} restrictions. See {@link #onTrustTimeout()}
286 * for determining when trust expires.
287 * @param flags TBDocumented
Adrian Roos7861c662014-07-25 15:37:28 +0200288 * @throws IllegalStateException if the agent is not currently managing trust.
Adrian Roosff2144c2014-03-28 13:02:19 +0100289 */
Jay Civelli4f227772014-06-11 15:41:31 -0700290 public final void grantTrust(
Adrian Roos94e15a52015-04-16 12:23:18 -0700291 final CharSequence message, final long durationMs, @GrantTrustFlags final int flags) {
Jay Civelli4f227772014-06-11 15:41:31 -0700292 synchronized (mLock) {
Adrian Roos7861c662014-07-25 15:37:28 +0200293 if (!mManagingTrust) {
294 throw new IllegalStateException("Cannot grant trust if agent is not managing trust."
295 + " Call setManagingTrust(true) first.");
296 }
Jay Civelli4f227772014-06-11 15:41:31 -0700297 if (mCallback != null) {
298 try {
Adrian Roos94e15a52015-04-16 12:23:18 -0700299 mCallback.grantTrust(message.toString(), durationMs, flags);
Jay Civelli4f227772014-06-11 15:41:31 -0700300 } catch (RemoteException e) {
301 onError("calling enableTrust()");
302 }
303 } else {
304 // Remember trust has been granted so we can effectively grant it once the service
305 // is bound.
306 mPendingGrantTrustTask = new Runnable() {
307 @Override
308 public void run() {
Adrian Roos94e15a52015-04-16 12:23:18 -0700309 grantTrust(message, durationMs, flags);
Jay Civelli4f227772014-06-11 15:41:31 -0700310 }
311 };
Adrian Roosff2144c2014-03-28 13:02:19 +0100312 }
313 }
314 }
315
316 /**
317 * Call to revoke trust on the device.
318 */
Adrian Roos7e03dfc2014-05-16 16:06:28 +0200319 public final void revokeTrust() {
Jay Civelli4f227772014-06-11 15:41:31 -0700320 synchronized (mLock) {
321 if (mPendingGrantTrustTask != null) {
322 mPendingGrantTrustTask = null;
323 }
324 if (mCallback != null) {
325 try {
326 mCallback.revokeTrust();
327 } catch (RemoteException e) {
328 onError("calling revokeTrust()");
329 }
Adrian Roosff2144c2014-03-28 13:02:19 +0100330 }
331 }
332 }
333
Adrian Roos7861c662014-07-25 15:37:28 +0200334 /**
335 * Call to notify the system if the agent is ready to manage trust.
336 *
337 * This property is not persistent across recreating the service and defaults to false.
338 * Therefore this method is typically called when initializing the agent in {@link #onCreate}.
339 *
340 * @param managingTrust indicates if the agent would like to manage trust.
341 */
342 public final void setManagingTrust(boolean managingTrust) {
343 synchronized (mLock) {
344 if (mManagingTrust != managingTrust) {
345 mManagingTrust = managingTrust;
346 if (mCallback != null) {
347 try {
348 mCallback.setManagingTrust(managingTrust);
349 } catch (RemoteException e) {
350 onError("calling setManagingTrust()");
351 }
352 }
353 }
354 }
355 }
356
Adrian Roosff2144c2014-03-28 13:02:19 +0100357 @Override
358 public final IBinder onBind(Intent intent) {
359 if (DEBUG) Slog.v(TAG, "onBind() intent = " + intent);
360 return new TrustAgentServiceWrapper();
361 }
362
363 private final class TrustAgentServiceWrapper extends ITrustAgentService.Stub {
Jim Millerd4efaac2014-08-14 18:02:45 -0700364 @Override /* Binder API */
Adrian Roosff2144c2014-03-28 13:02:19 +0100365 public void onUnlockAttempt(boolean successful) {
Jim Millerd4efaac2014-08-14 18:02:45 -0700366 mHandler.obtainMessage(MSG_UNLOCK_ATTEMPT, successful ? 1 : 0, 0).sendToTarget();
Adrian Roosff2144c2014-03-28 13:02:19 +0100367 }
368
Jim Millerd4efaac2014-08-14 18:02:45 -0700369 @Override /* Binder API */
370 public void onTrustTimeout() {
371 mHandler.sendEmptyMessage(MSG_TRUST_TIMEOUT);
372 }
373
374 @Override /* Binder API */
Jim Millere303bf42014-08-26 17:12:29 -0700375 public void onConfigure(List<PersistableBundle> args, IBinder token) {
376 mHandler.obtainMessage(MSG_CONFIGURE, new ConfigurationData(args, token))
377 .sendToTarget();
378 }
379
Adrian Roos481a6df2014-11-20 19:48:56 +0100380 @Override
381 public void onDeviceLocked() throws RemoteException {
382 mHandler.obtainMessage(MSG_DEVICE_LOCKED).sendToTarget();
383 }
384
385 @Override
386 public void onDeviceUnlocked() throws RemoteException {
387 mHandler.obtainMessage(MSG_DEVICE_UNLOCKED).sendToTarget();
388 }
389
Jim Millere303bf42014-08-26 17:12:29 -0700390 @Override /* Binder API */
Adrian Roosff2144c2014-03-28 13:02:19 +0100391 public void setCallback(ITrustAgentServiceCallback callback) {
Jay Civelli4f227772014-06-11 15:41:31 -0700392 synchronized (mLock) {
393 mCallback = callback;
Adrian Roos7861c662014-07-25 15:37:28 +0200394 // The managingTrust property is false implicitly on the server-side, so we only
395 // need to set it here if the agent has decided to manage trust.
396 if (mManagingTrust) {
397 try {
398 mCallback.setManagingTrust(mManagingTrust);
399 } catch (RemoteException e ) {
400 onError("calling setManagingTrust()");
401 }
402 }
Jay Civelli4f227772014-06-11 15:41:31 -0700403 if (mPendingGrantTrustTask != null) {
404 mPendingGrantTrustTask.run();
405 mPendingGrantTrustTask = null;
406 }
407 }
Adrian Roosff2144c2014-03-28 13:02:19 +0100408 }
Adrian Roosff2144c2014-03-28 13:02:19 +0100409 }
410
411}