summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/api/current.txt3
-rw-r--r--core/java/android/content/res/Resources.java5
-rw-r--r--core/java/android/os/OWNERS3
-rw-r--r--keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java111
-rw-r--r--keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java18
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java21
-rw-r--r--services/core/java/com/android/server/OWNERS3
-rw-r--r--services/core/java/com/android/server/input/InputManagerService.java68
-rw-r--r--services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java3
-rw-r--r--services/core/java/com/android/server/wm/AnrController.java102
-rw-r--r--services/core/java/com/android/server/wm/InputManagerCallback.java20
-rw-r--r--services/core/jni/com_android_server_input_InputManagerService.cpp57
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java25
-rw-r--r--telecomm/java/android/telecom/TelecomManager.java51
-rw-r--r--telecomm/java/com/android/internal/telecom/ITelecomService.aidl6
-rw-r--r--tests/TrustTests/Android.bp39
-rw-r--r--tests/TrustTests/AndroidManifest.xml75
-rw-r--r--tests/TrustTests/AndroidTest.xml28
-rw-r--r--tests/TrustTests/README.md40
-rw-r--r--tests/TrustTests/src/android/trust/BaseTrustAgentService.kt47
-rw-r--r--tests/TrustTests/src/android/trust/TrustTestActivity.kt30
-rw-r--r--tests/TrustTests/src/android/trust/test/GrantAndRevokeTrustTest.kt95
-rw-r--r--tests/TrustTests/src/android/trust/test/LockUserTest.kt68
-rw-r--r--tests/TrustTests/src/android/trust/test/UserUnlockRequestTest.kt81
-rw-r--r--tests/TrustTests/src/android/trust/test/lib/LockStateTrackingRule.kt83
-rw-r--r--tests/TrustTests/src/android/trust/test/lib/ScreenLockRule.kt105
-rw-r--r--tests/TrustTests/src/android/trust/test/lib/TrustAgentRule.kt117
32 files changed, 1148 insertions, 209 deletions
diff --git a/core/api/current.txt b/core/api/current.txt
index 4ab172d98d35..cd0bd8699794 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -40754,8 +40754,9 @@ package android.telecom {
method public String getDefaultDialerPackage();
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public android.telecom.PhoneAccountHandle getDefaultOutgoingPhoneAccount(String);
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.READ_SMS, android.Manifest.permission.READ_PHONE_NUMBERS}, conditional=true) public String getLine1Number(android.telecom.PhoneAccountHandle);
+ method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_OWN_CALLS) public java.util.List<android.telecom.PhoneAccountHandle> getOwnSelfManagedPhoneAccounts();
method public android.telecom.PhoneAccount getPhoneAccount(android.telecom.PhoneAccountHandle);
- method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.MANAGE_OWN_CALLS}) public java.util.List<android.telecom.PhoneAccountHandle> getSelfManagedPhoneAccounts();
+ method @NonNull @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public java.util.List<android.telecom.PhoneAccountHandle> getSelfManagedPhoneAccounts();
method public android.telecom.PhoneAccountHandle getSimCallManager();
method @Nullable public android.telecom.PhoneAccountHandle getSimCallManagerForSubscription(int);
method @Nullable public String getSystemDialerPackage();
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index ebef0535f077..a03286d3ec6f 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -2674,9 +2674,8 @@ public class Resources {
// Putting into a map keyed on the apk assets to deduplicate resources that are different
// objects but ultimately represent the same assets
Map<List<ApkAssets>, Resources> history = new ArrayMap<>();
- for (Resources r : sResourcesHistory) {
- history.put(Arrays.asList(r.mResourcesImpl.mAssets.getApkAssets()), r);
- }
+ sResourcesHistory.forEach(
+ r -> history.put(Arrays.asList(r.mResourcesImpl.mAssets.getApkAssets()), r));
int i = 0;
for (Resources r : history.values()) {
if (r != null) {
diff --git a/core/java/android/os/OWNERS b/core/java/android/os/OWNERS
index 5d9f2189df1b..8e5ed8f6e578 100644
--- a/core/java/android/os/OWNERS
+++ b/core/java/android/os/OWNERS
@@ -52,6 +52,9 @@ per-file *Power* = file:/services/core/java/com/android/server/power/OWNERS
per-file *Telephony* = file:/telephony/OWNERS
per-file *Zygote* = file:/ZYGOTE_OWNERS
+# Time
+per-file *Clock* = file:/services/core/java/com/android/server/timezonedetector/OWNERS
+
# RecoverySystem
per-file *Recovery* = file:/services/core/java/com/android/server/recoverysystem/OWNERS
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
index 2e85b304ec47..31dd10a8ed53 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -66,6 +66,7 @@ import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.ECGenParameterSpec;
+import java.security.spec.NamedParameterSpec;
import java.security.spec.RSAKeyGenParameterSpec;
import java.util.ArrayList;
import java.util.Arrays;
@@ -119,36 +120,42 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
private static final int RSA_MIN_KEY_SIZE = 512;
private static final int RSA_MAX_KEY_SIZE = 8192;
- private static final Map<String, Integer> SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE =
+ private static final Map<String, Integer> SUPPORTED_EC_CURVE_NAME_TO_SIZE =
new HashMap<String, Integer>();
- private static final List<String> SUPPORTED_EC_NIST_CURVE_NAMES = new ArrayList<String>();
- private static final List<Integer> SUPPORTED_EC_NIST_CURVE_SIZES = new ArrayList<Integer>();
+ private static final List<String> SUPPORTED_EC_CURVE_NAMES = new ArrayList<String>();
+ private static final List<Integer> SUPPORTED_EC_CURVE_SIZES = new ArrayList<Integer>();
+ private static final String CURVE_X_25519 = NamedParameterSpec.X25519.getName();
+ private static final String CURVE_ED_25519 = NamedParameterSpec.ED25519.getName();
+
static {
// Aliases for NIST P-224
- SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-224", 224);
- SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("secp224r1", 224);
+ SUPPORTED_EC_CURVE_NAME_TO_SIZE.put("p-224", 224);
+ SUPPORTED_EC_CURVE_NAME_TO_SIZE.put("secp224r1", 224);
// Aliases for NIST P-256
- SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-256", 256);
- SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("secp256r1", 256);
- SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("prime256v1", 256);
+ SUPPORTED_EC_CURVE_NAME_TO_SIZE.put("p-256", 256);
+ SUPPORTED_EC_CURVE_NAME_TO_SIZE.put("secp256r1", 256);
+ SUPPORTED_EC_CURVE_NAME_TO_SIZE.put("prime256v1", 256);
+ // Aliases for Curve 25519
+ SUPPORTED_EC_CURVE_NAME_TO_SIZE.put(CURVE_X_25519.toLowerCase(Locale.US), 256);
+ SUPPORTED_EC_CURVE_NAME_TO_SIZE.put(CURVE_ED_25519.toLowerCase(Locale.US), 256);
// Aliases for NIST P-384
- SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-384", 384);
- SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("secp384r1", 384);
+ SUPPORTED_EC_CURVE_NAME_TO_SIZE.put("p-384", 384);
+ SUPPORTED_EC_CURVE_NAME_TO_SIZE.put("secp384r1", 384);
// Aliases for NIST P-521
- SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-521", 521);
- SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("secp521r1", 521);
+ SUPPORTED_EC_CURVE_NAME_TO_SIZE.put("p-521", 521);
+ SUPPORTED_EC_CURVE_NAME_TO_SIZE.put("secp521r1", 521);
- SUPPORTED_EC_NIST_CURVE_NAMES.addAll(SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.keySet());
- Collections.sort(SUPPORTED_EC_NIST_CURVE_NAMES);
+ SUPPORTED_EC_CURVE_NAMES.addAll(SUPPORTED_EC_CURVE_NAME_TO_SIZE.keySet());
+ Collections.sort(SUPPORTED_EC_CURVE_NAMES);
- SUPPORTED_EC_NIST_CURVE_SIZES.addAll(
- new HashSet<Integer>(SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.values()));
- Collections.sort(SUPPORTED_EC_NIST_CURVE_SIZES);
+ SUPPORTED_EC_CURVE_SIZES.addAll(
+ new HashSet<Integer>(SUPPORTED_EC_CURVE_NAME_TO_SIZE.values()));
+ Collections.sort(SUPPORTED_EC_CURVE_SIZES);
}
private final int mOriginalKeymasterAlgorithm;
@@ -164,6 +171,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
private int mKeySizeBits;
private SecureRandom mRng;
private KeyDescriptor mAttestKeyDescriptor;
+ private String mEcCurveName;
private int[] mKeymasterPurposes;
private int[] mKeymasterBlockModes;
@@ -177,12 +185,15 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
mOriginalKeymasterAlgorithm = keymasterAlgorithm;
}
- private @EcCurve int keySize2EcCurve(int keySizeBits)
+ private static @EcCurve int keySizeAndNameToEcCurve(int keySizeBits, String ecCurveName)
throws InvalidAlgorithmParameterException {
switch (keySizeBits) {
case 224:
return EcCurve.P_224;
case 256:
+ if (isCurve25519(ecCurveName)) {
+ return EcCurve.CURVE_25519;
+ }
return EcCurve.P_256;
case 384:
return EcCurve.P_384;
@@ -247,7 +258,8 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
if (mKeySizeBits == -1) {
mKeySizeBits = getDefaultKeySize(keymasterAlgorithm);
}
- checkValidKeySize(keymasterAlgorithm, mKeySizeBits, mSpec.isStrongBoxBacked());
+ checkValidKeySize(keymasterAlgorithm, mKeySizeBits, mSpec.isStrongBoxBacked(),
+ mEcCurveName);
if (spec.getKeystoreAlias() == null) {
throw new InvalidAlgorithmParameterException("KeyStore entry alias not provided");
@@ -299,6 +311,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
mAttestKeyDescriptor = buildAndCheckAttestKeyDescriptor(spec);
checkAttestKeyPurpose(spec);
+ checkCorrectKeyPurposeForCurve(spec);
success = true;
} finally {
@@ -317,6 +330,42 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
}
}
+ private void checkCorrectKeyPurposeForCurve(KeyGenParameterSpec spec)
+ throws InvalidAlgorithmParameterException {
+ // Validate the key usage purposes against the curve. x25519 should be
+ // key exchange only, ed25519 signing and attesting.
+
+ if (!isCurve25519(mEcCurveName)) {
+ return;
+ }
+
+ if (mEcCurveName.equalsIgnoreCase(CURVE_X_25519)
+ && spec.getPurposes() != KeyProperties.PURPOSE_AGREE_KEY) {
+ throw new InvalidAlgorithmParameterException(
+ "x25519 may only be used for key agreement.");
+ } else if (mEcCurveName.equalsIgnoreCase(CURVE_ED_25519)
+ && !hasOnlyAllowedPurposeForEd25519(spec.getPurposes())) {
+ throw new InvalidAlgorithmParameterException(
+ "ed25519 may not be used for key agreement.");
+ }
+ }
+
+ private static boolean isCurve25519(String ecCurveName) {
+ if (ecCurveName == null) {
+ return false;
+ }
+ return ecCurveName.equalsIgnoreCase(CURVE_X_25519)
+ || ecCurveName.equalsIgnoreCase(CURVE_ED_25519);
+ }
+
+ private static boolean hasOnlyAllowedPurposeForEd25519(@KeyProperties.PurposeEnum int purpose) {
+ final int allowedPurposes = KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY
+ | KeyProperties.PURPOSE_ATTEST_KEY;
+ boolean hasAllowedPurpose = (purpose & allowedPurposes) != 0;
+ boolean hasDisallowedPurpose = (purpose & ~allowedPurposes) != 0;
+ return hasAllowedPurpose && !hasDisallowedPurpose;
+ }
+
private KeyDescriptor buildAndCheckAttestKeyDescriptor(KeyGenParameterSpec spec)
throws InvalidAlgorithmParameterException {
if (spec.getAttestKeyAlias() != null) {
@@ -473,6 +522,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
mRSAPublicExponent = null;
mRng = null;
mKeyStore = null;
+ mEcCurveName = null;
}
private void initAlgorithmSpecificParameters() throws InvalidAlgorithmParameterException {
@@ -514,13 +564,13 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
case KeymasterDefs.KM_ALGORITHM_EC:
if (algSpecificSpec instanceof ECGenParameterSpec) {
ECGenParameterSpec ecSpec = (ECGenParameterSpec) algSpecificSpec;
- String curveName = ecSpec.getName();
- Integer ecSpecKeySizeBits = SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.get(
- curveName.toLowerCase(Locale.US));
+ mEcCurveName = ecSpec.getName();
+ final Integer ecSpecKeySizeBits = SUPPORTED_EC_CURVE_NAME_TO_SIZE.get(
+ mEcCurveName.toLowerCase(Locale.US));
if (ecSpecKeySizeBits == null) {
throw new InvalidAlgorithmParameterException(
- "Unsupported EC curve name: " + curveName
- + ". Supported: " + SUPPORTED_EC_NIST_CURVE_NAMES);
+ "Unsupported EC curve name: " + mEcCurveName
+ + ". Supported: " + SUPPORTED_EC_CURVE_NAMES);
}
if (mKeySizeBits == -1) {
mKeySizeBits = ecSpecKeySizeBits;
@@ -744,7 +794,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
if (mKeymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_EC) {
params.add(KeyStore2ParameterUtils.makeEnum(
- Tag.EC_CURVE, keySize2EcCurve(mKeySizeBits)
+ Tag.EC_CURVE, keySizeAndNameToEcCurve(mKeySizeBits, mEcCurveName)
));
}
@@ -864,7 +914,8 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
private static void checkValidKeySize(
int keymasterAlgorithm,
int keySize,
- boolean isStrongBoxBacked)
+ boolean isStrongBoxBacked,
+ String mEcCurveName)
throws InvalidAlgorithmParameterException {
switch (keymasterAlgorithm) {
case KeymasterDefs.KM_ALGORITHM_EC:
@@ -873,9 +924,13 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
"Unsupported StrongBox EC key size: "
+ keySize + " bits. Supported: 256");
}
- if (!SUPPORTED_EC_NIST_CURVE_SIZES.contains(keySize)) {
+ if (isStrongBoxBacked && isCurve25519(mEcCurveName)) {
+ throw new InvalidAlgorithmParameterException(
+ "Unsupported StrongBox EC: " + mEcCurveName);
+ }
+ if (!SUPPORTED_EC_CURVE_SIZES.contains(keySize)) {
throw new InvalidAlgorithmParameterException("Unsupported EC key size: "
- + keySize + " bits. Supported: " + SUPPORTED_EC_NIST_CURVE_SIZES);
+ + keySize + " bits. Supported: " + SUPPORTED_EC_CURVE_SIZES);
}
break;
case KeymasterDefs.KM_ALGORITHM_RSA:
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
index 72a145fa6a05..358104fffbf6 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
@@ -66,6 +66,11 @@ public class AndroidKeyStoreProvider extends Provider {
private static final String DESEDE_SYSTEM_PROPERTY =
"ro.hardware.keystore_desede";
+ // Conscrypt returns the Ed25519 OID as the JCA key algorithm.
+ private static final String ED25519_OID = "1.3.101.112";
+ // Conscrypt returns "XDH" as the X25519 JCA key algorithm.
+ private static final String X25519_ALIAS = "XDH";
+
/** @hide **/
public AndroidKeyStoreProvider() {
super(PROVIDER_NAME, 1.0, "Android KeyStore security provider");
@@ -78,10 +83,16 @@ public class AndroidKeyStoreProvider extends Provider {
// java.security.KeyPairGenerator
put("KeyPairGenerator.EC", PACKAGE_NAME + ".AndroidKeyStoreKeyPairGeneratorSpi$EC");
put("KeyPairGenerator.RSA", PACKAGE_NAME + ".AndroidKeyStoreKeyPairGeneratorSpi$RSA");
+ put("KeyPairGenerator." + X25519_ALIAS,
+ PACKAGE_NAME + ".AndroidKeyStoreKeyPairGeneratorSpi$RSA");
+ put("KeyPairGenerator." + ED25519_OID,
+ PACKAGE_NAME + ".AndroidKeyStoreKeyPairGeneratorSpi$RSA");
// java.security.KeyFactory
putKeyFactoryImpl("EC");
putKeyFactoryImpl("RSA");
+ putKeyFactoryImpl(X25519_ALIAS);
+ putKeyFactoryImpl(ED25519_OID);
// javax.crypto.KeyGenerator
put("KeyGenerator.AES", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$AES");
@@ -219,12 +230,17 @@ public class AndroidKeyStoreProvider extends Provider {
KeyStoreSecurityLevel securityLevel = iSecurityLevel;
if (KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(jcaKeyAlgorithm)) {
-
return new AndroidKeyStoreECPublicKey(descriptor, metadata,
iSecurityLevel, (ECPublicKey) publicKey);
} else if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(jcaKeyAlgorithm)) {
return new AndroidKeyStoreRSAPublicKey(descriptor, metadata,
iSecurityLevel, (RSAPublicKey) publicKey);
+ } else if (ED25519_OID.equalsIgnoreCase(jcaKeyAlgorithm)) {
+ //TODO(b/214203951) missing classes in conscrypt
+ throw new ProviderException("Curve " + ED25519_OID + " not supported yet");
+ } else if (X25519_ALIAS.equalsIgnoreCase(jcaKeyAlgorithm)) {
+ //TODO(b/214203951) missing classes in conscrypt
+ throw new ProviderException("Curve " + X25519_ALIAS + " not supported yet");
} else {
throw new ProviderException("Unsupported Android Keystore public key algorithm: "
+ jcaKeyAlgorithm);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index c6a68dc98da6..58f79f3600de 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -1608,7 +1608,9 @@ public class BubbleStackView extends FrameLayout
Log.d(TAG, "addBubble: " + bubble);
}
- if (getBubbleCount() == 0 && shouldShowStackEdu()) {
+ final boolean firstBubble = getBubbleCount() == 0;
+
+ if (firstBubble && shouldShowStackEdu()) {
// Override the default stack position if we're showing user education.
mStackAnimationController.setStackPosition(mPositioner.getDefaultStartPosition());
}
@@ -1621,7 +1623,7 @@ public class BubbleStackView extends FrameLayout
new FrameLayout.LayoutParams(mPositioner.getBubbleSize(),
mPositioner.getBubbleSize()));
- if (getBubbleCount() == 0) {
+ if (firstBubble) {
mStackOnLeftOrWillBe = mStackAnimationController.isStackOnLeftSide();
}
// Set the dot position to the opposite of the side the stack is resting on, since the stack
@@ -1652,6 +1654,10 @@ public class BubbleStackView extends FrameLayout
bubble.cleanupViews();
}
updateExpandedView();
+ if (getBubbleCount() == 0 && !isExpanded()) {
+ // This is the last bubble and the stack is collapsed
+ updateStackPosition();
+ }
logBubbleEvent(bubble, FrameworkStatsLog.BUBBLE_UICHANGED__ACTION__DISMISSED);
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
index 7e1fce298fbd..ebc766635733 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
@@ -19,6 +19,8 @@ package com.android.systemui.dreams;
import android.content.Context;
import android.graphics.drawable.ColorDrawable;
import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowInsets;
import android.view.WindowManager;
@@ -177,9 +179,26 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ
}
mDreamOverlayContainerViewController.init();
+ // Make extra sure the container view has been removed from its old parent (otherwise we
+ // risk an IllegalStateException in some cases when setting the container view as the
+ // window's content view and the container view hasn't been properly removed previously).
+ removeContainerViewFromParent();
mWindow.setContentView(mDreamOverlayContainerViewController.getContainerView());
final WindowManager windowManager = mContext.getSystemService(WindowManager.class);
windowManager.addView(mWindow.getDecorView(), mWindow.getAttributes());
}
+
+ private void removeContainerViewFromParent() {
+ View containerView = mDreamOverlayContainerViewController.getContainerView();
+ if (containerView == null) {
+ return;
+ }
+ ViewGroup parentView = (ViewGroup) containerView.getParent();
+ if (parentView == null) {
+ return;
+ }
+ Log.w(TAG, "Removing dream overlay container view parent!");
+ parentView.removeView(containerView);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
index 582965a12528..35f29b94966f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
@@ -23,6 +23,7 @@ import android.content.Context
import android.graphics.Matrix
import android.graphics.Rect
import android.os.Handler
+import android.util.Log
import android.view.RemoteAnimationTarget
import android.view.SyncRtSurfaceTransactionApplier
import android.view.View
@@ -47,6 +48,8 @@ import dagger.Lazy
import javax.inject.Inject
import kotlin.math.min
+const val TAG = "KeyguardUnlock"
+
/**
* Starting scale factor for the app/launcher surface behind the keyguard, when it's animating
* in during keyguard exit.
@@ -584,8 +587,16 @@ class KeyguardUnlockAnimationController @Inject constructor(
* animation.
*/
fun hideKeyguardViewAfterRemoteAnimation() {
- // Hide the keyguard, with no fade out since we animated it away during the unlock.
- keyguardViewController.hide(surfaceBehindRemoteAnimationStartTime, 0 /* fadeOutDuration */)
+ if (keyguardViewController.isShowing) {
+ // Hide the keyguard, with no fade out since we animated it away during the unlock.
+ keyguardViewController.hide(
+ surfaceBehindRemoteAnimationStartTime,
+ 0 /* fadeOutDuration */
+ )
+ } else {
+ Log.e(TAG, "#hideKeyguardViewAfterRemoteAnimation called when keyguard view is not " +
+ "showing. Ignoring...")
+ }
}
private fun applyParamsToSurface(params: SyncRtSurfaceTransactionApplier.SurfaceParams) {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
index 9ea27634df6a..371e4f454a39 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
@@ -936,6 +936,9 @@ public class EdgeBackGestureHandler extends CurrentUserTracker
public void setBackAnimation(BackAnimation backAnimation) {
mBackAnimation = backAnimation;
+ if (mEdgeBackPlugin != null && mEdgeBackPlugin instanceof NavigationBarEdgePanel) {
+ ((NavigationBarEdgePanel) mEdgeBackPlugin).setBackAnimation(backAnimation);
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java
index a6bad15e0865..a6919e826d4f 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java
@@ -280,7 +280,7 @@ public class NavigationBarEdgePanel extends View implements NavigationEdgeBackPl
}
};
private BackCallback mBackCallback;
- private final BackAnimation mBackAnimation;
+ private BackAnimation mBackAnimation;
public NavigationBarEdgePanel(Context context,
BackAnimation backAnimation) {
@@ -385,6 +385,10 @@ public class NavigationBarEdgePanel extends View implements NavigationEdgeBackPl
mShowProtection = !isPrimaryDisplay;
}
+ public void setBackAnimation(BackAnimation backAnimation) {
+ mBackAnimation = backAnimation;
+ }
+
@Override
public void onDestroy() {
cancelFailsafe();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
index 2860b50c2295..b3d54590dc99 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
@@ -28,6 +28,7 @@ import android.service.dreams.DreamService;
import android.service.dreams.IDreamOverlay;
import android.service.dreams.IDreamOverlayCallback;
import android.testing.AndroidTestingRunner;
+import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.WindowManagerImpl;
@@ -99,6 +100,9 @@ public class DreamOverlayServiceTest extends SysuiTestCase {
@Mock
DreamPreviewComplication mPreviewComplication;
+ @Mock
+ ViewGroup mDreamOverlayContainerViewParent;
+
DreamOverlayService mService;
@Before
@@ -152,6 +156,23 @@ public class DreamOverlayServiceTest extends SysuiTestCase {
}
@Test
+ public void testDreamOverlayContainerViewRemovedFromOldParentWhenInitialized()
+ throws Exception {
+ when(mDreamOverlayContainerView.getParent())
+ .thenReturn(mDreamOverlayContainerViewParent)
+ .thenReturn(null);
+
+ final IBinder proxy = mService.onBind(new Intent());
+ final IDreamOverlay overlay = IDreamOverlay.Stub.asInterface(proxy);
+
+ // Inform the overlay service of dream starting.
+ overlay.startDream(mWindowParams, mDreamOverlayCallback);
+ mMainExecutor.runAllReady();
+
+ verify(mDreamOverlayContainerViewParent).removeView(mDreamOverlayContainerView);
+ }
+
+ @Test
public void testShouldShowComplicationsFalseByDefault() {
mService.onBind(new Intent());
diff --git a/services/core/java/com/android/server/OWNERS b/services/core/java/com/android/server/OWNERS
index 4129feb4e082..6ff8e36a1f82 100644
--- a/services/core/java/com/android/server/OWNERS
+++ b/services/core/java/com/android/server/OWNERS
@@ -21,14 +21,13 @@ per-file *AppOp* = file:/core/java/android/permission/OWNERS
per-file *Battery* = file:/BATTERY_STATS_OWNERS
per-file *BinaryTransparency* = file:/core/java/android/transparency/OWNERS
per-file *Binder* = file:/core/java/com/android/internal/os/BINDER_OWNERS
-per-file *Bluetooth* = file:/core/java/android/bluetooth/OWNERS
per-file *Gnss* = file:/services/core/java/com/android/server/location/OWNERS
per-file **IpSec* = file:/services/core/java/com/android/server/net/OWNERS
per-file **IpSec* = file:/services/core/java/com/android/server/vcn/OWNERS
per-file *Location* = file:/services/core/java/com/android/server/location/OWNERS
per-file *Network* = file:/services/core/java/com/android/server/net/OWNERS
per-file *Storage* = file:/core/java/android/os/storage/OWNERS
-per-file *TimeUpdate* = file:/core/java/android/app/timezone/OWNERS
+per-file *TimeUpdate* = file:/services/core/java/com/android/server/timezonedetector/OWNERS
per-file DynamicSystemService.java = file:/packages/DynamicSystemInstallationService/OWNERS
per-file GestureLauncherService.java = file:platform/packages/apps/EmergencyInfo:/OWNERS
per-file MmsServiceBroker.java = file:/telephony/OWNERS
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index c15242a45482..140a28f111e6 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -144,6 +144,7 @@ import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
+import java.util.OptionalInt;
/*
* Wraps the C++ InputManager and provides its callbacks.
@@ -2915,48 +2916,17 @@ public class InputManagerService extends IInputManager.Stub
// Native callback
@SuppressWarnings("unused")
- private void notifyWindowUnresponsive(IBinder token, String reason) {
- int gestureMonitorPid = -1;
- synchronized (mInputMonitors) {
- final GestureMonitorSpyWindow gestureMonitor = mInputMonitors.get(token);
- if (gestureMonitor != null) {
- gestureMonitorPid = gestureMonitor.mWindowHandle.ownerPid;
- }
- }
- if (gestureMonitorPid != -1) {
- mWindowManagerCallbacks.notifyGestureMonitorUnresponsive(gestureMonitorPid, reason);
- return;
- }
- mWindowManagerCallbacks.notifyWindowUnresponsive(token, reason);
- }
-
- // Native callback
- @SuppressWarnings("unused")
- private void notifyMonitorUnresponsive(int pid, String reason) {
- mWindowManagerCallbacks.notifyGestureMonitorUnresponsive(pid, reason);
+ private void notifyWindowUnresponsive(IBinder token, int pid, boolean isPidValid,
+ String reason) {
+ mWindowManagerCallbacks.notifyWindowUnresponsive(token,
+ isPidValid ? OptionalInt.of(pid) : OptionalInt.empty(), reason);
}
// Native callback
@SuppressWarnings("unused")
- private void notifyWindowResponsive(IBinder token) {
- int gestureMonitorPid = -1;
- synchronized (mInputMonitors) {
- final GestureMonitorSpyWindow gestureMonitor = mInputMonitors.get(token);
- if (gestureMonitor != null) {
- gestureMonitorPid = gestureMonitor.mWindowHandle.ownerPid;
- }
- }
- if (gestureMonitorPid != -1) {
- mWindowManagerCallbacks.notifyGestureMonitorResponsive(gestureMonitorPid);
- return;
- }
- mWindowManagerCallbacks.notifyWindowResponsive(token);
- }
-
- // Native callback
- @SuppressWarnings("unused")
- private void notifyMonitorResponsive(int pid) {
- mWindowManagerCallbacks.notifyGestureMonitorResponsive(pid);
+ private void notifyWindowResponsive(IBinder token, int pid, boolean isPidValid) {
+ mWindowManagerCallbacks.notifyWindowResponsive(token,
+ isPidValid ? OptionalInt.of(pid) : OptionalInt.empty());
}
// Native callback.
@@ -3329,34 +3299,22 @@ public class InputManagerService extends IInputManager.Stub
void notifyNoFocusedWindowAnr(InputApplicationHandle applicationHandle);
/**
- * Notify the window manager about a gesture monitor that is unresponsive.
- *
- * @param pid the pid of the gesture monitor process
- * @param reason the reason why this connection is unresponsive
- */
- void notifyGestureMonitorUnresponsive(int pid, @NonNull String reason);
-
- /**
* Notify the window manager about a window that is unresponsive.
*
* @param token the token that can be used to look up the window
+ * @param pid the pid of the window owner, if known
* @param reason the reason why this connection is unresponsive
*/
- void notifyWindowUnresponsive(@NonNull IBinder token, @NonNull String reason);
-
- /**
- * Notify the window manager about a gesture monitor that has become responsive.
- *
- * @param pid the pid of the gesture monitor process
- */
- void notifyGestureMonitorResponsive(int pid);
+ void notifyWindowUnresponsive(@NonNull IBinder token, @NonNull OptionalInt pid,
+ @NonNull String reason);
/**
* Notify the window manager about a window that has become responsive.
*
* @param token the token that can be used to look up the window
+ * @param pid the pid of the window owner, if known
*/
- void notifyWindowResponsive(@NonNull IBinder token);
+ void notifyWindowResponsive(@NonNull IBinder token, @NonNull OptionalInt pid);
/**
* This callback is invoked when an event first arrives to InputDispatcher and before it is
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 49553f4c91f4..36633cc635e7 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -1021,7 +1021,8 @@ final class DefaultPermissionGrantPolicy {
}
for (String packageName : packageNames) {
grantPermissionsToSystemPackage(NO_PM_CACHE, packageName, userId,
- PHONE_PERMISSIONS, ALWAYS_LOCATION_PERMISSIONS, SMS_PERMISSIONS);
+ PHONE_PERMISSIONS, ALWAYS_LOCATION_PERMISSIONS, SMS_PERMISSIONS,
+ NOTIFICATION_PERMISSIONS);
}
}
diff --git a/services/core/java/com/android/server/wm/AnrController.java b/services/core/java/com/android/server/wm/AnrController.java
index 3d54b27c819b..6befefda8a12 100644
--- a/services/core/java/com/android/server/wm/AnrController.java
+++ b/services/core/java/com/android/server/wm/AnrController.java
@@ -21,6 +21,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
import static com.android.server.wm.ActivityRecord.INVALID_PID;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import android.annotation.NonNull;
import android.os.Build;
import android.os.IBinder;
import android.os.Process;
@@ -35,6 +36,7 @@ import com.android.server.criticalevents.CriticalEventLog;
import java.io.File;
import java.util.ArrayList;
+import java.util.OptionalInt;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -75,7 +77,33 @@ class AnrController {
activity.inputDispatchingTimedOut(reason, INVALID_PID);
}
- void notifyWindowUnresponsive(IBinder inputToken, String reason) {
+
+ /**
+ * Notify a window was unresponsive.
+ *
+ * @param token - the input token of the window
+ * @param pid - the pid of the window, if known
+ * @param reason - the reason for the window being unresponsive
+ */
+ void notifyWindowUnresponsive(@NonNull IBinder token, @NonNull OptionalInt pid,
+ @NonNull String reason) {
+ if (notifyWindowUnresponsive(token, reason)) {
+ return;
+ }
+ if (!pid.isPresent()) {
+ Slog.w(TAG_WM, "Failed to notify that window token=" + token + " was unresponsive.");
+ return;
+ }
+ notifyWindowUnresponsive(pid.getAsInt(), reason);
+ }
+
+ /**
+ * Notify a window identified by its input token was unresponsive.
+ *
+ * @return true if the window was identified by the given input token and the request was
+ * handled, false otherwise.
+ */
+ private boolean notifyWindowUnresponsive(@NonNull IBinder inputToken, String reason) {
preDumpIfLockTooSlow();
final int pid;
final boolean aboveSystem;
@@ -83,10 +111,8 @@ class AnrController {
synchronized (mService.mGlobalLock) {
InputTarget target = mService.getInputTargetFromToken(inputToken);
if (target == null) {
- Slog.e(TAG_WM, "Unknown token, dropping notifyConnectionUnresponsive request");
- return;
+ return false;
}
-
WindowState windowState = target.getWindowState();
pid = target.getPid();
// Blame the activity if the input token belongs to the window. If the target is
@@ -102,34 +128,63 @@ class AnrController {
} else {
mService.mAmInternal.inputDispatchingTimedOut(pid, aboveSystem, reason);
}
+ return true;
+ }
+
+ /**
+ * Notify a window owned by the provided pid was unresponsive.
+ */
+ private void notifyWindowUnresponsive(int pid, String reason) {
+ Slog.i(TAG_WM, "ANR in input window owned by pid=" + pid + ". Reason: " + reason);
+ dumpAnrStateLocked(null /* activity */, null /* windowState */, reason);
+
+ // We cannot determine the z-order of the window, so place the anr dialog as high
+ // as possible.
+ mService.mAmInternal.inputDispatchingTimedOut(pid, true /*aboveSystem*/, reason);
+ }
+
+ /**
+ * Notify a window was responsive after previously being unresponsive.
+ *
+ * @param token - the input token of the window
+ * @param pid - the pid of the window, if known
+ */
+ void notifyWindowResponsive(@NonNull IBinder token, @NonNull OptionalInt pid) {
+ if (notifyWindowResponsive(token)) {
+ return;
+ }
+ if (!pid.isPresent()) {
+ Slog.w(TAG_WM, "Failed to notify that window token=" + token + " was responsive.");
+ return;
+ }
+ notifyWindowResponsive(pid.getAsInt());
}
- void notifyWindowResponsive(IBinder inputToken) {
+ /**
+ * Notify a window identified by its input token was responsive after previously being
+ * unresponsive.
+ *
+ * @return true if the window was identified by the given input token and the request was
+ * handled, false otherwise.
+ */
+ private boolean notifyWindowResponsive(@NonNull IBinder inputToken) {
final int pid;
synchronized (mService.mGlobalLock) {
InputTarget target = mService.getInputTargetFromToken(inputToken);
if (target == null) {
- Slog.e(TAG_WM, "Unknown token, dropping notifyWindowConnectionResponsive request");
- return;
+ return false;
}
pid = target.getPid();
}
mService.mAmInternal.inputDispatchingResumed(pid);
+ return true;
}
- void notifyGestureMonitorUnresponsive(int gestureMonitorPid, String reason) {
- preDumpIfLockTooSlow();
- synchronized (mService.mGlobalLock) {
- Slog.i(TAG_WM, "ANR in gesture monitor owned by pid:" + gestureMonitorPid
- + ". Reason: " + reason);
- dumpAnrStateLocked(null /* activity */, null /* windowState */, reason);
- }
- mService.mAmInternal.inputDispatchingTimedOut(gestureMonitorPid, /* aboveSystem */ true,
- reason);
- }
-
- void notifyGestureMonitorResponsive(int gestureMonitorPid) {
- mService.mAmInternal.inputDispatchingResumed(gestureMonitorPid);
+ /**
+ * Notify a window owned by the provided pid was responsive after previously being unresponsive.
+ */
+ private void notifyWindowResponsive(int pid) {
+ mService.mAmInternal.inputDispatchingResumed(pid);
}
/**
@@ -228,12 +283,7 @@ class AnrController {
mService.mAtmService.saveANRState(reason);
}
- private boolean isWindowAboveSystem(WindowState windowState) {
- if (windowState == null) {
- // If the window state is not available we cannot easily determine its z order. Try to
- // place the anr dialog as high as possible.
- return true;
- }
+ private boolean isWindowAboveSystem(@NonNull WindowState windowState) {
int systemAlertLayer = mService.mPolicy.getWindowLayerFromTypeLw(
TYPE_APPLICATION_OVERLAY, windowState.mOwnerCanAddInternalSystemWindow);
return windowState.mBaseLayer > systemAlertLayer;
diff --git a/services/core/java/com/android/server/wm/InputManagerCallback.java b/services/core/java/com/android/server/wm/InputManagerCallback.java
index 1f0fdcf0a8d2..8d1425d17d47 100644
--- a/services/core/java/com/android/server/wm/InputManagerCallback.java
+++ b/services/core/java/com/android/server/wm/InputManagerCallback.java
@@ -39,6 +39,7 @@ import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.input.InputManagerService;
import java.io.PrintWriter;
+import java.util.OptionalInt;
final class InputManagerCallback implements InputManagerService.WindowManagerCallbacks {
private static final String TAG = TAG_WITH_CLASS_NAME ? "InputManagerCallback" : TAG_WM;
@@ -98,23 +99,14 @@ final class InputManagerCallback implements InputManagerService.WindowManagerCal
}
@Override
- public void notifyGestureMonitorUnresponsive(int pid, @NonNull String reason) {
- mService.mAnrController.notifyGestureMonitorUnresponsive(pid, reason);
+ public void notifyWindowUnresponsive(@NonNull IBinder token, @NonNull OptionalInt pid,
+ @NonNull String reason) {
+ mService.mAnrController.notifyWindowUnresponsive(token, pid, reason);
}
@Override
- public void notifyWindowUnresponsive(@NonNull IBinder token, String reason) {
- mService.mAnrController.notifyWindowUnresponsive(token, reason);
- }
-
- @Override
- public void notifyGestureMonitorResponsive(int pid) {
- mService.mAnrController.notifyGestureMonitorResponsive(pid);
- }
-
- @Override
- public void notifyWindowResponsive(@NonNull IBinder token) {
- mService.mAnrController.notifyWindowResponsive(token);
+ public void notifyWindowResponsive(@NonNull IBinder token, @NonNull OptionalInt pid) {
+ mService.mAnrController.notifyWindowResponsive(token, pid);
}
/** Notifies that the input device configuration has changed. */
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 3c122b03d0d1..31b557949e36 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -96,8 +96,6 @@ static struct {
jmethodID notifyNoFocusedWindowAnr;
jmethodID notifyWindowUnresponsive;
jmethodID notifyWindowResponsive;
- jmethodID notifyMonitorUnresponsive;
- jmethodID notifyMonitorResponsive;
jmethodID notifyFocusChanged;
jmethodID notifySensorEvent;
jmethodID notifySensorAccuracy;
@@ -308,10 +306,9 @@ public:
void notifyConfigurationChanged(nsecs_t when) override;
// ANR-related callbacks -- start
void notifyNoFocusedWindowAnr(const std::shared_ptr<InputApplicationHandle>& handle) override;
- void notifyWindowUnresponsive(const sp<IBinder>& token, const std::string& reason) override;
- void notifyWindowResponsive(const sp<IBinder>& token) override;
- void notifyMonitorUnresponsive(int32_t pid, const std::string& reason) override;
- void notifyMonitorResponsive(int32_t pid) override;
+ void notifyWindowUnresponsive(const sp<IBinder>& token, std::optional<int32_t> pid,
+ const std::string& reason) override;
+ void notifyWindowResponsive(const sp<IBinder>& token, std::optional<int32_t> pid) override;
// ANR-related callbacks -- end
void notifyInputChannelBroken(const sp<IBinder>& token) override;
void notifyFocusChanged(const sp<IBinder>& oldToken, const sp<IBinder>& newToken) override;
@@ -838,6 +835,7 @@ void NativeInputManager::notifyNoFocusedWindowAnr(
}
void NativeInputManager::notifyWindowUnresponsive(const sp<IBinder>& token,
+ std::optional<int32_t> pid,
const std::string& reason) {
#if DEBUG_INPUT_DISPATCHER_POLICY
ALOGD("notifyWindowUnresponsive");
@@ -851,11 +849,12 @@ void NativeInputManager::notifyWindowUnresponsive(const sp<IBinder>& token,
ScopedLocalRef<jstring> reasonObj(env, env->NewStringUTF(reason.c_str()));
env->CallVoidMethod(mServiceObj, gServiceClassInfo.notifyWindowUnresponsive, tokenObj,
- reasonObj.get());
+ pid.value_or(0), pid.has_value(), reasonObj.get());
checkAndClearExceptionFromCallback(env, "notifyWindowUnresponsive");
}
-void NativeInputManager::notifyWindowResponsive(const sp<IBinder>& token) {
+void NativeInputManager::notifyWindowResponsive(const sp<IBinder>& token,
+ std::optional<int32_t> pid) {
#if DEBUG_INPUT_DISPATCHER_POLICY
ALOGD("notifyWindowResponsive");
#endif
@@ -866,39 +865,11 @@ void NativeInputManager::notifyWindowResponsive(const sp<IBinder>& token) {
jobject tokenObj = javaObjectForIBinder(env, token);
- env->CallVoidMethod(mServiceObj, gServiceClassInfo.notifyWindowResponsive, tokenObj);
+ env->CallVoidMethod(mServiceObj, gServiceClassInfo.notifyWindowResponsive, tokenObj,
+ pid.value_or(0), pid.has_value());
checkAndClearExceptionFromCallback(env, "notifyWindowResponsive");
}
-void NativeInputManager::notifyMonitorUnresponsive(int32_t pid, const std::string& reason) {
-#if DEBUG_INPUT_DISPATCHER_POLICY
- ALOGD("notifyMonitorUnresponsive");
-#endif
- ATRACE_CALL();
-
- JNIEnv* env = jniEnv();
- ScopedLocalFrame localFrame(env);
-
- ScopedLocalRef<jstring> reasonObj(env, env->NewStringUTF(reason.c_str()));
-
- env->CallVoidMethod(mServiceObj, gServiceClassInfo.notifyMonitorUnresponsive, pid,
- reasonObj.get());
- checkAndClearExceptionFromCallback(env, "notifyMonitorUnresponsive");
-}
-
-void NativeInputManager::notifyMonitorResponsive(int32_t pid) {
-#if DEBUG_INPUT_DISPATCHER_POLICY
- ALOGD("notifyMonitorResponsive");
-#endif
- ATRACE_CALL();
-
- JNIEnv* env = jniEnv();
- ScopedLocalFrame localFrame(env);
-
- env->CallVoidMethod(mServiceObj, gServiceClassInfo.notifyMonitorResponsive, pid);
- checkAndClearExceptionFromCallback(env, "notifyMonitorResponsive");
-}
-
void NativeInputManager::notifyInputChannelBroken(const sp<IBinder>& token) {
#if DEBUG_INPUT_DISPATCHER_POLICY
ALOGD("notifyInputChannelBroken");
@@ -2506,16 +2477,10 @@ int register_android_server_InputManager(JNIEnv* env) {
"(Landroid/view/InputApplicationHandle;)V");
GET_METHOD_ID(gServiceClassInfo.notifyWindowUnresponsive, clazz, "notifyWindowUnresponsive",
- "(Landroid/os/IBinder;Ljava/lang/String;)V");
-
- GET_METHOD_ID(gServiceClassInfo.notifyMonitorUnresponsive, clazz, "notifyMonitorUnresponsive",
- "(ILjava/lang/String;)V");
+ "(Landroid/os/IBinder;IZLjava/lang/String;)V");
GET_METHOD_ID(gServiceClassInfo.notifyWindowResponsive, clazz, "notifyWindowResponsive",
- "(Landroid/os/IBinder;)V");
-
- GET_METHOD_ID(gServiceClassInfo.notifyMonitorResponsive, clazz, "notifyMonitorResponsive",
- "(I)V");
+ "(Landroid/os/IBinder;IZ)V");
GET_METHOD_ID(gServiceClassInfo.filterInputEvent, clazz,
"filterInputEvent", "(Landroid/view/InputEvent;I)Z");
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 28bf0d239b26..5cda9ea66999 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -8610,20 +8610,23 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
admin.getPackageName(), userId, "set-device-owner");
Slogf.i(LOG_TAG, "Device owner set: " + admin + " on user " + userId);
+ }
- if (setProfileOwnerOnCurrentUserIfNecessary
- && mInjector.userManagerIsHeadlessSystemUserMode()) {
- int currentForegroundUser = getCurrentForegroundUserId();
- Slogf.i(LOG_TAG, "setDeviceOwner(): setting " + admin
- + " as profile owner on user " + currentForegroundUser);
- // Sets profile owner on current foreground user since
- // the human user will complete the DO setup workflow from there.
- manageUserUnchecked(/* deviceOwner= */ admin, /* profileOwner= */ admin,
- /* managedUser= */ currentForegroundUser, /* adminExtras= */ null,
- /* showDisclaimer= */ false);
+ if (setProfileOwnerOnCurrentUserIfNecessary
+ && mInjector.userManagerIsHeadlessSystemUserMode()) {
+ int currentForegroundUser;
+ synchronized (getLockObject()) {
+ currentForegroundUser = getCurrentForegroundUserId();
}
- return true;
+ Slogf.i(LOG_TAG, "setDeviceOwner(): setting " + admin
+ + " as profile owner on user " + currentForegroundUser);
+ // Sets profile owner on current foreground user since
+ // the human user will complete the DO setup workflow from there.
+ manageUserUnchecked(/* deviceOwner= */ admin, /* profileOwner= */ admin,
+ /* managedUser= */ currentForegroundUser, /* adminExtras= */ null,
+ /* showDisclaimer= */ false);
}
+ return true;
}
@Override
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index f43e5aacad33..df114dbabe5b 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -1292,31 +1292,22 @@ public class TelecomManager {
}
/**
- * Returns a list of {@link PhoneAccountHandle}s for self-managed {@link ConnectionService}s.
+ * Returns a list of {@link PhoneAccountHandle}s for all self-managed
+ * {@link ConnectionService}s owned by the calling {@link UserHandle}.
* <p>
* Self-Managed {@link ConnectionService}s have a {@link PhoneAccount} with
* {@link PhoneAccount#CAPABILITY_SELF_MANAGED}.
* <p>
* Requires permission {@link android.Manifest.permission#READ_PHONE_STATE}, or that the caller
- * is the default dialer app to get all phone account handles.
- * <P>
- * If the caller doesn't meet any of the above requirements and has {@link
- * android.Manifest.permission#MANAGE_OWN_CALLS}, the caller can get only the phone account
- * handles they have registered.
+ * is the default dialer app.
* <p>
- * A {@link SecurityException} will be thrown if the caller is not the default dialer
- * or the caller does not have at least one of the following permissions:
- * {@link android.Manifest.permission#READ_PHONE_STATE} permission,
- * {@link android.Manifest.permission#MANAGE_OWN_CALLS} permission
+ * A {@link SecurityException} will be thrown if a called is not the default dialer, or lacks
+ * the {@link android.Manifest.permission#READ_PHONE_STATE} permission.
*
* @return A list of {@code PhoneAccountHandle} objects.
*/
- @RequiresPermission(anyOf = {
- READ_PRIVILEGED_PHONE_STATE,
- android.Manifest.permission.READ_PHONE_STATE,
- android.Manifest.permission.MANAGE_OWN_CALLS
- })
- public List<PhoneAccountHandle> getSelfManagedPhoneAccounts() {
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+ public @NonNull List<PhoneAccountHandle> getSelfManagedPhoneAccounts() {
ITelecomService service = getTelecomService();
if (service != null) {
try {
@@ -1330,6 +1321,34 @@ public class TelecomManager {
}
/**
+ * Returns a list of {@link PhoneAccountHandle}s owned by the calling self-managed
+ * {@link ConnectionService}.
+ * <p>
+ * Self-Managed {@link ConnectionService}s have a {@link PhoneAccount} with
+ * {@link PhoneAccount#CAPABILITY_SELF_MANAGED}.
+ * <p>
+ * Requires permission {@link android.Manifest.permission#MANAGE_OWN_CALLS}
+ * <p>
+ * A {@link SecurityException} will be thrown if a caller lacks the
+ * {@link android.Manifest.permission#MANAGE_OWN_CALLS} permission.
+ *
+ * @return A list of {@code PhoneAccountHandle} objects.
+ */
+ @RequiresPermission(Manifest.permission.MANAGE_OWN_CALLS)
+ public @NonNull List<PhoneAccountHandle> getOwnSelfManagedPhoneAccounts() {
+ ITelecomService service = getTelecomService();
+ if (service != null) {
+ try {
+ return service.getOwnSelfManagedPhoneAccounts(mContext.getOpPackageName(),
+ mContext.getAttributionTag());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ throw new IllegalStateException("Telecom is not available");
+ }
+
+ /**
* Returns a list of {@link PhoneAccountHandle}s including those which have not been enabled
* by the user.
*
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index b9936ce2e1b2..9999c897d1b6 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -66,6 +66,12 @@ interface ITelecomService {
String callingFeatureId);
/**
+ * @see TelecomServiceImpl#getOwnSelfManagedPhoneAccounts
+ */
+ List<PhoneAccountHandle> getOwnSelfManagedPhoneAccounts(String callingPackage,
+ String callingFeatureId);
+
+ /**
* @see TelecomManager#getPhoneAccountsSupportingScheme
*/
List<PhoneAccountHandle> getPhoneAccountsSupportingScheme(in String uriScheme,
diff --git a/tests/TrustTests/Android.bp b/tests/TrustTests/Android.bp
new file mode 100644
index 000000000000..c9c6c5cf193b
--- /dev/null
+++ b/tests/TrustTests/Android.bp
@@ -0,0 +1,39 @@
+// 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 {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test {
+ name: "TrustTests",
+ srcs: [
+ "src/**/*.kt",
+ ],
+ static_libs: [
+ "androidx.test.rules",
+ "androidx.test.ext.junit",
+ "androidx.test.uiautomator",
+ "truth-prebuilt",
+ ],
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ ],
+ test_suites: [
+ "device-tests",
+ ],
+ platform_apis: true,
+ certificate: "platform",
+}
diff --git a/tests/TrustTests/AndroidManifest.xml b/tests/TrustTests/AndroidManifest.xml
new file mode 100644
index 000000000000..c94152da2bf6
--- /dev/null
+++ b/tests/TrustTests/AndroidManifest.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.trust.test"
+ android:targetSandboxVersion="2">
+
+ <uses-permission android:name="android.permission.ACCESS_KEYGUARD_SECURE_STORAGE" />
+ <uses-permission android:name="android.permission.BIND_DEVICE_ADMIN" />
+ <uses-permission android:name="android.permission.CONTROL_KEYGUARD" />
+ <uses-permission android:name="android.permission.DEVICE_POWER" />
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
+ <uses-permission android:name="android.permission.PROVIDE_TRUST_AGENT" />
+ <uses-permission android:name="android.permission.TRUST_LISTENER" />
+
+ <application>
+ <uses-library android:name="android.test.runner"/>
+ <activity android:name="android.trust.TrustTestActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
+
+ <service
+ android:name=".UserUnlockRequestTrustAgent"
+ 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>
+
+ <service
+ android:name=".LockUserTrustAgent"
+ 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>
+
+ <service
+ android:name=".GrantAndRevokeTrustAgent"
+ 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. -->
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.trust.test">
+ </instrumentation>
+</manifest>
diff --git a/tests/TrustTests/AndroidTest.xml b/tests/TrustTests/AndroidTest.xml
new file mode 100644
index 000000000000..61b711eb7273
--- /dev/null
+++ b/tests/TrustTests/AndroidTest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+<configuration description="TrustTests configuration">
+ <option name="test-tag" value="TrustTests" />
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="TrustTests.apk" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="android.trust.test" />
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+ <option name="hidden-api-checks" value="false" />
+ </test>
+</configuration>
diff --git a/tests/TrustTests/README.md b/tests/TrustTests/README.md
new file mode 100644
index 000000000000..3427e30536d9
--- /dev/null
+++ b/tests/TrustTests/README.md
@@ -0,0 +1,40 @@
+# TrustTests framework tests
+
+These tests test the "trust" part of the platform primarily implemented via TrustManagerService in
+the system server and TrustAgentService in system apps.
+
+Tests are separated into separate files based on major groupings. When creating new tests, find a
+_closely_ matching existing test file or create a new test file. Prefer many test files over large
+test files.
+
+Each test file has its own trust agent. To create a new trust agent:
+
+1. Create a new class extending from `BaseTrustAgentService` class in your test file
+2. Add a new `<service>` stanza to `AndroidManifest.xml` in this directory for the new agent
+ following the pattern fo the existing agents.
+
+To run:
+
+```atest TrustTests```
+
+## Testing approach:
+
+1. Test the agent service as a black box; avoid inspecting internal state of the service or
+ modifying the system code outside of this directory.
+2. The primary interface to the system is through these three points:
+ 1. `TrustAgentService`, your agent created by the `TrustAgentRule` and accessible via
+ the `agent` property of the rule.
+ 1. Call command methods (e.g. `grantTrust`) directly on the agent
+ 2. Listen to events (e.g. `onUserRequestedUnlock`) by implementing the method in
+ your test's agent class and tracking invocations. See `UserUnlockRequestTest` for an
+ example.
+ 2. `TrustManager` which is the interface the rest of the system (e.g. SystemUI) has to the
+ service.
+ 1. Through this API, simulate system events that the service cares about
+ (e.g. `reportUnlockAttempt`).
+ 3. `TrustListener` which is the interface the rest of the system (e.g. SystemUI) uses to receive
+ events from the service.
+ 1. Through this, verify behavior that affects the rest of the system. For example,
+ see `LockStateTrackingRule`.
+3. To re-use code between tests, prefer creating new rules alongside the existing rules or adding
+ functionality to a _closely_ matching existing rule.
diff --git a/tests/TrustTests/src/android/trust/BaseTrustAgentService.kt b/tests/TrustTests/src/android/trust/BaseTrustAgentService.kt
new file mode 100644
index 000000000000..493f3bd22d2b
--- /dev/null
+++ b/tests/TrustTests/src/android/trust/BaseTrustAgentService.kt
@@ -0,0 +1,47 @@
+/*
+ * 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
+
+import android.service.trust.TrustAgentService
+import android.util.Log
+import kotlin.reflect.KClass
+
+/**
+ * Base class for test trust agents.
+ */
+abstract class BaseTrustAgentService : TrustAgentService() {
+
+ override fun onCreate() {
+ super.onCreate()
+ Log.d(TAG, "${this::class.simpleName} created")
+ instances[this::class] = this
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ instances.remove(this::class)
+ }
+
+ companion object {
+ private val instances =
+ mutableMapOf<KClass<out BaseTrustAgentService>, BaseTrustAgentService>()
+ private const val TAG = "BaseTrustAgentService"
+
+ fun instance(serviceClass: KClass<out BaseTrustAgentService>): BaseTrustAgentService? {
+ return instances[serviceClass]!!
+ }
+ }
+}
diff --git a/tests/TrustTests/src/android/trust/TrustTestActivity.kt b/tests/TrustTests/src/android/trust/TrustTestActivity.kt
new file mode 100644
index 000000000000..6c56feace3d7
--- /dev/null
+++ b/tests/TrustTests/src/android/trust/TrustTestActivity.kt
@@ -0,0 +1,30 @@
+/*
+ * 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
+
+import android.app.Activity
+import android.os.Bundle
+
+/**
+ * Activity for testing Trust.
+ */
+class TrustTestActivity : Activity() {
+
+ public override fun onCreate(icicle: Bundle?) {
+ super.onCreate(icicle)
+ setTurnScreenOn(true)
+ }
+}
diff --git a/tests/TrustTests/src/android/trust/test/GrantAndRevokeTrustTest.kt b/tests/TrustTests/src/android/trust/test/GrantAndRevokeTrustTest.kt
new file mode 100644
index 000000000000..790afd389152
--- /dev/null
+++ b/tests/TrustTests/src/android/trust/test/GrantAndRevokeTrustTest.kt
@@ -0,0 +1,95 @@
+/*
+ * 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.trust.BaseTrustAgentService
+import android.trust.TrustTestActivity
+import android.trust.test.lib.LockStateTrackingRule
+import android.trust.test.lib.ScreenLockRule
+import android.trust.test.lib.TrustAgentRule
+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 org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.RuleChain
+import org.junit.runner.RunWith
+
+/**
+ * Test for testing revokeTrust & grantTrust for non-renewable trust.
+ *
+ * atest TrustTests:GrantAndRevokeTrustTest
+ */
+@RunWith(AndroidJUnit4::class)
+class GrantAndRevokeTrustTest {
+ private val uiDevice = UiDevice.getInstance(getInstrumentation())
+ private val activityScenarioRule = ActivityScenarioRule(TrustTestActivity::class.java)
+ private val lockStateTrackingRule = LockStateTrackingRule()
+ private val trustAgentRule = TrustAgentRule<GrantAndRevokeTrustAgent>()
+
+ @get:Rule
+ val rule: RuleChain = RuleChain
+ .outerRule(activityScenarioRule)
+ .around(ScreenLockRule())
+ .around(lockStateTrackingRule)
+ .around(trustAgentRule)
+
+ @Before
+ fun manageTrust() {
+ trustAgentRule.agent.setManagingTrust(true)
+ }
+
+ // This test serves a baseline for Grant tests, verifying that the default behavior of the
+ // device is to lock when put to sleep
+ @Test
+ fun sleepingDeviceWithoutGrantLocksDevice() {
+ uiDevice.sleep()
+ await()
+
+ lockStateTrackingRule.assertLocked()
+ }
+
+ @Test
+ fun grantKeepsDeviceUnlocked() {
+ trustAgentRule.agent.grantTrust(GRANT_MESSAGE, 10000, 0)
+ uiDevice.sleep()
+ await()
+
+ lockStateTrackingRule.assertUnlocked()
+ }
+
+ @Test
+ fun grantKeepsDeviceUnlocked_untilRevoked() {
+ trustAgentRule.agent.grantTrust(GRANT_MESSAGE, 0, 0)
+ await()
+ uiDevice.sleep()
+ trustAgentRule.agent.revokeTrust()
+ await()
+
+ lockStateTrackingRule.assertLocked()
+ }
+
+ companion object {
+ private const val TAG = "GrantAndRevokeTrustTest"
+ private const val GRANT_MESSAGE = "granted by test"
+ private fun await() = Thread.sleep(250)
+ }
+}
+
+class GrantAndRevokeTrustAgent : BaseTrustAgentService()
diff --git a/tests/TrustTests/src/android/trust/test/LockUserTest.kt b/tests/TrustTests/src/android/trust/test/LockUserTest.kt
new file mode 100644
index 000000000000..83fc28fee818
--- /dev/null
+++ b/tests/TrustTests/src/android/trust/test/LockUserTest.kt
@@ -0,0 +1,68 @@
+/*
+ * 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.trust.BaseTrustAgentService
+import android.trust.TrustTestActivity
+import android.trust.test.lib.LockStateTrackingRule
+import android.trust.test.lib.ScreenLockRule
+import android.trust.test.lib.TrustAgentRule
+import android.util.Log
+import androidx.test.ext.junit.rules.ActivityScenarioRule
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.google.common.truth.Truth.assertThat
+import org.junit.Ignore
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.RuleChain
+import org.junit.runner.RunWith
+
+/**
+ * Test for testing lockUser.
+ *
+ * atest TrustTests:LockUserTest
+ */
+@RunWith(AndroidJUnit4::class)
+class LockUserTest {
+ private val activityScenarioRule = ActivityScenarioRule(TrustTestActivity::class.java)
+ private val lockStateTrackingRule = LockStateTrackingRule()
+ private val trustAgentRule = TrustAgentRule<LockUserTrustAgent>()
+
+ @get:Rule
+ val rule: RuleChain = RuleChain
+ .outerRule(activityScenarioRule)
+ .around(ScreenLockRule())
+ .around(lockStateTrackingRule)
+ .around(trustAgentRule)
+
+ @Ignore("Causes issues with subsequent tests") // TODO: Enable test
+ @Test
+ fun lockUser_locksTheDevice() {
+ Log.i(TAG, "Locking user")
+ trustAgentRule.agent.lockUser()
+ await()
+
+ assertThat(lockStateTrackingRule.lockState.locked).isTrue()
+ }
+
+ companion object {
+ private const val TAG = "LockUserTest"
+ private fun await() = Thread.sleep(250)
+ }
+}
+
+class LockUserTrustAgent : BaseTrustAgentService()
diff --git a/tests/TrustTests/src/android/trust/test/UserUnlockRequestTest.kt b/tests/TrustTests/src/android/trust/test/UserUnlockRequestTest.kt
new file mode 100644
index 000000000000..f8783fbaf121
--- /dev/null
+++ b/tests/TrustTests/src/android/trust/test/UserUnlockRequestTest.kt
@@ -0,0 +1,81 @@
+/*
+ * 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.trust.BaseTrustAgentService
+import android.trust.TrustTestActivity
+import android.trust.test.lib.ScreenLockRule
+import android.trust.test.lib.TrustAgentRule
+import android.util.Log
+import androidx.test.core.app.ApplicationProvider.getApplicationContext
+import androidx.test.ext.junit.rules.ActivityScenarioRule
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.RuleChain
+import org.junit.runner.RunWith
+
+/**
+ * Test for testing the user unlock trigger.
+ *
+ * atest TrustTests:UserUnlockRequestTest
+ */
+@RunWith(AndroidJUnit4::class)
+class UserUnlockRequestTest {
+ private val context: Context = getApplicationContext()
+ private val trustManager = context.getSystemService(TrustManager::class.java) as TrustManager
+ private val userId = context.userId
+ private val activityScenarioRule = ActivityScenarioRule(TrustTestActivity::class.java)
+ private val trustAgentRule = TrustAgentRule<UserUnlockRequestTrustAgent>()
+
+ @get:Rule
+ val rule: RuleChain = RuleChain
+ .outerRule(activityScenarioRule)
+ .around(ScreenLockRule())
+ .around(trustAgentRule)
+
+ @Test
+ fun reportUserRequestedUnlock_propagatesToAgent() {
+ val oldCount = trustAgentRule.agent.onUserRequestedUnlockCallCount
+ trustManager.reportUserRequestedUnlock(userId)
+ await()
+
+ assertThat(trustAgentRule.agent.onUserRequestedUnlockCallCount)
+ .isEqualTo(oldCount + 1)
+ }
+
+ companion object {
+ private const val TAG = "UserUnlockRequestTest"
+ private fun await() = Thread.sleep(250)
+ }
+}
+
+class UserUnlockRequestTrustAgent : BaseTrustAgentService() {
+ var onUserRequestedUnlockCallCount: Long = 0
+ private set
+
+ override fun onUserRequestedUnlock() {
+ Log.i(TAG, "onUserRequestedUnlock")
+ onUserRequestedUnlockCallCount++
+ }
+
+ companion object {
+ private const val TAG = "UserUnlockRequestTrustAgent"
+ }
+}
diff --git a/tests/TrustTests/src/android/trust/test/lib/LockStateTrackingRule.kt b/tests/TrustTests/src/android/trust/test/lib/LockStateTrackingRule.kt
new file mode 100644
index 000000000000..0023af8893e2
--- /dev/null
+++ b/tests/TrustTests/src/android/trust/test/lib/LockStateTrackingRule.kt
@@ -0,0 +1,83 @@
+/*
+ * 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.lib
+
+import android.app.trust.TrustManager
+import android.app.trust.TrustManager.TrustListener
+import android.content.Context
+import android.util.Log
+import android.view.WindowManagerGlobal
+import androidx.test.core.app.ApplicationProvider.getApplicationContext
+import com.google.common.truth.Truth.assertThat
+import org.junit.rules.TestRule
+import org.junit.runner.Description
+import org.junit.runners.model.Statement
+
+/**
+ * Rule for tracking the lock state of the device based on events emitted to [TrustListener].
+ */
+class LockStateTrackingRule : TestRule {
+ private val context: Context = getApplicationContext()
+ private val windowManager = WindowManagerGlobal.getWindowManagerService()
+
+ @Volatile lateinit var lockState: LockState
+ private set
+
+ override fun apply(base: Statement, description: Description) = object : Statement() {
+ override fun evaluate() {
+ lockState = LockState(locked = windowManager.isKeyguardLocked)
+ val trustManager = context.getSystemService(TrustManager::class.java) as TrustManager
+ val listener = Listener()
+
+ trustManager.registerTrustListener(listener)
+ try {
+ base.evaluate()
+ } finally {
+ trustManager.unregisterTrustListener(listener)
+ }
+ }
+ }
+
+ fun assertLocked() = assertThat(lockState.locked).isTrue()
+ fun assertUnlocked() = assertThat(lockState.locked).isFalse()
+
+ inner class Listener : TrustListener {
+ override fun onTrustChanged(
+ enabled: Boolean,
+ userId: Int,
+ flags: Int,
+ trustGrantedMessages: MutableList<String>
+ ) {
+ Log.d(TAG, "Device became trusted=$enabled")
+ lockState = lockState.copy(locked = !enabled)
+ }
+
+ override fun onTrustManagedChanged(enabled: Boolean, userId: Int) {
+ }
+
+ override fun onTrustError(message: CharSequence) {
+ }
+ }
+
+ data class LockState(
+ val locked: Boolean? = null
+ )
+
+ companion object {
+ private const val TAG = "LockStateTrackingRule"
+ }
+}
diff --git a/tests/TrustTests/src/android/trust/test/lib/ScreenLockRule.kt b/tests/TrustTests/src/android/trust/test/lib/ScreenLockRule.kt
new file mode 100644
index 000000000000..c682a00eb8b9
--- /dev/null
+++ b/tests/TrustTests/src/android/trust/test/lib/ScreenLockRule.kt
@@ -0,0 +1,105 @@
+/*
+ * 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.lib
+
+import android.content.Context
+import android.util.Log
+import android.view.WindowManagerGlobal
+import androidx.test.core.app.ApplicationProvider.getApplicationContext
+import com.android.internal.widget.LockPatternUtils
+import com.android.internal.widget.LockscreenCredential
+import com.google.common.truth.Truth.assertWithMessage
+import org.junit.rules.TestRule
+import org.junit.runner.Description
+import org.junit.runners.model.Statement
+
+/**
+ * Sets a screen lock on the device for the duration of the test.
+ */
+class ScreenLockRule : TestRule {
+ private val context: Context = getApplicationContext()
+ private val windowManager = WindowManagerGlobal.getWindowManagerService()
+ private val lockPatternUtils = LockPatternUtils(context)
+ private var instantLockSavedValue = false
+
+ override fun apply(base: Statement, description: Description) = object : Statement() {
+ override fun evaluate() {
+ verifyNoScreenLockAlreadySet()
+ verifyKeyguardDismissed()
+ setScreenLock()
+ setLockOnPowerButton()
+
+ try {
+ base.evaluate()
+ } finally {
+ removeScreenLock()
+ revertLockOnPowerButton()
+ }
+ }
+ }
+
+ private fun verifyNoScreenLockAlreadySet() {
+ assertWithMessage("Screen Lock must not already be set on device")
+ .that(lockPatternUtils.isSecure(context.userId))
+ .isFalse()
+ }
+
+ private fun verifyKeyguardDismissed() {
+ windowManager.dismissKeyguard(null, null)
+ Thread.sleep(250)
+ assertWithMessage("Keyguard should be unlocked")
+ .that(windowManager.isKeyguardLocked)
+ .isFalse()
+ }
+
+ private fun setScreenLock() {
+ lockPatternUtils.setLockCredential(
+ LockscreenCredential.createPin(PIN),
+ LockscreenCredential.createNone(),
+ context.userId
+ )
+ assertWithMessage("Screen Lock should now be set")
+ .that(lockPatternUtils.isSecure(context.userId))
+ .isTrue()
+ Log.i(TAG, "Device PIN set to $PIN")
+ }
+
+ private fun setLockOnPowerButton() {
+ instantLockSavedValue = lockPatternUtils.getPowerButtonInstantlyLocks(context.userId)
+ lockPatternUtils.setPowerButtonInstantlyLocks(true, context.userId)
+ }
+
+ private fun removeScreenLock() {
+ lockPatternUtils.setLockCredential(
+ LockscreenCredential.createNone(),
+ LockscreenCredential.createPin(PIN),
+ context.userId
+ )
+ Log.i(TAG, "Device PIN cleared; waiting 50 ms then dismissing Keyguard")
+ Thread.sleep(50)
+ windowManager.dismissKeyguard(null, null)
+ }
+
+ private fun revertLockOnPowerButton() {
+ lockPatternUtils.setPowerButtonInstantlyLocks(instantLockSavedValue, context.userId)
+ }
+
+ companion object {
+ private const val TAG = "ScreenLockRule"
+ private const val PIN = "0000"
+ }
+}
diff --git a/tests/TrustTests/src/android/trust/test/lib/TrustAgentRule.kt b/tests/TrustTests/src/android/trust/test/lib/TrustAgentRule.kt
new file mode 100644
index 000000000000..2a9e00276475
--- /dev/null
+++ b/tests/TrustTests/src/android/trust/test/lib/TrustAgentRule.kt
@@ -0,0 +1,117 @@
+/*
+ * 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.lib
+
+import android.app.trust.TrustManager
+import android.content.ComponentName
+import android.content.Context
+import android.trust.BaseTrustAgentService
+import android.util.Log
+import androidx.test.core.app.ApplicationProvider.getApplicationContext
+import com.android.internal.widget.LockPatternUtils
+import com.google.common.truth.Truth.assertWithMessage
+import org.junit.rules.TestRule
+import org.junit.runner.Description
+import org.junit.runners.model.Statement
+import kotlin.reflect.KClass
+
+/**
+ * Enables a trust agent and causes the system service to bind to it.
+ *
+ * The enabled agent can be accessed during the test via the [agent] property.
+ *
+ * @constructor Creates the rule. Do not use; instead, use [invoke].
+ */
+class TrustAgentRule<T : BaseTrustAgentService>(
+ private val serviceClass: KClass<T>
+) : TestRule {
+ private val context: Context = getApplicationContext()
+ private val trustManager = context.getSystemService(TrustManager::class.java) as TrustManager
+ private val lockPatternUtils = LockPatternUtils(context)
+
+ val agent get() = BaseTrustAgentService.instance(serviceClass) as T
+
+ override fun apply(base: Statement, description: Description) = object : Statement() {
+ override fun evaluate() {
+ verifyTrustServiceRunning()
+ unlockDeviceWithCredential()
+ enableTrustAgent()
+ waitForEnablement()
+
+ try {
+ verifyAgentIsRunning()
+ base.evaluate()
+ } finally {
+ disableTrustAgent()
+ }
+ }
+ }
+
+ private fun verifyTrustServiceRunning() {
+ assertWithMessage("Trust service is not running").that(trustManager).isNotNull()
+ }
+
+ private fun unlockDeviceWithCredential() {
+ Log.d(TAG, "Unlocking device with credential")
+ trustManager.reportUnlockAttempt(true, context.userId)
+ }
+
+ private fun enableTrustAgent() {
+ val componentName = ComponentName(context, serviceClass.java)
+ val userId = context.userId
+ Log.i(TAG, "Enabling trust agent ${componentName.flattenToString()} for user $userId")
+ val agents = mutableListOf(componentName)
+ .plus(lockPatternUtils.getEnabledTrustAgents(userId))
+ .distinct()
+ lockPatternUtils.setEnabledTrustAgents(agents, userId)
+ }
+
+ private fun waitForEnablement() {
+ Log.d(TAG, "Waiting for $WAIT_TIME ms")
+ Thread.sleep(WAIT_TIME)
+ Log.d(TAG, "Done waiting")
+ }
+
+ private fun verifyAgentIsRunning() {
+ assertWithMessage("${serviceClass.simpleName} should be running")
+ .that(BaseTrustAgentService.instance(serviceClass)).isNotNull()
+ }
+
+ private fun disableTrustAgent() {
+ val componentName = ComponentName(context, serviceClass.java)
+ val userId = context.userId
+ Log.i(TAG, "Disabling trust agent ${componentName.flattenToString()} for user $userId")
+ val agents = lockPatternUtils.getEnabledTrustAgents(userId).toMutableList()
+ .distinct()
+ .minus(componentName)
+ lockPatternUtils.setEnabledTrustAgents(agents, userId)
+ }
+
+ companion object {
+ /**
+ * Creates a new rule for the specified agent class. Example usage:
+ * ```
+ * @get:Rule val rule = TrustAgentRule<MyTestAgent>()
+ * ```
+ */
+ inline operator fun <reified T : BaseTrustAgentService> invoke() =
+ TrustAgentRule(T::class)
+
+ private const val TAG = "TrustAgentRule"
+ private val WAIT_TIME = 1000L
+ }
+}