• 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