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