• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package android.service.trust;
18 
19 import android.Manifest;
20 import android.annotation.SdkConstant;
21 import android.annotation.SystemApi;
22 import android.app.Service;
23 import android.app.admin.DevicePolicyManager;
24 import android.content.ComponentName;
25 import android.content.Intent;
26 import android.content.pm.PackageManager;
27 import android.content.pm.ServiceInfo;
28 import android.os.Bundle;
29 import android.os.Handler;
30 import android.os.IBinder;
31 import android.os.Message;
32 import android.os.PersistableBundle;
33 import android.os.RemoteException;
34 import android.os.SystemClock;
35 import android.util.Log;
36 import android.util.Slog;
37 
38 import 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
74 public class TrustAgentService extends Service {
75     private final String TAG = TrustAgentService.class.getSimpleName() +
76             "[" + getClass().getSimpleName() + "]";
77     private static final boolean DEBUG = false;
78 
79     /**
80      * The {@link Intent} that must be declared as handled by the service.
81      */
82     @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
83     public static final String SERVICE_INTERFACE
84             = "android.service.trust.TrustAgentService";
85 
86     /**
87      * The name of the {@code meta-data} tag pointing to additional configuration of the trust
88      * agent.
89      */
90     public static final String TRUST_AGENT_META_DATA = "android.service.trust.trustagent";
91 
92     private static final int MSG_UNLOCK_ATTEMPT = 1;
93     private static final int MSG_CONFIGURE = 2;
94     private static final int MSG_TRUST_TIMEOUT = 3;
95     private static final int MSG_DEVICE_LOCKED = 4;
96     private static final int MSG_DEVICE_UNLOCKED = 5;
97 
98     /**
99      * Class containing raw data for a given configuration request.
100      */
101     private static final class ConfigurationData {
102         final IBinder token;
103         final List<PersistableBundle> options;
ConfigurationData(List<PersistableBundle> opts, IBinder t)104         ConfigurationData(List<PersistableBundle> opts, IBinder t) {
105             options = opts;
106             token = t;
107         }
108     }
109 
110     private ITrustAgentServiceCallback mCallback;
111 
112     private Runnable mPendingGrantTrustTask;
113 
114     private boolean mManagingTrust;
115 
116     // Lock used to access mPendingGrantTrustTask and mCallback.
117     private final Object mLock = new Object();
118 
119     private Handler mHandler = new Handler() {
120         public void handleMessage(android.os.Message msg) {
121             switch (msg.what) {
122                 case MSG_UNLOCK_ATTEMPT:
123                     onUnlockAttempt(msg.arg1 != 0);
124                     break;
125                 case MSG_CONFIGURE:
126                     ConfigurationData data = (ConfigurationData) msg.obj;
127                     boolean result = onConfigure(data.options);
128                     try {
129                         synchronized (mLock) {
130                             mCallback.onConfigureCompleted(result, data.token);
131                         }
132                     } catch (RemoteException e) {
133                         onError("calling onSetTrustAgentFeaturesEnabledCompleted()");
134                     }
135                     break;
136                 case MSG_TRUST_TIMEOUT:
137                     onTrustTimeout();
138                     break;
139                 case MSG_DEVICE_LOCKED:
140                     onDeviceLocked();
141                     break;
142                 case MSG_DEVICE_UNLOCKED:
143                     onDeviceUnlocked();
144                     break;
145             }
146         }
147     };
148 
149     @Override
onCreate()150     public void onCreate() {
151         super.onCreate();
152         ComponentName component = new ComponentName(this, getClass());
153         try {
154             ServiceInfo serviceInfo = getPackageManager().getServiceInfo(component, 0 /* flags */);
155             if (!Manifest.permission.BIND_TRUST_AGENT.equals(serviceInfo.permission)) {
156                 throw new IllegalStateException(component.flattenToShortString()
157                         + " is not declared with the permission "
158                         + "\"" + Manifest.permission.BIND_TRUST_AGENT + "\"");
159             }
160         } catch (PackageManager.NameNotFoundException e) {
161             Log.e(TAG, "Can't get ServiceInfo for " + component.toShortString());
162         }
163     }
164 
165     /**
166      * Called after the user attempts to authenticate in keyguard with their device credentials,
167      * such as pin, pattern or password.
168      *
169      * @param successful true if the user successfully completed the challenge.
170      */
onUnlockAttempt(boolean successful)171     public void onUnlockAttempt(boolean successful) {
172     }
173 
174     /**
175      * Called when the timeout provided by the agent expires.  Note that this may be called earlier
176      * than requested by the agent if the trust timeout is adjusted by the system or
177      * {@link DevicePolicyManager}.  The agent is expected to re-evaluate the trust state and only
178      * call {@link #grantTrust(CharSequence, long, boolean)} if the trust state should be
179      * continued.
180      */
onTrustTimeout()181     public void onTrustTimeout() {
182     }
183 
184     /**
185      * Called when the device enters a state where a PIN, pattern or
186      * password must be entered to unlock it.
187      */
onDeviceLocked()188     public void onDeviceLocked() {
189     }
190 
191     /**
192      * Called when the device leaves a state where a PIN, pattern or
193      * password must be entered to unlock it.
194      */
onDeviceUnlocked()195     public void onDeviceUnlocked() {
196     }
197 
onError(String msg)198     private void onError(String msg) {
199         Slog.v(TAG, "Remote exception while " + msg);
200     }
201 
202     /**
203      * Called when device policy admin wants to enable specific options for agent in response to
204      * {@link DevicePolicyManager#setKeyguardDisabledFeatures(ComponentName, int)} and
205      * {@link DevicePolicyManager#setTrustAgentConfiguration(ComponentName, ComponentName,
206      * PersistableBundle)}.
207      * <p>Agents that support configuration options should overload this method and return 'true'.
208      *
209      * @param options bundle containing all options or null if none.
210      * @return true if the {@link TrustAgentService} supports configuration options.
211      */
onConfigure(List<PersistableBundle> options)212     public boolean onConfigure(List<PersistableBundle> options) {
213         return false;
214     }
215 
216     /**
217      * Call to grant trust on the device.
218      *
219      * @param message describes why the device is trusted, e.g. "Trusted by location".
220      * @param durationMs amount of time in milliseconds to keep the device in a trusted state.
221      *    Trust for this agent will automatically be revoked when the timeout expires unless
222      *    extended by a subsequent call to this function. The timeout is measured from the
223      *    invocation of this function as dictated by {@link SystemClock#elapsedRealtime())}.
224      *    For security reasons, the value should be no larger than necessary.
225      *    The value may be adjusted by the system as necessary to comply with a policy controlled
226      *    by the system or {@link DevicePolicyManager} restrictions. See {@link #onTrustTimeout()}
227      *    for determining when trust expires.
228      * @param initiatedByUser this is a hint to the system that trust is being granted as the
229      *    direct result of user action - such as solving a security challenge. The hint is used
230      *    by the system to optimize the experience. Behavior may vary by device and release, so
231      *    one should only set this parameter if it meets the above criteria rather than relying on
232      *    the behavior of any particular device or release.
233      * @throws IllegalStateException if the agent is not currently managing trust.
234      */
grantTrust( final CharSequence message, final long durationMs, final boolean initiatedByUser)235     public final void grantTrust(
236             final CharSequence message, final long durationMs, final boolean initiatedByUser) {
237         synchronized (mLock) {
238             if (!mManagingTrust) {
239                 throw new IllegalStateException("Cannot grant trust if agent is not managing trust."
240                         + " Call setManagingTrust(true) first.");
241             }
242             if (mCallback != null) {
243                 try {
244                     mCallback.grantTrust(message.toString(), durationMs, initiatedByUser);
245                 } catch (RemoteException e) {
246                     onError("calling enableTrust()");
247                 }
248             } else {
249                 // Remember trust has been granted so we can effectively grant it once the service
250                 // is bound.
251                 mPendingGrantTrustTask = new Runnable() {
252                     @Override
253                     public void run() {
254                         grantTrust(message, durationMs, initiatedByUser);
255                     }
256                 };
257             }
258         }
259     }
260 
261     /**
262      * Call to revoke trust on the device.
263      */
revokeTrust()264     public final void revokeTrust() {
265         synchronized (mLock) {
266             if (mPendingGrantTrustTask != null) {
267                 mPendingGrantTrustTask = null;
268             }
269             if (mCallback != null) {
270                 try {
271                     mCallback.revokeTrust();
272                 } catch (RemoteException e) {
273                     onError("calling revokeTrust()");
274                 }
275             }
276         }
277     }
278 
279     /**
280      * Call to notify the system if the agent is ready to manage trust.
281      *
282      * This property is not persistent across recreating the service and defaults to false.
283      * Therefore this method is typically called when initializing the agent in {@link #onCreate}.
284      *
285      * @param managingTrust indicates if the agent would like to manage trust.
286      */
setManagingTrust(boolean managingTrust)287     public final void setManagingTrust(boolean managingTrust) {
288         synchronized (mLock) {
289             if (mManagingTrust != managingTrust) {
290                 mManagingTrust = managingTrust;
291                 if (mCallback != null) {
292                     try {
293                         mCallback.setManagingTrust(managingTrust);
294                     } catch (RemoteException e) {
295                         onError("calling setManagingTrust()");
296                     }
297                 }
298             }
299         }
300     }
301 
302     @Override
onBind(Intent intent)303     public final IBinder onBind(Intent intent) {
304         if (DEBUG) Slog.v(TAG, "onBind() intent = " + intent);
305         return new TrustAgentServiceWrapper();
306     }
307 
308     private final class TrustAgentServiceWrapper extends ITrustAgentService.Stub {
309         @Override /* Binder API */
onUnlockAttempt(boolean successful)310         public void onUnlockAttempt(boolean successful) {
311             mHandler.obtainMessage(MSG_UNLOCK_ATTEMPT, successful ? 1 : 0, 0).sendToTarget();
312         }
313 
314         @Override /* Binder API */
onTrustTimeout()315         public void onTrustTimeout() {
316             mHandler.sendEmptyMessage(MSG_TRUST_TIMEOUT);
317         }
318 
319         @Override /* Binder API */
onConfigure(List<PersistableBundle> args, IBinder token)320         public void onConfigure(List<PersistableBundle> args, IBinder token) {
321             mHandler.obtainMessage(MSG_CONFIGURE, new ConfigurationData(args, token))
322                     .sendToTarget();
323         }
324 
325         @Override
onDeviceLocked()326         public void onDeviceLocked() throws RemoteException {
327             mHandler.obtainMessage(MSG_DEVICE_LOCKED).sendToTarget();
328         }
329 
330         @Override
onDeviceUnlocked()331         public void onDeviceUnlocked() throws RemoteException {
332             mHandler.obtainMessage(MSG_DEVICE_UNLOCKED).sendToTarget();
333         }
334 
335         @Override /* Binder API */
setCallback(ITrustAgentServiceCallback callback)336         public void setCallback(ITrustAgentServiceCallback callback) {
337             synchronized (mLock) {
338                 mCallback = callback;
339                 // The managingTrust property is false implicitly on the server-side, so we only
340                 // need to set it here if the agent has decided to manage trust.
341                 if (mManagingTrust) {
342                     try {
343                         mCallback.setManagingTrust(mManagingTrust);
344                     } catch (RemoteException e ) {
345                         onError("calling setManagingTrust()");
346                     }
347                 }
348                 if (mPendingGrantTrustTask != null) {
349                     mPendingGrantTrustTask.run();
350                     mPendingGrantTrustTask = null;
351                 }
352             }
353         }
354     }
355 
356 }
357