Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d4efaac5 authored by Jim Miller's avatar Jim Miller
Browse files

Update TrustAgentService API after review.

Also documents timebase on related DevicePolicyManager API.

Fixes bugs 16401527 and 17046034

Change-Id: I8ee6d0055ab6f52ec71630344d3232f7875d9c1d
parent 7653a30e
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -1373,6 +1373,8 @@ public class DevicePolicyManager {
     * and its profiles or a particular one.
     * @param admin The name of the admin component to check, or null to aggregate
     * all admins.
     * @return time in milliseconds for the given admin or the minimum value (strictest) of
     * all admins if admin is null.
     */
    public long getMaximumTimeToLock(ComponentName admin) {
        return getMaximumTimeToLock(admin, UserHandle.myUserId());
+1 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import android.service.trust.ITrustAgentServiceCallback;
 */
interface ITrustAgentService {
    oneway void onUnlockAttempt(boolean successful);
    oneway void onTrustTimeout();
    oneway void setCallback(ITrustAgentServiceCallback callback);
    oneway void setTrustAgentFeaturesEnabled(in Bundle options, IBinder token);
}
+46 −14
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import android.os.SystemClock;
import android.util.Log;
import android.util.Slog;

@@ -37,7 +38,10 @@ import android.util.Slog;
 * A service that notifies the system about whether it believes the environment of the device
 * to be trusted.
 *
 * <p>Trust agents may only be provided by the platform.</p>
 * <p>Trust agents may only be provided by the platform. It is expected that there is only
 * one trust agent installed on the platform. In the event there is more than one,
 * either trust agent can enable trust.
 * </p>
 *
 * <p>To extend this class, you must declare the service in your manifest file with
 * the {@link android.Manifest.permission#BIND_TRUST_AGENT} permission
@@ -90,6 +94,7 @@ public class TrustAgentService extends Service {

    private static final int MSG_UNLOCK_ATTEMPT = 1;
    private static final int MSG_SET_TRUST_AGENT_FEATURES_ENABLED = 2;
    private static final int MSG_TRUST_TIMEOUT = 3;

    private ITrustAgentServiceCallback mCallback;

@@ -118,6 +123,9 @@ public class TrustAgentService extends Service {
                        onError("calling onSetTrustAgentFeaturesEnabledCompleted()");
                    }
                    break;
                case MSG_TRUST_TIMEOUT:
                    onTrustTimeout();
                    break;
            }
        }
    };
@@ -139,21 +147,32 @@ public class TrustAgentService extends Service {
    }

    /**
     * Called when the user attempted to authenticate on the device.
     * Called after the user attempts to authenticate in keyguard with their device credentials,
     * such as pin, pattern or password.
     *
     * @param successful true if the attempt succeeded
     * @param successful true if the user successfully completed the challenge.
     */
    public void onUnlockAttempt(boolean successful) {
    }

    /**
     * Called when the timeout provided by the agent expires.  Note that this may be called earlier
     * than requested by the agent if the trust timeout is adjusted by the system or
     * {@link DevicePolicyManager}.  The agent is expected to re-evaluate the trust state and only
     * call {@link #grantTrust(CharSequence, long, boolean)} if the trust state should be
     * continued.
     */
    public void onTrustTimeout() {
    }

    private void onError(String msg) {
        Slog.v(TAG, "Remote exception while " + msg);
    }

    /**
     * Called when device policy wants to restrict features in the TrustAgent in response to
     * Called when device policy wants to restrict features in the agent in response to
     * {@link DevicePolicyManager#setTrustAgentFeaturesEnabled(ComponentName, ComponentName, java.util.List) }.
     * TrustAgents that support this feature should overload this method and return 'true'.
     * Agents that support this feature should overload this method and return 'true'.
     *
     * The list of options can be obtained by calling
     * options.getStringArrayList({@link #KEY_FEATURES}). Presence of a feature string in the list
@@ -174,10 +193,19 @@ public class TrustAgentService extends Service {
     * Call to grant trust on the device.
     *
     * @param message describes why the device is trusted, e.g. "Trusted by location".
     * @param durationMs amount of time in milliseconds to keep the device in a trusted state. Trust
     *                   for this agent will automatically be revoked when the timeout expires.
     * @param initiatedByUser indicates that the user has explicitly initiated an action that proves
     *                        the user is about to use the device.
     * @param durationMs amount of time in milliseconds to keep the device in a trusted state.
     *    Trust for this agent will automatically be revoked when the timeout expires unless
     *    extended by a subsequent call to this function. The timeout is measured from the
     *    invocation of this function as dictated by {@link SystemClock#elapsedRealtime())}.
     *    For security reasons, the value should be no larger than necessary.
     *    The value may be adjusted by the system as necessary to comply with a policy controlled
     *    by the system or {@link DevicePolicyManager} restrictions. See {@link #onTrustTimeout()}
     *    for determining when trust expires.
     * @param initiatedByUser this is a hint to the system that trust is being granted as the
     *    direct result of user action - such as solving a security challenge. The hint is used
     *    by the system to optimize the experience. Behavior may vary by device and release, so
     *    one should only set this parameter if it meets the above criteria rather than relying on
     *    the behavior of any particular device or release.
     * @throws IllegalStateException if the agent is not currently managing trust.
     */
    public final void grantTrust(
@@ -254,13 +282,17 @@ public class TrustAgentService extends Service {
    }

    private final class TrustAgentServiceWrapper extends ITrustAgentService.Stub {
        @Override
        @Override /* Binder API */
        public void onUnlockAttempt(boolean successful) {
            mHandler.obtainMessage(MSG_UNLOCK_ATTEMPT, successful ? 1 : 0, 0)
                    .sendToTarget();
            mHandler.obtainMessage(MSG_UNLOCK_ATTEMPT, successful ? 1 : 0, 0).sendToTarget();
        }

        @Override
        @Override /* Binder API */
        public void onTrustTimeout() {
            mHandler.sendEmptyMessage(MSG_TRUST_TIMEOUT);
        }

        @Override /* Binder API */
        public void setCallback(ITrustAgentServiceCallback callback) {
            synchronized (mLock) {
                mCallback = callback;
@@ -280,7 +312,7 @@ public class TrustAgentService extends Service {
            }
        }

        @Override
        @Override /* Binder API */
        public void setTrustAgentFeaturesEnabled(Bundle features, IBinder token) {
            Message msg = mHandler.obtainMessage(MSG_SET_TRUST_AGENT_FEATURES_ENABLED, token);
            msg.setData(features);
+6 −0
Original line number Diff line number Diff line
@@ -75,6 +75,12 @@ public class SampleTrustAgent extends TrustAgentService
                .registerOnSharedPreferenceChangeListener(this);
    }

    @Override
    public void onTrustTimeout() {
        super.onTrustTimeout();
        Toast.makeText(this, "onTrustTimeout(): timeout expired", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onUnlockAttempt(boolean successful) {
        if (getReportUnlockAttempts(this)) {
+46 −2
Original line number Diff line number Diff line
@@ -16,16 +16,22 @@

package com.android.server.trust;

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.PatternMatcher;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
@@ -43,6 +49,9 @@ import java.util.List;
 * TrustManager and the actual TrustAgent.
 */
public class TrustAgentWrapper {
    private static final String EXTRA_COMPONENT_NAME = "componentName";
    private static final String TRUST_EXPIRED_ACTION = "android.server.trust.TRUST_EXPIRED_ACTION";
    private static final String PERMISSION = "android.permission.PROVIDE_TRUST_AGENT";
    private static final boolean DEBUG = false;
    private static final String TAG = "TrustAgentWrapper";

@@ -79,6 +88,20 @@ public class TrustAgentWrapper {
    private boolean mTrustDisabledByDpm;
    private boolean mManagingTrust;
    private IBinder mSetTrustAgentFeaturesToken;
    private AlarmManager mAlarmManager;
    private final Intent mAlarmIntent;

    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            ComponentName component = intent.getParcelableExtra(EXTRA_COMPONENT_NAME);
            if (TRUST_EXPIRED_ACTION.equals(intent.getAction())
                    && mName.equals(component)) {
                mHandler.removeMessages(MSG_TRUST_TIMEOUT);
                mHandler.sendEmptyMessage(MSG_TRUST_TIMEOUT);
            }
        }
    };

    private final Handler mHandler = new Handler() {
        @Override
@@ -95,8 +118,10 @@ public class TrustAgentWrapper {
                    boolean initiatedByUser = msg.arg1 != 0;
                    long durationMs = msg.getData().getLong(DATA_DURATION);
                    if (durationMs > 0) {
                        mHandler.removeMessages(MSG_TRUST_TIMEOUT);
                        mHandler.sendEmptyMessageDelayed(MSG_TRUST_TIMEOUT, durationMs);
                        long expiration = SystemClock.elapsedRealtime() + durationMs;
                        PendingIntent op = PendingIntent.getBroadcast(mContext, 0, mAlarmIntent,
                                PendingIntent.FLAG_CANCEL_CURRENT);
                        mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, expiration, op);
                    }
                    mTrustManagerService.mArchive.logGrantTrust(mUserId, mName,
                            (mMessage != null ? mMessage.toString() : null),
@@ -106,6 +131,7 @@ public class TrustAgentWrapper {
                case MSG_TRUST_TIMEOUT:
                    if (DEBUG) Slog.v(TAG, "Trust timed out : " + mName.flattenToShortString());
                    mTrustManagerService.mArchive.logTrustTimeout(mUserId, mName);
                    onTrustTimeout();
                    // Fall through.
                case MSG_REVOKE_TRUST:
                    mTrusted = false;
@@ -212,8 +238,19 @@ public class TrustAgentWrapper {
            Intent intent, UserHandle user) {
        mContext = context;
        mTrustManagerService = trustManagerService;
        mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
        mUserId = user.getIdentifier();
        mName = intent.getComponent();

        mAlarmIntent = new Intent(TRUST_EXPIRED_ACTION).putExtra(EXTRA_COMPONENT_NAME, mName);
        mAlarmIntent.setData(Uri.parse(mAlarmIntent.toUri(Intent.URI_INTENT_SCHEME)));

        final IntentFilter alarmFilter = new IntentFilter(TRUST_EXPIRED_ACTION);
        alarmFilter.addDataScheme(mAlarmIntent.getScheme());
        final String pathUri = mAlarmIntent.toUri(Intent.URI_INTENT_SCHEME);
        alarmFilter.addDataPath(pathUri, PatternMatcher.PATTERN_LITERAL);
        mContext.registerReceiver(mBroadcastReceiver, alarmFilter);

        // Schedules a restart for when connecting times out. If the connection succeeds,
        // the restart is canceled in mCallback's onConnected.
        scheduleRestart();
@@ -227,6 +264,13 @@ public class TrustAgentWrapper {
        Slog.w(TAG , "Remote Exception", e);
    }

    private void onTrustTimeout() {
        try {
            if (mTrustAgentService != null) mTrustAgentService.onTrustTimeout();
        } catch (RemoteException e) {
            onError(e);
        }
    }
    /**
     * @see android.service.trust.TrustAgentService#onUnlockAttempt(boolean)
     */