Merge "Add isActiveUnlockRunning" into udc-dev

This commit is contained in:
Derek Jedral
2023-05-11 04:11:03 +00:00
committed by Android (Google) Code Review
12 changed files with 305 additions and 12 deletions

View File

@@ -29,4 +29,5 @@ oneway interface ITrustListener {
in List<String> trustGrantedMessages);
void onTrustManagedChanged(boolean managed, int userId);
void onTrustError(in CharSequence message);
void onIsActiveUnlockRunningChanged(boolean isRunning, int userId);
}

View File

@@ -40,4 +40,5 @@ interface ITrustManager {
boolean isTrustUsuallyManaged(int userId);
void unlockedByBiometricForUser(int userId, in BiometricSourceType source);
void clearAllBiometricRecognized(in BiometricSourceType target, int unlockedUser);
boolean isActiveUnlockRunning(int userId);
}

View File

@@ -44,6 +44,7 @@ public class TrustManager {
private static final int MSG_TRUST_MANAGED_CHANGED = 2;
private static final int MSG_TRUST_ERROR = 3;
private static final int MSG_ENABLED_TRUST_AGENTS_CHANGED = 4;
private static final int MSG_IS_ACTIVE_UNLOCK_RUNNING = 5;
private static final String TAG = "TrustManager";
private static final String DATA_FLAGS = "initiatedByUser";
@@ -165,6 +166,17 @@ public class TrustManager {
}
}
/**
* Returns whether active unlock can be used to unlock the device for user {@code userId}.
*/
public boolean isActiveUnlockRunning(int userId) {
try {
return mService.isActiveUnlockRunning(userId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* Registers a listener for trust events.
*
@@ -206,6 +218,12 @@ public class TrustManager {
m.getData().putCharSequence(DATA_MESSAGE, message);
m.sendToTarget();
}
@Override
public void onIsActiveUnlockRunningChanged(boolean isRunning, int userId) {
mHandler.obtainMessage(MSG_IS_ACTIVE_UNLOCK_RUNNING,
(isRunning ? 1 : 0), userId, trustListener).sendToTarget();
}
};
mService.registerTrustListener(iTrustListener);
mTrustListeners.put(trustListener, iTrustListener);
@@ -295,6 +313,10 @@ public class TrustManager {
case MSG_ENABLED_TRUST_AGENTS_CHANGED:
((TrustListener) msg.obj).onEnabledTrustAgentsChanged(msg.arg1);
break;
case MSG_IS_ACTIVE_UNLOCK_RUNNING:
((TrustListener) msg.obj)
.onIsActiveUnlockRunningChanged(msg.arg1 != 0, msg.arg2);
break;
}
}
};
@@ -333,5 +355,12 @@ public class TrustManager {
* Reports that the enabled trust agents for the specified user has changed.
*/
void onEnabledTrustAgentsChanged(int userId);
/**
* Reports changes on if the device can be unlocked with active unlock.
* @param isRunning If true, the device can be unlocked with active unlock.
* @param userId The user, for which the state changed.
*/
void onIsActiveUnlockRunningChanged(boolean isRunning, int userId);
}
}

View File

