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 com.android.server.trust;
     18 
     19 import android.app.AlarmManager;
     20 import android.app.PendingIntent;
     21 import android.app.admin.DevicePolicyManager;
     22 import android.content.BroadcastReceiver;
     23 import android.content.ComponentName;
     24 import android.content.Context;
     25 import android.content.Intent;
     26 import android.content.IntentFilter;
     27 import android.content.ServiceConnection;
     28 import android.net.Uri;
     29 import android.os.Binder;
     30 import android.os.Handler;
     31 import android.os.IBinder;
     32 import android.os.Message;
     33 import android.os.PatternMatcher;
     34 import android.os.PersistableBundle;
     35 import android.os.RemoteException;
     36 import android.os.SystemClock;
     37 import android.os.UserHandle;
     38 import android.util.Log;
     39 import android.util.Slog;
     40 import android.service.trust.ITrustAgentService;
     41 import android.service.trust.ITrustAgentServiceCallback;
     42 
     43 import java.util.List;
     44 
     45 /**
     46  * A wrapper around a TrustAgentService interface. Coordinates communication between
     47  * TrustManager and the actual TrustAgent.
     48  */
     49 public class TrustAgentWrapper {
     50     private static final String EXTRA_COMPONENT_NAME = "componentName";
     51     private static final String TRUST_EXPIRED_ACTION = "android.server.trust.TRUST_EXPIRED_ACTION";
     52     private static final String PERMISSION = android.Manifest.permission.PROVIDE_TRUST_AGENT;
     53     private static final boolean DEBUG = false;
     54     private static final String TAG = "TrustAgentWrapper";
     55 
     56     private static final int MSG_GRANT_TRUST = 1;
     57     private static final int MSG_REVOKE_TRUST = 2;
     58     private static final int MSG_TRUST_TIMEOUT = 3;
     59     private static final int MSG_RESTART_TIMEOUT = 4;
     60     private static final int MSG_SET_TRUST_AGENT_FEATURES_COMPLETED = 5;
     61     private static final int MSG_MANAGING_TRUST = 6;
     62 
     63     /**
     64      * Time in uptime millis that we wait for the service connection, both when starting
     65      * and when the service disconnects.
     66      */
     67     private static final long RESTART_TIMEOUT_MILLIS = 5 * 60000;
     68 
     69     /**
     70      * Long extra for {@link #MSG_GRANT_TRUST}
     71      */
     72     private static final String DATA_DURATION = "duration";
     73 
     74     private final TrustManagerService mTrustManagerService;
     75     private final int mUserId;
     76     private final Context mContext;
     77     private final ComponentName mName;
     78 
     79     private ITrustAgentService mTrustAgentService;
     80     private boolean mBound;
     81     private long mScheduledRestartUptimeMillis;
     82     private long mMaximumTimeToLock; // from DevicePolicyManager
     83 
     84     // Trust state
     85     private boolean mTrusted;
     86     private CharSequence mMessage;
     87     private boolean mTrustDisabledByDpm;
     88     private boolean mManagingTrust;
     89     private IBinder mSetTrustAgentFeaturesToken;
     90     private AlarmManager mAlarmManager;
     91     private final Intent mAlarmIntent;
     92     private PendingIntent mAlarmPendingIntent;
     93 
     94     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
     95         @Override
     96         public void onReceive(Context context, Intent intent) {
     97             ComponentName component = intent.getParcelableExtra(EXTRA_COMPONENT_NAME);
     98             if (TRUST_EXPIRED_ACTION.equals(intent.getAction())
     99                     && mName.equals(component)) {
    100                 mHandler.removeMessages(MSG_TRUST_TIMEOUT);
    101                 mHandler.sendEmptyMessage(MSG_TRUST_TIMEOUT);
    102             }
    103         }
    104     };
    105 
    106     private final Handler mHandler = new Handler() {
    107         @Override
    108         public void handleMessage(Message msg) {
    109             switch (msg.what) {
    110                 case MSG_GRANT_TRUST:
    111                     if (!isConnected()) {
    112                         Log.w(TAG, "Agent is not connected, cannot grant trust: "
    113                                 + mName.flattenToShortString());
    114                         return;
    115                     }
    116                     mTrusted = true;
    117                     mMessage = (CharSequence) msg.obj;
    118                     boolean initiatedByUser = msg.arg1 != 0;
    119                     long durationMs = msg.getData().getLong(DATA_DURATION);
    120                     if (durationMs > 0) {
    121                         final long duration;
    122                         if (mMaximumTimeToLock != 0) {
    123                             // Enforce DevicePolicyManager timeout.  This is here as a safeguard to
    124                             // ensure trust agents are evaluating trust state at least as often as
    125                             // the policy dictates. Admins that want more guarantees should be using
    126                             // DevicePolicyManager#KEYGUARD_DISABLE_TRUST_AGENTS.
    127                             duration = Math.min(durationMs, mMaximumTimeToLock);
    128                             if (DEBUG) {
    129                                 Log.v(TAG, "DPM lock timeout in effect. Timeout adjusted from "
    130                                     + durationMs + " to " + duration);
    131                             }
    132                         } else {
    133                             duration = durationMs;
    134                         }
    135                         long expiration = SystemClock.elapsedRealtime() + duration;
    136                         mAlarmPendingIntent = PendingIntent.getBroadcast(mContext, 0, mAlarmIntent,
    137                                 PendingIntent.FLAG_CANCEL_CURRENT);
    138                         mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, expiration,
    139                                 mAlarmPendingIntent);
    140                     }
    141                     mTrustManagerService.mArchive.logGrantTrust(mUserId, mName,
    142                             (mMessage != null ? mMessage.toString() : null),
    143                             durationMs, initiatedByUser);
    144                     mTrustManagerService.updateTrust(mUserId, initiatedByUser);
    145                     break;
    146                 case MSG_TRUST_TIMEOUT:
    147                     if (DEBUG) Slog.v(TAG, "Trust timed out : " + mName.flattenToShortString());
    148                     mTrustManagerService.mArchive.logTrustTimeout(mUserId, mName);
    149                     onTrustTimeout();
    150                     // Fall through.
    151                 case MSG_REVOKE_TRUST:
    152                     mTrusted = false;
    153                     mMessage = null;
    154                     mHandler.removeMessages(MSG_TRUST_TIMEOUT);
    155                     if (msg.what == MSG_REVOKE_TRUST) {
    156                         mTrustManagerService.mArchive.logRevokeTrust(mUserId, mName);
    157                     }
    158                     mTrustManagerService.updateTrust(mUserId, false);
    159                     break;
    160                 case MSG_RESTART_TIMEOUT:
    161                     destroy();
    162                     mTrustManagerService.resetAgent(mName, mUserId);
    163                     break;
    164                 case MSG_SET_TRUST_AGENT_FEATURES_COMPLETED:
    165                     IBinder token = (IBinder) msg.obj;
    166                     boolean result = msg.arg1 != 0;
    167                     if (mSetTrustAgentFeaturesToken == token) {
    168                         mSetTrustAgentFeaturesToken = null;
    169                         if (mTrustDisabledByDpm && result) {
    170                             if (DEBUG) Log.v(TAG, "Re-enabling agent because it acknowledged "
    171                                     + "enabled features: " + mName);
    172                             mTrustDisabledByDpm = false;
    173                             mTrustManagerService.updateTrust(mUserId, false);
    174                         }
    175                     } else {
    176                         if (DEBUG) Log.w(TAG, "Ignoring MSG_SET_TRUST_AGENT_FEATURES_COMPLETED "
    177                                 + "with obsolete token: " + mName);
    178                     }
    179                     break;
    180                 case MSG_MANAGING_TRUST:
    181                     mManagingTrust = msg.arg1 != 0;
    182                     if (!mManagingTrust) {
    183                         mTrusted = false;
    184                         mMessage = null;
    185                     }
    186                     mTrustManagerService.mArchive.logManagingTrust(mUserId, mName, mManagingTrust);
    187                     mTrustManagerService.updateTrust(mUserId, false);
    188                     break;
    189             }
    190         }
    191     };
    192 
    193     private ITrustAgentServiceCallback mCallback = new ITrustAgentServiceCallback.Stub() {
    194 
    195         @Override
    196         public void grantTrust(CharSequence userMessage, long durationMs, boolean initiatedByUser) {
    197             if (DEBUG) Slog.v(TAG, "enableTrust(" + userMessage + ", durationMs = " + durationMs
    198                         + ", initiatedByUser = " + initiatedByUser + ")");
    199 
    200             Message msg = mHandler.obtainMessage(
    201                     MSG_GRANT_TRUST, initiatedByUser ? 1 : 0, 0, userMessage);
    202             msg.getData().putLong(DATA_DURATION, durationMs);
    203             msg.sendToTarget();
    204         }
    205 
    206         @Override
    207         public void revokeTrust() {
    208             if (DEBUG) Slog.v(TAG, "revokeTrust()");
    209             mHandler.sendEmptyMessage(MSG_REVOKE_TRUST);
    210         }
    211 
    212         @Override
    213         public void setManagingTrust(boolean managingTrust) {
    214             if (DEBUG) Slog.v(TAG, "managingTrust()");
    215             mHandler.obtainMessage(MSG_MANAGING_TRUST, managingTrust ? 1 : 0, 0).sendToTarget();
    216         }
    217 
    218         @Override
    219         public void onConfigureCompleted(boolean result, IBinder token) {
    220             if (DEBUG) Slog.v(TAG, "onSetTrustAgentFeaturesEnabledCompleted(result=" + result);
    221             mHandler.obtainMessage(MSG_SET_TRUST_AGENT_FEATURES_COMPLETED,
    222                     result ? 1 : 0, 0, token).sendToTarget();
    223         }
    224     };
    225 
    226     private final ServiceConnection mConnection = new ServiceConnection() {
    227         @Override
    228         public void onServiceConnected(ComponentName name, IBinder service) {
    229             if (DEBUG) Log.v(TAG, "TrustAgent started : " + name.flattenToString());
    230             mHandler.removeMessages(MSG_RESTART_TIMEOUT);
    231             mTrustAgentService = ITrustAgentService.Stub.asInterface(service);
    232             mTrustManagerService.mArchive.logAgentConnected(mUserId, name);
    233             setCallback(mCallback);
    234             updateDevicePolicyFeatures();
    235 
    236             if (mTrustManagerService.isDeviceLockedInner(mUserId)) {
    237                 onDeviceLocked();
    238             } else {
    239                 onDeviceUnlocked();
    240             }
    241         }
    242 
    243         @Override
    244         public void onServiceDisconnected(ComponentName name) {
    245             if (DEBUG) Log.v(TAG, "TrustAgent disconnected : " + name.flattenToShortString());
    246             mTrustAgentService = null;
    247             mManagingTrust = false;
    248             mSetTrustAgentFeaturesToken = null;
    249             mTrustManagerService.mArchive.logAgentDied(mUserId, name);
    250             mHandler.sendEmptyMessage(MSG_REVOKE_TRUST);
    251             if (mBound) {
    252                 scheduleRestart();
    253             }
    254             // mTrustDisabledByDpm maintains state
    255         }
    256     };
    257 
    258     public TrustAgentWrapper(Context context, TrustManagerService trustManagerService,
    259             Intent intent, UserHandle user) {
    260         mContext = context;
    261         mTrustManagerService = trustManagerService;
    262         mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
    263         mUserId = user.getIdentifier();
    264         mName = intent.getComponent();
    265 
    266         mAlarmIntent = new Intent(TRUST_EXPIRED_ACTION).putExtra(EXTRA_COMPONENT_NAME, mName);
    267         mAlarmIntent.setData(Uri.parse(mAlarmIntent.toUri(Intent.URI_INTENT_SCHEME)));
    268         mAlarmIntent.setPackage(context.getPackageName());
    269 
    270         final IntentFilter alarmFilter = new IntentFilter(TRUST_EXPIRED_ACTION);
    271         alarmFilter.addDataScheme(mAlarmIntent.getScheme());
    272         final String pathUri = mAlarmIntent.toUri(Intent.URI_INTENT_SCHEME);
    273         alarmFilter.addDataPath(pathUri, PatternMatcher.PATTERN_LITERAL);
    274         mContext.registerReceiver(mBroadcastReceiver, alarmFilter, PERMISSION, null);
    275 
    276         // Schedules a restart for when connecting times out. If the connection succeeds,
    277         // the restart is canceled in mCallback's onConnected.
    278         scheduleRestart();
    279         mBound = context.bindServiceAsUser(intent, mConnection, Context.BIND_AUTO_CREATE, user);
    280         if (!mBound) {
    281             Log.e(TAG, "Can't bind to TrustAgent " + mName.flattenToShortString());
    282         }
    283     }
    284 
    285     private void onError(Exception e) {
    286         Slog.w(TAG , "Remote Exception", e);
    287     }
    288 
    289     private void onTrustTimeout() {
    290         try {
    291             if (mTrustAgentService != null) mTrustAgentService.onTrustTimeout();
    292         } catch (RemoteException e) {
    293             onError(e);
    294         }
    295     }
    296 
    297     /**
    298      * @see android.service.trust.TrustAgentService#onUnlockAttempt(boolean)
    299      */
    300     public void onUnlockAttempt(boolean successful) {
    301         try {
    302             if (mTrustAgentService != null) mTrustAgentService.onUnlockAttempt(successful);
    303         } catch (RemoteException e) {
    304             onError(e);
    305         }
    306     }
    307 
    308     /**
    309      * @see android.service.trust.TrustAgentService#onDeviceLocked()
    310      */
    311     public void onDeviceLocked() {
    312         try {
    313             if (mTrustAgentService != null) mTrustAgentService.onDeviceLocked();
    314         } catch (RemoteException e) {
    315             onError(e);
    316         }
    317     }
    318 
    319     /**
    320      * @see android.service.trust.TrustAgentService#onDeviceUnlocked()
    321      */
    322     public void onDeviceUnlocked() {
    323         try {
    324             if (mTrustAgentService != null) mTrustAgentService.onDeviceUnlocked();
    325         } catch (RemoteException e) {
    326             onError(e);
    327         }
    328     }
    329 
    330     private void setCallback(ITrustAgentServiceCallback callback) {
    331         try {
    332             if (mTrustAgentService != null) {
    333                 mTrustAgentService.setCallback(callback);
    334             }
    335         } catch (RemoteException e) {
    336             onError(e);
    337         }
    338     }
    339 
    340     boolean updateDevicePolicyFeatures() {
    341         boolean trustDisabled = false;
    342         if (DEBUG) Slog.v(TAG, "updateDevicePolicyFeatures(" + mName + ")");
    343         try {
    344             if (mTrustAgentService != null) {
    345                 DevicePolicyManager dpm =
    346                     (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
    347 
    348                 if ((dpm.getKeyguardDisabledFeatures(null, mUserId)
    349                         & DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS) != 0) {
    350                     List<PersistableBundle> config = dpm.getTrustAgentConfiguration(
    351                             null, mName, mUserId);
    352                     trustDisabled = true;
    353                     if (DEBUG) Slog.v(TAG, "Detected trust agents disabled. Config = " + config);
    354                     if (config != null && config.size() > 0) {
    355                         if (DEBUG) {
    356                             Slog.v(TAG, "TrustAgent " + mName.flattenToShortString()
    357                                     + " disabled until it acknowledges "+ config);
    358                         }
    359                         mSetTrustAgentFeaturesToken = new Binder();
    360                         mTrustAgentService.onConfigure(config, mSetTrustAgentFeaturesToken);
    361                     }
    362                 }
    363                 final long maxTimeToLock = dpm.getMaximumTimeToLock(null);
    364                 if (maxTimeToLock != mMaximumTimeToLock) {
    365                     // If the timeout changes, cancel the alarm and send a timeout event to have
    366                     // the agent re-evaluate trust.
    367                     mMaximumTimeToLock = maxTimeToLock;
    368                     if (mAlarmPendingIntent != null) {
    369                         mAlarmManager.cancel(mAlarmPendingIntent);
    370                         mAlarmPendingIntent = null;
    371                         mHandler.sendEmptyMessage(MSG_TRUST_TIMEOUT);
    372                     }
    373                 }
    374             }
    375         } catch (RemoteException e) {
    376             onError(e);
    377         }
    378         if (mTrustDisabledByDpm != trustDisabled) {
    379             mTrustDisabledByDpm = trustDisabled;
    380             mTrustManagerService.updateTrust(mUserId, false);
    381         }
    382         return trustDisabled;
    383     }
    384 
    385     public boolean isTrusted() {
    386         return mTrusted && mManagingTrust && !mTrustDisabledByDpm;
    387     }
    388 
    389     public boolean isManagingTrust() {
    390         return mManagingTrust && !mTrustDisabledByDpm;
    391     }
    392 
    393     public CharSequence getMessage() {
    394         return mMessage;
    395     }
    396 
    397     public void destroy() {
    398         mHandler.removeMessages(MSG_RESTART_TIMEOUT);
    399 
    400         if (!mBound) {
    401             return;
    402         }
    403         if (DEBUG) Log.v(TAG, "TrustAgent unbound : " + mName.flattenToShortString());
    404         mTrustManagerService.mArchive.logAgentStopped(mUserId, mName);
    405         mContext.unbindService(mConnection);
    406         mBound = false;
    407         mTrustAgentService = null;
    408         mSetTrustAgentFeaturesToken = null;
    409         mHandler.sendEmptyMessage(MSG_REVOKE_TRUST);
    410     }
    411 
    412     public boolean isConnected() {
    413         return mTrustAgentService != null;
    414     }
    415 
    416     public boolean isBound() {
    417         return mBound;
    418     }
    419 
    420     /**
    421      * If not connected, returns the time at which the agent is restarted.
    422      *
    423      * @return restart time in uptime millis.
    424      */
    425     public long getScheduledRestartUptimeMillis() {
    426         return mScheduledRestartUptimeMillis;
    427     }
    428 
    429     private void scheduleRestart() {
    430         mHandler.removeMessages(MSG_RESTART_TIMEOUT);
    431         mScheduledRestartUptimeMillis = SystemClock.uptimeMillis() + RESTART_TIMEOUT_MILLIS;
    432         mHandler.sendEmptyMessageAtTime(MSG_RESTART_TIMEOUT, mScheduledRestartUptimeMillis);
    433     }
    434 }
    435