blob: a3178e2d5cad9dfe020e1b5d54feb6050a6707ca [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 Roosff2144c2014-03-28 13:02:19 +010020import android.annotation.SdkConstant;
Adrian Roosa06d5ca2014-07-28 15:14:21 +020021import android.annotation.SystemApi;
Adrian Roosff2144c2014-03-28 13:02:19 +010022import android.app.Service;
Jim Miller604e7552014-07-18 19:00:02 -070023import android.app.admin.DevicePolicyManager;
Adrian Rooscb9fbc32014-05-16 23:55:56 +020024import android.content.ComponentName;
Adrian Roosff2144c2014-03-28 13:02:19 +010025import android.content.Intent;
Adrian Rooscb9fbc32014-05-16 23:55:56 +020026import android.content.pm.PackageManager;
27import android.content.pm.ServiceInfo;
Adrian Roosff2144c2014-03-28 13:02:19 +010028import android.os.Handler;
29import android.os.IBinder;
Jim Millere303bf42014-08-26 17:12:29 -070030import android.os.PersistableBundle;
Adrian Roosff2144c2014-03-28 13:02:19 +010031import android.os.RemoteException;
Adrian Rooscb9fbc32014-05-16 23:55:56 +020032import android.util.Log;
Adrian Roosff2144c2014-03-28 13:02:19 +010033import android.util.Slog;
34
Jim Millere303bf42014-08-26 17:12:29 -070035import java.util.List;
36
Adrian Roosff2144c2014-03-28 13:02:19 +010037/**
38 * A service that notifies the system about whether it believes the environment of the device
39 * to be trusted.
40 *
Jim Millerd4efaac2014-08-14 18:02:45 -070041 * <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>
Adrian Roos18ea8932014-05-28 14:53:06 +020045 *
Adrian Roosff2144c2014-03-28 13:02:19 +010046 * <p>To extend this class, you must declare the service in your manifest file with
Adrian Roos7e03dfc2014-05-16 16:06:28 +020047 * the {@link android.Manifest.permission#BIND_TRUST_AGENT} permission
Adrian Roosff2144c2014-03-28 13:02:19 +010048 * and include an intent filter with the {@link #SERVICE_INTERFACE} action. For example:</p>
49 * <pre>
50 * &lt;service android:name=".TrustAgent"
51 * android:label="&#64;string/service_name"
Adrian Roos7e03dfc2014-05-16 16:06:28 +020052 * android:permission="android.permission.BIND_TRUST_AGENT">
Adrian Roosff2144c2014-03-28 13:02:19 +010053 * &lt;intent-filter>
54 * &lt;action android:name="android.service.trust.TrustAgentService" />
55 * &lt;/intent-filter>
56 * &lt;meta-data android:name="android.service.trust.trustagent"
57 * android:value="&#64;xml/trust_agent" />
58 * &lt;/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>
Adrian Roos7e03dfc2014-05-16 16:06:28 +020065 * &lt;trust-agent xmlns:android="http://schemas.android.com/apk/res/android"
Adrian Roosff2144c2014-03-28 13:02:19 +010066 * android:settingsActivity=".TrustAgentSettings" /></pre>
Adrian Roosa06d5ca2014-07-28 15:14:21 +020067 *
68 * @hide
Adrian Roosff2144c2014-03-28 13:02:19 +010069 */
Adrian Roosa06d5ca2014-07-28 15:14:21 +020070@SystemApi
Adrian Roosff2144c2014-03-28 13:02:19 +010071public class TrustAgentService extends Service {
72 private final String TAG = TrustAgentService.class.getSimpleName() +
73 "[" + getClass().getSimpleName() + "]";
Adrian Roos7861c662014-07-25 15:37:28 +020074 private static final boolean DEBUG = false;
75
Adrian Roosff2144c2014-03-28 13:02:19 +010076 /**
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 private static final int MSG_UNLOCK_ATTEMPT = 1;
Jim Millere303bf42014-08-26 17:12:29 -070090 private static final int MSG_CONFIGURE = 2;
Jim Millerd4efaac2014-08-14 18:02:45 -070091 private static final int MSG_TRUST_TIMEOUT = 3;
Adrian Roos481a6df2014-11-20 19:48:56 +010092 private static final int MSG_DEVICE_LOCKED = 4;
93 private static final int MSG_DEVICE_UNLOCKED = 5;
Adrian Roosff2144c2014-03-28 13:02:19 +010094
Jim Millere303bf42014-08-26 17:12:29 -070095 /**
Jim Millere303bf42014-08-26 17:12:29 -070096 * Class containing raw data for a given configuration request.
97 */
98 private static final class ConfigurationData {
99 final IBinder token;
100 final List<PersistableBundle> options;
101 ConfigurationData(List<PersistableBundle> opts, IBinder t) {
102 options = opts;
103 token = t;
104 }
105 }
106
Adrian Roosff2144c2014-03-28 13:02:19 +0100107 private ITrustAgentServiceCallback mCallback;
108
Jay Civelli4f227772014-06-11 15:41:31 -0700109 private Runnable mPendingGrantTrustTask;
110
Adrian Roos7861c662014-07-25 15:37:28 +0200111 private boolean mManagingTrust;
112
Jay Civelli4f227772014-06-11 15:41:31 -0700113 // Lock used to access mPendingGrantTrustTask and mCallback.
114 private final Object mLock = new Object();
115
Adrian Roosff2144c2014-03-28 13:02:19 +0100116 private Handler mHandler = new Handler() {
117 public void handleMessage(android.os.Message msg) {
118 switch (msg.what) {
119 case MSG_UNLOCK_ATTEMPT:
120 onUnlockAttempt(msg.arg1 != 0);
121 break;
Jim Millere303bf42014-08-26 17:12:29 -0700122 case MSG_CONFIGURE:
123 ConfigurationData data = (ConfigurationData) msg.obj;
Jim Miller0814d412014-11-06 18:40:15 -0800124 boolean result = onConfigure(data.options);
Adrian Roosa43fd032015-03-09 19:10:15 +0100125 if (data.token != null) {
126 try {
127 synchronized (mLock) {
128 mCallback.onConfigureCompleted(result, data.token);
129 }
130 } catch (RemoteException e) {
131 onError("calling onSetTrustAgentFeaturesEnabledCompleted()");
Adrian Roos8f211582014-07-29 15:09:57 +0200132 }
Adrian Roos8f211582014-07-29 15:09:57 +0200133 }
134 break;
Jim Millerd4efaac2014-08-14 18:02:45 -0700135 case MSG_TRUST_TIMEOUT:
136 onTrustTimeout();
137 break;
Adrian Roos481a6df2014-11-20 19:48:56 +0100138 case MSG_DEVICE_LOCKED:
139 onDeviceLocked();
140 break;
141 case MSG_DEVICE_UNLOCKED:
142 onDeviceUnlocked();
143 break;
Adrian Roosff2144c2014-03-28 13:02:19 +0100144 }
Adrian Roos8f211582014-07-29 15:09:57 +0200145 }
Adrian Roosff2144c2014-03-28 13:02:19 +0100146 };
147
Adrian Rooscb9fbc32014-05-16 23:55:56 +0200148 @Override
149 public void onCreate() {
150 super.onCreate();
151 ComponentName component = new ComponentName(this, getClass());
152 try {
153 ServiceInfo serviceInfo = getPackageManager().getServiceInfo(component, 0 /* flags */);
154 if (!Manifest.permission.BIND_TRUST_AGENT.equals(serviceInfo.permission)) {
155 throw new IllegalStateException(component.flattenToShortString()
156 + " is not declared with the permission "
157 + "\"" + Manifest.permission.BIND_TRUST_AGENT + "\"");
158 }
159 } catch (PackageManager.NameNotFoundException e) {
160 Log.e(TAG, "Can't get ServiceInfo for " + component.toShortString());
161 }
162 }
163
Adrian Roosff2144c2014-03-28 13:02:19 +0100164 /**
Jim Millerd4efaac2014-08-14 18:02:45 -0700165 * Called after the user attempts to authenticate in keyguard with their device credentials,
166 * such as pin, pattern or password.
Adrian Roosff2144c2014-03-28 13:02:19 +0100167 *
Jim Millerd4efaac2014-08-14 18:02:45 -0700168 * @param successful true if the user successfully completed the challenge.
Adrian Roosff2144c2014-03-28 13:02:19 +0100169 */
Adrian Roos7e03dfc2014-05-16 16:06:28 +0200170 public void onUnlockAttempt(boolean successful) {
Adrian Roosff2144c2014-03-28 13:02:19 +0100171 }
172
Jim Millerd4efaac2014-08-14 18:02:45 -0700173 /**
174 * Called when the timeout provided by the agent expires. Note that this may be called earlier
175 * than requested by the agent if the trust timeout is adjusted by the system or
176 * {@link DevicePolicyManager}. The agent is expected to re-evaluate the trust state and only
177 * call {@link #grantTrust(CharSequence, long, boolean)} if the trust state should be
178 * continued.
179 */
180 public void onTrustTimeout() {
181 }
182
Adrian Roos481a6df2014-11-20 19:48:56 +0100183 /**
184 * Called when the device enters a state where a PIN, pattern or
185 * password must be entered to unlock it.
186 */
187 public void onDeviceLocked() {
188 }
189
190 /**
191 * Called when the device leaves a state where a PIN, pattern or
192 * password must be entered to unlock it.
193 */
194 public void onDeviceUnlocked() {
195 }
196
Adrian Roosff2144c2014-03-28 13:02:19 +0100197 private void onError(String msg) {
198 Slog.v(TAG, "Remote exception while " + msg);
199 }
200
201 /**
Jim Millere303bf42014-08-26 17:12:29 -0700202 * Called when device policy admin wants to enable specific options for agent in response to
203 * {@link DevicePolicyManager#setKeyguardDisabledFeatures(ComponentName, int)} and
204 * {@link DevicePolicyManager#setTrustAgentConfiguration(ComponentName, ComponentName,
205 * PersistableBundle)}.
206 * <p>Agents that support configuration options should overload this method and return 'true'.
Jim Miller604e7552014-07-18 19:00:02 -0700207 *
Adrian Roosa43fd032015-03-09 19:10:15 +0100208 * @param options The aggregated list of options or an empty list if no restrictions apply.
Jim Millere303bf42014-08-26 17:12:29 -0700209 * @return true if the {@link TrustAgentService} supports configuration options.
Jim Miller604e7552014-07-18 19:00:02 -0700210 */
Jim Miller0814d412014-11-06 18:40:15 -0800211 public boolean onConfigure(List<PersistableBundle> options) {
Jim Miller604e7552014-07-18 19:00:02 -0700212 return false;
213 }
214
215 /**
Adrian Roos7e03dfc2014-05-16 16:06:28 +0200216 * Call to grant trust on the device.
Adrian Roosff2144c2014-03-28 13:02:19 +0100217 *
218 * @param message describes why the device is trusted, e.g. "Trusted by location".
Jim Millerd4efaac2014-08-14 18:02:45 -0700219 * @param durationMs amount of time in milliseconds to keep the device in a trusted state.
220 * Trust for this agent will automatically be revoked when the timeout expires unless
221 * extended by a subsequent call to this function. The timeout is measured from the
222 * invocation of this function as dictated by {@link SystemClock#elapsedRealtime())}.
223 * For security reasons, the value should be no larger than necessary.
224 * The value may be adjusted by the system as necessary to comply with a policy controlled
225 * by the system or {@link DevicePolicyManager} restrictions. See {@link #onTrustTimeout()}
226 * for determining when trust expires.
227 * @param initiatedByUser this is a hint to the system that trust is being granted as the
228 * direct result of user action - such as solving a security challenge. The hint is used
229 * by the system to optimize the experience. Behavior may vary by device and release, so
230 * one should only set this parameter if it meets the above criteria rather than relying on
231 * the behavior of any particular device or release.
Adrian Roos7861c662014-07-25 15:37:28 +0200232 * @throws IllegalStateException if the agent is not currently managing trust.
Adrian Roosff2144c2014-03-28 13:02:19 +0100233 */
Jay Civelli4f227772014-06-11 15:41:31 -0700234 public final void grantTrust(
235 final CharSequence message, final long durationMs, final boolean initiatedByUser) {
236 synchronized (mLock) {
Adrian Roos7861c662014-07-25 15:37:28 +0200237 if (!mManagingTrust) {
238 throw new IllegalStateException("Cannot grant trust if agent is not managing trust."
239 + " Call setManagingTrust(true) first.");
240 }
Jay Civelli4f227772014-06-11 15:41:31 -0700241 if (mCallback != null) {
242 try {
243 mCallback.grantTrust(message.toString(), durationMs, initiatedByUser);
244 } catch (RemoteException e) {
245 onError("calling enableTrust()");
246 }
247 } else {
248 // Remember trust has been granted so we can effectively grant it once the service
249 // is bound.
250 mPendingGrantTrustTask = new Runnable() {
251 @Override
252 public void run() {
253 grantTrust(message, durationMs, initiatedByUser);
254 }
255 };
Adrian Roosff2144c2014-03-28 13:02:19 +0100256 }
257 }
258 }
259
260 /**
261 * Call to revoke trust on the device.
262 */
Adrian Roos7e03dfc2014-05-16 16:06:28 +0200263 public final void revokeTrust() {
Jay Civelli4f227772014-06-11 15:41:31 -0700264 synchronized (mLock) {
265 if (mPendingGrantTrustTask != null) {
266 mPendingGrantTrustTask = null;
267 }
268 if (mCallback != null) {
269 try {
270 mCallback.revokeTrust();
271 } catch (RemoteException e) {
272 onError("calling revokeTrust()");
273 }
Adrian Roosff2144c2014-03-28 13:02:19 +0100274 }
275 }
276 }
277
Adrian Roos7861c662014-07-25 15:37:28 +0200278 /**
279 * Call to notify the system if the agent is ready to manage trust.
280 *
281 * This property is not persistent across recreating the service and defaults to false.
282 * Therefore this method is typically called when initializing the agent in {@link #onCreate}.
283 *
284 * @param managingTrust indicates if the agent would like to manage trust.
285 */
286 public final void setManagingTrust(boolean managingTrust) {
287 synchronized (mLock) {
288 if (mManagingTrust != managingTrust) {
289 mManagingTrust = managingTrust;
290 if (mCallback != null) {
291 try {
292 mCallback.setManagingTrust(managingTrust);
293 } catch (RemoteException e) {
294 onError("calling setManagingTrust()");
295 }
296 }
297 }
298 }
299 }
300
Adrian Roosff2144c2014-03-28 13:02:19 +0100301 @Override
302 public final IBinder onBind(Intent intent) {
303 if (DEBUG) Slog.v(TAG, "onBind() intent = " + intent);
304 return new TrustAgentServiceWrapper();
305 }
306
307 private final class TrustAgentServiceWrapper extends ITrustAgentService.Stub {
Jim Millerd4efaac2014-08-14 18:02:45 -0700308 @Override /* Binder API */
Adrian Roosff2144c2014-03-28 13:02:19 +0100309 public void onUnlockAttempt(boolean successful) {
Jim Millerd4efaac2014-08-14 18:02:45 -0700310 mHandler.obtainMessage(MSG_UNLOCK_ATTEMPT, successful ? 1 : 0, 0).sendToTarget();
Adrian Roosff2144c2014-03-28 13:02:19 +0100311 }
312
Jim Millerd4efaac2014-08-14 18:02:45 -0700313 @Override /* Binder API */
314 public void onTrustTimeout() {
315 mHandler.sendEmptyMessage(MSG_TRUST_TIMEOUT);
316 }
317
318 @Override /* Binder API */
Jim Millere303bf42014-08-26 17:12:29 -0700319 public void onConfigure(List<PersistableBundle> args, IBinder token) {
320 mHandler.obtainMessage(MSG_CONFIGURE, new ConfigurationData(args, token))
321 .sendToTarget();
322 }
323
Adrian Roos481a6df2014-11-20 19:48:56 +0100324 @Override
325 public void onDeviceLocked() throws RemoteException {
326 mHandler.obtainMessage(MSG_DEVICE_LOCKED).sendToTarget();
327 }
328
329 @Override
330 public void onDeviceUnlocked() throws RemoteException {
331 mHandler.obtainMessage(MSG_DEVICE_UNLOCKED).sendToTarget();
332 }
333
Jim Millere303bf42014-08-26 17:12:29 -0700334 @Override /* Binder API */
Adrian Roosff2144c2014-03-28 13:02:19 +0100335 public void setCallback(ITrustAgentServiceCallback callback) {
Jay Civelli4f227772014-06-11 15:41:31 -0700336 synchronized (mLock) {
337 mCallback = callback;
Adrian Roos7861c662014-07-25 15:37:28 +0200338 // The managingTrust property is false implicitly on the server-side, so we only
339 // need to set it here if the agent has decided to manage trust.
340 if (mManagingTrust) {
341 try {
342 mCallback.setManagingTrust(mManagingTrust);
343 } catch (RemoteException e ) {
344 onError("calling setManagingTrust()");
345 }
346 }
Jay Civelli4f227772014-06-11 15:41:31 -0700347 if (mPendingGrantTrustTask != null) {
348 mPendingGrantTrustTask.run();
349 mPendingGrantTrustTask = null;
350 }
351 }
Adrian Roosff2144c2014-03-28 13:02:19 +0100352 }
Adrian Roosff2144c2014-03-28 13:02:19 +0100353 }
354
355}