TrustAgentService.java revision 327323d2b337077433fe02438a79cc98e91799e3
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.IntDef;
21import android.annotation.SdkConstant;
22import android.annotation.SystemApi;
23import android.app.Service;
24import android.app.admin.DevicePolicyManager;
25import android.content.ComponentName;
26import android.content.Intent;
27import android.content.pm.PackageManager;
28import android.content.pm.ServiceInfo;
29import android.os.Handler;
30import android.os.IBinder;
31import android.os.PersistableBundle;
32import android.os.RemoteException;
33import android.util.Log;
34import android.util.Slog;
35
36import java.lang.annotation.Retention;
37import java.lang.annotation.RetentionPolicy;
38import java.util.List;
39
40/**
41 * A service that notifies the system about whether it believes the environment of the device
42 * to be trusted.
43 *
44 * <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>
48 *
49 * <p>To extend this class, you must declare the service in your manifest file with
50 * the {@link android.Manifest.permission#BIND_TRUST_AGENT} permission
51 * 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"
55 *          android:permission="android.permission.BIND_TRUST_AGENT">
56 *     &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>
68 * &lt;trust-agent xmlns:android="http://schemas.android.com/apk/res/android"
69 *          android:settingsActivity=".TrustAgentSettings" /></pre>
70 *
71 * @hide
72 */
73@SystemApi
74public class TrustAgentService extends Service {
75
76    private final String TAG = TrustAgentService.class.getSimpleName() +
77            "[" + getClass().getSimpleName() + "]";
78    private static final boolean DEBUG = false;
79
80    /**
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
93
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
121    private static final int MSG_UNLOCK_ATTEMPT = 1;
122    private static final int MSG_CONFIGURE = 2;
123    private static final int MSG_TRUST_TIMEOUT = 3;
124    private static final int MSG_DEVICE_LOCKED = 4;
125    private static final int MSG_DEVICE_UNLOCKED = 5;
126    private static final int MSG_UNLOCK_LOCKOUT = 6;
127
128    /**
129     * Class containing raw data for a given configuration request.
130     */
131    private static final class ConfigurationData {
132        final IBinder token;
133        final List<PersistableBundle> options;
134        ConfigurationData(List<PersistableBundle> opts, IBinder t) {
135            options = opts;
136            token = t;
137        }
138    }
139
140    private ITrustAgentServiceCallback mCallback;
141
142    private Runnable mPendingGrantTrustTask;
143
144    private boolean mManagingTrust;
145
146    // Lock used to access mPendingGrantTrustTask and mCallback.
147    private final Object mLock = new Object();
148
149    private Handler mHandler = new Handler() {
150        public void handleMessage(android.os.Message msg) {
151            switch (msg.what) {
152                case MSG_UNLOCK_ATTEMPT:
153                    onUnlockAttempt(msg.arg1 != 0);
154                    break;
155                case MSG_UNLOCK_LOCKOUT:
156                    onDeviceUnlockLockout(msg.arg1);
157                    break;
158                case MSG_CONFIGURE:
159                    ConfigurationData data = (ConfigurationData) msg.obj;
160                    boolean result = onConfigure(data.options);
161                    if (data.token != null) {
162                        try {
163                            synchronized (mLock) {
164                                mCallback.onConfigureCompleted(result, data.token);
165                            }
166                        } catch (RemoteException e) {
167                            onError("calling onSetTrustAgentFeaturesEnabledCompleted()");
168                        }
169                    }
170                    break;
171                case MSG_TRUST_TIMEOUT:
172                    onTrustTimeout();
173                    break;
174                case MSG_DEVICE_LOCKED:
175                    onDeviceLocked();
176                    break;
177                case MSG_DEVICE_UNLOCKED:
178                    onDeviceUnlocked();
179                    break;
180            }
181        }
182    };
183
184    @Override
185    public void onCreate() {
186        super.onCreate();
187        ComponentName component = new ComponentName(this, getClass());
188        try {
189            ServiceInfo serviceInfo = getPackageManager().getServiceInfo(component, 0 /* flags */);
190            if (!Manifest.permission.BIND_TRUST_AGENT.equals(serviceInfo.permission)) {
191                throw new IllegalStateException(component.flattenToShortString()
192                        + " is not declared with the permission "
193                        + "\"" + Manifest.permission.BIND_TRUST_AGENT + "\"");
194            }
195        } catch (PackageManager.NameNotFoundException e) {
196            Log.e(TAG, "Can't get ServiceInfo for " + component.toShortString());
197        }
198    }
199
200    /**
201     * Called after the user attempts to authenticate in keyguard with their device credentials,
202     * such as pin, pattern or password.
203     *
204     * @param successful true if the user successfully completed the challenge.
205     */
206    public void onUnlockAttempt(boolean successful) {
207    }
208
209    /**
210     * Called when the timeout provided by the agent expires.  Note that this may be called earlier
211     * than requested by the agent if the trust timeout is adjusted by the system or
212     * {@link DevicePolicyManager}.  The agent is expected to re-evaluate the trust state and only
213     * call {@link #grantTrust(CharSequence, long, boolean)} if the trust state should be
214     * continued.
215     */
216    public void onTrustTimeout() {
217    }
218
219    /**
220     * Called when the device enters a state where a PIN, pattern or
221     * password must be entered to unlock it.
222     */
223    public void onDeviceLocked() {
224    }
225
226    /**
227     * Called when the device leaves a state where a PIN, pattern or
228     * password must be entered to unlock it.
229     */
230    public void onDeviceUnlocked() {
231    }
232
233    /**
234     * Called when the device enters a temporary unlock lockout.
235     *
236     * <p>This occurs when the user has consecutively failed to unlock the device too many times,
237     * and must wait until a timeout has passed to perform another attempt. The user may then only
238     * use strong authentication mechanisms (PIN, pattern or password) to unlock the device.
239     * Calls to {@link #grantTrust(CharSequence, long, int)} will be ignored until the user has
240     * unlocked the device and {@link #onDeviceUnlocked()} is called.
241     *
242     * @param timeoutMs The amount of time, in milliseconds, that needs to elapse before the user
243     *    can attempt to unlock the device again.
244     */
245    public void onDeviceUnlockLockout(long timeoutMs) {
246    }
247
248    private void onError(String msg) {
249        Slog.v(TAG, "Remote exception while " + msg);
250    }
251
252    /**
253     * Called when device policy admin wants to enable specific options for agent in response to
254     * {@link DevicePolicyManager#setKeyguardDisabledFeatures(ComponentName, int)} and
255     * {@link DevicePolicyManager#setTrustAgentConfiguration(ComponentName, ComponentName,
256     * PersistableBundle)}.
257     * <p>Agents that support configuration options should overload this method and return 'true'.
258     *
259     * @param options The aggregated list of options or an empty list if no restrictions apply.
260     * @return true if the {@link TrustAgentService} supports configuration options.
261     */
262    public boolean onConfigure(List<PersistableBundle> options) {
263        return false;
264    }
265
266    /**
267     * Call to grant trust on the device.
268     *
269     * @param message describes why the device is trusted, e.g. "Trusted by location".
270     * @param durationMs amount of time in milliseconds to keep the device in a trusted state.
271     *    Trust for this agent will automatically be revoked when the timeout expires unless
272     *    extended by a subsequent call to this function. The timeout is measured from the
273     *    invocation of this function as dictated by {@link SystemClock#elapsedRealtime())}.
274     *    For security reasons, the value should be no larger than necessary.
275     *    The value may be adjusted by the system as necessary to comply with a policy controlled
276     *    by the system or {@link DevicePolicyManager} restrictions. See {@link #onTrustTimeout()}
277     *    for determining when trust expires.
278     * @param initiatedByUser this is a hint to the system that trust is being granted as the
279     *    direct result of user action - such as solving a security challenge. The hint is used
280     *    by the system to optimize the experience. Behavior may vary by device and release, so
281     *    one should only set this parameter if it meets the above criteria rather than relying on
282     *    the behavior of any particular device or release. Corresponds to
283     *    {@link #FLAG_GRANT_TRUST_INITIATED_BY_USER}.
284     * @throws IllegalStateException if the agent is not currently managing trust.
285     *
286     * @deprecated use {@link #grantTrust(CharSequence, long, int)} instead.
287     */
288    @Deprecated
289    public final void grantTrust(
290            final CharSequence message, final long durationMs, final boolean initiatedByUser) {
291        grantTrust(message, durationMs, initiatedByUser ? FLAG_GRANT_TRUST_INITIATED_BY_USER : 0);
292    }
293
294    /**
295     * Call to grant trust on the device.
296     *
297     * @param message describes why the device is trusted, e.g. "Trusted by location".
298     * @param durationMs amount of time in milliseconds to keep the device in a trusted state.
299     *    Trust for this agent will automatically be revoked when the timeout expires unless
300     *    extended by a subsequent call to this function. The timeout is measured from the
301     *    invocation of this function as dictated by {@link SystemClock#elapsedRealtime())}.
302     *    For security reasons, the value should be no larger than necessary.
303     *    The value may be adjusted by the system as necessary to comply with a policy controlled
304     *    by the system or {@link DevicePolicyManager} restrictions. See {@link #onTrustTimeout()}
305     *    for determining when trust expires.
306     * @param flags TBDocumented
307     * @throws IllegalStateException if the agent is not currently managing trust.
308     */
309    public final void grantTrust(
310            final CharSequence message, final long durationMs, @GrantTrustFlags final int flags) {
311        synchronized (mLock) {
312            if (!mManagingTrust) {
313                throw new IllegalStateException("Cannot grant trust if agent is not managing trust."
314                        + " Call setManagingTrust(true) first.");
315            }
316            if (mCallback != null) {
317                try {
318                    mCallback.grantTrust(message.toString(), durationMs, flags);
319                } catch (RemoteException e) {
320                    onError("calling enableTrust()");
321                }
322            } else {
323                // Remember trust has been granted so we can effectively grant it once the service
324                // is bound.
325                mPendingGrantTrustTask = new Runnable() {
326                    @Override
327                    public void run() {
328                        grantTrust(message, durationMs, flags);
329                    }
330                };
331            }
332        }
333    }
334
335    /**
336     * Call to revoke trust on the device.
337     */
338    public final void revokeTrust() {
339        synchronized (mLock) {
340            if (mPendingGrantTrustTask != null) {
341                mPendingGrantTrustTask = null;
342            }
343            if (mCallback != null) {
344                try {
345                    mCallback.revokeTrust();
346                } catch (RemoteException e) {
347                    onError("calling revokeTrust()");
348                }
349            }
350        }
351    }
352
353    /**
354     * Call to notify the system if the agent is ready to manage trust.
355     *
356     * This property is not persistent across recreating the service and defaults to false.
357     * Therefore this method is typically called when initializing the agent in {@link #onCreate}.
358     *
359     * @param managingTrust indicates if the agent would like to manage trust.
360     */
361    public final void setManagingTrust(boolean managingTrust) {
362        synchronized (mLock) {
363            if (mManagingTrust != managingTrust) {
364                mManagingTrust = managingTrust;
365                if (mCallback != null) {
366                    try {
367                        mCallback.setManagingTrust(managingTrust);
368                    } catch (RemoteException e) {
369                        onError("calling setManagingTrust()");
370                    }
371                }
372            }
373        }
374    }
375
376    @Override
377    public final IBinder onBind(Intent intent) {
378        if (DEBUG) Slog.v(TAG, "onBind() intent = " + intent);
379        return new TrustAgentServiceWrapper();
380    }
381
382    private final class TrustAgentServiceWrapper extends ITrustAgentService.Stub {
383        @Override /* Binder API */
384        public void onUnlockAttempt(boolean successful) {
385            mHandler.obtainMessage(MSG_UNLOCK_ATTEMPT, successful ? 1 : 0, 0).sendToTarget();
386        }
387
388        @Override
389        public void onUnlockLockout(int timeoutMs) {
390            mHandler.obtainMessage(MSG_UNLOCK_LOCKOUT, timeoutMs, 0).sendToTarget();
391        }
392
393        @Override /* Binder API */
394        public void onTrustTimeout() {
395            mHandler.sendEmptyMessage(MSG_TRUST_TIMEOUT);
396        }
397
398        @Override /* Binder API */
399        public void onConfigure(List<PersistableBundle> args, IBinder token) {
400            mHandler.obtainMessage(MSG_CONFIGURE, new ConfigurationData(args, token))
401                    .sendToTarget();
402        }
403
404        @Override
405        public void onDeviceLocked() throws RemoteException {
406            mHandler.obtainMessage(MSG_DEVICE_LOCKED).sendToTarget();
407        }
408
409        @Override
410        public void onDeviceUnlocked() throws RemoteException {
411            mHandler.obtainMessage(MSG_DEVICE_UNLOCKED).sendToTarget();
412        }
413
414        @Override /* Binder API */
415        public void setCallback(ITrustAgentServiceCallback callback) {
416            synchronized (mLock) {
417                mCallback = callback;
418                // The managingTrust property is false implicitly on the server-side, so we only
419                // need to set it here if the agent has decided to manage trust.
420                if (mManagingTrust) {
421                    try {
422                        mCallback.setManagingTrust(mManagingTrust);
423                    } catch (RemoteException e ) {
424                        onError("calling setManagingTrust()");
425                    }
426                }
427                if (mPendingGrantTrustTask != null) {
428                    mPendingGrantTrustTask.run();
429                    mPendingGrantTrustTask = null;
430                }
431            }
432        }
433    }
434
435}
436