Add isActiveUnlockRunning
Add isActiveUnlockRunning and onIsActiveUnlockRunningChanged, in order to track when active unlock is available on the device or not. Listeners are notified if the value is true on subscription. Test: atest, local build, verify listeners notified Bug: b/267322286 Change-Id: Ibceac9d721190a4da3905e71d11c4424f7ee9676 Merged-In: Ibceac9d721190a4da3905e71d11c4424f7ee9676
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -95,6 +95,11 @@ constructor(
|
||||
"onTrustManagedChanged"
|
||||
)
|
||||
}
|
||||
|
||||
override fun onIsActiveUnlockRunningChanged(
|
||||
isRunning: Boolean,
|
||||
userId: Int
|
||||
) = Unit
|
||||
}
|
||||
trustManager.registerTrustListener(callback)
|
||||
logger.trustListenerRegistered()
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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. -->
|
||||
|
||||
@@ -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()
|
||||
@@ -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(
|
||||
|
||||
@@ -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) {
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user