Home | History | Annotate | Download | only in trust
      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;
    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
    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      */
    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      */
    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      */
    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      */
    195     public void onDeviceUnlocked() {
    196     }
    197 
    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      */
    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      */
    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      */
    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      */
    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
    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 */
    310         public void onUnlockAttempt(boolean successful) {
    311             mHandler.obtainMessage(MSG_UNLOCK_ATTEMPT, successful ? 1 : 0, 0).sendToTarget();
    312         }
    313 
    314         @Override /* Binder API */
    315         public void onTrustTimeout() {
    316             mHandler.sendEmptyMessage(MSG_TRUST_TIMEOUT);
    317         }
    318 
    319         @Override /* Binder API */
    320         public void onConfigure(List<PersistableBundle> args, IBinder token) {
    321             mHandler.obtainMessage(MSG_CONFIGURE, new ConfigurationData(args, token))
    322                     .sendToTarget();
    323         }
    324 
    325         @Override
    326         public void onDeviceLocked() throws RemoteException {
    327             mHandler.obtainMessage(MSG_DEVICE_LOCKED).sendToTarget();
    328         }
    329 
    330         @Override
    331         public void onDeviceUnlocked() throws RemoteException {
    332             mHandler.obtainMessage(MSG_DEVICE_UNLOCKED).sendToTarget();
    333         }
    334 
    335         @Override /* Binder API */
    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