@@ -570,6 +570,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
}
}
@Override
public void onIsActiveUnlockRunningChanged(boolean isRunning, int userId) {
}
/**
* Whether the trust granted call with its passed flags should dismiss keyguard.
* It's assumed that the trust was granted for the current user.

View File

@@ -95,6 +95,11 @@ constructor(
"onTrustManagedChanged"
)
}
override fun onIsActiveUnlockRunningChanged(
isRunning: Boolean,
userId: Int
) = Unit
}
trustManager.registerTrustListener(callback)
logger.trustListenerRegistered()

View File

@@ -442,6 +442,11 @@ public class Fingerprint21UdfpsMock extends Fingerprint21 implements TrustManage
}
@Override
public void onIsActiveUnlockRunningChanged(boolean isRunning, int userId) {
}
@Override
@NonNull
public List<FingerprintSensorPropertiesInternal> getSensorProperties() {

View File

@@ -667,6 +667,10 @@ public class TrustAgentWrapper {
return mTrustable && mManagingTrust && !mTrustDisabledByDpm;
}
public boolean isTrustableOrWaitingForDowngrade() {
return mWaitingForTrustableDowngrade || isTrustable();
}
/** Set the trustagent as not trustable */
public void setUntrustable() {
mTrustable = false;

View File

@@ -149,6 +149,7 @@ public class TrustManagerService extends SystemService {
private static final String PRIV_NAMESPACE = "http://schemas.android.com/apk/prv/res/android";
private final ArraySet<AgentInfo> mActiveAgents = new ArraySet<>();
private final SparseBooleanArray mLastActiveUnlockRunningState = new SparseBooleanArray();
private final ArrayList<ITrustListener> mTrustListeners = new ArrayList<>();
private final Receiver mReceiver = new Receiver();
@@ -681,6 +682,7 @@ public class TrustManagerService extends SystemService {
boolean isNowTrusted = pendingTrustState == TrustState.TRUSTED;
boolean newlyUnlocked = !alreadyUnlocked && isNowTrusted;
maybeActiveUnlockRunningChanged(userId);
dispatchOnTrustChanged(
isNowTrusted, newlyUnlocked, userId, flags, getTrustGrantedMessages(userId));
if (isNowTrusted != wasTrusted) {
@@ -921,6 +923,18 @@ public class TrustManagerService extends SystemService {
}
}
private void maybeActiveUnlockRunningChanged(int userId) {
boolean oldValue = mLastActiveUnlockRunningState.get(userId);
boolean newValue = aggregateIsActiveUnlockRunning(userId);
if (oldValue == newValue) {
return;
}
mLastActiveUnlockRunningState.put(userId, newValue);
for (int i = 0; i < mTrustListeners.size(); i++) {
notifyListenerIsActiveUnlockRunning(mTrustListeners.get(i), newValue, userId);
}
}
private void refreshDeviceLockedForUser(int userId) {
refreshDeviceLockedForUser(userId, UserHandle.USER_NULL);
}
@@ -1325,6 +1339,27 @@ public class TrustManagerService extends SystemService {
return false;
}
private boolean aggregateIsActiveUnlockRunning(int userId) {
if (!mStrongAuthTracker.isTrustAllowedForUser(userId)) {
return false;
}
synchronized (mUserTrustState) {
TrustState currentState = mUserTrustState.get(userId);
if (currentState != TrustState.TRUSTED && currentState != TrustState.TRUSTABLE) {
return false;
}
}
for (int i = 0; i < mActiveAgents.size(); i++) {
AgentInfo info = mActiveAgents.valueAt(i);
if (info.userId == userId) {
if (info.agent.isTrustableOrWaitingForDowngrade()) {
return true;
}
}
}
return false;
}
/**
* We downgrade to trustable whenever keyguard changes its showing value.
* - becomes showing: something has caused the device to show keyguard which happens due to
@@ -1366,7 +1401,7 @@ public class TrustManagerService extends SystemService {
for (int i = 0; i < mActiveAgents.size(); i++) {
AgentInfo info = mActiveAgents.valueAt(i);
if (info.userId == userId) {
if (info.agent.isManagingTrust()) {
if (info.agent.isTrustableOrWaitingForDowngrade()) {
return true;
}
}
@@ -1424,6 +1459,26 @@ public class TrustManagerService extends SystemService {
}
}
private void notifyListenerIsActiveUnlockRunningInitialState(ITrustListener listener) {
int numUsers = mLastActiveUnlockRunningState.size();
for (int i = 0; i < numUsers; i++) {
int userId = mLastActiveUnlockRunningState.keyAt(i);
boolean isRunning = aggregateIsActiveUnlockRunning(userId);
notifyListenerIsActiveUnlockRunning(listener, isRunning, userId);
}
}
private void notifyListenerIsActiveUnlockRunning(
ITrustListener listener, boolean isRunning, int userId) {
try {
listener.onIsActiveUnlockRunningChanged(isRunning, userId);
} catch (DeadObjectException e) {
Slog.d(TAG, "TrustListener dead while trying to notify Active Unlock running state");
} catch (RemoteException e) {
Slog.e(TAG, "Exception while notifying TrustListener.", e);
}
}
// Listeners
private void addListener(ITrustListener listener) {
@@ -1433,6 +1488,7 @@ public class TrustManagerService extends SystemService {
}
}
mTrustListeners.add(listener);
notifyListenerIsActiveUnlockRunningInitialState(listener);
updateTrustAll();
}
@@ -1747,6 +1803,8 @@ public class TrustManagerService extends SystemService {
fout.print(": trusted=" + dumpBool(aggregateIsTrusted(user.id)));
fout.print(", trustManaged=" + dumpBool(aggregateIsTrustManaged(user.id)));
fout.print(", deviceLocked=" + dumpBool(isDeviceLockedInner(user.id)));
fout.print(", isActiveUnlockRunning=" + dumpBool(
aggregateIsActiveUnlockRunning(user.id)));
fout.print(", strongAuthRequired=" + dumpHex(
mStrongAuthTracker.getStrongAuthForUser(user.id)));
fout.println();
@@ -1865,6 +1923,16 @@ public class TrustManagerService extends SystemService {
}
message.sendToTarget();
}
@Override
public boolean isActiveUnlockRunning(int userId) throws RemoteException {
final long identity = Binder.clearCallingIdentity();
try {
return aggregateIsActiveUnlockRunning(userId);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
};
private boolean isTrustUsuallyManagedInternal(int userId) {

View File

@@ -78,6 +78,16 @@
<action android:name="android.service.trust.TrustAgentService" />
</intent-filter>
</service>
<service
android:name=".IsActiveUnlockRunningTrustAgent"
android:exported="true"
android:label="Test Agent"
android:permission="android.permission.BIND_TRUST_AGENT">
<intent-filter>
<action android:name="android.service.trust.TrustAgentService" />
</intent-filter>
</service>
</application>
<!-- self-instrumenting test package. -->

View File

@@ -0,0 +1,131 @@
/*
* Copyright (C) 2022 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.trust.test
import android.app.trust.TrustManager
import android.content.Context
import android.service.trust.TrustAgentService.FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE
import android.trust.BaseTrustAgentService
import android.trust.TrustTestActivity
import android.trust.test.lib.LockStateTrackingRule
import android.trust.test.lib.ScreenLockRule
import android.trust.test.lib.TestTrustListener
import android.trust.test.lib.TrustAgentRule
import androidx.test.core.app.ApplicationProvider.getApplicationContext
import androidx.test.ext.junit.rules.ActivityScenarioRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
import androidx.test.uiautomator.UiDevice
import com.google.common.truth.Truth.assertThat
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.rules.RuleChain
import org.junit.runner.RunWith
/**
* Test for testing isActiveUnlockRunning.
*
* atest TrustTests:IsActiveUnlockRunningTest
*/
@RunWith(AndroidJUnit4::class)
class IsActiveUnlockRunningTest {
private val uiDevice = UiDevice.getInstance(getInstrumentation())
private val context: Context = getApplicationContext()
private val userId = context.userId
private val trustManager = context.getSystemService(TrustManager::class.java) as TrustManager
private val activityScenarioRule = ActivityScenarioRule(TrustTestActivity::class.java)
private val lockStateTrackingRule = LockStateTrackingRule()
private val trustAgentRule = TrustAgentRule<IsActiveUnlockRunningTrustAgent>()
private val listener = object : TestTrustListener() {
var isRunning = false
private set
override fun onIsActiveUnlockRunningChanged(isRunning: Boolean, userId: Int) {
this.isRunning = isRunning
}
}
@get:Rule
val rule: RuleChain = RuleChain
.outerRule(activityScenarioRule)
.around(ScreenLockRule())
.around(lockStateTrackingRule)
.around(trustAgentRule)
@Before
fun manageTrust() {
trustAgentRule.agent.setManagingTrust(true)
trustManager.registerTrustListener(listener)
}
@After
fun unregisterListener() {
trustManager.unregisterTrustListener(listener)
}
@Test
fun defaultState_isActiveUnlockRunningIsFalse() {
assertThat(trustManager.isActiveUnlockRunning(userId)).isFalse()
assertThat(listener.isRunning).isFalse()
}
@Test
fun grantTrustLockedDevice_isActiveUnlockRunningIsFalse() {
uiDevice.sleep()
lockStateTrackingRule.assertLocked()
uiDevice.wakeUp()
trustAgentRule.agent.grantTrust(
GRANT_MESSAGE, 0, FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE) {}
assertThat(trustManager.isActiveUnlockRunning(userId)).isFalse()
assertThat(listener.isRunning).isFalse()
}
@Test
fun grantTrustUnlockedDevice_isActiveUnlockRunningIsTrueWhileLocked() {
trustAgentRule.agent.grantTrust(
GRANT_MESSAGE, 0, FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE) {}
uiDevice.sleep()
lockStateTrackingRule.assertLocked()
assertThat(trustManager.isActiveUnlockRunning(userId)).isTrue()
assertThat(listener.isRunning).isTrue()
}
@Test
fun trustRevoked_isActiveUnlockRunningIsFalse() {
trustAgentRule.agent.grantTrust(
GRANT_MESSAGE, 0, FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE) {}
trustAgentRule.agent.revokeTrust()
assertThat(trustManager.isActiveUnlockRunning(userId)).isFalse()
assertThat(listener.isRunning).isFalse()
}
companion object {
private const val GRANT_MESSAGE = "granted by test"
private fun await(millis: Long) = Thread.sleep(millis)
}
}
class IsActiveUnlockRunningTrustAgent : BaseTrustAgentService()

View File

@@ -17,7 +17,6 @@
package android.trust.test.lib
import android.app.trust.TrustManager
import android.app.trust.TrustManager.TrustListener
import android.content.Context
import android.util.Log
import android.view.WindowManagerGlobal
@@ -60,7 +59,7 @@ class LockStateTrackingRule : TestRule {
wait("locked per TrustListener") { lockState.locked == false }
}
inner class Listener : TrustListener {
inner class Listener : TestTrustListener() {
override fun onTrustChanged(
enabled: Boolean,
newlyUnlocked: Boolean,
@@ -71,15 +70,6 @@ class LockStateTrackingRule : TestRule {
Log.d(TAG, "Device became trusted=$enabled")
lockState = lockState.copy(locked = !enabled)
}
override fun onTrustManagedChanged(enabled: Boolean, userId: Int) {
}
override fun onTrustError(message: CharSequence) {
}
override fun onEnabledTrustAgentsChanged(userId: Int) {
}
}
data class LockState(

View File

@@ -0,0 +1,45 @@
/*
* Copyright (C) 2023 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.trust.test.lib
import android.app.trust.TrustManager.TrustListener
/**
* A listener that has default empty implementations for all [TrustListener] methods.
*/
open class TestTrustListener : TrustListener {
override fun onTrustChanged(
enabled: Boolean,
newlyUnlocked: Boolean,
userId: Int,
flags: Int,
trustGrantedMessages: MutableList<String>
) {
}
override fun onTrustManagedChanged(enabled: Boolean, userId: Int) {
}
override fun onTrustError(message: CharSequence) {
}
override fun onEnabledTrustAgentsChanged(userId: Int) {
}
override fun onIsActiveUnlockRunningChanged(isRunning: Boolean, userId: Int) {
}
}