/** * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.service.trust; import android.Manifest; import android.annotation.SdkConstant; import android.annotation.SystemApi; import android.app.Service; import android.app.admin.DevicePolicyManager; import android.content.ComponentName; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ServiceInfo; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.PersistableBundle; import android.os.RemoteException; import android.os.SystemClock; import android.util.Log; import android.util.Slog; import java.util.List; /** * A service that notifies the system about whether it believes the environment of the device * to be trusted. * *
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. *
* *To extend this class, you must declare the service in your manifest file with * the {@link android.Manifest.permission#BIND_TRUST_AGENT} permission * and include an intent filter with the {@link #SERVICE_INTERFACE} action. For example:
** <service android:name=".TrustAgent" * android:label="@string/service_name" * android:permission="android.permission.BIND_TRUST_AGENT"> * <intent-filter> * <action android:name="android.service.trust.TrustAgentService" /> * </intent-filter> * <meta-data android:name="android.service.trust.trustagent" * android:value="@xml/trust_agent" /> * </service>* *
The associated meta-data file can specify an activity that is accessible through Settings * and should allow configuring the trust agent, as defined in * {@link android.R.styleable#TrustAgent}. For example:
* ** <trust-agent xmlns:android="http://schemas.android.com/apk/res/android" * android:settingsActivity=".TrustAgentSettings" />* * @hide */ @SystemApi public class TrustAgentService extends Service { private final String TAG = TrustAgentService.class.getSimpleName() + "[" + getClass().getSimpleName() + "]"; private static final boolean DEBUG = false; /** * The {@link Intent} that must be declared as handled by the service. */ @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION) public static final String SERVICE_INTERFACE = "android.service.trust.TrustAgentService"; /** * The name of the {@code meta-data} tag pointing to additional configuration of the trust * agent. */ public static final String TRUST_AGENT_META_DATA = "android.service.trust.trustagent"; private static final int MSG_UNLOCK_ATTEMPT = 1; private static final int MSG_CONFIGURE = 2; private static final int MSG_TRUST_TIMEOUT = 3; /** * Container class for a list of configuration options and helper methods */ public static final class Configuration { public final List
Agents that support configuration options should overload this method and return 'true'.
*
* @param options bundle containing all options or null if none.
* @return true if the {@link TrustAgentService} supports configuration options.
*/
public boolean onConfigure(Configuration options) {
return false;
}
/**
* 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 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(
final CharSequence message, final long durationMs, final boolean initiatedByUser) {
synchronized (mLock) {
if (!mManagingTrust) {
throw new IllegalStateException("Cannot grant trust if agent is not managing trust."
+ " Call setManagingTrust(true) first.");
}
if (mCallback != null) {
try {
mCallback.grantTrust(message.toString(), durationMs, initiatedByUser);
} catch (RemoteException e) {
onError("calling enableTrust()");
}
} else {
// Remember trust has been granted so we can effectively grant it once the service
// is bound.
mPendingGrantTrustTask = new Runnable() {
@Override
public void run() {
grantTrust(message, durationMs, initiatedByUser);
}
};
}
}
}
/**
* Call to revoke trust on the device.
*/
public final void revokeTrust() {
synchronized (mLock) {
if (mPendingGrantTrustTask != null) {
mPendingGrantTrustTask = null;
}
if (mCallback != null) {
try {
mCallback.revokeTrust();
} catch (RemoteException e) {
onError("calling revokeTrust()");
}
}
}
}
/**
* Call to notify the system if the agent is ready to manage trust.
*
* This property is not persistent across recreating the service and defaults to false.
* Therefore this method is typically called when initializing the agent in {@link #onCreate}.
*
* @param managingTrust indicates if the agent would like to manage trust.
*/
public final void setManagingTrust(boolean managingTrust) {
synchronized (mLock) {
if (mManagingTrust != managingTrust) {
mManagingTrust = managingTrust;
if (mCallback != null) {
try {
mCallback.setManagingTrust(managingTrust);
} catch (RemoteException e) {
onError("calling setManagingTrust()");
}
}
}
}
}
@Override
public final IBinder onBind(Intent intent) {
if (DEBUG) Slog.v(TAG, "onBind() intent = " + intent);
return new TrustAgentServiceWrapper();
}
private final class TrustAgentServiceWrapper extends ITrustAgentService.Stub {
@Override /* Binder API */
public void onUnlockAttempt(boolean successful) {
mHandler.obtainMessage(MSG_UNLOCK_ATTEMPT, successful ? 1 : 0, 0).sendToTarget();
}
@Override /* Binder API */
public void onTrustTimeout() {
mHandler.sendEmptyMessage(MSG_TRUST_TIMEOUT);
}
@Override /* Binder API */
public void onConfigure(List