blob: 3429a0380052a0a308172a144644955cea220b52 [file] [log] [blame]
/*
* Copyright (C) 2020 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 com.google.android.connecteddevice.trust;
import static com.google.android.connecteddevice.util.SafeLog.logd;
import static com.google.android.connecteddevice.util.SafeLog.loge;
import static com.google.android.connecteddevice.util.SafeLog.logw;
import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
import android.service.trust.TrustAgentService;
import com.google.android.connecteddevice.trust.api.ITrustedDeviceAgentDelegate;
import com.google.android.connecteddevice.trust.api.ITrustedDeviceManager;
import java.time.Duration;
/** Service to provide TrustAgent functionality to the trusted device feature. */
public class TrustedDeviceAgentService extends TrustAgentService {
private static final String TAG = "TrustedDeviceAgentService";
/** Keep device in trusted state. */
private static final long TRUST_DURATION_MS = 0L;
private static final String RETRY_HANDLER_THREAD_NAME = "trusted_device_retry";
private static final int MAX_RETRIES = 200;
private static final Duration RETRY_DURATION = Duration.ofMillis(10);
private HandlerThread retryThread;
private Handler retryHandler;
private ITrustedDeviceManager trustedDeviceManager;
private int retries;
@Override
public void onCreate() {
super.onCreate();
logd(TAG, "Starting trust agent service.");
TrustedDeviceEventLog.onTrustAgentStarted();
Intent intent = new Intent(this, TrustedDeviceManagerService.class);
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
retryThread = new HandlerThread(RETRY_HANDLER_THREAD_NAME);
retryThread.start();
retryHandler = new Handler(retryThread.getLooper());
}
@Override
public void onDestroy() {
logd(TAG, "Destroying trust agent service.");
try {
trustedDeviceManager.clearTrustedDeviceAgentDelegate(trustedDeviceAgentDelegate);
} catch (RemoteException e) {
loge(TAG, "Error while disconnecting from TrustedDeviceManager.");
}
unbindService(serviceConnection);
if (retryThread != null) {
retryThread.quit();
}
super.onDestroy();
}
@Override
public void onEscrowTokenAdded(byte[] token, long handle, UserHandle user) {
super.onEscrowTokenAdded(token, handle, user);
try {
trustedDeviceManager.onEscrowTokenAdded(user.getIdentifier(), handle);
} catch (RemoteException e) {
loge(TAG, "Error while notifying that an escrow token was added.", e);
}
}
@Override
public void onEscrowTokenStateReceived(long handle, int tokenState) {
super.onEscrowTokenStateReceived(handle, tokenState);
if (tokenState == TrustAgentService.TOKEN_STATE_ACTIVE) {
try {
trustedDeviceManager.onEscrowTokenActivated(ActivityManager.getCurrentUser(), handle);
} catch (RemoteException e) {
loge(TAG, "Error while notifying that an escrow token was activated.", e);
}
}
}
@Override
public void onDeviceUnlocked() {
super.onDeviceUnlocked();
TrustedDeviceEventLog.onUserUnlocked();
try {
trustedDeviceManager.onUserUnlocked();
} catch (RemoteException e) {
loge(TAG, "Error while notifying that the device was unlocked.", e);
}
}
private final ServiceConnection serviceConnection =
new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
trustedDeviceManager = ITrustedDeviceManager.Stub.asInterface(service);
try {
trustedDeviceManager.setTrustedDeviceAgentDelegate(trustedDeviceAgentDelegate);
logd(TAG, "Successfully connected to TrustedDeviceManager.");
} catch (RemoteException e) {
loge(TAG, "Error while establishing connection to TrustedDeviceManager.", e);
}
}
@Override
public void onServiceDisconnected(ComponentName name) {}
};
private final ITrustedDeviceAgentDelegate trustedDeviceAgentDelegate =
new ITrustedDeviceAgentDelegate.Stub() {
@Override
public void addEscrowToken(byte[] token, int userId) {
logd(TAG, "Adding new escrow token for user " + userId + ".");
try {
TrustedDeviceAgentService.this.addEscrowToken(token, UserHandle.of(userId));
return;
} catch (IllegalStateException e) {
if (++retries > MAX_RETRIES) {
loge(
TAG,
"Maximum number of retries for adding an escrow token has "
+ "been exceeded. Aborting.",
e);
return;
}
}
logw(TAG, "Trust agent has not been bound to yet. Retry #" + retries + ".");
retryHandler.postDelayed(() -> addEscrowToken(token, userId), RETRY_DURATION.toMillis());
}
@Override
public void unlockUserWithToken(byte[] token, long handle, int userId) {
setManagingTrust(true);
TrustedDeviceAgentService.this.unlockUserWithToken(handle, token, UserHandle.of(userId));
grantTrust(
"Granting trust from escrow token for user " + userId + ".",
TRUST_DURATION_MS,
FLAG_GRANT_TRUST_DISMISS_KEYGUARD);
}
@Override
public void removeEscrowToken(long handle, int userId) {
logd(TAG, "Removing escrow token for user " + userId + ".");
TrustedDeviceAgentService.this.removeEscrowToken(handle, UserHandle.of(userId));
}
};
}