Merge "Trust agents can show a message to the user on grant"

This commit is contained in:
Beverly Tai
2022-01-21 20:51:45 +00:00
committed by Android (Google) Code Review
8 changed files with 106 additions and 20 deletions

View File

@@ -16,13 +16,16 @@
*/
package android.app.trust;
import java.util.List;
/**
* Private API to be notified about trust changes.
*
* {@hide}
*/
oneway interface ITrustListener {
void onTrustChanged(boolean enabled, int userId, int flags);
void onTrustChanged(boolean enabled, int userId, int flags,
in List<String> trustGrantedMessages);
void onTrustManagedChanged(boolean managed, int userId);
void onTrustError(in CharSequence message);
}

View File

@@ -29,6 +29,9 @@ import android.os.Message;
import android.os.RemoteException;
import android.util.ArrayMap;
import java.util.ArrayList;
import java.util.List;
/**
* See {@link com.android.server.trust.TrustManagerService}
* @hide
@@ -43,6 +46,7 @@ public class TrustManager {
private static final String TAG = "TrustManager";
private static final String DATA_FLAGS = "initiatedByUser";
private static final String DATA_MESSAGE = "message";
private static final String DATA_GRANTED_MESSAGES = "grantedMessages";
private final ITrustManager mService;
private final ArrayMap<TrustListener, ITrustListener> mTrustListeners;
@@ -152,12 +156,15 @@ public class TrustManager {
try {
ITrustListener.Stub iTrustListener = new ITrustListener.Stub() {
@Override
public void onTrustChanged(boolean enabled, int userId, int flags) {
public void onTrustChanged(boolean enabled, int userId, int flags,
List<String> trustGrantedMessages) {
Message m = mHandler.obtainMessage(MSG_TRUST_CHANGED, (enabled ? 1 : 0), userId,
trustListener);
if (flags != 0) {
m.getData().putInt(DATA_FLAGS, flags);
}
m.getData().putCharSequenceArrayList(
DATA_GRANTED_MESSAGES, (ArrayList) trustGrantedMessages);
m.sendToTarget();
}
@@ -244,14 +251,15 @@ public class TrustManager {
switch(msg.what) {
case MSG_TRUST_CHANGED:
int flags = msg.peekData() != null ? msg.peekData().getInt(DATA_FLAGS) : 0;
((TrustListener)msg.obj).onTrustChanged(msg.arg1 != 0, msg.arg2, flags);
((TrustListener) msg.obj).onTrustChanged(msg.arg1 != 0, msg.arg2, flags,
msg.getData().getStringArrayList(DATA_GRANTED_MESSAGES));
break;
case MSG_TRUST_MANAGED_CHANGED:
((TrustListener)msg.obj).onTrustManagedChanged(msg.arg1 != 0, msg.arg2);
break;
case MSG_TRUST_ERROR:
final CharSequence message = msg.peekData().getCharSequence(DATA_MESSAGE);
((TrustListener)msg.obj).onTrustError(message);
((TrustListener) msg.obj).onTrustError(message);
}
}
};
@@ -265,8 +273,11 @@ public class TrustManager {
* @param flags Flags specified by the trust agent when granting trust. See
* {@link android.service.trust.TrustAgentService#grantTrust(CharSequence, long, int)
* TrustAgentService.grantTrust(CharSequence, long, int)}.
* @param trustGrantedMessages Messages to display to the user when trust has been granted
* by one or more trust agents.
*/
void onTrustChanged(boolean enabled, int userId, int flags);
void onTrustChanged(boolean enabled, int userId, int flags,
List<String> trustGrantedMessages);
/**
* Reports that whether trust is managed has changed

View File

@@ -437,7 +437,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
}
@Override
public void onTrustChanged(boolean enabled, int userId, int flags) {
public void onTrustChanged(boolean enabled, int userId, int flags,
List<String> trustGrantedMessages) {
Assert.isMainThread();
boolean wasTrusted = mUserHasTrust.get(userId, false);
mUserHasTrust.put(userId, enabled);
@@ -459,6 +460,19 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
}
}
}
if (KeyguardUpdateMonitor.getCurrentUser() == userId && getUserHasTrust(userId)) {
CharSequence message = null;
if (trustGrantedMessages != null && trustGrantedMessages.size() > 0) {
message = trustGrantedMessages.get(0); // for now only shows the first in the list
}
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
cb.showTrustGrantedMessage(message);
}
}
}
}
@Override

View File

@@ -23,6 +23,8 @@ import android.os.SystemClock;
import android.telephony.TelephonyManager;
import android.view.WindowManagerPolicyConstants;
import androidx.annotation.Nullable;
import com.android.settingslib.fuelgauge.BatteryStatus;
import com.android.systemui.statusbar.KeyguardIndicationController;
@@ -215,6 +217,11 @@ public class KeyguardUpdateMonitorCallback {
*/
public void onTrustGrantedWithFlags(int flags, int userId) { }
/**
* Called when setting the trust granted message.
*/
public void showTrustGrantedMessage(@Nullable CharSequence message) { }
/**
* Called when a biometric has been acquired.
* <p>

View File

@@ -107,6 +107,7 @@ import org.mockito.MockitoAnnotations;
import org.mockito.MockitoSession;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -175,6 +176,8 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
private LatencyTracker mLatencyTracker;
@Captor
private ArgumentCaptor<StatusBarStateController.StateListener> mStatusBarStateListenerCaptor;
@Mock
private KeyguardUpdateMonitorCallback mTestCallback;
// Direct executor
private Executor mBackgroundExecutor = Runnable::run;
private Executor mMainExecutor = Runnable::run;
@@ -252,11 +255,13 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
verify(mStatusBarStateController).addCallback(mStatusBarStateListenerCaptor.capture());
mStatusBarStateListener = mStatusBarStateListenerCaptor.getValue();
mKeyguardUpdateMonitor.registerCallback(mTestCallback);
}
@After
public void tearDown() {
mMockitoSession.finishMocking();
mKeyguardUpdateMonitor.removeCallback(mTestCallback);
mKeyguardUpdateMonitor.destroy();
}
@@ -596,7 +601,8 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mTestableLooper.processAllMessages();
when(mKeyguardBypassController.canBypass()).thenReturn(true);
mKeyguardUpdateMonitor.onTrustChanged(true /* enabled */,
KeyguardUpdateMonitor.getCurrentUser(), 0 /* flags */);
KeyguardUpdateMonitor.getCurrentUser(), 0 /* flags */,
new ArrayList<>());
mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean());
}
@@ -606,7 +612,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mKeyguardUpdateMonitor.dispatchStartedWakingUp();
mTestableLooper.processAllMessages();
mKeyguardUpdateMonitor.onTrustChanged(true /* enabled */,
KeyguardUpdateMonitor.getCurrentUser(), 0 /* flags */);
KeyguardUpdateMonitor.getCurrentUser(), 0 /* flags */, new ArrayList<>());
mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
anyBoolean());
@@ -751,7 +757,8 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
@Test
public void testGetUserCanSkipBouncer_whenTrust() {
int user = KeyguardUpdateMonitor.getCurrentUser();
mKeyguardUpdateMonitor.onTrustChanged(true /* enabled */, user, 0 /* flags */);
mKeyguardUpdateMonitor.onTrustChanged(true /* enabled */, user, 0 /* flags */,
new ArrayList<>());
assertThat(mKeyguardUpdateMonitor.getUserCanSkipBouncer(user)).isTrue();
}
@@ -982,7 +989,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
// WHEN trust is enabled (ie: via smartlock)
mKeyguardUpdateMonitor.onTrustChanged(true /* enabled */,
KeyguardUpdateMonitor.getCurrentUser(), 0 /* flags */);
KeyguardUpdateMonitor.getCurrentUser(), 0 /* flags */, new ArrayList<>());
// THEN we shouldn't listen for udfps
assertThat(mKeyguardUpdateMonitor.shouldListenForFingerprint(true)).isEqualTo(false);
@@ -1066,6 +1073,17 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
anyBoolean());
}
@Test
public void testShowTrustGrantedMessage_onTrustGranted() {
// WHEN trust is enabled (ie: via some trust agent) with a trustGranted string
mKeyguardUpdateMonitor.onTrustChanged(true /* enabled */,
KeyguardUpdateMonitor.getCurrentUser(), 0 /* flags */,
Arrays.asList("Unlocked by wearable"));
// THEN the showTrustGrantedMessage should be called with the first message
verify(mTestCallback).showTrustGrantedMessage("Unlocked by wearable");
}
private void setKeyguardBouncerVisibility(boolean isVisible) {
mKeyguardUpdateMonitor.sendKeyguardBouncerChanged(isVisible);
mTestableLooper.processAllMessages();

View File

@@ -414,7 +414,8 @@ public class Fingerprint21UdfpsMock extends Fingerprint21 implements TrustManage
}
@Override
public void onTrustChanged(boolean enabled, int userId, int flags) {
public void onTrustChanged(boolean enabled, int userId, int flags,
List<String> trustGrantedMessages) {
mUserHasTrust.put(userId, enabled);
}

View File

@@ -16,6 +16,8 @@
package com.android.server.trust;
import static android.service.trust.TrustAgentService.FLAG_GRANT_TRUST_DISPLAY_MESSAGE;
import android.annotation.TargetApi;
import android.app.AlarmManager;
import android.app.PendingIntent;
@@ -99,6 +101,7 @@ public class TrustAgentWrapper {
// Trust state
private boolean mTrusted;
private CharSequence mMessage;
private boolean mDisplayTrustGrantedMessage;
private boolean mTrustDisabledByDpm;
private boolean mManagingTrust;
private IBinder mSetTrustAgentFeaturesToken;
@@ -132,6 +135,7 @@ public class TrustAgentWrapper {
mTrusted = true;
mMessage = (CharSequence) msg.obj;
int flags = msg.arg1;
mDisplayTrustGrantedMessage = (flags & FLAG_GRANT_TRUST_DISPLAY_MESSAGE) != 0;
long durationMs = msg.getData().getLong(DATA_DURATION);
if (durationMs > 0) {
final long duration;
@@ -166,6 +170,7 @@ public class TrustAgentWrapper {
// Fall through.
case MSG_REVOKE_TRUST:
mTrusted = false;
mDisplayTrustGrantedMessage = false;
mMessage = null;
mHandler.removeMessages(MSG_TRUST_TIMEOUT);
if (msg.what == MSG_REVOKE_TRUST) {
@@ -199,6 +204,7 @@ public class TrustAgentWrapper {
mManagingTrust = msg.arg1 != 0;
if (!mManagingTrust) {
mTrusted = false;
mDisplayTrustGrantedMessage = false;
mMessage = null;
}
mTrustManagerService.mArchive.logManagingTrust(mUserId, mName, mManagingTrust);
@@ -271,12 +277,13 @@ public class TrustAgentWrapper {
private ITrustAgentServiceCallback mCallback = new ITrustAgentServiceCallback.Stub() {
@Override
public void grantTrust(CharSequence userMessage, long durationMs, int flags) {
if (DEBUG) Slog.d(TAG, "enableTrust(" + userMessage + ", durationMs = " + durationMs
public void grantTrust(CharSequence message, long durationMs, int flags) {
if (DEBUG) {
Slog.d(TAG, "enableTrust(" + message + ", durationMs = " + durationMs
+ ", flags = " + flags + ")");
}
Message msg = mHandler.obtainMessage(
MSG_GRANT_TRUST, flags, 0, userMessage);
Message msg = mHandler.obtainMessage(MSG_GRANT_TRUST, flags, 0, message);
msg.getData().putLong(DATA_DURATION, durationMs);
msg.sendToTarget();
}
@@ -592,6 +599,14 @@ public class TrustAgentWrapper {
return mMessage;
}
/**
* Whether the trust agent would like to display {@link #getMessage()} to the user when trust
* is granted.
*/
public boolean shouldDisplayTrustGrantedMessage() {
return mDisplayTrustGrantedMessage;
}
public void destroy() {
mHandler.removeMessages(MSG_RESTART_TIMEOUT);

View File

@@ -75,7 +75,6 @@ import com.android.internal.content.PackageMonitor;
import com.android.internal.util.DumpUtils;
import com.android.internal.widget.LockPatternUtils;
import com.android.server.SystemService;
import com.android.server.SystemService.TargetUser;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -392,7 +391,6 @@ public class TrustManagerService extends SystemService {
}
}
public void updateTrust(int userId, int flags) {
updateTrust(userId, flags, false /* isFromUnlock */);
}
@@ -432,7 +430,7 @@ public class TrustManagerService extends SystemService {
changed = mUserIsTrusted.get(userId) != trusted;
mUserIsTrusted.put(userId, trusted);
}
dispatchOnTrustChanged(trusted, userId, flags);
dispatchOnTrustChanged(trusted, userId, flags, getTrustGrantedMessages(userId));
if (changed) {
refreshDeviceLockedForUser(userId);
if (!trusted) {
@@ -952,6 +950,24 @@ public class TrustManagerService extends SystemService {
return false;
}
private List<String> getTrustGrantedMessages(int userId) {
if (!mStrongAuthTracker.isTrustAllowedForUser(userId)) {
return new ArrayList<>();
}
List<String> trustGrantedMessages = new ArrayList<>();
for (int i = 0; i < mActiveAgents.size(); i++) {
AgentInfo info = mActiveAgents.valueAt(i);
if (info.userId == userId
&& info.agent.isTrusted()
&& info.agent.shouldDisplayTrustGrantedMessage()
&& !TextUtils.isEmpty(info.agent.getMessage())) {
trustGrantedMessages.add(info.agent.getMessage().toString());
}
}
return trustGrantedMessages;
}
private boolean aggregateIsTrustManaged(int userId) {
if (!mStrongAuthTracker.isTrustAllowedForUser(userId)) {
return false;
@@ -1021,7 +1037,8 @@ public class TrustManagerService extends SystemService {
}
}
private void dispatchOnTrustChanged(boolean enabled, int userId, int flags) {
private void dispatchOnTrustChanged(boolean enabled, int userId, int flags,
@NonNull List<String> trustGrantedMessages) {
if (DEBUG) {
Log.i(TAG, "onTrustChanged(" + enabled + ", " + userId + ", 0x"
+ Integer.toHexString(flags) + ")");
@@ -1029,7 +1046,7 @@ public class TrustManagerService extends SystemService {
if (!enabled) flags = 0;
for (int i = 0; i < mTrustListeners.size(); i++) {
try {
mTrustListeners.get(i).onTrustChanged(enabled, userId, flags);
mTrustListeners.get(i).onTrustChanged(enabled, userId, flags, trustGrantedMessages);
} catch (DeadObjectException e) {
Slog.d(TAG, "Removing dead TrustListener.");
mTrustListeners.remove(i);