TrustAgentService.java revision d4efaac5d54cdb3735b032bb76a5639949f33216
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.os.SystemClock;
34import android.util.Log;
35import android.util.Slog;
36
37/**
38 * A service that notifies the system about whether it believes the environment of the device
39 * to be trusted.
40 *
41 * <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>
45 *
46 * <p>To extend this class, you must declare the service in your manifest file with
47 * the {@link android.Manifest.permission#BIND_TRUST_AGENT} permission
48 * 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"
52 *          android:permission="android.permission.BIND_TRUST_AGENT">
53 *     &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>
65 * &lt;trust-agent xmlns:android="http://schemas.android.com/apk/res/android"
66 *          android:settingsActivity=".TrustAgentSettings" /></pre>
67 *
68 * @hide
69 */
70@SystemApi
71public class TrustAgentService extends Service {
72    private final String TAG = TrustAgentService.class.getSimpleName() +
73            "[" + getClass().getSimpleName() + "]";
74    private static final boolean DEBUG = false;
75
76    /**
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    /**
90     * A white list of features that the given trust agent should support when otherwise disabled
91     * by device policy.
92     */
93    public static final String KEY_FEATURES = "trust_agent_features";
94
95    private static final int MSG_UNLOCK_ATTEMPT = 1;
96    private static final int MSG_SET_TRUST_AGENT_FEATURES_ENABLED = 2;
97    private static final int MSG_TRUST_TIMEOUT = 3;
98
99    private ITrustAgentServiceCallback mCallback;
100
101    private Runnable mPendingGrantTrustTask;
102
103    private boolean mManagingTrust;
104
105    // Lock used to access mPendingGrantTrustTask and mCallback.
106    private final Object mLock = new Object();
107
108    private Handler mHandler = new Handler() {
109        public void handleMessage(android.os.Message msg) {
110            switch (msg.what) {
111                case MSG_UNLOCK_ATTEMPT:
112                    onUnlockAttempt(msg.arg1 != 0);
113                    break;
114                case MSG_SET_TRUST_AGENT_FEATURES_ENABLED:
115                    Bundle features = msg.peekData();
116                    IBinder token = (IBinder) msg.obj;
117                    boolean result = onSetTrustAgentFeaturesEnabled(features);
118                    try {
119                        synchronized (mLock) {
120                            mCallback.onSetTrustAgentFeaturesEnabledCompleted(result, token);
121                        }
122                    } catch (RemoteException e) {
123                        onError("calling onSetTrustAgentFeaturesEnabledCompleted()");
124                    }
125                    break;
126                case MSG_TRUST_TIMEOUT:
127                    onTrustTimeout();
128                    break;
129            }
130        }
131    };
132
133    @Override
134    public void onCreate() {
135        super.onCreate();
136        ComponentName component = new ComponentName(this, getClass());
137        try {
138            ServiceInfo serviceInfo = getPackageManager().getServiceInfo(component, 0 /* flags */);
139            if (!Manifest.permission.BIND_TRUST_AGENT.equals(serviceInfo.permission)) {
140                throw new IllegalStateException(component.flattenToShortString()
141                        + " is not declared with the permission "
142                        + "\"" + Manifest.permission.BIND_TRUST_AGENT + "\"");
143            }
144        } catch (PackageManager.NameNotFoundException e) {
145            Log.e(TAG, "Can't get ServiceInfo for " + component.toShortString());
146        }
147    }
148
149    /**
150     * Called after the user attempts to authenticate in keyguard with their device credentials,
151     * such as pin, pattern or password.
152     *
153     * @param successful true if the user successfully completed the challenge.
154     */
155    public void onUnlockAttempt(boolean successful) {
156    }
157
158    /**
159     * Called when the timeout provided by the agent expires.  Note that this may be called earlier
160     * than requested by the agent if the trust timeout is adjusted by the system or
161     * {@link DevicePolicyManager}.  The agent is expected to re-evaluate the trust state and only
162     * call {@link #grantTrust(CharSequence, long, boolean)} if the trust state should be
163     * continued.
164     */
165    public void onTrustTimeout() {
166    }
167
168    private void onError(String msg) {
169        Slog.v(TAG, "Remote exception while " + msg);
170    }
171
172    /**
173     * Called when device policy wants to restrict features in the agent in response to
174     * {@link DevicePolicyManager#setTrustAgentFeaturesEnabled(ComponentName, ComponentName, java.util.List) }.
175     * Agents that support this feature should overload this method and return 'true'.
176     *
177     * The list of options can be obtained by calling
178     * options.getStringArrayList({@link #KEY_FEATURES}). Presence of a feature string in the list
179     * means it should be enabled ("white-listed"). Absence of the feature means it should be
180     * disabled. An empty list means all features should be disabled.
181     *
182     * This function is only called if {@link DevicePolicyManager#KEYGUARD_DISABLE_TRUST_AGENTS} is
183     * set.
184     *
185     * @param options Option feature bundle.
186     * @return true if the {@link TrustAgentService} supports this feature.
187     */
188    public boolean onSetTrustAgentFeaturesEnabled(Bundle options) {
189        return false;
190    }
191
192    /**
193     * Call to grant trust on the device.
194     *
195     * @param message describes why the device is trusted, e.g. "Trusted by location".
196     * @param durationMs amount of time in milliseconds to keep the device in a trusted state.
197     *    Trust for this agent will automatically be revoked when the timeout expires unless
198     *    extended by a subsequent call to this function. The timeout is measured from the
199     *    invocation of this function as dictated by {@link SystemClock#elapsedRealtime())}.
200     *    For security reasons, the value should be no larger than necessary.
201     *    The value may be adjusted by the system as necessary to comply with a policy controlled
202     *    by the system or {@link DevicePolicyManager} restrictions. See {@link #onTrustTimeout()}
203     *    for determining when trust expires.
204     * @param initiatedByUser this is a hint to the system that trust is being granted as the
205     *    direct result of user action - such as solving a security challenge. The hint is used
206     *    by the system to optimize the experience. Behavior may vary by device and release, so
207     *    one should only set this parameter if it meets the above criteria rather than relying on
208     *    the behavior of any particular device or release.
209     * @throws IllegalStateException if the agent is not currently managing trust.
210     */
211    public final void grantTrust(
212            final CharSequence message, final long durationMs, final boolean initiatedByUser) {
213        synchronized (mLock) {
214            if (!mManagingTrust) {
215                throw new IllegalStateException("Cannot grant trust if agent is not managing trust."
216                        + " Call setManagingTrust(true) first.");
217            }
218            if (mCallback != null) {
219                try {
220                    mCallback.grantTrust(message.toString(), durationMs, initiatedByUser);
221                } catch (RemoteException e) {
222                    onError("calling enableTrust()");
223                }
224            } else {
225                // Remember trust has been granted so we can effectively grant it once the service
226                // is bound.
227                mPendingGrantTrustTask = new Runnable() {
228                    @Override
229                    public void run() {
230                        grantTrust(message, durationMs, initiatedByUser);
231                    }
232                };
233            }
234        }
235    }
236
237    /**
238     * Call to revoke trust on the device.
239     */
240    public final void revokeTrust() {
241        synchronized (mLock) {
242            if (mPendingGrantTrustTask != null) {
243                mPendingGrantTrustTask = null;
244            }
245            if (mCallback != null) {
246                try {
247                    mCallback.revokeTrust();
248                } catch (RemoteException e) {
249                    onError("calling revokeTrust()");
250                }
251            }
252        }
253    }
254
255    /**
256     * Call to notify the system if the agent is ready to manage trust.
257     *
258     * This property is not persistent across recreating the service and defaults to false.
259     * Therefore this method is typically called when initializing the agent in {@link #onCreate}.
260     *
261     * @param managingTrust indicates if the agent would like to manage trust.
262     */
263    public final void setManagingTrust(boolean managingTrust) {
264        synchronized (mLock) {
265            if (mManagingTrust != managingTrust) {
266                mManagingTrust = managingTrust;
267                if (mCallback != null) {
268                    try {
269                        mCallback.setManagingTrust(managingTrust);
270                    } catch (RemoteException e) {
271                        onError("calling setManagingTrust()");
272                    }
273                }
274            }
275        }
276    }
277
278    @Override
279    public final IBinder onBind(Intent intent) {
280        if (DEBUG) Slog.v(TAG, "onBind() intent = " + intent);
281        return new TrustAgentServiceWrapper();
282    }
283
284    private final class TrustAgentServiceWrapper extends ITrustAgentService.Stub {
285        @Override /* Binder API */
286        public void onUnlockAttempt(boolean successful) {
287            mHandler.obtainMessage(MSG_UNLOCK_ATTEMPT, successful ? 1 : 0, 0).sendToTarget();
288        }
289
290        @Override /* Binder API */
291        public void onTrustTimeout() {
292            mHandler.sendEmptyMessage(MSG_TRUST_TIMEOUT);
293        }
294
295        @Override /* Binder API */
296        public void setCallback(ITrustAgentServiceCallback callback) {
297            synchronized (mLock) {
298                mCallback = callback;
299                // The managingTrust property is false implicitly on the server-side, so we only
300                // need to set it here if the agent has decided to manage trust.
301                if (mManagingTrust) {
302                    try {
303                        mCallback.setManagingTrust(mManagingTrust);
304                    } catch (RemoteException e ) {
305                        onError("calling setManagingTrust()");
306                    }
307                }
308                if (mPendingGrantTrustTask != null) {
309                    mPendingGrantTrustTask.run();
310                    mPendingGrantTrustTask = null;
311                }
312            }
313        }
314
315        @Override /* Binder API */
316        public void setTrustAgentFeaturesEnabled(Bundle features, IBinder token) {
317            Message msg = mHandler.obtainMessage(MSG_SET_TRUST_AGENT_FEATURES_ENABLED, token);
318            msg.setData(features);
319            msg.sendToTarget();
320        }
321    }
322
323}
324