From 7dcbfb02c9bd1e6ba05168637c8c5b66f95696db Mon Sep 17 00:00:00 2001 From: Benjamin Franz Date: Tue, 16 Jan 2018 15:16:16 +0000 Subject: [PATCH 001/179] Block root task from being shown in recents Do not show the root task of lock task mode in recents and thereby block it from being swiped away. Bug: 70332786 Test: manual Change-Id: I529c2896faae6b6d94ba3b758d15f40d83fb8573 --- .../java/com/android/server/am/LockTaskController.java | 10 ++++++++++ .../core/java/com/android/server/am/RecentTasks.java | 5 +++++ 2 files changed, 15 insertions(+) diff --git a/services/core/java/com/android/server/am/LockTaskController.java b/services/core/java/com/android/server/am/LockTaskController.java index ed39329844ef..7eb0bf4bb0a8 100644 --- a/services/core/java/com/android/server/am/LockTaskController.java +++ b/services/core/java/com/android/server/am/LockTaskController.java @@ -284,6 +284,16 @@ public class LockTaskController { return false; } + /** + * @return the root task of the lock task. + */ + TaskRecord getRootTask() { + if (mLockTaskModeTasks.isEmpty()) { + return null; + } + return mLockTaskModeTasks.get(0); + } + private boolean isLockTaskModeViolationInternal(TaskRecord task, boolean isNewClearTask) { // TODO: Double check what's going on here. If the task is already in lock task mode, it's // likely whitelisted, so will return false below. diff --git a/services/core/java/com/android/server/am/RecentTasks.java b/services/core/java/com/android/server/am/RecentTasks.java index fc8b624f6b7e..345246856d28 100644 --- a/services/core/java/com/android/server/am/RecentTasks.java +++ b/services/core/java/com/android/server/am/RecentTasks.java @@ -1150,6 +1150,11 @@ class RecentTasks { } } + // If we're in lock task mode, ignore the root task + if (task == mService.mLockTaskController.getRootTask()) { + return false; + } + return true; } -- GitLab From d184ba54350506d7460905f601714ee56242c01a Mon Sep 17 00:00:00 2001 From: Jong Wook Kim Date: Fri, 9 Mar 2018 14:12:55 -0800 Subject: [PATCH 002/179] "02:00:00:00:00:00" invalid for MAC randomization Since we are using "02:00:00:00:00:00" as the default/invalid MAC address in the Wifi Framework, we should make it invalid for Connected MAC Randomization for consistency. Updated the configuration to use "02:00:00:00:00:00" as the default invalid MAC and attempt multiple time to generate valid random MAC. Bug: 74436465 Bug: 74446723 Test: Unittest Change-Id: Ia5ac806d478191d7e8fad247d5c3a1b97d16498f --- .../android/net/wifi/WifiConfiguration.java | 39 +++++++++++++------ .../net/wifi/WifiConfigurationTest.java | 32 +++++++++++---- 2 files changed, 52 insertions(+), 19 deletions(-) diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java index 21ae3a923946..b77b1ad5f255 100644 --- a/wifi/java/android/net/wifi/WifiConfiguration.java +++ b/wifi/java/android/net/wifi/WifiConfiguration.java @@ -25,11 +25,13 @@ import android.net.MacAddress; import android.net.ProxyInfo; import android.net.StaticIpConfiguration; import android.net.Uri; +import android.net.wifi.WifiInfo; import android.os.Parcel; import android.os.Parcelable; import android.os.UserHandle; import android.text.TextUtils; import android.util.BackupUtils; +import android.util.Log; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; @@ -76,6 +78,8 @@ public class WifiConfiguration implements Parcelable { /** {@hide} */ private String mPasspointManagementObjectTree; + /** {@hide} */ + private static final int MAXIMUM_RANDOM_MAC_GENERATION_RETRY = 3; /** * Recognized key management schemes. @@ -798,27 +802,37 @@ public class WifiConfiguration implements Parcelable { * @hide * Randomized MAC address to use with this particular network */ + @NonNull private MacAddress mRandomizedMacAddress; /** * @hide * Checks if the given MAC address can be used for Connected Mac Randomization - * by verifying that it is non-null, unicast, and locally assigned. + * by verifying that it is non-null, unicast, locally assigned, and not default mac. * @param mac MacAddress to check * @return true if mac is good to use */ - private boolean isValidMacAddressForRandomization(MacAddress mac) { - return mac != null && !mac.isMulticastAddress() && mac.isLocallyAssigned(); + public static boolean isValidMacAddressForRandomization(MacAddress mac) { + return mac != null && !mac.isMulticastAddress() && mac.isLocallyAssigned() + && !MacAddress.fromString(WifiInfo.DEFAULT_MAC_ADDRESS).equals(mac); } /** * @hide * Returns Randomized MAC address to use with the network. - * If it is not set/valid, create a new randomized address. + * If it is not set/valid, creates a new randomized address. + * If it can't generate a valid mac, returns the default MAC. */ - public MacAddress getOrCreateRandomizedMacAddress() { - if (!isValidMacAddressForRandomization(mRandomizedMacAddress)) { + public @NonNull MacAddress getOrCreateRandomizedMacAddress() { + int randomMacGenerationCount = 0; + while (!isValidMacAddressForRandomization(mRandomizedMacAddress) + && randomMacGenerationCount < MAXIMUM_RANDOM_MAC_GENERATION_RETRY) { mRandomizedMacAddress = MacAddress.createRandomUnicastAddress(); + randomMacGenerationCount++; + } + + if (!isValidMacAddressForRandomization(mRandomizedMacAddress)) { + mRandomizedMacAddress = MacAddress.fromString(WifiInfo.DEFAULT_MAC_ADDRESS); } return mRandomizedMacAddress; } @@ -828,10 +842,7 @@ public class WifiConfiguration implements Parcelable { * Returns MAC address set to be the local randomized MAC address. * Does not guarantee that the returned address is valid for use. */ - public MacAddress getRandomizedMacAddress() { - if (mRandomizedMacAddress == null) { - mRandomizedMacAddress = MacAddress.ALL_ZEROS_ADDRESS; - } + public @NonNull MacAddress getRandomizedMacAddress() { return mRandomizedMacAddress; } @@ -839,7 +850,11 @@ public class WifiConfiguration implements Parcelable { * @hide * @param mac MacAddress to change into */ - public void setRandomizedMacAddress(MacAddress mac) { + public void setRandomizedMacAddress(@NonNull MacAddress mac) { + if (mac == null) { + Log.e(TAG, "setRandomizedMacAddress received null MacAddress."); + return; + } mRandomizedMacAddress = mac; } @@ -1532,7 +1547,7 @@ public class WifiConfiguration implements Parcelable { creatorUid = -1; shared = true; dtimInterval = 0; - mRandomizedMacAddress = MacAddress.ALL_ZEROS_ADDRESS; + mRandomizedMacAddress = MacAddress.fromString(WifiInfo.DEFAULT_MAC_ADDRESS); } /** diff --git a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java index 8a3a7f5a2d79..35179847541c 100644 --- a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java +++ b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java @@ -18,12 +18,14 @@ package android.net.wifi; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertFalse; import android.os.Parcel; import android.net.MacAddress; import android.net.wifi.WifiConfiguration.NetworkSelectionStatus; +import android.net.wifi.WifiInfo; import org.junit.Before; import org.junit.Test; @@ -176,22 +178,25 @@ public class WifiConfigurationTest { @Test public void testGetOrCreateRandomizedMacAddress_SavesAndReturnsSameAddress() { WifiConfiguration config = new WifiConfiguration(); - assertEquals(MacAddress.ALL_ZEROS_ADDRESS, config.getRandomizedMacAddress()); + MacAddress defaultMac = MacAddress.fromString(WifiInfo.DEFAULT_MAC_ADDRESS); + assertEquals(defaultMac, config.getRandomizedMacAddress()); MacAddress firstMacAddress = config.getOrCreateRandomizedMacAddress(); MacAddress secondMacAddress = config.getOrCreateRandomizedMacAddress(); + assertNotEquals(defaultMac, firstMacAddress); assertEquals(firstMacAddress, secondMacAddress); } @Test public void testSetRandomizedMacAddress_ChangesSavedAddress() { WifiConfiguration config = new WifiConfiguration(); - assertEquals(MacAddress.ALL_ZEROS_ADDRESS, config.getRandomizedMacAddress()); + MacAddress defaultMac = MacAddress.fromString(WifiInfo.DEFAULT_MAC_ADDRESS); + assertEquals(defaultMac, config.getRandomizedMacAddress()); MacAddress macToChangeInto = MacAddress.createRandomUnicastAddress(); config.setRandomizedMacAddress(macToChangeInto); - MacAddress macAfterChange = config.getOrCreateRandomizedMacAddress(); + MacAddress macAfterChange = config.getRandomizedMacAddress(); assertEquals(macToChangeInto, macAfterChange); } @@ -200,24 +205,37 @@ public class WifiConfigurationTest { public void testGetOrCreateRandomizedMacAddress_ReRandomizesInvalidAddress() { WifiConfiguration config = new WifiConfiguration(); + MacAddress defaultMac = MacAddress.fromString(WifiInfo.DEFAULT_MAC_ADDRESS); MacAddress macAddressZeroes = MacAddress.ALL_ZEROS_ADDRESS; MacAddress macAddressMulticast = MacAddress.fromString("03:ff:ff:ff:ff:ff"); MacAddress macAddressGlobal = MacAddress.fromString("fc:ff:ff:ff:ff:ff"); config.setRandomizedMacAddress(null); MacAddress macAfterChange = config.getOrCreateRandomizedMacAddress(); - assertFalse(macAfterChange.equals(null)); + assertNotEquals(macAfterChange, null); + + config.setRandomizedMacAddress(defaultMac); + macAfterChange = config.getOrCreateRandomizedMacAddress(); + assertNotEquals(macAfterChange, defaultMac); config.setRandomizedMacAddress(macAddressZeroes); macAfterChange = config.getOrCreateRandomizedMacAddress(); - assertFalse(macAfterChange.equals(macAddressZeroes)); + assertNotEquals(macAfterChange, macAddressZeroes); config.setRandomizedMacAddress(macAddressMulticast); macAfterChange = config.getOrCreateRandomizedMacAddress(); - assertFalse(macAfterChange.equals(macAddressMulticast)); + assertNotEquals(macAfterChange, macAddressMulticast); config.setRandomizedMacAddress(macAddressGlobal); macAfterChange = config.getOrCreateRandomizedMacAddress(); - assertFalse(macAfterChange.equals(macAddressGlobal)); + assertNotEquals(macAfterChange, macAddressGlobal); + } + + @Test + public void testSetRandomizedMacAddress_DoesNothingWhenNull() { + WifiConfiguration config = new WifiConfiguration(); + MacAddress defaultMac = MacAddress.fromString(WifiInfo.DEFAULT_MAC_ADDRESS); + config.setRandomizedMacAddress(null); + assertEquals(defaultMac, config.getRandomizedMacAddress()); } } -- GitLab From cccad1971e4f04db7c8db8b0a9d6afd95937fc5e Mon Sep 17 00:00:00 2001 From: Victor Hsieh Date: Mon, 19 Mar 2018 15:57:02 -0700 Subject: [PATCH 003/179] Fix fs-verity per fs-verity spec change - Reorder and adjust fields per fs-verity format change. - Since header + tree is no longer full page size, pass the length with shared memory (which is full pages). - Fix offset and padding of patch extension. - It is now required to issue the measure ioctl (via assertFsverityRootHashMatches) right after fs-verity is enabled. Test: adb install a new priv app, saw fs-verity log in dmesg. Read the whole file successfully. Bug: 30972906 Change-Id: I480ae2b5debaf76ef24dadf2d79d1903c7967f03 --- .../android/util/apk/ApkVerityBuilder.java | 60 +++++++++++-------- .../java/com/android/server/pm/Installer.java | 4 +- .../server/pm/PackageManagerService.java | 7 ++- .../android/server/security/VerityUtils.java | 47 +++++++++++---- 4 files changed, 78 insertions(+), 40 deletions(-) diff --git a/core/java/android/util/apk/ApkVerityBuilder.java b/core/java/android/util/apk/ApkVerityBuilder.java index 3b8fc5c53d2a..f15e1a1a7c52 100644 --- a/core/java/android/util/apk/ApkVerityBuilder.java +++ b/core/java/android/util/apk/ApkVerityBuilder.java @@ -72,22 +72,31 @@ abstract class ApkVerityBuilder { signatureInfo.centralDirOffset - signatureInfo.apkSigningBlockOffset; long dataSize = apk.length() - signingBlockSize; int[] levelOffset = calculateVerityLevelOffset(dataSize); + int merkleTreeSize = levelOffset[levelOffset.length - 1]; ByteBuffer output = bufferFactory.create( - CHUNK_SIZE_BYTES + // fsverity header + extensions + padding - levelOffset[levelOffset.length - 1]); // Merkle tree size + merkleTreeSize + + CHUNK_SIZE_BYTES); // maximum size of fsverity metadata output.order(ByteOrder.LITTLE_ENDIAN); - ByteBuffer header = slice(output, 0, FSVERITY_HEADER_SIZE_BYTES); - ByteBuffer extensions = slice(output, FSVERITY_HEADER_SIZE_BYTES, CHUNK_SIZE_BYTES); - ByteBuffer tree = slice(output, CHUNK_SIZE_BYTES, output.limit()); + ByteBuffer tree = slice(output, 0, merkleTreeSize); + ByteBuffer header = slice(output, merkleTreeSize, + merkleTreeSize + FSVERITY_HEADER_SIZE_BYTES); + ByteBuffer extensions = slice(output, merkleTreeSize + FSVERITY_HEADER_SIZE_BYTES, + merkleTreeSize + CHUNK_SIZE_BYTES); byte[] apkDigestBytes = new byte[DIGEST_SIZE_BYTES]; ByteBuffer apkDigest = ByteBuffer.wrap(apkDigestBytes); apkDigest.order(ByteOrder.LITTLE_ENDIAN); + // NB: Buffer limit is set inside once finished. calculateFsveritySignatureInternal(apk, signatureInfo, tree, apkDigest, header, extensions); - output.rewind(); + // Put the reverse offset to fs-verity header at the end. + output.position(merkleTreeSize + FSVERITY_HEADER_SIZE_BYTES + extensions.limit()); + output.putInt(FSVERITY_HEADER_SIZE_BYTES + extensions.limit() + + 4); // size of this integer right before EOF + output.flip(); + return new ApkVerityResult(output, apkDigestBytes); } @@ -101,7 +110,8 @@ abstract class ApkVerityBuilder { ByteBuffer verityBlock = ByteBuffer.allocate(CHUNK_SIZE_BYTES) .order(ByteOrder.LITTLE_ENDIAN); ByteBuffer header = slice(verityBlock, 0, FSVERITY_HEADER_SIZE_BYTES); - ByteBuffer extensions = slice(verityBlock, FSVERITY_HEADER_SIZE_BYTES, CHUNK_SIZE_BYTES); + ByteBuffer extensions = slice(verityBlock, FSVERITY_HEADER_SIZE_BYTES, + CHUNK_SIZE_BYTES - FSVERITY_HEADER_SIZE_BYTES); calculateFsveritySignatureInternal(apk, signatureInfo, null, null, header, extensions); @@ -328,10 +338,10 @@ abstract class ApkVerityBuilder { buffer.put((byte) 12); // log2(block-size): log2(4096) buffer.put((byte) 7); // log2(leaves-per-node): log2(4096 / 32) - buffer.putShort((short) 1); // meta algorithm, SHA256_MODE == 1 - buffer.putShort((short) 1); // data algorithm, SHA256_MODE == 1 + buffer.putShort((short) 1); // meta algorithm, SHA256 == 1 + buffer.putShort((short) 1); // data algorithm, SHA256 == 1 - buffer.putInt(0x0); // flags + buffer.putInt(0); // flags buffer.putInt(0); // reserved buffer.putLong(fileSize); // original file size @@ -362,12 +372,11 @@ abstract class ApkVerityBuilder { // // struct fsverity_extension_patch { // __le64 offset; - // u8 length; - // u8 reserved[7]; // u8 databytes[]; // }; final int kSizeOfFsverityExtensionHeader = 8; + final int kExtensionSizeAlignment = 8; { // struct fsverity_extension #1 @@ -385,24 +394,25 @@ abstract class ApkVerityBuilder { { // struct fsverity_extension #2 - final int kSizeOfFsverityPatchExtension = - 8 + // offset size - 1 + // size of length from offset (up to 255) - 7 + // reserved - ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_SIZE; - final int kPadding = (int) divideRoundup(kSizeOfFsverityPatchExtension % 8, 8); + final int kTotalSize = kSizeOfFsverityExtensionHeader + + 8 // offset size + + ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_SIZE; - buffer.putShort((short) // total size of extension, padded to 64-bit alignment - (kSizeOfFsverityExtensionHeader + kSizeOfFsverityPatchExtension + kPadding)); + buffer.putShort((short) kTotalSize); buffer.put((byte) 1); // ID of patch extension skip(buffer, 5); // reserved // struct fsverity_extension_patch - buffer.putLong(eocdOffset); // offset - buffer.put((byte) ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_SIZE); // length - skip(buffer, 7); // reserved - buffer.putInt(Math.toIntExact(signingBlockOffset)); // databytes - skip(buffer, kPadding); // padding + buffer.putLong(eocdOffset + ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_OFFSET); // offset + buffer.putInt(Math.toIntExact(signingBlockOffset)); // databytes + + // The extension needs to be 0-padded at the end, since the length may not be multiple + // of 8. + int kPadding = kExtensionSizeAlignment - kTotalSize % kExtensionSizeAlignment; + if (kPadding == kExtensionSizeAlignment) { + kPadding = 0; + } + skip(buffer, kPadding); // padding } buffer.flip(); diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java index 24abf8657b88..9d3f48b428ce 100644 --- a/services/core/java/com/android/server/pm/Installer.java +++ b/services/core/java/com/android/server/pm/Installer.java @@ -484,11 +484,11 @@ public class Installer extends SystemService { } } - public void installApkVerity(String filePath, FileDescriptor verityInput) + public void installApkVerity(String filePath, FileDescriptor verityInput, int contentSize) throws InstallerException { if (!checkBeforeRemote()) return; try { - mInstalld.installApkVerity(filePath, verityInput); + mInstalld.installApkVerity(filePath, verityInput, contentSize); } catch (Exception e) { throw InstallerException.from(e); } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 26e9a9a287af..e04ccbdda90c 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -17212,8 +17212,11 @@ public class PackageManagerService extends IPackageManager.Stub if (Build.IS_DEBUGGABLE) Slog.i(TAG, "Enabling apk verity to " + apkPath); FileDescriptor fd = result.getUnownedFileDescriptor(); try { - mInstaller.installApkVerity(apkPath, fd); - } catch (InstallerException e) { + final byte[] signedRootHash = VerityUtils.generateFsverityRootHash(apkPath); + mInstaller.installApkVerity(apkPath, fd, result.getContentSize()); + mInstaller.assertFsverityRootHashMatches(apkPath, signedRootHash); + } catch (InstallerException | IOException | DigestException | + NoSuchAlgorithmException e) { res.setError(INSTALL_FAILED_INTERNAL_ERROR, "Failed to set up verity: " + e); return; diff --git a/services/core/java/com/android/server/security/VerityUtils.java b/services/core/java/com/android/server/security/VerityUtils.java index d2d0e60dc742..180f34355c94 100644 --- a/services/core/java/com/android/server/security/VerityUtils.java +++ b/services/core/java/com/android/server/security/VerityUtils.java @@ -26,6 +26,7 @@ import android.system.Os; import android.util.apk.ApkSignatureVerifier; import android.util.apk.ByteBufferFactory; import android.util.apk.SignatureNotFoundException; +import android.util.Pair; import android.util.Slog; import java.io.FileDescriptor; @@ -59,12 +60,15 @@ abstract public class VerityUtils { return SetupResult.skipped(); } - shm = generateApkVerityIntoSharedMemory(apkPath, signedRootHash); + Pair result = generateApkVerityIntoSharedMemory(apkPath, + signedRootHash); + shm = result.first; + int contentSize = result.second; FileDescriptor rfd = shm.getFileDescriptor(); if (rfd == null || !rfd.valid()) { return SetupResult.failed(); } - return SetupResult.ok(Os.dup(rfd)); + return SetupResult.ok(Os.dup(rfd), contentSize); } catch (IOException | SecurityException | DigestException | NoSuchAlgorithmException | SignatureNotFoundException | ErrnoException e) { Slog.e(TAG, "Failed to set up apk verity: ", e); @@ -85,10 +89,20 @@ abstract public class VerityUtils { } /** - * Returns a {@code SharedMemory} that contains Merkle tree and fsverity headers for the given - * apk, in the form that can immediately be used for fsverity setup. + * {@see ApkSignatureVerifier#getVerityRootHash(String)}. */ - private static SharedMemory generateApkVerityIntoSharedMemory( + public static byte[] getVerityRootHash(@NonNull String apkPath) + throws IOException, SignatureNotFoundException, SecurityException { + return ApkSignatureVerifier.getVerityRootHash(apkPath); + } + + /** + * Returns a pair of {@code SharedMemory} and {@code Integer}. The {@code SharedMemory} contains + * Merkle tree and fsverity headers for the given apk, in the form that can immediately be used + * for fsverity setup. The data is aligned to the beginning of {@code SharedMemory}, and has + * length equals to the returned {@code Integer}. + */ + private static Pair generateApkVerityIntoSharedMemory( String apkPath, byte[] expectedRootHash) throws IOException, SecurityException, DigestException, NoSuchAlgorithmException, SignatureNotFoundException { @@ -101,6 +115,7 @@ abstract public class VerityUtils { throw new SecurityException("Locally generated verity root hash does not match"); } + int contentSize = shmBufferFactory.getBufferLimit(); SharedMemory shm = shmBufferFactory.releaseSharedMemory(); if (shm == null) { throw new IllegalStateException("Failed to generate verity tree into shared memory"); @@ -108,7 +123,7 @@ abstract public class VerityUtils { if (!shm.setProtect(PROT_READ)) { throw new SecurityException("Failed to set up shared memory correctly"); } - return shm; + return Pair.create(shm, contentSize); } public static class SetupResult { @@ -123,22 +138,24 @@ abstract public class VerityUtils { private final int mCode; private final FileDescriptor mFileDescriptor; + private final int mContentSize; - public static SetupResult ok(@NonNull FileDescriptor fileDescriptor) { - return new SetupResult(RESULT_OK, fileDescriptor); + public static SetupResult ok(@NonNull FileDescriptor fileDescriptor, int contentSize) { + return new SetupResult(RESULT_OK, fileDescriptor, contentSize); } public static SetupResult skipped() { - return new SetupResult(RESULT_SKIPPED, null); + return new SetupResult(RESULT_SKIPPED, null, -1); } public static SetupResult failed() { - return new SetupResult(RESULT_FAILED, null); + return new SetupResult(RESULT_FAILED, null, -1); } - private SetupResult(int code, FileDescriptor fileDescriptor) { + private SetupResult(int code, FileDescriptor fileDescriptor, int contentSize) { this.mCode = code; this.mFileDescriptor = fileDescriptor; + this.mContentSize = contentSize; } public boolean isFailed() { @@ -152,6 +169,10 @@ abstract public class VerityUtils { public @NonNull FileDescriptor getUnownedFileDescriptor() { return mFileDescriptor; } + + public int getContentSize() { + return mContentSize; + } } /** A {@code ByteBufferFactory} that creates a shared memory backed {@code ByteBuffer}. */ @@ -188,5 +209,9 @@ abstract public class VerityUtils { mShm = null; return tmp; } + + public int getBufferLimit() { + return mBuffer == null ? -1 : mBuffer.limit(); + } } } -- GitLab From c4d58b8978454a3cf7ecdd4d7205fbdf68ca9cd7 Mon Sep 17 00:00:00 2001 From: Evan Rosky Date: Fri, 23 Mar 2018 18:29:29 -0700 Subject: [PATCH 004/179] Restored focusableViewAvailable logic on visibility change Since visibility effects children, it's state change should report focusableViewAvailable even though it, itself, may not be focusable. Bug: 76027633 Test: CTS View_FocusHandlingTest Change-Id: I83f949ec33bcac02e75e21727a120d3018d9382a --- core/java/android/view/View.java | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index afff19b0be31..0ca3d144d32f 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -13914,11 +13914,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mAttachInfo.mUnbufferedDispatchRequested = true; } + private boolean hasSize() { + return (mBottom > mTop) && (mRight > mLeft); + } + private boolean canTakeFocus() { return ((mViewFlags & VISIBILITY_MASK) == VISIBLE) && ((mViewFlags & FOCUSABLE) == FOCUSABLE) && ((mViewFlags & ENABLED_MASK) == ENABLED) - && (sCanFocusZeroSized || !isLayoutValid() || (mBottom > mTop) && (mRight > mLeft)); + && (sCanFocusZeroSized || !isLayoutValid() || hasSize()); } /** @@ -13979,7 +13983,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, || focusableChangedByAuto == 0 || viewRootImpl == null || viewRootImpl.mThread == Thread.currentThread()) { - shouldNotifyFocusableAvailable = true; + shouldNotifyFocusableAvailable = canTakeFocus(); } } } @@ -13998,11 +14002,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, needGlobalAttributesUpdate(true); - // a view becoming visible is worth notifying the parent - // about in case nothing has focus. even if this specific view - // isn't focusable, it may contain something that is, so let - // the root view try to give this focus if nothing else does. - shouldNotifyFocusableAvailable = true; + // a view becoming visible is worth notifying the parent about in case nothing has + // focus. Even if this specific view isn't focusable, it may contain something that + // is, so let the root view try to give this focus if nothing else does. + shouldNotifyFocusableAvailable = hasSize(); } } @@ -14011,16 +14014,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback, // a view becoming enabled should notify the parent as long as the view is also // visible and the parent wasn't already notified by becoming visible during this // setFlags invocation. - shouldNotifyFocusableAvailable = true; + shouldNotifyFocusableAvailable = canTakeFocus(); } else { if (isFocused()) clearFocus(); } } - if (shouldNotifyFocusableAvailable) { - if (mParent != null && canTakeFocus()) { - mParent.focusableViewAvailable(this); - } + if (shouldNotifyFocusableAvailable && mParent != null) { + mParent.focusableViewAvailable(this); } /* Check if the GONE bit has changed */ -- GitLab From 57378939c51541166ea670c1ddea963bd04a567e Mon Sep 17 00:00:00 2001 From: Eric Sandness Date: Tue, 27 Mar 2018 13:22:52 +0100 Subject: [PATCH 005/179] Permission Check For DPM Get IME API Require the caller of DPM.getPermittedInputMethodsForCurrentUser() to hold the MANAGE_USERS permission. The only callers should be settings apps which already hold this permission. Bug: 62343414 Test: Manage IME list in the Settings app Test: com.google.android.gts.devicepolicy.DeviceOwnerTest#testPermitInputMethods Change-Id: I0d162f8f51d16e403a950ee5d942502c2cf20181 --- core/java/android/app/admin/DevicePolicyManager.java | 1 + .../android/server/devicepolicy/DevicePolicyManagerService.java | 1 + 2 files changed, 2 insertions(+) diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 3015398e97ee..d0d630133593 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -6340,6 +6340,7 @@ public class DevicePolicyManager { * @hide */ @SystemApi + @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public @Nullable List getPermittedInputMethodsForCurrentUser() { throwIfParentInstance("getPermittedInputMethodsForCurrentUser"); if (mService != null) { diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 1e216a3cff86..160016d9625f 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -8738,6 +8738,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { @Override public List getPermittedInputMethodsForCurrentUser() { + enforceManageUsers(); UserInfo currentUser; try { currentUser = mInjector.getIActivityManager().getCurrentUser(); -- GitLab From 0f8ea543c165102e079b0a64afdfc600fe5e0387 Mon Sep 17 00:00:00 2001 From: Amin Shaikh Date: Tue, 27 Mar 2018 11:09:27 -0400 Subject: [PATCH 006/179] Control the QS label marquees. - Start the marquee when fully expanded and pause when collapsed. - Also do not change qs label to multiline once it's already been resized to single line. Change-Id: I2dd4f6b5473a6a5147999c29441537227751b705 Fixes: 74757991 Test: visual --- .../android/systemui/plugins/qs/QSTileView.java | 2 ++ .../com/android/systemui/qs/PagedTileLayout.java | 7 +++++++ .../src/com/android/systemui/qs/QSFragment.java | 1 + .../src/com/android/systemui/qs/QSPanel.java | 2 ++ .../android/systemui/qs/tileimpl/QSTileView.java | 16 +++++++++------- 5 files changed, 21 insertions(+), 7 deletions(-) diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTileView.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTileView.java index 53f7e44bc25a..ad300f43d88d 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTileView.java +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTileView.java @@ -50,4 +50,6 @@ public abstract class QSTileView extends LinearLayout { public abstract void onStateChanged(State state); public abstract int getDetailY(); + + public void setExpansion(float expansion) {} } diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java index 892395222d1f..c548cf6a6519 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java +++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java @@ -167,6 +167,13 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout { } } + @Override + public void setExpansion(float expansion) { + for (TileRecord tr : mTiles) { + tr.tileView.setExpansion(expansion); + } + } + public void setPageListener(PageListener listener) { mPageListener = listener; } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java index 29f3c43a1fa4..e532217fc260 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java @@ -291,6 +291,7 @@ public class QSFragment extends Fragment implements QS { mHeader.setExpansion(mKeyguardShowing, expansion, panelTranslationY); mFooter.setExpansion(mKeyguardShowing ? 1 : expansion); mQSPanel.getQsTileRevealController().setExpansion(expansion); + mQSPanel.getTileLayout().setExpansion(expansion); mQSPanel.setTranslationY(translationScaleY * heightDiff); mQSDetail.setFullyExpanded(fullyExpanded); diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java index 61e3065fd4a3..6368a6b32787 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java @@ -616,5 +616,7 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne boolean updateResources(); void setListening(boolean listening); + + default void setExpansion(float expansion) {} } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java index 3cb4c71fc98c..d21b06f02f16 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java @@ -32,12 +32,10 @@ import com.android.systemui.R; import com.android.systemui.plugins.qs.QSIconView; import com.android.systemui.plugins.qs.QSTile; - import java.util.Objects; /** View that represents a standard quick settings tile. **/ public class QSTileView extends QSTileBaseView { - private static final int DEFAULT_MAX_LINES = 2; private static final boolean DUAL_TARGET_ALLOWED = false; private View mDivider; protected TextView mLabel; @@ -87,22 +85,17 @@ public class QSTileView extends QSTileBaseView { mLabelContainer.setClipChildren(false); mLabelContainer.setClipToPadding(false); mLabel = mLabelContainer.findViewById(R.id.tile_label); - mLabel.setSelected(true); // Allow marquee to work. mPadLock = mLabelContainer.findViewById(R.id.restricted_padlock); mDivider = mLabelContainer.findViewById(R.id.underline); mExpandIndicator = mLabelContainer.findViewById(R.id.expand_indicator); mExpandSpace = mLabelContainer.findViewById(R.id.expand_space); mSecondLine = mLabelContainer.findViewById(R.id.app_label); mSecondLine.setAlpha(.6f); - mSecondLine.setSelected(true); // Allow marquee to work. addView(mLabelContainer); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - if (mLabel.getMaxLines() != DEFAULT_MAX_LINES) { - mLabel.setMaxLines(DEFAULT_MAX_LINES); - } super.onMeasure(widthMeasureSpec, heightMeasureSpec); // Remeasure view if the secondary label text will be cut off. @@ -113,6 +106,15 @@ public class QSTileView extends QSTileBaseView { } } + @Override + public void setExpansion(float expansion) { + // Start the marquee when fully expanded and stop when fully collapsed. Leave as is for + // other expansion ratios since there is no way way to pause the marquee. + boolean selected = expansion == 1f ? true : expansion == 0f ? false : mLabel.isSelected(); + mLabel.setSelected(selected); + mSecondLine.setSelected(selected); + } + @Override protected void handleStateChanged(QSTile.State state) { super.handleStateChanged(state); -- GitLab From 684d195227bf9eaeb21698cbdcf865afb570c454 Mon Sep 17 00:00:00 2001 From: Yangster-mac Date: Sat, 24 Mar 2018 16:47:16 -0700 Subject: [PATCH 007/179] E2e test for periodic alarm. Test: new test BUG: b/76281156 Change-Id: I60cb28baaeec6996e946a7cb3358ec8e0aca80e5 --- cmds/statsd/Android.mk | 1 + cmds/statsd/src/StatsLogProcessor.cpp | 4 +- cmds/statsd/src/StatsLogProcessor.h | 9 ++- cmds/statsd/src/StatsService.cpp | 2 +- cmds/statsd/src/anomaly/AlarmTracker.cpp | 15 ++-- cmds/statsd/src/anomaly/AlarmTracker.h | 6 ++ cmds/statsd/src/metrics/MetricsManager.cpp | 4 +- cmds/statsd/src/metrics/MetricsManager.h | 5 +- cmds/statsd/tests/e2e/Alarm_e2e_test.cpp | 92 ++++++++++++++++++++++ cmds/statsd/tests/statsd_test_util.cpp | 4 +- 10 files changed, 127 insertions(+), 15 deletions(-) create mode 100644 cmds/statsd/tests/e2e/Alarm_e2e_test.cpp diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk index 1aef0c4c43c5..7723615245b7 100644 --- a/cmds/statsd/Android.mk +++ b/cmds/statsd/Android.mk @@ -202,6 +202,7 @@ LOCAL_SRC_FILES := \ tests/statsd_test_util.cpp \ tests/e2e/WakelockDuration_e2e_test.cpp \ tests/e2e/MetricConditionLink_e2e_test.cpp \ + tests/e2e/Alarm_e2e_test.cpp \ tests/e2e/Attribution_e2e_test.cpp \ tests/e2e/GaugeMetric_e2e_push_test.cpp \ tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp \ diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp index a35570bd7bba..dac731d6b521 100644 --- a/cmds/statsd/src/StatsLogProcessor.cpp +++ b/cmds/statsd/src/StatsLogProcessor.cpp @@ -87,7 +87,7 @@ StatsLogProcessor::~StatsLogProcessor() { } void StatsLogProcessor::onAnomalyAlarmFired( - const uint64_t timestampNs, + const uint64_t& timestampNs, unordered_set, SpHash> alarmSet) { std::lock_guard lock(mMetricsMutex); for (const auto& itr : mMetricsManagers) { @@ -95,7 +95,7 @@ void StatsLogProcessor::onAnomalyAlarmFired( } } void StatsLogProcessor::onPeriodicAlarmFired( - const uint64_t timestampNs, + const uint64_t& timestampNs, unordered_set, SpHash> alarmSet) { std::lock_guard lock(mMetricsMutex); diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h index a07a35587b11..387a9295055f 100644 --- a/cmds/statsd/src/StatsLogProcessor.h +++ b/cmds/statsd/src/StatsLogProcessor.h @@ -51,12 +51,12 @@ public: /* Tells MetricsManager that the alarms in alarmSet have fired. Modifies anomaly alarmSet. */ void onAnomalyAlarmFired( - const uint64_t timestampNs, + const uint64_t& timestampNs, unordered_set, SpHash> alarmSet); /* Tells MetricsManager that the alarms in alarmSet have fired. Modifies periodic alarmSet. */ void onPeriodicAlarmFired( - const uint64_t timestampNs, + const uint64_t& timestampNs, unordered_set, SpHash> alarmSet); /* Flushes data to disk. Data on memory will be gone after written to disk. */ @@ -74,6 +74,10 @@ private: return mAnomalyAlarmMonitor; } + inline sp getPeriodicAlarmMonitor() const { + return mPeriodicAlarmMonitor; + } + mutable mutex mMetricsMutex; std::unordered_map> mMetricsManagers; @@ -147,6 +151,7 @@ private: FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket); FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_multiple_buckets); FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_long_refractory_period); + FRIEND_TEST(AlarmE2eTest, TestMultipleAlarms); }; } // namespace statsd diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp index b03b4b4a942c..192152876da7 100644 --- a/cmds/statsd/src/StatsService.cpp +++ b/cmds/statsd/src/StatsService.cpp @@ -698,7 +698,7 @@ Status StatsService::informAlarmForSubscriberTriggeringFired() { "Only system uid can call informAlarmForSubscriberTriggeringFired"); } - uint64_t currentTimeSec = time(nullptr); + uint64_t currentTimeSec = getElapsedRealtimeSec(); std::unordered_set, SpHash> alarmSet = mPeriodicAlarmMonitor->popSoonerThan(static_cast(currentTimeSec)); if (alarmSet.size() > 0) { diff --git a/cmds/statsd/src/anomaly/AlarmTracker.cpp b/cmds/statsd/src/anomaly/AlarmTracker.cpp index eb283838afd7..249cb596d3c6 100644 --- a/cmds/statsd/src/anomaly/AlarmTracker.cpp +++ b/cmds/statsd/src/anomaly/AlarmTracker.cpp @@ -39,12 +39,14 @@ AlarmTracker::AlarmTracker(uint64_t startMillis, VLOG("AlarmTracker() called"); mAlarmSec = (startMillis + mAlarmConfig.offset_millis()) / MS_PER_SEC; mInternalAlarm = new InternalAlarm{static_cast(mAlarmSec)}; - mAlarmMonitor->add(mInternalAlarm); + if (mAlarmMonitor != nullptr) { + mAlarmMonitor->add(mInternalAlarm); + } } AlarmTracker::~AlarmTracker() { VLOG("~AlarmTracker() called"); - if (mInternalAlarm != nullptr) { + if (mInternalAlarm != nullptr && mAlarmMonitor != nullptr) { mAlarmMonitor->remove(mInternalAlarm); } } @@ -61,7 +63,8 @@ uint64_t AlarmTracker::findNextAlarmSec(uint64_t currentTimeSec) { void AlarmTracker::informAlarmsFired( const uint64_t& timestampNs, unordered_set, SpHash>& firedAlarms) { - if (firedAlarms.empty() || firedAlarms.find(mInternalAlarm) == firedAlarms.end()) { + if (firedAlarms.empty() || mInternalAlarm == nullptr || + firedAlarms.find(mInternalAlarm) == firedAlarms.end()) { return; } if (!mSubscriptions.empty()) { @@ -69,9 +72,11 @@ void AlarmTracker::informAlarmsFired( mSubscriptions); } firedAlarms.erase(mInternalAlarm); - mAlarmSec = findNextAlarmSec(timestampNs / NS_PER_SEC); + mAlarmSec = findNextAlarmSec((timestampNs-1) / NS_PER_SEC + 1); // round up mInternalAlarm = new InternalAlarm{static_cast(mAlarmSec)}; - mAlarmMonitor->add(mInternalAlarm); + if (mAlarmMonitor != nullptr) { + mAlarmMonitor->add(mInternalAlarm); + } } } // namespace statsd diff --git a/cmds/statsd/src/anomaly/AlarmTracker.h b/cmds/statsd/src/anomaly/AlarmTracker.h index d59dacaa1b69..13180a53ccbf 100644 --- a/cmds/statsd/src/anomaly/AlarmTracker.h +++ b/cmds/statsd/src/anomaly/AlarmTracker.h @@ -48,6 +48,11 @@ public: unordered_set, SpHash>& firedAlarms); protected: + // For test only. Returns the alarm timestamp in seconds. Otherwise returns 0. + inline uint32_t getAlarmTimestampSec() const { + return mInternalAlarm == nullptr ? 0 : mInternalAlarm->timestampSec; + } + uint64_t findNextAlarmSec(uint64_t currentTimeMillis); // statsd_config.proto Alarm message that defines this tracker. @@ -69,6 +74,7 @@ protected: sp mInternalAlarm; FRIEND_TEST(AlarmTrackerTest, TestTriggerTimestamp); + FRIEND_TEST(AlarmE2eTest, TestMultipleAlarms); }; } // namespace statsd diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp index c773d4f1387e..80a860c82c6e 100644 --- a/cmds/statsd/src/metrics/MetricsManager.cpp +++ b/cmds/statsd/src/metrics/MetricsManager.cpp @@ -350,7 +350,7 @@ void MetricsManager::onLogEvent(const LogEvent& event) { } void MetricsManager::onAnomalyAlarmFired( - const uint64_t timestampNs, + const uint64_t& timestampNs, unordered_set, SpHash>& alarmSet) { for (const auto& itr : mAllAnomalyTrackers) { itr->informAlarmsFired(timestampNs, alarmSet); @@ -358,7 +358,7 @@ void MetricsManager::onAnomalyAlarmFired( } void MetricsManager::onPeriodicAlarmFired( - const uint64_t timestampNs, + const uint64_t& timestampNs, unordered_set, SpHash>& alarmSet) { for (const auto& itr : mAllPeriodicAlarmTrackers) { itr->informAlarmsFired(timestampNs, alarmSet); diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h index 05ce84d7ea8f..da0cd4a29d3b 100644 --- a/cmds/statsd/src/metrics/MetricsManager.h +++ b/cmds/statsd/src/metrics/MetricsManager.h @@ -48,11 +48,11 @@ public: void onLogEvent(const LogEvent& event); void onAnomalyAlarmFired( - const uint64_t timestampNs, + const uint64_t& timestampNs, unordered_set, SpHash>& alarmSet); void onPeriodicAlarmFired( - const uint64_t timestampNs, + const uint64_t& timestampNs, unordered_set, SpHash>& alarmSet); void notifyAppUpgrade(const uint64_t& eventTimeNs, const string& apk, const int uid, @@ -184,6 +184,7 @@ private: FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_multiple_buckets); FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_long_refractory_period); + FRIEND_TEST(AlarmE2eTest, TestMultipleAlarms); }; } // namespace statsd diff --git a/cmds/statsd/tests/e2e/Alarm_e2e_test.cpp b/cmds/statsd/tests/e2e/Alarm_e2e_test.cpp new file mode 100644 index 000000000000..73c4e7b859de --- /dev/null +++ b/cmds/statsd/tests/e2e/Alarm_e2e_test.cpp @@ -0,0 +1,92 @@ +// Copyright (C) 2017 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. + +#include + +#include "src/StatsLogProcessor.h" +#include "src/stats_log_util.h" +#include "tests/statsd_test_util.h" + +#include + +namespace android { +namespace os { +namespace statsd { + +#ifdef __ANDROID__ + +namespace { + +StatsdConfig CreateStatsdConfig() { + StatsdConfig config; + config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root. + + auto alarm = config.add_alarm(); + alarm->set_id(123456); + alarm->set_offset_millis(TimeUnitToBucketSizeInMillis(TEN_MINUTES)); + alarm->set_period_millis(TimeUnitToBucketSizeInMillis(ONE_HOUR)); + + alarm = config.add_alarm(); + alarm->set_id(654321); + alarm->set_offset_millis(TimeUnitToBucketSizeInMillis(FIVE_MINUTES)); + alarm->set_period_millis(TimeUnitToBucketSizeInMillis(THIRTY_MINUTES)); + return config; +} + +} // namespace + +TEST(AlarmE2eTest, TestMultipleAlarms) { + auto config = CreateStatsdConfig(); + int64_t bucketStartTimeNs = 10000000000; + + ConfigKey cfgKey; + auto processor = CreateStatsLogProcessor(bucketStartTimeNs / NS_PER_SEC, config, cfgKey); + EXPECT_EQ(processor->mMetricsManagers.size(), 1u); + EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); + EXPECT_EQ(2u, processor->mMetricsManagers.begin()->second->mAllPeriodicAlarmTrackers.size()); + + auto alarmTracker1 = processor->mMetricsManagers.begin()->second->mAllPeriodicAlarmTrackers[0]; + auto alarmTracker2 = processor->mMetricsManagers.begin()->second->mAllPeriodicAlarmTrackers[1]; + + int64_t alarmTimestampSec0 = bucketStartTimeNs / NS_PER_SEC + 10 * 60; + int64_t alarmTimestampSec1 = bucketStartTimeNs / NS_PER_SEC + 5 * 60; + EXPECT_EQ(alarmTimestampSec0, alarmTracker1->getAlarmTimestampSec()); + EXPECT_EQ(alarmTimestampSec1, alarmTracker2->getAlarmTimestampSec()); + + // Alarm fired. + const int64_t alarmFiredTimestampSec0 = alarmTimestampSec1 + 5; + auto alarmSet = processor->getPeriodicAlarmMonitor()->popSoonerThan( + static_cast(alarmFiredTimestampSec0)); + EXPECT_EQ(1u, alarmSet.size()); + processor->onPeriodicAlarmFired(alarmFiredTimestampSec0 * NS_PER_SEC, alarmSet); + EXPECT_EQ(alarmTimestampSec0, alarmTracker1->getAlarmTimestampSec()); + EXPECT_EQ(alarmTimestampSec1 + 30 * 60, alarmTracker2->getAlarmTimestampSec()); + + // Alarms fired very late. + const int64_t alarmFiredTimestampSec1 = alarmTimestampSec0 + 2 * 60 * 60 + 125; + alarmSet = processor->getPeriodicAlarmMonitor()->popSoonerThan( + static_cast(alarmFiredTimestampSec1)); + EXPECT_EQ(2u, alarmSet.size()); + processor->onPeriodicAlarmFired(alarmFiredTimestampSec1 * NS_PER_SEC, alarmSet); + EXPECT_EQ(alarmTimestampSec0 + 60 * 60 * 3, alarmTracker1->getAlarmTimestampSec()); + EXPECT_EQ(alarmTimestampSec1 + 30 * 60 * 5, alarmTracker2->getAlarmTimestampSec()); +} + +#else +GTEST_LOG_(INFO) << "This test does nothing.\n"; +#endif + +} // namespace statsd +} // namespace os +} // namespace android diff --git a/cmds/statsd/tests/statsd_test_util.cpp b/cmds/statsd/tests/statsd_test_util.cpp index ce44a35cbf21..8a93770c64ce 100644 --- a/cmds/statsd/tests/statsd_test_util.cpp +++ b/cmds/statsd/tests/statsd_test_util.cpp @@ -450,7 +450,9 @@ sp CreateStatsLogProcessor(const long timeBaseSec, const Stat sp anomalyAlarmMonitor = new AlarmMonitor(1, [](const sp&, int64_t){}, [](const sp&){}); - sp periodicAlarmMonitor; + sp periodicAlarmMonitor = + new AlarmMonitor(1, [](const sp&, int64_t){}, + [](const sp&){}); sp processor = new StatsLogProcessor( uidMap, anomalyAlarmMonitor, periodicAlarmMonitor, timeBaseSec, [](const ConfigKey&){}); processor->OnConfigUpdated(key, config); -- GitLab From f6c75dc190ce7345dd8a6b7e7a232317ba7649f2 Mon Sep 17 00:00:00 2001 From: Amin Shaikh Date: Tue, 27 Mar 2018 10:37:19 -0400 Subject: [PATCH 008/179] Update mobile data icons. Change-Id: I6828f04d125f4aeb23d1f7cad2a57cc2640e4105 Fixes: 76142951 Test: visual --- .../res/drawable/ic_1x_mobiledata.xml | 16 ++++---- .../res/drawable/ic_3g_mobiledata.xml | 16 ++++---- .../res/drawable/ic_4g_mobiledata.xml | 14 +++---- .../res/drawable/ic_4g_plus_mobiledata.xml | 16 ++++---- .../SystemUI/res/drawable/ic_e_mobiledata.xml | 12 +++--- .../SystemUI/res/drawable/ic_g_mobiledata.xml | 12 +++--- .../SystemUI/res/drawable/ic_h_mobiledata.xml | 12 +++--- .../res/drawable/ic_h_plus_mobiledata.xml | 14 +++---- .../res/drawable/ic_lte_mobiledata.xml | 16 ++++---- .../res/drawable/ic_lte_plus_mobiledata.xml | 18 ++++----- .../res/drawable/stat_sys_roaming.xml | 39 +++++++++---------- .../res/layout/mobile_signal_group.xml | 3 +- 12 files changed, 94 insertions(+), 94 deletions(-) diff --git a/packages/SystemUI/res/drawable/ic_1x_mobiledata.xml b/packages/SystemUI/res/drawable/ic_1x_mobiledata.xml index 726d814f7eb2..c0e0e59a88e2 100644 --- a/packages/SystemUI/res/drawable/ic_1x_mobiledata.xml +++ b/packages/SystemUI/res/drawable/ic_1x_mobiledata.xml @@ -14,17 +14,17 @@ limitations under the License. --> + android:width="14dp" + android:height="17dp" + android:viewportWidth="14" + android:viewportHeight="17"> + android:pathData="M3.77,13.48H2.55V5.05L0.46,5.98V4.84l3.12-1.36h0.19V13.48z" /> + android:pathData="M10.14,7.34l1.87-3.81h1.47L10.9,8.46l2.65,5.02h-1.48l-1.91-3.88l-1.92,3.88H6.74L9.4,8.46l-2.6-4.94h1.46L10.14,7.34z" /> - \ No newline at end of file + android:pathData="M 0 0 H 14 V 17 H 0 V 0 Z" /> + diff --git a/packages/SystemUI/res/drawable/ic_3g_mobiledata.xml b/packages/SystemUI/res/drawable/ic_3g_mobiledata.xml index 7a539ffe3471..e4a5bf8a9130 100644 --- a/packages/SystemUI/res/drawable/ic_3g_mobiledata.xml +++ b/packages/SystemUI/res/drawable/ic_3g_mobiledata.xml @@ -14,17 +14,17 @@ limitations under the License. --> + android:width="14dp" + android:height="17dp" + android:viewportWidth="14" + android:viewportHeight="17"> + android:pathData="M1.9,7.88h0.77c0.5,0,0.88-0.15,1.15-0.46s0.4-0.72,0.4-1.25c0-1.17-0.45-1.75-1.35-1.75c-0.43,0-0.77,0.16-1.02,0.47 S1.49,5.62,1.49,6.13h-1.2c0-0.8,0.24-1.46,0.73-1.97s1.11-0.78,1.86-0.78c0.78,0,1.41,0.25,1.87,0.73S5.43,5.31,5.43,6.2 c0,0.46-0.12,0.89-0.36,1.29S4.52,8.18,4.14,8.37c0.94,0.35,1.41,1.12,1.41,2.33c0,0.89-0.25,1.6-0.74,2.12 c-0.49,0.53-1.14,0.79-1.94,0.79c-0.79,0-1.43-0.25-1.91-0.75c-0.49-0.5-0.73-1.17-0.73-2.01h1.21c0,0.53,0.13,0.95,0.38,1.26 c0.26,0.31,0.6,0.47,1.05,0.47c0.45,0,0.81-0.15,1.08-0.46s0.4-0.77,0.4-1.39c0-1.21-0.57-1.81-1.72-1.81H1.9V7.88z" /> + android:pathData="M13.77,12.24l-0.22,0.27c-0.63,0.73-1.55,1.1-2.76,1.1c-1.08,0-1.92-0.36-2.53-1.07c-0.61-0.71-0.93-1.72-0.94-3.02V7.56 c0-1.39,0.28-2.44,0.84-3.13s1.39-1.04,2.51-1.04c0.95,0,1.69,0.26,2.23,0.79s0.83,1.28,0.89,2.26h-1.25 C12.47,5.82,12.3,5.33,12,4.98s-0.74-0.52-1.34-0.52c-0.72,0-1.24,0.23-1.57,0.7S8.59,6.37,8.58,7.4v2.03c0,1,0.19,1.77,0.57,2.31 c0.38,0.54,0.93,0.8,1.65,0.8c0.67,0,1.19-0.16,1.54-0.49l0.18-0.17V9.59H10.7V8.52h3.07V12.24z" /> - \ No newline at end of file + android:pathData="M 0 0 H 14 V 17 H 0 V 0 Z" /> + diff --git a/packages/SystemUI/res/drawable/ic_4g_mobiledata.xml b/packages/SystemUI/res/drawable/ic_4g_mobiledata.xml index b2fab0c80d51..e98560b9c0a2 100644 --- a/packages/SystemUI/res/drawable/ic_4g_mobiledata.xml +++ b/packages/SystemUI/res/drawable/ic_4g_mobiledata.xml @@ -14,17 +14,17 @@ limitations under the License. --> + android:width="14dp" + android:height="17dp" + android:viewportWidth="14" + android:viewportHeight="17"> + android:pathData="M5.07,10.13h1.11v1.03H5.07v2.31H3.86v-2.31H0.1v-0.75l3.7-6.9h1.27V10.13z M1.44,10.13h2.42V5.4L1.44,10.13z" /> + android:pathData="M13.9,12.24l-0.22,0.27c-0.63,0.73-1.55,1.1-2.76,1.1c-1.08,0-1.92-0.36-2.53-1.07c-0.61-0.71-0.93-1.72-0.94-3.02V7.56 c0-1.39,0.28-2.44,0.84-3.13s1.39-1.04,2.51-1.04c0.95,0,1.69,0.26,2.23,0.79s0.83,1.28,0.89,2.26h-1.25 c-0.05-0.62-0.22-1.1-0.52-1.45s-0.74-0.52-1.34-0.52c-0.72,0-1.24,0.23-1.57,0.7S8.72,6.37,8.71,7.4v2.03 c0,1,0.19,1.77,0.57,2.31c0.38,0.54,0.93,0.8,1.65,0.8c0.67,0,1.19-0.16,1.54-0.49l0.18-0.17V9.59h-1.82V8.52h3.07V12.24z" /> + android:pathData="M 0 0 H 14 V 17 H 0 V 0 Z" /> diff --git a/packages/SystemUI/res/drawable/ic_4g_plus_mobiledata.xml b/packages/SystemUI/res/drawable/ic_4g_plus_mobiledata.xml index bdbb2df3ce0e..bf39ea2798b3 100644 --- a/packages/SystemUI/res/drawable/ic_4g_plus_mobiledata.xml +++ b/packages/SystemUI/res/drawable/ic_4g_plus_mobiledata.xml @@ -14,20 +14,20 @@ limitations under the License. --> + android:width="22dp" + android:height="17dp" + android:viewportWidth="22" + android:viewportHeight="17"> + android:pathData="M5.32,10.13h1.11v1.03H5.32v2.31H4.11v-2.31H0.35v-0.75l3.7-6.9h1.27V10.13z M1.69,10.13h2.42V5.4L1.69,10.13z" /> + android:pathData="M14.15,12.24l-0.22,0.27c-0.63,0.73-1.55,1.1-2.76,1.1c-1.08,0-1.92-0.36-2.53-1.07c-0.61-0.71-0.93-1.72-0.94-3.02V7.56 c0-1.39,0.28-2.44,0.84-3.13s1.39-1.04,2.51-1.04c0.95,0,1.69,0.26,2.23,0.79s0.83,1.28,0.89,2.26H12.9 c-0.05-0.62-0.22-1.1-0.52-1.45s-0.74-0.52-1.34-0.52c-0.72,0-1.24,0.23-1.57,0.7S8.97,6.37,8.96,7.4v2.03 c0,1,0.19,1.77,0.57,2.31c0.38,0.54,0.93,0.8,1.65,0.8c0.67,0,1.19-0.16,1.54-0.49l0.18-0.17V9.59h-1.82V8.52h3.07V12.24z" /> + android:pathData="M 19.3 5.74 L 19.3 3.39 L 18 3.39 L 18 5.74 L 15.65 5.74 L 15.65 7.04 L 18 7.04 L 18 9.39 L 19.3 9.39 L 19.3 7.04 L 21.65 7.04 L 21.65 5.74 Z" /> + android:pathData="M 0 0 H 22 V 17 H 0 V 0 Z" /> diff --git a/packages/SystemUI/res/drawable/ic_e_mobiledata.xml b/packages/SystemUI/res/drawable/ic_e_mobiledata.xml index 1a4a2e362b47..ca601d6c36ab 100644 --- a/packages/SystemUI/res/drawable/ic_e_mobiledata.xml +++ b/packages/SystemUI/res/drawable/ic_e_mobiledata.xml @@ -14,14 +14,14 @@ limitations under the License. --> + android:width="6dp" + android:height="17dp" + android:viewportWidth="6" + android:viewportHeight="17"> + android:pathData="M5.1,8.88H1.57v3.53h4.1v1.07H0.32V3.52h5.28V4.6H1.57V7.8H5.1V8.88z" /> + android:pathData="M 0 0 H 6 V 17 H 0 V 0 Z" /> diff --git a/packages/SystemUI/res/drawable/ic_g_mobiledata.xml b/packages/SystemUI/res/drawable/ic_g_mobiledata.xml index d6a0488544fd..8ff6d7a5cc88 100644 --- a/packages/SystemUI/res/drawable/ic_g_mobiledata.xml +++ b/packages/SystemUI/res/drawable/ic_g_mobiledata.xml @@ -14,14 +14,14 @@ limitations under the License. --> + android:width="7dp" + android:height="17dp" + android:viewportWidth="7" + android:viewportHeight="17"> + android:pathData="M6.73,12.24l-0.22,0.27c-0.63,0.73-1.55,1.1-2.76,1.1c-1.08,0-1.92-0.36-2.53-1.07c-0.61-0.71-0.93-1.72-0.94-3.02V7.56 c0-1.39,0.28-2.44,0.84-3.13S2.5,3.39,3.62,3.39c0.95,0,1.69,0.26,2.23,0.79s0.83,1.28,0.89,2.26H5.48 c-0.05-0.62-0.22-1.1-0.52-1.45S4.22,4.46,3.62,4.46c-0.72,0-1.24,0.23-1.57,0.7S1.54,6.37,1.53,7.4v2.03c0,1,0.19,1.77,0.57,2.31 c0.38,0.54,0.93,0.8,1.65,0.8c0.67,0,1.19-0.16,1.54-0.49l0.18-0.17V9.59H3.66V8.52h3.07V12.24z" /> + android:pathData="M 0 0 H 7 V 17 H 0 V 0 Z" /> diff --git a/packages/SystemUI/res/drawable/ic_h_mobiledata.xml b/packages/SystemUI/res/drawable/ic_h_mobiledata.xml index be85bbb4f79b..68ea58e33f31 100644 --- a/packages/SystemUI/res/drawable/ic_h_mobiledata.xml +++ b/packages/SystemUI/res/drawable/ic_h_mobiledata.xml @@ -14,14 +14,14 @@ limitations under the License. --> + android:width="7dp" + android:height="17dp" + android:viewportWidth="7" + android:viewportHeight="17"> + android:pathData="M6.76,13.48H5.5v-4.6H1.49v4.6H0.24V3.52h1.25V7.8H5.5V3.52h1.26V13.48z" /> + android:pathData="M 0 0 H 7 V 17 H 0 V 0 Z" /> diff --git a/packages/SystemUI/res/drawable/ic_h_plus_mobiledata.xml b/packages/SystemUI/res/drawable/ic_h_plus_mobiledata.xml index f31f83c51412..4212800217ec 100644 --- a/packages/SystemUI/res/drawable/ic_h_plus_mobiledata.xml +++ b/packages/SystemUI/res/drawable/ic_h_plus_mobiledata.xml @@ -14,17 +14,17 @@ limitations under the License. --> + android:width="15dp" + android:height="17dp" + android:viewportWidth="15" + android:viewportHeight="17"> + android:pathData="M7.01,13.48H5.75v-4.6H1.74v4.6H0.49V3.52h1.25V7.8h4.01V3.52h1.26V13.48z" /> + android:pathData="M 12.16 5.74 L 12.16 3.39 L 10.86 3.39 L 10.86 5.74 L 8.51 5.74 L 8.51 7.04 L 10.86 7.04 L 10.86 9.39 L 12.16 9.39 L 12.16 7.04 L 14.51 7.04 L 14.51 5.74 Z" /> + android:pathData="M 0 0 H 15 V 17 H 0 V 0 Z" /> diff --git a/packages/SystemUI/res/drawable/ic_lte_mobiledata.xml b/packages/SystemUI/res/drawable/ic_lte_mobiledata.xml index e45b5e05aff0..7536f5134cbe 100644 --- a/packages/SystemUI/res/drawable/ic_lte_mobiledata.xml +++ b/packages/SystemUI/res/drawable/ic_lte_mobiledata.xml @@ -14,20 +14,20 @@ limitations under the License. --> + android:width="18dp" + android:height="17dp" + android:viewportWidth="18" + android:viewportHeight="17"> + android:pathData="M1.34,12.4h3.9v1.07H0.08V3.52h1.26V12.4z" /> + android:pathData="M11.1,4.6H8.48v8.88H7.23V4.6H4.62V3.52h6.48V4.6z" /> + android:pathData="M17.34,8.88h-3.52v3.53h4.1v1.07h-5.35V3.52h5.28V4.6h-4.03V7.8h3.52V8.88z" /> + android:pathData="M 0 0 H 18 V 17 H 0 V 0 Z" /> diff --git a/packages/SystemUI/res/drawable/ic_lte_plus_mobiledata.xml b/packages/SystemUI/res/drawable/ic_lte_plus_mobiledata.xml index 553a5bdc021e..302e3bdc5287 100644 --- a/packages/SystemUI/res/drawable/ic_lte_plus_mobiledata.xml +++ b/packages/SystemUI/res/drawable/ic_lte_plus_mobiledata.xml @@ -14,23 +14,23 @@ limitations under the License. --> + android:width="26dp" + android:height="17dp" + android:viewportWidth="26" + android:viewportHeight="17"> + android:pathData="M1.59,12.4h3.9v1.07H0.33V3.52h1.26V12.4z" /> + android:pathData="M11.35,4.6H8.73v8.88H7.48V4.6H4.87V3.52h6.48V4.6z" /> + android:pathData="M17.59,8.88h-3.52v3.53h4.1v1.07h-5.35V3.52h5.28V4.6h-4.03V7.8h3.52V8.88z" /> + android:pathData="M 23.32 5.74 L 23.32 3.39 L 22.02 3.39 L 22.02 5.74 L 19.67 5.74 L 19.67 7.04 L 22.02 7.04 L 22.02 9.39 L 23.32 9.39 L 23.32 7.04 L 25.67 7.04 L 25.67 5.74 Z" /> + android:pathData="M 0 0 H 26 V 17 H 0 V 0 Z" /> diff --git a/packages/SystemUI/res/drawable/stat_sys_roaming.xml b/packages/SystemUI/res/drawable/stat_sys_roaming.xml index bd2edf39d929..0dd9f5a39f91 100644 --- a/packages/SystemUI/res/drawable/stat_sys_roaming.xml +++ b/packages/SystemUI/res/drawable/stat_sys_roaming.xml @@ -1,28 +1,27 @@ - - - - \ No newline at end of file + android:viewportWidth="17" + android:viewportHeight="17"> + + + + diff --git a/packages/SystemUI/res/layout/mobile_signal_group.xml b/packages/SystemUI/res/layout/mobile_signal_group.xml index cc6e3bfbebaa..5ecd380c6950 100644 --- a/packages/SystemUI/res/layout/mobile_signal_group.xml +++ b/packages/SystemUI/res/layout/mobile_signal_group.xml @@ -50,7 +50,8 @@ android:layout_height="wrap_content" android:layout_width="wrap_content" android:layout_gravity="center_vertical" - android:paddingEnd="1dp" + android:paddingStart="1dp" + android:paddingEnd="2dp" android:visibility="gone" /> Date: Wed, 14 Mar 2018 19:01:14 -0700 Subject: [PATCH 009/179] Add documentation for TCP interactions with transforms Updates API documentation to mention that TCP sockets where transforms are deactivated will not send FIN packets. Bug: 74851550 Test: API updates only Merged-In: I8169f221c8c747538a8bddfbf02dcc73c9337189 Change-Id: I8169f221c8c747538a8bddfbf02dcc73c9337189 (cherry picked from commit 7d31a2f3579eff80c3cef07feadf77dbfcbfcd17) --- core/java/android/net/IpSecManager.java | 26 +++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index 972b9c074690..a88fe0428a06 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -305,6 +305,19 @@ public final class IpSecManager { * will throw IOException if the user deactivates the transform (by calling {@link * IpSecTransform#close()}) without calling {@link #removeTransportModeTransforms}. * + *

Note that when applied to TCP sockets, calling {@link IpSecTransform#close()} on an + * applied transform before completion of graceful shutdown may result in the shutdown sequence + * failing to complete. As such, applications requiring graceful shutdown MUST close the socket + * prior to deactivating the applied transform. Socket closure may be performed asynchronously + * (in batches), so the returning of a close function does not guarantee shutdown of a socket. + * Setting an SO_LINGER timeout results in socket closure being performed synchronously, and is + * sufficient to ensure shutdown. + * + * Specifically, if the transform is deactivated (by calling {@link IpSecTransform#close()}), + * prior to the socket being closed, the standard [FIN - FIN/ACK - ACK], or the reset [RST] + * packets are dropped due to the lack of a valid Transform. Similarly, if a socket without the + * SO_LINGER option set is closed, the delayed/batched FIN packets may be dropped. + * *

Rekey Procedure

* *

When applying a new tranform to a socket in the outbound direction, the previous transform @@ -373,6 +386,19 @@ public final class IpSecManager { * will throw IOException if the user deactivates the transform (by calling {@link * IpSecTransform#close()}) without calling {@link #removeTransportModeTransforms}. * + *

Note that when applied to TCP sockets, calling {@link IpSecTransform#close()} on an + * applied transform before completion of graceful shutdown may result in the shutdown sequence + * failing to complete. As such, applications requiring graceful shutdown MUST close the socket + * prior to deactivating the applied transform. Socket closure may be performed asynchronously + * (in batches), so the returning of a close function does not guarantee shutdown of a socket. + * Setting an SO_LINGER timeout results in socket closure being performed synchronously, and is + * sufficient to ensure shutdown. + * + * Specifically, if the transform is deactivated (by calling {@link IpSecTransform#close()}), + * prior to the socket being closed, the standard [FIN - FIN/ACK - ACK], or the reset [RST] + * packets are dropped due to the lack of a valid Transform. Similarly, if a socket without the + * SO_LINGER option set is closed, the delayed/batched FIN packets may be dropped. + * *

Rekey Procedure

* *

When applying a new tranform to a socket in the outbound direction, the previous transform -- GitLab From bc064d4b4b7685876b8cc48830e7571a5a3ecb2e Mon Sep 17 00:00:00 2001 From: Makoto Onuki Date: Tue, 27 Mar 2018 14:48:42 -0700 Subject: [PATCH 010/179] Make battery saver suggestion configurable Test: Manual test with: settings put global low_power_mode_suggestion_params start_nth=2,end_nth=3 Bug: 74120126 Change-Id: If165892477b41547a3880e2e961a38328b33c5bd --- core/java/android/provider/Settings.java | 9 +++- .../android/provider/SettingsBackupTest.java | 1 + .../fuelgauge/BatterySaverUtils.java | 45 ++++++++++++++----- 3 files changed, 44 insertions(+), 11 deletions(-) diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 70f343ee5f57..aa8e3f6cdb02 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -11053,7 +11053,14 @@ public final class Settings { */ public static final String LOW_POWER_MODE_TRIGGER_LEVEL_MAX = "low_power_trigger_level_max"; - /** + /** + * See com.android.settingslib.fuelgauge.BatterySaverUtils. + * @hide + */ + public static final String LOW_POWER_MODE_SUGGESTION_PARAMS = + "low_power_mode_suggestion_params"; + + /** * If not 0, the activity manager will aggressively finish activities and * processes as soon as they are no longer needed. If 0, the normal * extended lifetime is used. diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java index 2a3fcadb5144..e354407e4e08 100644 --- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java +++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java @@ -267,6 +267,7 @@ public class SettingsBackupTest { Settings.Global.LOW_POWER_MODE, Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL_MAX, Settings.Global.LOW_POWER_MODE_STICKY, + Settings.Global.LOW_POWER_MODE_SUGGESTION_PARAMS, Settings.Global.LTE_SERVICE_FORCED, Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE, Settings.Global.MAX_SOUND_TRIGGER_DETECTION_SERVICE_OPS_PER_DAY, diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java index 28833a349372..835ff07c4006 100644 --- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java @@ -22,8 +22,9 @@ import android.content.Intent; import android.os.PowerManager; import android.provider.Settings.Global; import android.provider.Settings.Secure; -import android.support.annotation.VisibleForTesting; +import android.util.KeyValueListParser; import android.util.Log; +import android.util.Slog; /** * Utilities related to battery saver. @@ -48,13 +49,35 @@ public class BatterySaverUtils { public static final String ACTION_SHOW_AUTO_SAVER_SUGGESTION = "PNW.autoSaverSuggestion"; - /** - * We show the auto battery saver suggestion notification when the user manually enables - * battery saver for the START_NTH time through the END_NTH time. - * (We won't show it for END_NTH + 1 time and after.) - */ - private static final int AUTO_SAVER_SUGGESTION_START_NTH = 4; - private static final int AUTO_SAVER_SUGGESTION_END_NTH = 8; + private static class Parameters { + private final Context mContext; + + /** + * We show the auto battery saver suggestion notification when the user manually enables + * battery saver for the START_NTH time through the END_NTH time. + * (We won't show it for END_NTH + 1 time and after.) + */ + private static final int AUTO_SAVER_SUGGESTION_START_NTH = 4; + private static final int AUTO_SAVER_SUGGESTION_END_NTH = 8; + + public final int startNth; + public final int endNth; + + public Parameters(Context context) { + mContext = context; + + final String newValue = Global.getString(mContext.getContentResolver(), + Global.LOW_POWER_MODE_SUGGESTION_PARAMS); + final KeyValueListParser parser = new KeyValueListParser(','); + try { + parser.setString(newValue); + } catch (IllegalArgumentException e) { + Slog.wtf(TAG, "Bad constants: " + newValue); + } + startNth = parser.getInt("start_nth", AUTO_SAVER_SUGGESTION_START_NTH); + endNth = parser.getInt("end_nth", AUTO_SAVER_SUGGESTION_END_NTH); + } + } /** * Enable / disable battery saver by user request. @@ -85,8 +108,10 @@ public class BatterySaverUtils { Secure.getInt(cr, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, 0) + 1; Secure.putInt(cr, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, count); - if ((count >= AUTO_SAVER_SUGGESTION_START_NTH) - && (count <= AUTO_SAVER_SUGGESTION_END_NTH) + final Parameters parameters = new Parameters(context); + + if ((count >= parameters.startNth) + && (count <= parameters.endNth) && Global.getInt(cr, Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0) == 0 && Secure.getInt(cr, Secure.SUPPRESS_AUTO_BATTERY_SAVER_SUGGESTION, 0) == 0) { -- GitLab From d9c9fff1399e09ae49c6cd6e131d884e9e0bc96e Mon Sep 17 00:00:00 2001 From: Pavel Maltsev Date: Thu, 22 Mar 2018 11:41:32 -0700 Subject: [PATCH 011/179] Add OEM_PAID capability to system api Some system apps should be able to request OEM_PAID networks. This makes a lot of sense when Android is used as in-vehicle infotainment systems. Bug: 68762530 Test: runtest -x frameworks/base/tests/net/ -c android.net.NetworkCapabilitiesTest Change-Id: Ic916de7522a9f803a2410bc4e3e82101fd9d0dbd --- api/system-current.txt | 4 ++++ core/java/android/net/NetworkCapabilities.java | 2 ++ 2 files changed, 6 insertions(+) diff --git a/api/system-current.txt b/api/system-current.txt index 5568dbad0e8c..9971335faacd 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -3102,6 +3102,10 @@ package android.net { field public static final int ERROR_INVALID_NETWORK = 1; // 0x1 } + public final class NetworkCapabilities implements android.os.Parcelable { + field public static final int NET_CAPABILITY_OEM_PAID = 22; // 0x16 + } + public class NetworkKey implements android.os.Parcelable { ctor public NetworkKey(android.net.WifiKey); method public int describeContents(); diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java index ff5714b38212..374b3abcb641 100644 --- a/core/java/android/net/NetworkCapabilities.java +++ b/core/java/android/net/NetworkCapabilities.java @@ -17,6 +17,7 @@ package android.net; import android.annotation.IntDef; +import android.annotation.SystemApi; import android.net.ConnectivityManager.NetworkCallback; import android.os.Parcel; import android.os.Parcelable; @@ -276,6 +277,7 @@ public final class NetworkCapabilities implements Parcelable { * this network can be used by system apps to upload telemetry data. * @hide */ + @SystemApi public static final int NET_CAPABILITY_OEM_PAID = 22; private static final int MIN_NET_CAPABILITY = NET_CAPABILITY_MMS; -- GitLab From 8faeab8735f1a5759b24583d55853a488639546b Mon Sep 17 00:00:00 2001 From: Mathew Inwood Date: Fri, 16 Mar 2018 14:26:08 +0000 Subject: [PATCH 012/179] Configurable hidden API exemptions. Extend the existing hidden_api_blacklist_exemptions config to support a list of API signature prefixes to exclude from hidden API enforcement. Push this list down to the zygote process when that process is created, and when the list changes. This minimizes overhead, but should also ensure that all new processes get the latest whitelist. Test: $ adb shell settings put global hidden_api_blacklist_exemptions \ Test: Landroid/view/RemoteAnimationDefinition\\\;:Landroid/app/ActivityManager\\\$TaskDescription\\\; Test: Manually verify logcat output from app which uses named APIs Bug: 73337509 (cherry picked from commit 2c6f97d4c9e09a89ef3b0a96539bf6a9ab8d326c) Merged-In: Ib1245b69da4dac50c6968f1be62f1a74591dc433 Change-Id: I7b590f272fdcfcda5f18e216788ac34bc58beaed --- core/java/android/os/ZygoteProcess.java | 56 ++++++++++++++++++- .../android/internal/os/ZygoteConnection.java | 29 +++++++++- .../com/android/internal/os/ZygoteInit.java | 4 ++ .../server/am/ActivityManagerService.java | 22 +++++++- 4 files changed, 105 insertions(+), 6 deletions(-) diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java index ca4c796ab62d..b9dd376f464b 100644 --- a/core/java/android/os/ZygoteProcess.java +++ b/core/java/android/os/ZygoteProcess.java @@ -32,6 +32,7 @@ import java.io.OutputStreamWriter; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.UUID; @@ -157,6 +158,13 @@ public class ZygoteProcess { */ private final Object mLock = new Object(); + /** + * List of exemptions to the API blacklist. These are prefix matches on the runtime format + * symbol signature. Any matching symbol is treated by the runtime as being on the light grey + * list. + */ + private List mApiBlacklistExemptions = Collections.emptyList(); + /** * The state of the connection to the primary zygote. */ @@ -175,7 +183,7 @@ public class ZygoteProcess { * The process will continue running after this function returns. * *

If processes are not enabled, a new thread in the caller's - * process is created and main() of processClass called there. + * process is created and main() of processclass called there. * *

The niceName parameter, if not an empty string, is a custom name to * give to the process instead of using processClass. This allows you to @@ -453,6 +461,49 @@ public class ZygoteProcess { } } + /** + * Push hidden API blacklisting exemptions into the zygote process(es). + * + *

The list of exemptions will take affect for all new processes forked from the zygote after + * this call. + * + * @param exemptions List of hidden API exemption prefixes. + */ + public void setApiBlacklistExemptions(List exemptions) { + synchronized (mLock) { + mApiBlacklistExemptions = exemptions; + maybeSetApiBlacklistExemptions(primaryZygoteState, true); + maybeSetApiBlacklistExemptions(secondaryZygoteState, true); + } + } + + @GuardedBy("mLock") + private void maybeSetApiBlacklistExemptions(ZygoteState state, boolean sendIfEmpty) { + if (state == null || state.isClosed()) { + return; + } + if (!sendIfEmpty && mApiBlacklistExemptions.isEmpty()) { + return; + } + try { + state.writer.write(Integer.toString(mApiBlacklistExemptions.size() + 1)); + state.writer.newLine(); + state.writer.write("--set-api-blacklist-exemptions"); + state.writer.newLine(); + for (int i = 0; i < mApiBlacklistExemptions.size(); ++i) { + state.writer.write(mApiBlacklistExemptions.get(i)); + state.writer.newLine(); + } + state.writer.flush(); + int status = state.inputStream.readInt(); + if (status != 0) { + Slog.e(LOG_TAG, "Failed to set API blacklist exemptions; status " + status); + } + } catch (IOException ioe) { + Slog.e(LOG_TAG, "Failed to set API blacklist exemptions", ioe); + } + } + /** * Tries to open socket to Zygote process if not already open. If * already open, does nothing. May block and retry. Requires that mLock be held. @@ -467,8 +518,8 @@ public class ZygoteProcess { } catch (IOException ioe) { throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe); } + maybeSetApiBlacklistExemptions(primaryZygoteState, false); } - if (primaryZygoteState.matches(abi)) { return primaryZygoteState; } @@ -480,6 +531,7 @@ public class ZygoteProcess { } catch (IOException ioe) { throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe); } + maybeSetApiBlacklistExemptions(secondaryZygoteState, false); } if (secondaryZygoteState.matches(abi)) { diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java index cd83c57f60f9..5d40a7300919 100644 --- a/core/java/com/android/internal/os/ZygoteConnection.java +++ b/core/java/com/android/internal/os/ZygoteConnection.java @@ -47,6 +47,8 @@ import java.io.IOException; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import java.util.Arrays; + import libcore.io.IoUtils; /** @@ -159,6 +161,11 @@ class ZygoteConnection { return null; } + if (parsedArgs.apiBlacklistExemptions != null) { + handleApiBlacklistExemptions(parsedArgs.apiBlacklistExemptions); + return null; + } + if (parsedArgs.permittedCapabilities != 0 || parsedArgs.effectiveCapabilities != 0) { throw new ZygoteSecurityException("Client may not specify capabilities: " + "permitted=0x" + Long.toHexString(parsedArgs.permittedCapabilities) + @@ -278,6 +285,15 @@ class ZygoteConnection { } } + private void handleApiBlacklistExemptions(String[] exemptions) { + try { + ZygoteInit.setApiBlacklistExemptions(exemptions); + mSocketOutStream.writeInt(0); + } catch (IOException ioe) { + throw new IllegalStateException("Error writing to command socket", ioe); + } + } + protected void preload() { ZygoteInit.lazyPreload(); } @@ -438,6 +454,12 @@ class ZygoteConnection { */ boolean startChildZygote; + /** + * Exemptions from API blacklisting. These are sent to the pre-forked zygote at boot time, + * or when they change, via --set-api-blacklist-exemptions. + */ + String[] apiBlacklistExemptions; + /** * Constructs instance and parses args * @param args zygote command-line args @@ -592,6 +614,11 @@ class ZygoteConnection { preloadDefault = true; } else if (arg.equals("--start-child-zygote")) { startChildZygote = true; + } else if (arg.equals("--set-api-blacklist-exemptions")) { + // consume all remaining args; this is a stand-alone command, never included + // with the regular fork command. + apiBlacklistExemptions = Arrays.copyOfRange(args, curArg + 1, args.length); + curArg = args.length; } else { break; } @@ -606,7 +633,7 @@ class ZygoteConnection { throw new IllegalArgumentException( "Unexpected arguments after --preload-package."); } - } else if (!preloadDefault) { + } else if (!preloadDefault && apiBlacklistExemptions == null) { if (!seenRuntimeArgs) { throw new IllegalArgumentException("Unexpected argument : " + args[curArg]); } diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java index 9467eccd3ff7..c5d41db934da 100644 --- a/core/java/com/android/internal/os/ZygoteInit.java +++ b/core/java/com/android/internal/os/ZygoteInit.java @@ -514,6 +514,10 @@ public class ZygoteInit { /* should never reach here */ } + public static void setApiBlacklistExemptions(String[] exemptions) { + VMRuntime.getRuntime().setHiddenApiExemptions(exemptions); + } + /** * Creates a PathClassLoader for the given class path that is associated with a shared * namespace, i.e., this classloader can access platform-private native libraries. The diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index e3584e639abc..998bb49be7d8 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -2873,13 +2873,15 @@ public class ActivityManagerService extends IActivityManager.Stub } /** - * Encapsulates the globla setting "hidden_api_blacklist_exemptions", including tracking the + * Encapsulates the global setting "hidden_api_blacklist_exemptions", including tracking the * latest value via a content observer. */ static class HiddenApiBlacklist extends ContentObserver { private final Context mContext; private boolean mBlacklistDisabled; + private String mExemptionsStr; + private List mExemptions = Collections.emptyList(); public HiddenApiBlacklist(Handler handler, Context context) { super(handler); @@ -2895,8 +2897,22 @@ public class ActivityManagerService extends IActivityManager.Stub } private void update() { - mBlacklistDisabled = "*".equals(Settings.Global.getString(mContext.getContentResolver(), - Settings.Global.HIDDEN_API_BLACKLIST_EXEMPTIONS)); + String exemptions = Settings.Global.getString(mContext.getContentResolver(), + Settings.Global.HIDDEN_API_BLACKLIST_EXEMPTIONS); + if (!TextUtils.equals(exemptions, mExemptionsStr)) { + mExemptionsStr = exemptions; + if ("*".equals(exemptions)) { + mBlacklistDisabled = true; + mExemptions = Collections.emptyList(); + } else { + mBlacklistDisabled = false; + mExemptions = TextUtils.isEmpty(exemptions) + ? Collections.emptyList() + : Arrays.asList(exemptions.split(":")); + } + zygoteProcess.setApiBlacklistExemptions(mExemptions); + } + } boolean isDisabled() { -- GitLab From 78ae1060c6950c274ef833a5ef64fdd5787056d2 Mon Sep 17 00:00:00 2001 From: Benjamin Franz Date: Mon, 26 Mar 2018 11:01:32 +0100 Subject: [PATCH 013/179] Update to lock task features API 1. Throw if notifications is given without home feature, as this configuration allows potential escape routes. 2. Default power button menu to be on in order to be consistent with existing lock task behaviour before P. Bug: 71790952 Bug: 74381063 Test: manual Change-Id: I2383c087a18739a158d55edcd84d22d1abdb887a --- .../app/admin/DevicePolicyManager.java | 42 +++++++++---------- .../DevicePolicyManagerService.java | 7 +++- .../devicepolicy/DevicePolicyManagerTest.java | 3 +- 3 files changed, 28 insertions(+), 24 deletions(-) diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 4cb7f89cec5c..9da432a91fe5 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -1612,8 +1612,6 @@ public class DevicePolicyManager { *

  • keyguard * * - * This is the default configuration for LockTask. - * * @see #setLockTaskFeatures(ComponentName, int) */ public static final int LOCK_TASK_FEATURE_NONE = 0; @@ -1631,7 +1629,10 @@ public class DevicePolicyManager { /** * Enable notifications during LockTask mode. This includes notification icons on the status * bar, heads-up notifications, and the expandable notification shade. Note that the Quick - * Settings panel will still be disabled. + * Settings panel remains disabled. This feature flag can only be used in combination with + * {@link #LOCK_TASK_FEATURE_HOME}. {@link #setLockTaskFeatures(ComponentName, int)} + * throws an {@link IllegalArgumentException} if this feature flag is defined without + * {@link #LOCK_TASK_FEATURE_HOME}. * * @see #setLockTaskFeatures(ComponentName, int) */ @@ -1664,6 +1665,9 @@ public class DevicePolicyManager { * the user long-presses the power button, for example. Note that the user may not be able to * power off the device if this flag is not set. * + *

    This flag is enabled by default until {@link #setLockTaskFeatures(ComponentName, int)} is + * called for the first time. + * * @see #setLockTaskFeatures(ComponentName, int) */ public static final int LOCK_TASK_FEATURE_GLOBAL_ACTIONS = 1 << 4; @@ -7167,30 +7171,24 @@ public class DevicePolicyManager { } /** - * Sets which system features to enable for LockTask mode. - *

    - * Feature flags set through this method will only take effect for the duration when the device - * is in LockTask mode. If this method is not called, none of the features listed here will be - * enabled. - *

    - * This function can only be called by the device owner, a profile owner of an affiliated user - * or profile, or the profile owner when no device owner is set. See {@link #isAffiliatedUser}. - * Any features set via this method will be cleared if the user becomes unaffiliated. + * Sets which system features are enabled when the device runs in lock task mode. This method + * doesn't affect the features when lock task mode is inactive. Any system features not included + * in {@code flags} are implicitly disabled when calling this method. By default, only + * {@link #LOCK_TASK_FEATURE_GLOBAL_ACTIONS} is enabled—all the other features are disabled. To + * disable the global actions dialog, call this method omitting + * {@link #LOCK_TASK_FEATURE_GLOBAL_ACTIONS}. + * + *

    This method can only be called by the device owner, a profile owner of an affiliated + * user or profile, or the profile owner when no device owner is set. See + * {@link #isAffiliatedUser}. + * Any features set using this method are cleared if the user becomes unaffiliated. * * @param admin Which {@link DeviceAdminReceiver} this request is associated with. - * @param flags Bitfield of feature flags: - * {@link #LOCK_TASK_FEATURE_NONE} (default), - * {@link #LOCK_TASK_FEATURE_SYSTEM_INFO}, - * {@link #LOCK_TASK_FEATURE_NOTIFICATIONS}, - * {@link #LOCK_TASK_FEATURE_HOME}, - * {@link #LOCK_TASK_FEATURE_OVERVIEW}, - * {@link #LOCK_TASK_FEATURE_GLOBAL_ACTIONS}, - * {@link #LOCK_TASK_FEATURE_KEYGUARD} + * @param flags The system features enabled during lock task mode. * @throws SecurityException if {@code admin} is not the device owner, the profile owner of an * affiliated user or profile, or the profile owner when no device owner is set. * @see #isAffiliatedUser - * @throws SecurityException if {@code admin} is not the device owner or the profile owner. - */ + **/ public void setLockTaskFeatures(@NonNull ComponentName admin, @LockTaskFeature int flags) { throwIfParentInstance("setLockTaskFeatures"); if (mService != null) { diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 2e07703020e8..6292ab8abb65 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -51,6 +51,7 @@ import static android.app.admin.DevicePolicyManager.ID_TYPE_MEID; import static android.app.admin.DevicePolicyManager.ID_TYPE_SERIAL; import static android.app.admin.DevicePolicyManager.LEAVE_ALL_SYSTEM_APPS_ENABLED; import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_HOME; +import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_NOTIFICATIONS; import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_OVERVIEW; import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX; import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; @@ -592,7 +593,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { List mLockTaskPackages = new ArrayList<>(); // Bitfield of feature flags to be enabled during LockTask mode. - int mLockTaskFeatures = DevicePolicyManager.LOCK_TASK_FEATURE_NONE; + // We default on the power button menu, in order to be consistent with pre-P behaviour. + int mLockTaskFeatures = DevicePolicyManager.LOCK_TASK_FEATURE_GLOBAL_ACTIONS; boolean mStatusBarDisabled = false; @@ -9882,6 +9884,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { boolean hasOverview = (flags & LOCK_TASK_FEATURE_OVERVIEW) != 0; Preconditions.checkArgument(hasHome || !hasOverview, "Cannot use LOCK_TASK_FEATURE_OVERVIEW without LOCK_TASK_FEATURE_HOME"); + boolean hasNotification = (flags & LOCK_TASK_FEATURE_NOTIFICATIONS) != 0; + Preconditions.checkArgument(hasHome || !hasNotification, + "Cannot use LOCK_TASK_FEATURE_NOTIFICATIONS without LOCK_TASK_FEATURE_HOME"); final int userHandle = mInjector.userHandleGetCallingUserId(); synchronized (this) { diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java index 43490d312dbc..873fbfff55d0 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -3723,7 +3723,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { } private void verifyLockTaskState(int userId) throws Exception { - verifyLockTaskState(userId, new String[0], DevicePolicyManager.LOCK_TASK_FEATURE_NONE); + verifyLockTaskState(userId, new String[0], + DevicePolicyManager.LOCK_TASK_FEATURE_GLOBAL_ACTIONS); } private void verifyLockTaskState(int userId, String[] packages, int flags) throws Exception { -- GitLab From b559e75ddc6377c7cf7f554235cca4ad34b2fe64 Mon Sep 17 00:00:00 2001 From: Mathew Inwood Date: Wed, 28 Mar 2018 13:01:37 +0100 Subject: [PATCH 014/179] Use commas to separate API exemptions list, not colon. A colon appears in the type signature of a field, so is not safe to use in this context. Test: m Test: $ adb shell settings put global hidden_api_blacklist_exemptions \ Test: > Landroid/app/Activity;->mResumed:Z,Landroid/view/RemoteAnimationDefinition\\\; Bug: 73337509 (cherry picked from commit 51a1d4453c44cdb12bbb8a27aa9ef40a431b0f6a) Merged-In: Ia9171fecc9c3ed265b87921b31458de25304486e Change-Id: I112db6bf0a54dbf7c7e229eb18f29d5034d42e10 --- .../core/java/com/android/server/am/ActivityManagerService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 998bb49be7d8..08e5d44c8832 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -2908,7 +2908,7 @@ public class ActivityManagerService extends IActivityManager.Stub mBlacklistDisabled = false; mExemptions = TextUtils.isEmpty(exemptions) ? Collections.emptyList() - : Arrays.asList(exemptions.split(":")); + : Arrays.asList(exemptions.split(",")); } zygoteProcess.setApiBlacklistExemptions(mExemptions); } -- GitLab From 23bc81d34a2c605fd3c18f341a32860d1d4790b4 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 27 Mar 2018 14:25:55 -0600 Subject: [PATCH 015/179] API for granting/revoking runtime permissions. Expose these as public API, since they're useful for devices where the raw "pm grant" or "pm revoke" commands can be flaky. Test: builds, boots Bug: 75315597 Change-Id: I2de94587945f08fd09ebe729bb9872542a11ef26 --- api/current.txt | 4 ++ api/test-current.txt | 6 +- core/java/android/app/UiAutomation.java | 84 +++++++++++++++++++------ core/res/AndroidManifest.xml | 4 +- 4 files changed, 75 insertions(+), 23 deletions(-) diff --git a/api/current.txt b/api/current.txt index 5e7fa591385e..9f9f7b845c8a 100644 --- a/api/current.txt +++ b/api/current.txt @@ -6112,8 +6112,12 @@ package android.app { method public android.view.WindowAnimationFrameStats getWindowAnimationFrameStats(); method public android.view.WindowContentFrameStats getWindowContentFrameStats(int); method public java.util.List getWindows(); + method public void grantRuntimePermission(java.lang.String, java.lang.String); + method public void grantRuntimePermissionAsUser(java.lang.String, java.lang.String, android.os.UserHandle); method public boolean injectInputEvent(android.view.InputEvent, boolean); method public boolean performGlobalAction(int); + method public void revokeRuntimePermission(java.lang.String, java.lang.String); + method public void revokeRuntimePermissionAsUser(java.lang.String, java.lang.String, android.os.UserHandle); method public void setOnAccessibilityEventListener(android.app.UiAutomation.OnAccessibilityEventListener); method public boolean setRotation(int); method public void setRunAsMonkey(boolean); diff --git a/api/test-current.txt b/api/test-current.txt index e84d204919f0..be294e31fc32 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -1,8 +1,10 @@ package android { public static final class Manifest.permission { + field public static final java.lang.String ACTIVITY_EMBEDDING = "android.permission.ACTIVITY_EMBEDDING"; field public static final java.lang.String BRIGHTNESS_SLIDER_USAGE = "android.permission.BRIGHTNESS_SLIDER_USAGE"; field public static final java.lang.String CONFIGURE_DISPLAY_BRIGHTNESS = "android.permission.CONFIGURE_DISPLAY_BRIGHTNESS"; + field public static final java.lang.String MANAGE_ACTIVITY_STACKS = "android.permission.MANAGE_ACTIVITY_STACKS"; } } @@ -127,8 +129,8 @@ package android.app { public final class UiAutomation { method public void destroy(); method public android.os.ParcelFileDescriptor[] executeShellCommandRw(java.lang.String); - method public boolean grantRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle); - method public boolean revokeRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle); + method public deprecated boolean grantRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle); + method public deprecated boolean revokeRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle); } public class UiModeManager { diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java index 8f0168530273..bd4933a2081c 100644 --- a/core/java/android/app/UiAutomation.java +++ b/core/java/android/app/UiAutomation.java @@ -24,7 +24,6 @@ import android.accessibilityservice.IAccessibilityServiceConnection; import android.annotation.NonNull; import android.annotation.TestApi; import android.graphics.Bitmap; -import android.graphics.Canvas; import android.graphics.Point; import android.graphics.Rect; import android.graphics.Region; @@ -47,6 +46,7 @@ import android.view.accessibility.AccessibilityInteractionClient; import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.AccessibilityWindowInfo; import android.view.accessibility.IAccessibilityInteractionConnection; + import libcore.io.IoUtils; import java.io.IOException; @@ -876,16 +876,36 @@ public final class UiAutomation { } /** - * Grants a runtime permission to a package for a user. + * Grants a runtime permission to a package. * @param packageName The package to which to grant. * @param permission The permission to grant. - * @return Whether granting succeeded. - * + * @throws SecurityException if unable to grant the permission. + */ + public void grantRuntimePermission(String packageName, String permission) { + grantRuntimePermissionAsUser(packageName, permission, android.os.Process.myUserHandle()); + } + + /** + * @deprecated replaced by + * {@link #grantRuntimePermissionAsUser(String, String, UserHandle)}. * @hide */ + @Deprecated @TestApi public boolean grantRuntimePermission(String packageName, String permission, UserHandle userHandle) { + grantRuntimePermissionAsUser(packageName, permission, userHandle); + return true; + } + + /** + * Grants a runtime permission to a package for a user. + * @param packageName The package to which to grant. + * @param permission The permission to grant. + * @throws SecurityException if unable to grant the permission. + */ + public void grantRuntimePermissionAsUser(String packageName, String permission, + UserHandle userHandle) { synchronized (mLock) { throwIfNotConnectedLocked(); } @@ -896,25 +916,42 @@ public final class UiAutomation { // Calling out without a lock held. mUiAutomationConnection.grantRuntimePermission(packageName, permission, userHandle.getIdentifier()); - // TODO: The package manager API should return boolean. - return true; - } catch (RemoteException re) { - Log.e(LOG_TAG, "Error granting runtime permission", re); + } catch (Exception e) { + throw new SecurityException("Error granting runtime permission", e); } - return false; } /** - * Revokes a runtime permission from a package for a user. - * @param packageName The package from which to revoke. - * @param permission The permission to revoke. - * @return Whether revoking succeeded. - * + * Revokes a runtime permission from a package. + * @param packageName The package to which to grant. + * @param permission The permission to grant. + * @throws SecurityException if unable to revoke the permission. + */ + public void revokeRuntimePermission(String packageName, String permission) { + revokeRuntimePermissionAsUser(packageName, permission, android.os.Process.myUserHandle()); + } + + /** + * @deprecated replaced by + * {@link #revokeRuntimePermissionAsUser(String, String, UserHandle)}. * @hide */ + @Deprecated @TestApi public boolean revokeRuntimePermission(String packageName, String permission, UserHandle userHandle) { + revokeRuntimePermissionAsUser(packageName, permission, userHandle); + return true; + } + + /** + * Revokes a runtime permission from a package. + * @param packageName The package to which to grant. + * @param permission The permission to grant. + * @throws SecurityException if unable to revoke the permission. + */ + public void revokeRuntimePermissionAsUser(String packageName, String permission, + UserHandle userHandle) { synchronized (mLock) { throwIfNotConnectedLocked(); } @@ -925,12 +962,9 @@ public final class UiAutomation { // Calling out without a lock held. mUiAutomationConnection.revokeRuntimePermission(packageName, permission, userHandle.getIdentifier()); - // TODO: The package manager API should return boolean. - return true; - } catch (RemoteException re) { - Log.e(LOG_TAG, "Error revoking runtime permission", re); + } catch (Exception e) { + throw new SecurityException("Error granting runtime permission", e); } - return false; } /** @@ -949,6 +983,7 @@ public final class UiAutomation { synchronized (mLock) { throwIfNotConnectedLocked(); } + warnIfBetterCommand(command); ParcelFileDescriptor source = null; ParcelFileDescriptor sink = null; @@ -991,6 +1026,7 @@ public final class UiAutomation { synchronized (mLock) { throwIfNotConnectedLocked(); } + warnIfBetterCommand(command); ParcelFileDescriptor source_read = null; ParcelFileDescriptor sink_read = null; @@ -1056,6 +1092,16 @@ public final class UiAutomation { } } + private void warnIfBetterCommand(String cmd) { + if (cmd.startsWith("pm grant ")) { + Log.w(LOG_TAG, "UiAutomation.grantRuntimePermission() " + + "is more robust and should be used instead of 'pm grant'"); + } else if (cmd.startsWith("pm revoke ")) { + Log.w(LOG_TAG, "UiAutomation.revokeRuntimePermission() " + + "is more robust and should be used instead of 'pm revoke'"); + } + } + private class IAccessibilityServiceClientImpl extends IAccessibilityServiceClientWrapper { public IAccessibilityServiceClientImpl(Looper looper) { diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index c4d3667badde..a35b5ff3a485 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -2003,11 +2003,11 @@ - + - + -- GitLab From 39b9fb373c8da878199e0da39647db6fca53b4de Mon Sep 17 00:00:00 2001 From: Jason Monk Date: Tue, 27 Mar 2018 10:45:23 -0400 Subject: [PATCH 016/179] Slices: Fix up some formatting and add examples Test: TH Change-Id: Ia95306d9a44e6a9861958bd7f2b3b697a7ecb4cc Fixes: 76462142 Fixes: 76461933 --- core/java/android/app/slice/SliceManager.java | 28 +++++++++++++------ 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/core/java/android/app/slice/SliceManager.java b/core/java/android/app/slice/SliceManager.java index 1afe53d8a7b5..88b198b40be9 100644 --- a/core/java/android/app/slice/SliceManager.java +++ b/core/java/android/app/slice/SliceManager.java @@ -81,6 +81,17 @@ public class SliceManager { * An activity can be statically linked to a slice uri by including a meta-data item * for this key that contains a valid slice uri for the same application declaring * the activity. + * + *

    +     * {@literal
    +     * 
    +     *     
    +     *  }
    +     * 
    + * + * @see #mapIntentToUri(Intent) + * @see SliceProvider#onMapIntentToUri(Intent) */ public static final String SLICE_METADATA_KEY = "android.metadata.SLICE_URI"; @@ -257,16 +268,17 @@ public class SliceManager { *

    * This goes through a several stage resolution process to determine if any slice * can represent this intent. - * - If the intent contains data that {@link ContentResolver#getType} is - * {@link SliceProvider#SLICE_TYPE} then the data will be returned. - * - If the intent with {@link #CATEGORY_SLICE} added resolves to a provider, then + *

      + *
    1. If the intent contains data that {@link ContentResolver#getType} is + * {@link SliceProvider#SLICE_TYPE} then the data will be returned.
    2. + *
    3. If the intent with {@link #CATEGORY_SLICE} added resolves to a provider, then * the provider will be asked to {@link SliceProvider#onMapIntentToUri} and that result - * will be returned. - * - Lastly, if the intent explicitly points at an activity, and that activity has + * will be returned.
    4. + *
    5. Lastly, if the intent explicitly points at an activity, and that activity has * meta-data for key {@link #SLICE_METADATA_KEY}, then the Uri specified there will be - * returned. - * - If no slice is found, then {@code null} is returned. - * + * returned.
    6. + *
    7. If no slice is found, then {@code null} is returned.
    8. + *
    * @param intent The intent associated with a slice. * @return The Slice Uri provided by the app or null if none exists. * @see Slice -- GitLab From 9697c6c5611e7520d5a11c3a938d778c3035071e Mon Sep 17 00:00:00 2001 From: jiabin Date: Tue, 20 Mar 2018 17:13:04 -0700 Subject: [PATCH 017/179] Make back mic available when getting all available mic. Remove the checkType of filtering back mic. Make getAddress() public in AudioDeviceInfo to distinguish different built in mic. Bug: 64038649 Test: run cts Change-Id: I943b7f74f44db7068644f5ffa1b5410cbf567f11 --- api/current.txt | 2 ++ media/java/android/media/AudioDeviceInfo.java | 3 +-- media/java/android/media/AudioManager.java | 3 +-- media/java/android/media/MicrophoneInfo.java | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/api/current.txt b/api/current.txt index 6a9f00e46b07..09fb7a8be460 100644 --- a/api/current.txt +++ b/api/current.txt @@ -21926,6 +21926,7 @@ package android.media { } public final class AudioDeviceInfo { + method public java.lang.String getAddress(); method public int[] getChannelCounts(); method public int[] getChannelIndexMasks(); method public int[] getChannelMasks(); @@ -25122,6 +25123,7 @@ package android.media { } public final class MicrophoneInfo { + method public java.lang.String getAddress(); method public java.util.List> getChannelMapping(); method public java.lang.String getDescription(); method public int getDirectionality(); diff --git a/media/java/android/media/AudioDeviceInfo.java b/media/java/android/media/AudioDeviceInfo.java index 86dfc9c88723..ca895fcdfc4a 100644 --- a/media/java/android/media/AudioDeviceInfo.java +++ b/media/java/android/media/AudioDeviceInfo.java @@ -226,11 +226,10 @@ public final class AudioDeviceInfo { } /** - * @hide * @return The "address" string of the device. This generally contains device-specific * parameters. */ - public String getAddress() { + public @NonNull String getAddress() { return mPort.address(); } diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index 1536bb688073..a0d168c508be 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -4595,8 +4595,7 @@ public class AudioManager { private static boolean checkTypes(AudioDevicePort port) { return AudioDeviceInfo.convertInternalDeviceToDeviceType(port.type()) != - AudioDeviceInfo.TYPE_UNKNOWN && - port.type() != AudioSystem.DEVICE_IN_BACK_MIC; + AudioDeviceInfo.TYPE_UNKNOWN; } /** diff --git a/media/java/android/media/MicrophoneInfo.java b/media/java/android/media/MicrophoneInfo.java index 004efea64d2d..d6399a4163fe 100644 --- a/media/java/android/media/MicrophoneInfo.java +++ b/media/java/android/media/MicrophoneInfo.java @@ -17,6 +17,7 @@ package android.media; import android.annotation.IntDef; +import android.annotation.NonNull; import android.util.Pair; import java.lang.annotation.Retention; @@ -224,12 +225,11 @@ public final class MicrophoneInfo { } /** - * @hide * Returns The "address" string of the microphone that corresponds to the * address returned by {@link AudioDeviceInfo#getAddress()} * @return the address of the microphone */ - public String getAddress() { + public @NonNull String getAddress() { return mAddress; } -- GitLab From 64481195e13e2dd7197fff569344e5a263b7871a Mon Sep 17 00:00:00 2001 From: Leon Scroggins III Date: Wed, 28 Mar 2018 09:17:42 -0400 Subject: [PATCH 018/179] Rename ImageDecoder.setResize Bug: 76448408 Bug: 73537624 Test: Ib40d65c68a6c709b6456f2145ad8a5557a941494 setResize is two verbs, and "resize" implies we're changing the size of an existing object. In truth, the method specifies the desired size. So rename setResize(int, int) to setTargetSize, which clearly specifies the behavior. Rename setResize(int sampleSize) to setSampleSize. Hide getSampledSize, which looks too similar to the newly named setSampleSize. In addition, b/76448408 suggests hiding it. It isn't really necessary anyway, since a client can just call setSampleSize - no need to query and call setTargetSize manually. Since there is no way for a client to know that a RAW image couldn't be decoded to the desired size (could previously be done with getSampledSize), make setSampleSize do the extra scaling. This is a better API anyway. Change-Id: I84c29fdc6bdfb999a7f712fdc069304ae9676ba6 --- api/current.txt | 5 +- api/removed.txt | 2 + .../java/android/graphics/ImageDecoder.java | 85 ++++++++++++++++--- 3 files changed, 78 insertions(+), 14 deletions(-) diff --git a/api/current.txt b/api/current.txt index dda00ba8e94d..a01ef0d4a09c 100644 --- a/api/current.txt +++ b/api/current.txt @@ -13635,7 +13635,6 @@ package android.graphics { method public android.graphics.ImageDecoder.OnPartialImageListener getOnPartialImageListener(); method public android.graphics.PostProcessor getPostProcessor(); method public boolean getRequireUnpremultiplied(); - method public android.util.Size getSampledSize(int); method public android.graphics.ImageDecoder setAllocator(int); method public android.graphics.ImageDecoder setConserveMemory(boolean); method public android.graphics.ImageDecoder setCrop(android.graphics.Rect); @@ -13644,8 +13643,8 @@ package android.graphics { method public android.graphics.ImageDecoder setOnPartialImageListener(android.graphics.ImageDecoder.OnPartialImageListener); method public android.graphics.ImageDecoder setPostProcessor(android.graphics.PostProcessor); method public android.graphics.ImageDecoder setRequireUnpremultiplied(boolean); - method public android.graphics.ImageDecoder setResize(int, int); - method public android.graphics.ImageDecoder setResize(int); + method public android.graphics.ImageDecoder setSampleSize(int); + method public android.graphics.ImageDecoder setTargetSize(int, int); field public static final int ALLOCATOR_DEFAULT = 0; // 0x0 field public static final int ALLOCATOR_HARDWARE = 3; // 0x3 field public static final int ALLOCATOR_SHARED_MEMORY = 2; // 0x2 diff --git a/api/removed.txt b/api/removed.txt index 9fe25c90872b..5863e777bb14 100644 --- a/api/removed.txt +++ b/api/removed.txt @@ -184,6 +184,8 @@ package android.graphics { public final class ImageDecoder implements java.lang.AutoCloseable { method public deprecated boolean getAsAlphaMask(); method public deprecated android.graphics.ImageDecoder setAsAlphaMask(boolean); + method public deprecated android.graphics.ImageDecoder setResize(int, int); + method public deprecated android.graphics.ImageDecoder setResize(int); field public static final deprecated int ERROR_SOURCE_ERROR = 3; // 0x3 field public static final deprecated int ERROR_SOURCE_EXCEPTION = 1; // 0x1 field public static final deprecated int ERROR_SOURCE_INCOMPLETE = 2; // 0x2 diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java index 5ca0ad63159f..6939907bb419 100644 --- a/graphics/java/android/graphics/ImageDecoder.java +++ b/graphics/java/android/graphics/ImageDecoder.java @@ -766,7 +766,7 @@ public final class ImageDecoder implements AutoCloseable { * *

    This takes an input that functions like * {@link BitmapFactory.Options#inSampleSize}. It returns a width and - * height that can be acheived by sampling the encoded image. Other widths + * height that can be achieved by sampling the encoded image. Other widths * and heights may be supported, but will require an additional (internal) * scaling step. Such internal scaling is *not* supported with * {@link #setRequireUnpremultiplied} set to {@code true}.

    @@ -774,6 +774,8 @@ public final class ImageDecoder implements AutoCloseable { * @param sampleSize Sampling rate of the encoded image. * @return {@link android.util.Size} of the width and height after * sampling. + * + * @hide */ @NonNull public Size getSampledSize(int sampleSize) { @@ -789,14 +791,28 @@ public final class ImageDecoder implements AutoCloseable { } // Modifiers + /** @removed + * @deprecated Renamed to {@link #setTargetSize}. + */ + @java.lang.Deprecated + public ImageDecoder setResize(int width, int height) { + return this.setTargetSize(width, height); + } + /** - * Resize the output to have the following size. + * Specify the size of the output {@link Drawable} or {@link Bitmap}. + * + *

    By default, the output size will match the size of the encoded + * image, which can be retrieved from the {@link ImageInfo} in + * {@link OnHeaderDecodedListener#onHeaderDecoded}.

    + * + *

    Only the last call to this or {@link #setSampleSize} is respected.

    * * @param width must be greater than 0. * @param height must be greater than 0. * @return this object for chaining. */ - public ImageDecoder setResize(int width, int height) { + public ImageDecoder setTargetSize(int width, int height) { if (width <= 0 || height <= 0) { throw new IllegalArgumentException("Dimensions must be positive! " + "provided (" + width + ", " + height + ")"); @@ -807,18 +823,65 @@ public final class ImageDecoder implements AutoCloseable { return this; } + /** @removed + * @deprecated Renamed to {@link #setSampleSize}. + */ + @java.lang.Deprecated + public ImageDecoder setResize(int sampleSize) { + return this.setSampleSize(sampleSize); + } + + private int getTargetDimension(int original, int sampleSize, int computed) { + // Sampling will never result in a smaller size than 1. + if (sampleSize >= original) { + return 1; + } + + // Use integer divide to find the desired size. If that is what + // getSampledSize computed, that is the size to use. + int target = original / sampleSize; + if (computed == target) { + return computed; + } + + // If sampleSize does not divide evenly into original, the decoder + // may round in either direction. It just needs to get a result that + // is close. + int reverse = computed * sampleSize; + if (Math.abs(reverse - original) < sampleSize) { + // This is the size that can be decoded most efficiently. + return computed; + } + + // The decoder could not get close (e.g. it is a DNG image). + return target; + } + /** - * Resize based on a sample size. + * Set the target size with a sampleSize. + * + *

    By default, the output size will match the size of the encoded + * image, which can be retrieved from the {@link ImageInfo} in + * {@link OnHeaderDecodedListener#onHeaderDecoded}.

    * - *

    This has the same effect as passing the result of - * {@link #getSampledSize} to {@link #setResize(int, int)}.

    + *

    Requests the decoder to subsample the original image, returning a + * smaller image to save memory. The sample size is the number of pixels + * in either dimension that correspond to a single pixel in the output. + * For example, sampleSize == 4 returns an image that is 1/4 the + * width/height of the original, and 1/16 the number of pixels.

    + * + *

    Must be greater than or equal to 1.

    + * + *

    Only the last call to this or {@link #setTargetSize} is respected.

    * * @param sampleSize Sampling rate of the encoded image. * @return this object for chaining. */ - public ImageDecoder setResize(int sampleSize) { + public ImageDecoder setSampleSize(int sampleSize) { Size size = this.getSampledSize(sampleSize); - return this.setResize(size.getWidth(), size.getHeight()); + int targetWidth = getTargetDimension(mWidth, sampleSize, size.getWidth()); + int targetHeight = getTargetDimension(mHeight, sampleSize, size.getHeight()); + return this.setTargetSize(targetWidth, targetHeight); } private boolean requestedResize() { @@ -972,8 +1035,8 @@ public final class ImageDecoder implements AutoCloseable { * Crop the output to {@code subset} of the (possibly) scaled image. * *

    {@code subset} must be contained within the size set by - * {@link #setResize} or the bounds of the image if setResize was not - * called. Otherwise an {@link IllegalStateException} will be thrown by + * {@link #setTargetSize} or the bounds of the image if setTargetSize was + * not called. Otherwise an {@link IllegalStateException} will be thrown by * {@link #decodeDrawable}/{@link #decodeBitmap}.

    * *

    NOT intended as a replacement for @@ -1353,7 +1416,7 @@ public final class ImageDecoder implements AutoCloseable { float scale = (float) dstDensity / srcDensity; int scaledWidth = (int) (decoder.mWidth * scale + 0.5f); int scaledHeight = (int) (decoder.mHeight * scale + 0.5f); - decoder.setResize(scaledWidth, scaledHeight); + decoder.setTargetSize(scaledWidth, scaledHeight); return dstDensity; } -- GitLab From 36716eb4709503f2ef370c6f67273440cd91d18c Mon Sep 17 00:00:00 2001 From: Brian Young Date: Fri, 23 Feb 2018 18:04:20 +0000 Subject: [PATCH 019/179] Add "Unlocked device required" key API This adds the API methods and values for keyguard-bound keys, but contains none of the actual functionality. Test: CTS tests in CtsKeystoreTestCases Bug: 67752510 Merged-In: Iccd7dafd77258d903d11353e02ba3ab956050c40 Change-Id: Iccd7dafd77258d903d11353e02ba3ab956050c40 (cherry picked from commit fd75c7232aebc8690f004de3486b3b9a44f3e0b0) --- .../security/keymaster/KeymasterDefs.java | 3 ++ keystore/java/android/security/KeyStore.java | 5 ++- .../keystore/KeyGenParameterSpec.java | 30 +++++++++++++- .../security/keystore/KeyProtection.java | 39 ++++++++++++++++--- .../security/keystore/KeymasterUtils.java | 5 ++- .../policy/keyguard/KeyguardStateMonitor.java | 2 +- 6 files changed, 71 insertions(+), 13 deletions(-) diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java index 1d1333504350..f4dcce1e7e58 100644 --- a/core/java/android/security/keymaster/KeymasterDefs.java +++ b/core/java/android/security/keymaster/KeymasterDefs.java @@ -75,6 +75,7 @@ public final class KeymasterDefs { public static final int KM_TAG_ALLOW_WHILE_ON_BODY = KM_BOOL | 506; public static final int KM_TAG_TRUSTED_USER_PRESENCE_REQUIRED = KM_BOOL | 507; public static final int KM_TAG_TRUSTED_CONFIRMATION_REQUIRED = KM_BOOL | 508; + public static final int KM_TAG_UNLOCKED_DEVICE_REQUIRED = KM_BOOL | 509; public static final int KM_TAG_ALL_APPLICATIONS = KM_BOOL | 600; public static final int KM_TAG_APPLICATION_ID = KM_BYTES | 601; @@ -216,6 +217,7 @@ public final class KeymasterDefs { public static final int KM_ERROR_MISSING_MIN_MAC_LENGTH = -58; public static final int KM_ERROR_UNSUPPORTED_MIN_MAC_LENGTH = -59; public static final int KM_ERROR_CANNOT_ATTEST_IDS = -66; + public static final int KM_ERROR_DEVICE_LOCKED = -72; public static final int KM_ERROR_UNIMPLEMENTED = -100; public static final int KM_ERROR_VERSION_MISMATCH = -101; public static final int KM_ERROR_UNKNOWN_ERROR = -1000; @@ -262,6 +264,7 @@ public final class KeymasterDefs { sErrorCodeToString.put(KM_ERROR_INVALID_MAC_LENGTH, "Invalid MAC or authentication tag length"); sErrorCodeToString.put(KM_ERROR_CANNOT_ATTEST_IDS, "Unable to attest device ids"); + sErrorCodeToString.put(KM_ERROR_DEVICE_LOCKED, "Device locked"); sErrorCodeToString.put(KM_ERROR_UNIMPLEMENTED, "Not implemented"); sErrorCodeToString.put(KM_ERROR_UNKNOWN_ERROR, "Unknown error"); } diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java index 1924bbe764c7..33ce582eda96 100644 --- a/keystore/java/android/security/KeyStore.java +++ b/keystore/java/android/security/KeyStore.java @@ -278,7 +278,7 @@ public class KeyStore { /** * Attempt to lock the keystore for {@code user}. * - * @param user Android user to lock. + * @param userId Android user to lock. * @return whether {@code user}'s keystore was locked. */ public boolean lock(int userId) { @@ -299,7 +299,7 @@ public class KeyStore { * This is required before keystore entries created with FLAG_ENCRYPTED can be accessed or * created. * - * @param user Android user ID to operate on + * @param userId Android user ID to operate on * @param password user's keystore password. Should be the most recent value passed to * {@link #onUserPasswordChanged} for the user. * @@ -545,6 +545,7 @@ public class KeyStore { try { args = args != null ? args : new KeymasterArguments(); entropy = entropy != null ? entropy : new byte[0]; + // TODO(67752510): Apply USER_ID tag return mBinder.begin(getToken(), alias, purpose, pruneable, args, entropy, uid); } catch (RemoteException e) { Log.w(TAG, "Cannot connect to keystore", e); diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java index 4b9f3c803481..5d596cbbbc44 100644 --- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java +++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java @@ -266,6 +266,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu private final boolean mInvalidatedByBiometricEnrollment; private final boolean mIsStrongBoxBacked; private final boolean mUserConfirmationRequired; + private final boolean mUnlockedDeviceRequired; /** * @hide should be built with Builder @@ -296,7 +297,8 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu boolean userAuthenticationValidWhileOnBody, boolean invalidatedByBiometricEnrollment, boolean isStrongBoxBacked, - boolean userConfirmationRequired) { + boolean userConfirmationRequired, + boolean unlockedDeviceRequired) { if (TextUtils.isEmpty(keyStoreAlias)) { throw new IllegalArgumentException("keyStoreAlias must not be empty"); } @@ -345,6 +347,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu mInvalidatedByBiometricEnrollment = invalidatedByBiometricEnrollment; mIsStrongBoxBacked = isStrongBoxBacked; mUserConfirmationRequired = userConfirmationRequired; + mUnlockedDeviceRequired = unlockedDeviceRequired; } /** @@ -669,6 +672,15 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu return mIsStrongBoxBacked; } + /** + * @hide Returns {@code true} if the key cannot be used unless the device screen is unlocked. + * + * @see Builder#setUnlockedDeviceRequired(boolean) + */ + public boolean isUnlockedDeviceRequired() { + return mUnlockedDeviceRequired; + } + /** * @hide */ @@ -707,6 +719,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu private boolean mInvalidatedByBiometricEnrollment = true; private boolean mIsStrongBoxBacked = false; private boolean mUserConfirmationRequired; + private boolean mUnlockedDeviceRequired = false; /** * Creates a new instance of the {@code Builder}. @@ -1274,6 +1287,18 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu return this; } + /** + * @hide Sets whether the keystore requires the screen to be unlocked before allowing decryption + * using this key. If this is set to {@code true}, any attempt to decrypt using this key + * while the screen is locked will fail. A locked device requires a PIN, password, + * fingerprint, or other trusted factor to access. + */ + @NonNull + public Builder setUnlockedDeviceRequired(boolean unlockedDeviceRequired) { + mUnlockedDeviceRequired = unlockedDeviceRequired; + return this; + } + /** * Builds an instance of {@code KeyGenParameterSpec}. */ @@ -1305,7 +1330,8 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu mUserAuthenticationValidWhileOnBody, mInvalidatedByBiometricEnrollment, mIsStrongBoxBacked, - mUserConfirmationRequired); + mUserConfirmationRequired, + mUnlockedDeviceRequired); } } } diff --git a/keystore/java/android/security/keystore/KeyProtection.java b/keystore/java/android/security/keystore/KeyProtection.java index 95eeec704847..cc7870ce1889 100644 --- a/keystore/java/android/security/keystore/KeyProtection.java +++ b/keystore/java/android/security/keystore/KeyProtection.java @@ -224,12 +224,13 @@ public final class KeyProtection implements ProtectionParameter, UserAuthArgs { private final boolean mRandomizedEncryptionRequired; private final boolean mUserAuthenticationRequired; private final int mUserAuthenticationValidityDurationSeconds; - private final boolean mTrustedUserPresenceRequred; + private final boolean mTrustedUserPresenceRequired; private final boolean mUserAuthenticationValidWhileOnBody; private final boolean mInvalidatedByBiometricEnrollment; private final long mBoundToSecureUserId; private final boolean mCriticalToDeviceEncryption; private final boolean mUserConfirmationRequired; + private final boolean mUnlockedDeviceRequired; private KeyProtection( Date keyValidityStart, @@ -243,12 +244,13 @@ public final class KeyProtection implements ProtectionParameter, UserAuthArgs { boolean randomizedEncryptionRequired, boolean userAuthenticationRequired, int userAuthenticationValidityDurationSeconds, - boolean trustedUserPresenceRequred, + boolean trustedUserPresenceRequired, boolean userAuthenticationValidWhileOnBody, boolean invalidatedByBiometricEnrollment, long boundToSecureUserId, boolean criticalToDeviceEncryption, - boolean userConfirmationRequired) { + boolean userConfirmationRequired, + boolean unlockedDeviceRequired) { mKeyValidityStart = Utils.cloneIfNotNull(keyValidityStart); mKeyValidityForOriginationEnd = Utils.cloneIfNotNull(keyValidityForOriginationEnd); mKeyValidityForConsumptionEnd = Utils.cloneIfNotNull(keyValidityForConsumptionEnd); @@ -262,12 +264,13 @@ public final class KeyProtection implements ProtectionParameter, UserAuthArgs { mRandomizedEncryptionRequired = randomizedEncryptionRequired; mUserAuthenticationRequired = userAuthenticationRequired; mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds; - mTrustedUserPresenceRequred = trustedUserPresenceRequred; + mTrustedUserPresenceRequired = trustedUserPresenceRequired; mUserAuthenticationValidWhileOnBody = userAuthenticationValidWhileOnBody; mInvalidatedByBiometricEnrollment = invalidatedByBiometricEnrollment; mBoundToSecureUserId = boundToSecureUserId; mCriticalToDeviceEncryption = criticalToDeviceEncryption; mUserConfirmationRequired = userConfirmationRequired; + mUnlockedDeviceRequired = unlockedDeviceRequired; } /** @@ -444,7 +447,7 @@ public final class KeyProtection implements ProtectionParameter, UserAuthArgs { * been performed between the {@code Signature.initSign()} and {@code Signature.sign()} calls. */ public boolean isTrustedUserPresenceRequired() { - return mTrustedUserPresenceRequred; + return mTrustedUserPresenceRequired; } /** @@ -504,6 +507,15 @@ public final class KeyProtection implements ProtectionParameter, UserAuthArgs { return mCriticalToDeviceEncryption; } + /** + * @hide Returns {@code true} if the key cannot be used unless the device screen is unlocked. + * + * @see Builder#setUnlockedDeviceRequired(boolean) + */ + public boolean isUnlockedDeviceRequired() { + return mUnlockedDeviceRequired; + } + /** * Builder of {@link KeyProtection} instances. */ @@ -524,6 +536,8 @@ public final class KeyProtection implements ProtectionParameter, UserAuthArgs { private boolean mUserAuthenticationValidWhileOnBody; private boolean mInvalidatedByBiometricEnrollment = true; private boolean mUserConfirmationRequired; + private boolean mUnlockedDeviceRequired = false; + private long mBoundToSecureUserId = GateKeeper.INVALID_SECURE_USER_ID; private boolean mCriticalToDeviceEncryption = false; @@ -913,6 +927,18 @@ public final class KeyProtection implements ProtectionParameter, UserAuthArgs { return this; } + /** + * @hide Sets whether the keystore requires the screen to be unlocked before allowing decryption + * using this key. If this is set to {@code true}, any attempt to decrypt using this key + * while the screen is locked will fail. A locked device requires a PIN, password, + * fingerprint, or other trusted factor to access. + */ + @NonNull + public Builder setUnlockedDeviceRequired(boolean unlockedDeviceRequired) { + mUnlockedDeviceRequired = unlockedDeviceRequired; + return this; + } + /** * Builds an instance of {@link KeyProtection}. * @@ -937,7 +963,8 @@ public final class KeyProtection implements ProtectionParameter, UserAuthArgs { mInvalidatedByBiometricEnrollment, mBoundToSecureUserId, mCriticalToDeviceEncryption, - mUserConfirmationRequired); + mUserConfirmationRequired, + mUnlockedDeviceRequired); } } } diff --git a/keystore/java/android/security/keystore/KeymasterUtils.java b/keystore/java/android/security/keystore/KeymasterUtils.java index 0ef08f237b4e..d194f0b9e4e9 100644 --- a/keystore/java/android/security/keystore/KeymasterUtils.java +++ b/keystore/java/android/security/keystore/KeymasterUtils.java @@ -101,8 +101,9 @@ public abstract class KeymasterUtils { * state (e.g., secure lock screen not set up) for generating or importing keys that * require user authentication. */ - public static void addUserAuthArgs(KeymasterArguments args, - UserAuthArgs spec) { + public static void addUserAuthArgs(KeymasterArguments args, UserAuthArgs spec) { + // TODO (67752510): Implement "unlocked device required" + if (spec.isUserConfirmationRequired()) { args.addBoolean(KeymasterDefs.KM_TAG_TRUSTED_CONFIRMATION_REQUIRED); } diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java index 941cd4441e23..37e79e70d70a 100644 --- a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java +++ b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java @@ -130,4 +130,4 @@ public class KeyguardStateMonitor extends IKeyguardStateCallback.Stub { pw.println(prefix + "mTrusted=" + mTrusted); pw.println(prefix + "mCurrentUserId=" + mCurrentUserId); } -} \ No newline at end of file +} -- GitLab From f85438093b01747cf658b6ab0f12622446135bb7 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Wed, 28 Mar 2018 10:31:55 -0600 Subject: [PATCH 020/179] Better public volumes handling on secondary users. Public volumes are only mounted for a single user at a time, so only show notifications and launch Intents for the relevant user. Test: manual Bug: 73642796 Change-Id: I012206bad031ed37659b6dbec2ef1eec389410da --- .../src/com/android/systemui/usb/StorageNotification.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java index 7ffca173be86..d52746599aa1 100644 --- a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java +++ b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java @@ -323,10 +323,10 @@ public class StorageNotification extends SystemUI { if (notif != null) { mNotificationManager.notifyAsUser(vol.getId(), SystemMessage.NOTE_STORAGE_PUBLIC, - notif, UserHandle.ALL); + notif, UserHandle.of(vol.getMountUserId())); } else { mNotificationManager.cancelAsUser(vol.getId(), SystemMessage.NOTE_STORAGE_PUBLIC, - UserHandle.ALL); + UserHandle.of(vol.getMountUserId())); } } -- GitLab From 92892163d58b580056d38f6ca2c93fb714b9e4b8 Mon Sep 17 00:00:00 2001 From: Annie Meng Date: Thu, 15 Mar 2018 14:45:46 +0000 Subject: [PATCH 021/179] DO NOT MERGE Unrevert update references to backup agent timeouts Cherry-picked from master (ag/3800434). Reintroduce change (ag/3742803) that was reverted due to SUW crash (ag/3780292). Updates references to backup/restore agent timeouts from hardcoded constants to the Global setting backup_agent_timeout_parameters. Bug: 70276070 Test: 1) m -j RunFrameworksServicesRoboTests 2) Manual testing of affected backup/restore paths: - Wipe device; restore cloud backup via SUW - adb shell bmgr list sets - adb shell bmgr restore [package] - adb shell bmgr restore [token] - adb backup -all - adb backup -shared - adb backup -obb -all - adb shell bmgr backupnow --all - adb shell bmgr backupnow [key value package] - adb shell bmgr backupnow [full data package] - adb backup -keyvalue [key value package] - adb restore backup.ab Change-Id: If9aad572d688451d37178cd7c2d7844be054953c --- .../backup/BackupAgentTimeoutParameters.java | 23 +++++++++++++++++ .../server/backup/BackupManagerService.java | 18 +++++++------ .../backup/BackupManagerServiceInterface.java | 3 +++ .../backup/KeyValueAdbBackupEngine.java | 14 ++++++++--- .../backup/fullbackup/FullBackupEngine.java | 15 ++++++----- .../fullbackup/FullBackupObbConnection.java | 11 ++++++-- .../PerformFullTransportBackupTask.java | 25 ++++++++++++++----- .../server/backup/internal/BackupHandler.java | 10 ++++++-- .../backup/internal/PerformBackupTask.java | 11 ++++++-- .../restore/AdbRestoreFinishedLatch.java | 11 ++++++-- .../backup/restore/FullRestoreEngine.java | 16 +++++++----- .../backup/restore/PerformAdbRestoreTask.java | 20 ++++++++++----- .../restore/PerformUnifiedRestoreTask.java | 19 +++++++++----- .../server/backup/PerformBackupTaskTest.java | 12 ++++++++- .../restore/ActiveRestoreSessionTest.java | 14 ++++++++++- .../BackupManagerServiceTestUtils.java | 5 +++- 16 files changed, 174 insertions(+), 53 deletions(-) diff --git a/services/backup/java/com/android/server/backup/BackupAgentTimeoutParameters.java b/services/backup/java/com/android/server/backup/BackupAgentTimeoutParameters.java index 4de2c9b8e79f..49fa1ccce5fe 100644 --- a/services/backup/java/com/android/server/backup/BackupAgentTimeoutParameters.java +++ b/services/backup/java/com/android/server/backup/BackupAgentTimeoutParameters.java @@ -21,6 +21,7 @@ import android.os.Handler; import android.provider.Settings; import android.util.KeyValueListParser; import android.util.KeyValueSettingObserver; +import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; @@ -31,6 +32,8 @@ import com.android.internal.annotations.VisibleForTesting; * are represented as a comma-delimited key value list. */ public class BackupAgentTimeoutParameters extends KeyValueSettingObserver { + private static final String TAG = "BackupAgentTimeout"; + @VisibleForTesting public static final String SETTING = Settings.Global.BACKUP_AGENT_TIMEOUT_PARAMETERS; @@ -120,30 +123,50 @@ public class BackupAgentTimeoutParameters extends KeyValueSettingObserver { public long getKvBackupAgentTimeoutMillis() { synchronized (mLock) { + if (BackupManagerService.DEBUG_SCHEDULING) { + Slog.v(TAG, "getKvBackupAgentTimeoutMillis(): " + mKvBackupAgentTimeoutMillis); + } return mKvBackupAgentTimeoutMillis; } } public long getFullBackupAgentTimeoutMillis() { synchronized (mLock) { + if (BackupManagerService.DEBUG_SCHEDULING) { + Slog.v(TAG, "getFullBackupAgentTimeoutMillis(): " + mFullBackupAgentTimeoutMillis); + } return mFullBackupAgentTimeoutMillis; } } public long getSharedBackupAgentTimeoutMillis() { synchronized (mLock) { + if (BackupManagerService.DEBUG_SCHEDULING) { + Slog.v( + TAG, + "getSharedBackupAgentTimeoutMillis(): " + mSharedBackupAgentTimeoutMillis); + } return mSharedBackupAgentTimeoutMillis; } } public long getRestoreAgentTimeoutMillis() { synchronized (mLock) { + if (BackupManagerService.DEBUG_SCHEDULING) { + Slog.v(TAG, "getRestoreAgentTimeoutMillis(): " + mRestoreAgentTimeoutMillis); + } return mRestoreAgentTimeoutMillis; } } public long getRestoreAgentFinishedTimeoutMillis() { synchronized (mLock) { + if (BackupManagerService.DEBUG_SCHEDULING) { + Slog.v( + TAG, + "getRestoreAgentFinishedTimeoutMillis(): " + + mRestoreAgentFinishedTimeoutMillis); + } return mRestoreAgentFinishedTimeoutMillis; } } diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java index d6f6c6cf1fc3..bd51af270dd8 100644 --- a/services/backup/java/com/android/server/backup/BackupManagerService.java +++ b/services/backup/java/com/android/server/backup/BackupManagerService.java @@ -215,13 +215,6 @@ public class BackupManagerService implements BackupManagerServiceInterface { // Timeout interval for deciding that a bind or clear-data has taken too long private static final long TIMEOUT_INTERVAL = 10 * 1000; - // Timeout intervals for agent backup & restore operations - public static final long TIMEOUT_BACKUP_INTERVAL = 30 * 1000; - public static final long TIMEOUT_FULL_BACKUP_INTERVAL = 5 * 60 * 1000; - public static final long TIMEOUT_SHARED_BACKUP_INTERVAL = 30 * 60 * 1000; - public static final long TIMEOUT_RESTORE_INTERVAL = 60 * 1000; - public static final long TIMEOUT_RESTORE_FINISHED_INTERVAL = 30 * 1000; - // User confirmation timeout for a full backup/restore operation. It's this long in // order to give them time to enter the backup password. private static final long TIMEOUT_FULL_CONFIRMATION = 60 * 1000; @@ -232,6 +225,7 @@ public class BackupManagerService implements BackupManagerServiceInterface { private static final int BUSY_BACKOFF_FUZZ = 1000 * 60 * 60 * 2; // two hours private BackupManagerConstants mConstants; + private final BackupAgentTimeoutParameters mAgentTimeoutParameters; private Context mContext; private PackageManager mPackageManager; private IPackageManager mPackageManagerBinder; @@ -315,6 +309,10 @@ public class BackupManagerService implements BackupManagerServiceInterface { return mConstants; } + public BackupAgentTimeoutParameters getAgentTimeoutParameters() { + return mAgentTimeoutParameters; + } + public Context getContext() { return mContext; } @@ -799,6 +797,10 @@ public class BackupManagerService implements BackupManagerServiceInterface { mBackupManagerBinder = Trampoline.asInterface(parent.asBinder()); + mAgentTimeoutParameters = new + BackupAgentTimeoutParameters(Handler.getMain(), mContext.getContentResolver()); + mAgentTimeoutParameters.start(); + // spin up the backup/restore handler thread mBackupHandler = new BackupHandler(this, backupThread.getLooper()); @@ -3407,7 +3409,7 @@ public class BackupManagerService implements BackupManagerServiceInterface { } mActiveRestoreSession = new ActiveRestoreSession(this, packageName, transport); mBackupHandler.sendEmptyMessageDelayed(MSG_RESTORE_SESSION_TIMEOUT, - TIMEOUT_RESTORE_INTERVAL); + mAgentTimeoutParameters.getRestoreAgentTimeoutMillis()); } return mActiveRestoreSession; } diff --git a/services/backup/java/com/android/server/backup/BackupManagerServiceInterface.java b/services/backup/java/com/android/server/backup/BackupManagerServiceInterface.java index 7b021c64eaf8..aabe7f611845 100644 --- a/services/backup/java/com/android/server/backup/BackupManagerServiceInterface.java +++ b/services/backup/java/com/android/server/backup/BackupManagerServiceInterface.java @@ -191,4 +191,7 @@ public interface BackupManagerServiceInterface { void dump(FileDescriptor fd, PrintWriter pw, String[] args); IBackupManager getBackupManagerBinder(); + + // Gets access to the backup/restore agent timeout parameters. + BackupAgentTimeoutParameters getAgentTimeoutParameters(); } diff --git a/services/backup/java/com/android/server/backup/KeyValueAdbBackupEngine.java b/services/backup/java/com/android/server/backup/KeyValueAdbBackupEngine.java index 47558775d19e..7f0030a5064e 100644 --- a/services/backup/java/com/android/server/backup/KeyValueAdbBackupEngine.java +++ b/services/backup/java/com/android/server/backup/KeyValueAdbBackupEngine.java @@ -4,8 +4,8 @@ import static android.os.ParcelFileDescriptor.MODE_CREATE; import static android.os.ParcelFileDescriptor.MODE_READ_ONLY; import static android.os.ParcelFileDescriptor.MODE_READ_WRITE; import static android.os.ParcelFileDescriptor.MODE_TRUNCATE; + import static com.android.server.backup.BackupManagerService.OP_TYPE_BACKUP_WAIT; -import static com.android.server.backup.BackupManagerService.TIMEOUT_BACKUP_INTERVAL; import android.app.ApplicationThreadConstants; import android.app.IBackupAgent; @@ -19,6 +19,7 @@ import android.os.RemoteException; import android.os.SELinux; import android.util.Slog; +import com.android.internal.util.Preconditions; import com.android.server.backup.utils.FullBackupUtils; import libcore.io.IoUtils; @@ -59,6 +60,7 @@ public class KeyValueAdbBackupEngine { private ParcelFileDescriptor mSavedState; private ParcelFileDescriptor mBackupData; private ParcelFileDescriptor mNewState; + private final BackupAgentTimeoutParameters mAgentTimeoutParameters; public KeyValueAdbBackupEngine(OutputStream output, PackageInfo packageInfo, BackupManagerServiceInterface backupManagerService, PackageManager packageManager, @@ -81,6 +83,9 @@ public class KeyValueAdbBackupEngine { pkg + BACKUP_KEY_VALUE_NEW_STATE_FILENAME_SUFFIX); mManifestFile = new File(mDataDir, BackupManagerService.BACKUP_MANIFEST_FILENAME); + mAgentTimeoutParameters = Preconditions.checkNotNull( + backupManagerService.getAgentTimeoutParameters(), + "Timeout parameters cannot be null"); } public void backupOnePackage() throws IOException { @@ -148,8 +153,9 @@ public class KeyValueAdbBackupEngine { // Return true on backup success, false otherwise private boolean invokeAgentForAdbBackup(String packageName, IBackupAgent agent) { int token = mBackupManagerService.generateRandomIntegerToken(); + long kvBackupAgentTimeoutMillis = mAgentTimeoutParameters.getKvBackupAgentTimeoutMillis(); try { - mBackupManagerService.prepareOperationTimeout(token, TIMEOUT_BACKUP_INTERVAL, null, + mBackupManagerService.prepareOperationTimeout(token, kvBackupAgentTimeoutMillis, null, OP_TYPE_BACKUP_WAIT); // Start backup and wait for BackupManagerService to get callback for success or timeout @@ -231,14 +237,14 @@ public class KeyValueAdbBackupEngine { } private void writeBackupData() throws IOException { - int token = mBackupManagerService.generateRandomIntegerToken(); + long kvBackupAgentTimeoutMillis = mAgentTimeoutParameters.getKvBackupAgentTimeoutMillis(); ParcelFileDescriptor[] pipes = null; try { pipes = ParcelFileDescriptor.createPipe(); - mBackupManagerService.prepareOperationTimeout(token, TIMEOUT_BACKUP_INTERVAL, null, + mBackupManagerService.prepareOperationTimeout(token, kvBackupAgentTimeoutMillis, null, OP_TYPE_BACKUP_WAIT); // We will have to create a runnable that will read the manifest and backup data we diff --git a/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java b/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java index 0582abac91d4..56946596eea3 100644 --- a/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java +++ b/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java @@ -25,9 +25,6 @@ import static com.android.server.backup.BackupManagerService.MORE_DEBUG; import static com.android.server.backup.BackupManagerService.OP_TYPE_BACKUP_WAIT; import static com.android.server.backup.BackupManagerService.SHARED_BACKUP_AGENT_PACKAGE; import static com.android.server.backup.BackupManagerService.TAG; -import static com.android.server.backup.BackupManagerService.TIMEOUT_FULL_BACKUP_INTERVAL; -import static com.android.server.backup.BackupManagerService - .TIMEOUT_SHARED_BACKUP_INTERVAL; import android.app.ApplicationThreadConstants; import android.app.IBackupAgent; @@ -44,9 +41,11 @@ import android.util.Log; import android.util.Slog; import android.util.StringBuilderPrinter; +import com.android.internal.util.Preconditions; import com.android.server.AppWidgetBackupBridge; -import com.android.server.backup.BackupRestoreTask; +import com.android.server.backup.BackupAgentTimeoutParameters; import com.android.server.backup.BackupManagerService; +import com.android.server.backup.BackupRestoreTask; import com.android.server.backup.utils.FullBackupUtils; import java.io.BufferedOutputStream; @@ -75,6 +74,7 @@ public class FullBackupEngine { private final long mQuota; private final int mOpToken; private final int mTransportFlags; + private final BackupAgentTimeoutParameters mAgentTimeoutParameters; class FullBackupRunner implements Runnable { @@ -137,8 +137,8 @@ public class FullBackupEngine { final boolean isSharedStorage = mPackage.packageName.equals(SHARED_BACKUP_AGENT_PACKAGE); final long timeout = isSharedStorage ? - TIMEOUT_SHARED_BACKUP_INTERVAL : - TIMEOUT_FULL_BACKUP_INTERVAL; + mAgentTimeoutParameters.getSharedBackupAgentTimeoutMillis() : + mAgentTimeoutParameters.getFullBackupAgentTimeoutMillis(); if (DEBUG) { Slog.d(TAG, "Calling doFullBackup() on " + mPackage.packageName); @@ -180,6 +180,9 @@ public class FullBackupEngine { mQuota = quota; mOpToken = opToken; mTransportFlags = transportFlags; + mAgentTimeoutParameters = Preconditions.checkNotNull( + backupManagerService.getAgentTimeoutParameters(), + "Timeout parameters cannot be null"); } public int preflightCheck() throws RemoteException { diff --git a/services/backup/java/com/android/server/backup/fullbackup/FullBackupObbConnection.java b/services/backup/java/com/android/server/backup/fullbackup/FullBackupObbConnection.java index 40b6967a729a..bc7d9fc691dd 100644 --- a/services/backup/java/com/android/server/backup/fullbackup/FullBackupObbConnection.java +++ b/services/backup/java/com/android/server/backup/fullbackup/FullBackupObbConnection.java @@ -19,7 +19,6 @@ package com.android.server.backup.fullbackup; import static com.android.server.backup.BackupManagerService.MORE_DEBUG; import static com.android.server.backup.BackupManagerService.OP_TYPE_BACKUP_WAIT; import static com.android.server.backup.BackupManagerService.TAG; -import static com.android.server.backup.BackupManagerService.TIMEOUT_FULL_BACKUP_INTERVAL; import android.app.backup.IBackupManager; import android.content.ComponentName; @@ -33,6 +32,8 @@ import android.os.UserHandle; import android.util.Slog; import com.android.internal.backup.IObbBackupService; +import com.android.internal.util.Preconditions; +import com.android.server.backup.BackupAgentTimeoutParameters; import com.android.server.backup.BackupManagerService; import com.android.server.backup.utils.FullBackupUtils; @@ -46,10 +47,14 @@ public class FullBackupObbConnection implements ServiceConnection { private BackupManagerService backupManagerService; volatile IObbBackupService mService; + private final BackupAgentTimeoutParameters mAgentTimeoutParameters; public FullBackupObbConnection(BackupManagerService backupManagerService) { this.backupManagerService = backupManagerService; mService = null; + mAgentTimeoutParameters = Preconditions.checkNotNull( + backupManagerService.getAgentTimeoutParameters(), + "Timeout parameters cannot be null"); } public void establish() { @@ -75,8 +80,10 @@ public class FullBackupObbConnection implements ServiceConnection { try { pipes = ParcelFileDescriptor.createPipe(); int token = backupManagerService.generateRandomIntegerToken(); + long fullBackupAgentTimeoutMillis = + mAgentTimeoutParameters.getFullBackupAgentTimeoutMillis(); backupManagerService.prepareOperationTimeout( - token, TIMEOUT_FULL_BACKUP_INTERVAL, null, OP_TYPE_BACKUP_WAIT); + token, fullBackupAgentTimeoutMillis, null, OP_TYPE_BACKUP_WAIT); mService.backupObbs(pkg.packageName, pipes[1], token, backupManagerService.getBackupManagerBinder()); FullBackupUtils.routeSocketDataToOutput(pipes[0], out); diff --git a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java index 2c2dd8528cb1..a40afc3cfa4d 100644 --- a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java +++ b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java @@ -22,7 +22,6 @@ import static com.android.server.backup.BackupManagerService.MORE_DEBUG; import static com.android.server.backup.BackupManagerService.OP_PENDING; import static com.android.server.backup.BackupManagerService.OP_TYPE_BACKUP; import static com.android.server.backup.BackupManagerService.OP_TYPE_BACKUP_WAIT; -import static com.android.server.backup.BackupManagerService.TIMEOUT_FULL_BACKUP_INTERVAL; import android.annotation.Nullable; import android.app.IBackupAgent; @@ -43,7 +42,9 @@ import android.util.Log; import android.util.Slog; import com.android.internal.backup.IBackupTransport; +import com.android.internal.util.Preconditions; import com.android.server.EventLogTags; +import com.android.server.backup.BackupAgentTimeoutParameters; import com.android.server.backup.BackupRestoreTask; import com.android.server.backup.FullBackupJob; import com.android.server.backup.BackupManagerService; @@ -146,6 +147,7 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba private volatile boolean mIsDoingBackup; private volatile boolean mCancelAll; private final int mCurrentOpToken; + private final BackupAgentTimeoutParameters mAgentTimeoutParameters; public PerformFullTransportBackupTask(BackupManagerService backupManagerService, TransportClient transportClient, @@ -167,6 +169,9 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba mUserInitiated = userInitiated; mCurrentOpToken = backupManagerService.generateRandomIntegerToken(); mBackupRunnerOpToken = backupManagerService.generateRandomIntegerToken(); + mAgentTimeoutParameters = Preconditions.checkNotNull( + backupManagerService.getAgentTimeoutParameters(), + "Timeout parameters cannot be null"); if (backupManagerService.isBackupOperationInProgress()) { if (DEBUG) { @@ -698,9 +703,11 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba @Override public int preflightFullBackup(PackageInfo pkg, IBackupAgent agent) { int result; + long fullBackupAgentTimeoutMillis = + mAgentTimeoutParameters.getFullBackupAgentTimeoutMillis(); try { backupManagerService.prepareOperationTimeout( - mCurrentOpToken, TIMEOUT_FULL_BACKUP_INTERVAL, this, OP_TYPE_BACKUP_WAIT); + mCurrentOpToken, fullBackupAgentTimeoutMillis, this, OP_TYPE_BACKUP_WAIT); backupManagerService.addBackupTrace("preflighting"); if (MORE_DEBUG) { Slog.d(TAG, "Preflighting full payload of " + pkg.packageName); @@ -713,7 +720,7 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba // timeout had been produced. In case of a real backstop timeout, mResult // will still contain the value it was constructed with, AGENT_ERROR, which // intentionaly falls into the "just report failure" code. - mLatch.await(TIMEOUT_FULL_BACKUP_INTERVAL, TimeUnit.MILLISECONDS); + mLatch.await(fullBackupAgentTimeoutMillis, TimeUnit.MILLISECONDS); long totalSize = mResult.get(); // If preflight timed out, mResult will contain error code as int. @@ -769,8 +776,10 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba @Override public long getExpectedSizeOrErrorCode() { + long fullBackupAgentTimeoutMillis = + mAgentTimeoutParameters.getFullBackupAgentTimeoutMillis(); try { - mLatch.await(TIMEOUT_FULL_BACKUP_INTERVAL, TimeUnit.MILLISECONDS); + mLatch.await(fullBackupAgentTimeoutMillis, TimeUnit.MILLISECONDS); return mResult.get(); } catch (InterruptedException e) { return BackupTransport.NO_MORE_DATA; @@ -863,8 +872,10 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba // If preflight succeeded, returns positive number - preflight size, // otherwise return negative error code. long getPreflightResultBlocking() { + long fullBackupAgentTimeoutMillis = + mAgentTimeoutParameters.getFullBackupAgentTimeoutMillis(); try { - mPreflightLatch.await(TIMEOUT_FULL_BACKUP_INTERVAL, TimeUnit.MILLISECONDS); + mPreflightLatch.await(fullBackupAgentTimeoutMillis, TimeUnit.MILLISECONDS); if (mIsCancelled) { return BackupManager.ERROR_BACKUP_CANCELLED; } @@ -879,8 +890,10 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba } int getBackupResultBlocking() { + long fullBackupAgentTimeoutMillis = + mAgentTimeoutParameters.getFullBackupAgentTimeoutMillis(); try { - mBackupLatch.await(TIMEOUT_FULL_BACKUP_INTERVAL, TimeUnit.MILLISECONDS); + mBackupLatch.await(fullBackupAgentTimeoutMillis, TimeUnit.MILLISECONDS); if (mIsCancelled) { return BackupManager.ERROR_BACKUP_CANCELLED; } diff --git a/services/backup/java/com/android/server/backup/internal/BackupHandler.java b/services/backup/java/com/android/server/backup/internal/BackupHandler.java index 136fada43b1f..69f08ae49a2e 100644 --- a/services/backup/java/com/android/server/backup/internal/BackupHandler.java +++ b/services/backup/java/com/android/server/backup/internal/BackupHandler.java @@ -19,7 +19,6 @@ package com.android.server.backup.internal; import static com.android.server.backup.BackupManagerService.DEBUG; import static com.android.server.backup.BackupManagerService.MORE_DEBUG; import static com.android.server.backup.BackupManagerService.TAG; -import static com.android.server.backup.BackupManagerService.TIMEOUT_RESTORE_INTERVAL; import android.app.backup.RestoreSet; import android.content.Intent; @@ -33,7 +32,9 @@ import android.util.Pair; import android.util.Slog; import com.android.internal.backup.IBackupTransport; +import com.android.internal.util.Preconditions; import com.android.server.EventLogTags; +import com.android.server.backup.BackupAgentTimeoutParameters; import com.android.server.backup.BackupManagerService; import com.android.server.backup.BackupRestoreTask; import com.android.server.backup.DataChangedJournal; @@ -81,10 +82,14 @@ public class BackupHandler extends Handler { public static final int MSG_OP_COMPLETE = 21; private final BackupManagerService backupManagerService; + private final BackupAgentTimeoutParameters mAgentTimeoutParameters; public BackupHandler(BackupManagerService backupManagerService, Looper looper) { super(looper); this.backupManagerService = backupManagerService; + mAgentTimeoutParameters = Preconditions.checkNotNull( + backupManagerService.getAgentTimeoutParameters(), + "Timeout parameters cannot be null"); } public void handleMessage(Message msg) { @@ -322,7 +327,8 @@ public class BackupHandler extends Handler { // Done: reset the session timeout clock removeMessages(MSG_RESTORE_SESSION_TIMEOUT); - sendEmptyMessageDelayed(MSG_RESTORE_SESSION_TIMEOUT, TIMEOUT_RESTORE_INTERVAL); + sendEmptyMessageDelayed(MSG_RESTORE_SESSION_TIMEOUT, + mAgentTimeoutParameters.getRestoreAgentTimeoutMillis()); params.listener.onFinished(callerLogString); } diff --git a/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java b/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java index 11394e66a0f0..ac605b1ddd69 100644 --- a/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java +++ b/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java @@ -24,7 +24,6 @@ import static com.android.server.backup.BackupManagerService.OP_PENDING; import static com.android.server.backup.BackupManagerService.OP_TYPE_BACKUP; import static com.android.server.backup.BackupManagerService.OP_TYPE_BACKUP_WAIT; import static com.android.server.backup.BackupManagerService.PACKAGE_MANAGER_SENTINEL; -import static com.android.server.backup.BackupManagerService.TIMEOUT_BACKUP_INTERVAL; import static com.android.server.backup.internal.BackupHandler.MSG_BACKUP_OPERATION_TIMEOUT; import static com.android.server.backup.internal.BackupHandler.MSG_BACKUP_RESTORE_STEP; @@ -55,8 +54,10 @@ import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.backup.IBackupTransport; +import com.android.internal.util.Preconditions; import com.android.server.AppWidgetBackupBridge; import com.android.server.EventLogTags; +import com.android.server.backup.BackupAgentTimeoutParameters; import com.android.server.backup.BackupRestoreTask; import com.android.server.backup.DataChangedJournal; import com.android.server.backup.KeyValueBackupJob; @@ -142,6 +143,7 @@ public class PerformBackupTask implements BackupRestoreTask { private boolean mFinished; private final boolean mUserInitiated; private final boolean mNonIncremental; + private final BackupAgentTimeoutParameters mAgentTimeoutParameters; private volatile boolean mCancelAll; @@ -162,6 +164,9 @@ public class PerformBackupTask implements BackupRestoreTask { mPendingFullBackups = pendingFullBackups; mUserInitiated = userInitiated; mNonIncremental = nonIncremental; + mAgentTimeoutParameters = Preconditions.checkNotNull( + backupManagerService.getAgentTimeoutParameters(), + "Timeout parameters cannot be null"); mStateDir = new File(backupManagerService.getBaseStateDir(), dirName); mCurrentOpToken = backupManagerService.generateRandomIntegerToken(); @@ -711,8 +716,10 @@ public class PerformBackupTask implements BackupRestoreTask { // Initiate the target's backup pass backupManagerService.addBackupTrace("setting timeout"); + long kvBackupAgentTimeoutMillis = + mAgentTimeoutParameters.getKvBackupAgentTimeoutMillis(); backupManagerService.prepareOperationTimeout( - mEphemeralOpToken, TIMEOUT_BACKUP_INTERVAL, this, OP_TYPE_BACKUP_WAIT); + mEphemeralOpToken, kvBackupAgentTimeoutMillis, this, OP_TYPE_BACKUP_WAIT); backupManagerService.addBackupTrace("calling agent doBackup()"); agent.doBackup( diff --git a/services/backup/java/com/android/server/backup/restore/AdbRestoreFinishedLatch.java b/services/backup/java/com/android/server/backup/restore/AdbRestoreFinishedLatch.java index e4f3a9d5cd0a..a8c7ce6ad832 100644 --- a/services/backup/java/com/android/server/backup/restore/AdbRestoreFinishedLatch.java +++ b/services/backup/java/com/android/server/backup/restore/AdbRestoreFinishedLatch.java @@ -18,10 +18,11 @@ package com.android.server.backup.restore; import static com.android.server.backup.BackupManagerService.DEBUG; import static com.android.server.backup.BackupManagerService.MORE_DEBUG; -import static com.android.server.backup.BackupManagerService.TIMEOUT_FULL_BACKUP_INTERVAL; import android.util.Slog; +import com.android.internal.util.Preconditions; +import com.android.server.backup.BackupAgentTimeoutParameters; import com.android.server.backup.BackupManagerService; import com.android.server.backup.BackupRestoreTask; @@ -37,18 +38,24 @@ public class AdbRestoreFinishedLatch implements BackupRestoreTask { private BackupManagerService backupManagerService; final CountDownLatch mLatch; private final int mCurrentOpToken; + private final BackupAgentTimeoutParameters mAgentTimeoutParameters; public AdbRestoreFinishedLatch(BackupManagerService backupManagerService, int currentOpToken) { this.backupManagerService = backupManagerService; mLatch = new CountDownLatch(1); mCurrentOpToken = currentOpToken; + mAgentTimeoutParameters = Preconditions.checkNotNull( + backupManagerService.getAgentTimeoutParameters(), + "Timeout parameters cannot be null"); } void await() { boolean latched = false; + long fullBackupAgentTimeoutMillis = + mAgentTimeoutParameters.getFullBackupAgentTimeoutMillis(); try { - latched = mLatch.await(TIMEOUT_FULL_BACKUP_INTERVAL, TimeUnit.MILLISECONDS); + latched = mLatch.await(fullBackupAgentTimeoutMillis, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { Slog.w(TAG, "Interrupted!"); } diff --git a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java index c1a1c1dc10e7..b1b066489bd5 100644 --- a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java +++ b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java @@ -23,9 +23,6 @@ import static com.android.server.backup.BackupManagerService.MORE_DEBUG; import static com.android.server.backup.BackupManagerService.OP_TYPE_RESTORE_WAIT; import static com.android.server.backup.BackupManagerService.SHARED_BACKUP_AGENT_PACKAGE; import static com.android.server.backup.BackupManagerService.TAG; -import static com.android.server.backup.BackupManagerService.TIMEOUT_RESTORE_INTERVAL; -import static com.android.server.backup.BackupManagerService - .TIMEOUT_SHARED_BACKUP_INTERVAL; import static com.android.server.backup.internal.BackupHandler.MSG_RESTORE_OPERATION_TIMEOUT; import android.app.ApplicationThreadConstants; @@ -42,11 +39,13 @@ import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.util.Slog; +import com.android.internal.util.Preconditions; import com.android.server.LocalServices; +import com.android.server.backup.BackupAgentTimeoutParameters; +import com.android.server.backup.BackupManagerService; import com.android.server.backup.BackupRestoreTask; import com.android.server.backup.FileMetadata; import com.android.server.backup.KeyValueAdbRestoreEngine; -import com.android.server.backup.BackupManagerService; import com.android.server.backup.fullbackup.FullBackupObbConnection; import com.android.server.backup.utils.BytesReadListener; import com.android.server.backup.utils.FullBackupRestoreObserverUtils; @@ -121,6 +120,8 @@ public class FullRestoreEngine extends RestoreEngine { final int mEphemeralOpToken; + private final BackupAgentTimeoutParameters mAgentTimeoutParameters; + public FullRestoreEngine(BackupManagerService backupManagerService, BackupRestoreTask monitorTask, IFullBackupRestoreObserver observer, IBackupManagerMonitor monitor, PackageInfo onlyPackage, boolean allowApks, @@ -135,6 +136,9 @@ public class FullRestoreEngine extends RestoreEngine { mAllowObbs = allowObbs; mBuffer = new byte[32 * 1024]; mBytes = 0; + mAgentTimeoutParameters = Preconditions.checkNotNull( + backupManagerService.getAgentTimeoutParameters(), + "Timeout parameters cannot be null"); } public IBackupAgent getAgent() { @@ -381,8 +385,8 @@ public class FullRestoreEngine extends RestoreEngine { long toCopy = info.size; final boolean isSharedStorage = pkg.equals(SHARED_BACKUP_AGENT_PACKAGE); final long timeout = isSharedStorage ? - TIMEOUT_SHARED_BACKUP_INTERVAL : - TIMEOUT_RESTORE_INTERVAL; + mAgentTimeoutParameters.getSharedBackupAgentTimeoutMillis() : + mAgentTimeoutParameters.getRestoreAgentTimeoutMillis(); try { mBackupManagerService.prepareOperationTimeout(token, timeout, diff --git a/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java index dacde0b9af68..77163d348e1c 100644 --- a/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java +++ b/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java @@ -16,8 +16,6 @@ package com.android.server.backup.restore; -import static com.android.server.backup.BackupPasswordManager.PBKDF_CURRENT; -import static com.android.server.backup.BackupPasswordManager.PBKDF_FALLBACK; import static com.android.server.backup.BackupManagerService.BACKUP_FILE_HEADER_MAGIC; import static com.android.server.backup.BackupManagerService.BACKUP_FILE_VERSION; import static com.android.server.backup.BackupManagerService.BACKUP_MANIFEST_FILENAME; @@ -28,8 +26,8 @@ import static com.android.server.backup.BackupManagerService.OP_TYPE_RESTORE_WAI import static com.android.server.backup.BackupManagerService.SETTINGS_PACKAGE; import static com.android.server.backup.BackupManagerService.SHARED_BACKUP_AGENT_PACKAGE; import static com.android.server.backup.BackupManagerService.TAG; -import static com.android.server.backup.BackupManagerService.TIMEOUT_FULL_BACKUP_INTERVAL; -import static com.android.server.backup.BackupManagerService.TIMEOUT_RESTORE_INTERVAL; +import static com.android.server.backup.BackupPasswordManager.PBKDF_CURRENT; +import static com.android.server.backup.BackupPasswordManager.PBKDF_FALLBACK; import static com.android.server.backup.internal.BackupHandler.MSG_RESTORE_OPERATION_TIMEOUT; import android.app.ApplicationThreadConstants; @@ -48,7 +46,9 @@ import android.os.RemoteException; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.Preconditions; import com.android.server.LocalServices; +import com.android.server.backup.BackupAgentTimeoutParameters; import com.android.server.backup.BackupManagerService; import com.android.server.backup.FileMetadata; import com.android.server.backup.KeyValueAdbRestoreEngine; @@ -101,6 +101,7 @@ public class PerformAdbRestoreTask implements Runnable { private byte[] mWidgetData = null; private long mBytes; + private final BackupAgentTimeoutParameters mAgentTimeoutParameters; // Runner that can be placed on a separate thread to do in-process invocation // of the "restore finished" API asynchronously. Used by adb restore. @@ -155,6 +156,9 @@ public class PerformAdbRestoreTask implements Runnable { mAgentPackage = null; mTargetApp = null; mObbConnection = new FullBackupObbConnection(backupManagerService); + mAgentTimeoutParameters = Preconditions.checkNotNull( + backupManagerService.getAgentTimeoutParameters(), + "Timeout parameters cannot be null"); // Which packages we've already wiped data on. We prepopulate this // with a whitelist of packages known to be unclearable. @@ -643,9 +647,11 @@ public class PerformAdbRestoreTask implements Runnable { if (okay) { boolean agentSuccess = true; long toCopy = info.size; + long restoreAgentTimeoutMillis = + mAgentTimeoutParameters.getRestoreAgentTimeoutMillis(); try { mBackupManagerService.prepareOperationTimeout( - token, TIMEOUT_RESTORE_INTERVAL, null, OP_TYPE_RESTORE_WAIT); + token, restoreAgentTimeoutMillis, null, OP_TYPE_RESTORE_WAIT); if (FullBackup.OBB_TREE_TOKEN.equals(info.domain)) { if (DEBUG) { @@ -820,10 +826,12 @@ public class PerformAdbRestoreTask implements Runnable { // In the adb restore case, we do restore-finished here if (doRestoreFinished) { final int token = mBackupManagerService.generateRandomIntegerToken(); + long fullBackupAgentTimeoutMillis = + mAgentTimeoutParameters.getFullBackupAgentTimeoutMillis(); final AdbRestoreFinishedLatch latch = new AdbRestoreFinishedLatch( mBackupManagerService, token); mBackupManagerService.prepareOperationTimeout( - token, TIMEOUT_FULL_BACKUP_INTERVAL, latch, OP_TYPE_RESTORE_WAIT); + token, fullBackupAgentTimeoutMillis, latch, OP_TYPE_RESTORE_WAIT); if (mTargetApp.processName.equals("system")) { if (MORE_DEBUG) { Slog.d(TAG, "system agent - restoreFinished on thread"); diff --git a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java index 4b467e5a0399..12d72d8a4637 100644 --- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java +++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java @@ -23,9 +23,6 @@ import static com.android.server.backup.BackupManagerService.OP_TYPE_RESTORE_WAI import static com.android.server.backup.BackupManagerService.PACKAGE_MANAGER_SENTINEL; import static com.android.server.backup.BackupManagerService.SETTINGS_PACKAGE; import static com.android.server.backup.BackupManagerService.TAG; -import static com.android.server.backup.BackupManagerService - .TIMEOUT_RESTORE_FINISHED_INTERVAL; -import static com.android.server.backup.BackupManagerService.TIMEOUT_RESTORE_INTERVAL; import static com.android.server.backup.internal.BackupHandler.MSG_BACKUP_RESTORE_STEP; import static com.android.server.backup.internal.BackupHandler.MSG_RESTORE_OPERATION_TIMEOUT; import static com.android.server.backup.internal.BackupHandler.MSG_RESTORE_SESSION_TIMEOUT; @@ -56,9 +53,11 @@ import android.util.EventLog; import android.util.Slog; import com.android.internal.backup.IBackupTransport; +import com.android.internal.util.Preconditions; import com.android.server.AppWidgetBackupBridge; import com.android.server.EventLogTags; import com.android.server.LocalServices; +import com.android.server.backup.BackupAgentTimeoutParameters; import com.android.server.backup.BackupRestoreTask; import com.android.server.backup.BackupUtils; import com.android.server.backup.PackageManagerBackupAgent; @@ -160,6 +159,7 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask { ParcelFileDescriptor mNewState; private final int mEphemeralOpToken; + private final BackupAgentTimeoutParameters mAgentTimeoutParameters; // This task can assume that the wakelock is properly held for it and doesn't have to worry // about releasing it. @@ -190,6 +190,9 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask { mFinished = false; mDidLaunch = false; mListener = listener; + mAgentTimeoutParameters = Preconditions.checkNotNull( + backupManagerService.getAgentTimeoutParameters(), + "Timeout parameters cannot be null"); if (targetPackage != null) { // Single package restore @@ -760,8 +763,9 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask { // Kick off the restore, checking for hung agents. The timeout or // the operationComplete() callback will schedule the next step, // so we do not do that here. + long restoreAgentTimeoutMillis = mAgentTimeoutParameters.getRestoreAgentTimeoutMillis(); backupManagerService.prepareOperationTimeout( - mEphemeralOpToken, TIMEOUT_RESTORE_INTERVAL, this, OP_TYPE_RESTORE_WAIT); + mEphemeralOpToken, restoreAgentTimeoutMillis, this, OP_TYPE_RESTORE_WAIT); mAgent.doRestore(mBackupData, appVersionCode, mNewState, mEphemeralOpToken, backupManagerService.getBackupManagerBinder()); } catch (Exception e) { @@ -813,9 +817,11 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask { Slog.d(TAG, "restoreFinished packageName=" + mCurrentPackage.packageName); } try { + long restoreAgentFinishedTimeoutMillis = + mAgentTimeoutParameters.getRestoreAgentFinishedTimeoutMillis(); backupManagerService .prepareOperationTimeout(mEphemeralOpToken, - TIMEOUT_RESTORE_FINISHED_INTERVAL, this, + restoreAgentFinishedTimeoutMillis, this, OP_TYPE_RESTORE_WAIT); mAgent.doRestoreFinished(mEphemeralOpToken, backupManagerService.getBackupManagerBinder()); @@ -1109,9 +1115,10 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask { } else { // We were invoked via an active restore session, not by the Package // Manager, so start up the session timeout again. + long restoreAgentTimeoutMillis = mAgentTimeoutParameters.getRestoreAgentTimeoutMillis(); backupManagerService.getBackupHandler().sendEmptyMessageDelayed( MSG_RESTORE_SESSION_TIMEOUT, - TIMEOUT_RESTORE_INTERVAL); + restoreAgentTimeoutMillis); } // Kick off any work that may be needed regarding app widget restores diff --git a/services/robotests/src/com/android/server/backup/PerformBackupTaskTest.java b/services/robotests/src/com/android/server/backup/PerformBackupTaskTest.java index f603a09baa37..fa41220dc44c 100644 --- a/services/robotests/src/com/android/server/backup/PerformBackupTaskTest.java +++ b/services/robotests/src/com/android/server/backup/PerformBackupTaskTest.java @@ -147,6 +147,15 @@ public class PerformBackupTaskTest { Looper backupLooper = startBackupThreadAndGetLooper(); mShadowBackupLooper = shadowOf(backupLooper); + + Handler mainHandler = new Handler(Looper.getMainLooper()); + BackupAgentTimeoutParameters agentTimeoutParameters = + new BackupAgentTimeoutParameters(mainHandler, application.getContentResolver()); + agentTimeoutParameters.start(); + + // We need to mock BMS timeout parameters before initializing the BackupHandler since + // the constructor of BackupHandler relies on the timeout parameters. + when(mBackupManagerService.getAgentTimeoutParameters()).thenReturn(agentTimeoutParameters); mBackupHandler = new BackupHandler(mBackupManagerService, backupLooper); mBackupManager = spy(FakeIBackupManager.class); @@ -157,7 +166,8 @@ public class PerformBackupTaskTest { mTransportManager, packageManager, mBackupHandler, - mWakeLock); + mWakeLock, + agentTimeoutParameters); when(mBackupManagerService.getBaseStateDir()).thenReturn(mBaseStateDir); when(mBackupManagerService.getDataDir()).thenReturn(dataDir); when(mBackupManagerService.getBackupManagerBinder()).thenReturn(mBackupManager); diff --git a/services/robotests/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java b/services/robotests/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java index 03792b1d40ba..92d6bbd54fab 100644 --- a/services/robotests/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java +++ b/services/robotests/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java @@ -41,12 +41,14 @@ import android.app.backup.IRestoreSession; import android.app.backup.RestoreSet; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; +import android.os.Handler; import android.os.Looper; import android.os.PowerManager; import android.os.RemoteException; import android.platform.test.annotations.Presubmit; import com.android.server.EventLogTags; +import com.android.server.backup.BackupAgentTimeoutParameters; import com.android.server.backup.BackupManagerService; import com.android.server.backup.TransportManager; import com.android.server.backup.internal.BackupHandler; @@ -115,6 +117,15 @@ public class ActiveRestoreSessionTest { Looper backupLooper = startBackupThreadAndGetLooper(); mShadowBackupLooper = shadowOf(backupLooper); + + Handler mainHandler = new Handler(Looper.getMainLooper()); + BackupAgentTimeoutParameters agentTimeoutParameters = + new BackupAgentTimeoutParameters(mainHandler, application.getContentResolver()); + agentTimeoutParameters.start(); + + // We need to mock BMS timeout parameters before initializing the BackupHandler since + // the constructor of BackupHandler relies on it. + when(mBackupManagerService.getAgentTimeoutParameters()).thenReturn(agentTimeoutParameters); BackupHandler backupHandler = new BackupHandler(mBackupManagerService, backupLooper); mWakeLock = createBackupWakeLock(application); @@ -125,7 +136,8 @@ public class ActiveRestoreSessionTest { mTransportManager, application.getPackageManager(), backupHandler, - mWakeLock); + mWakeLock, + agentTimeoutParameters); when(mBackupManagerService.getPendingRestores()).thenReturn(new ArrayDeque<>()); } diff --git a/services/robotests/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java b/services/robotests/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java index c210fdea6e89..5a886e33622f 100644 --- a/services/robotests/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java +++ b/services/robotests/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java @@ -28,6 +28,7 @@ import android.os.Looper; import android.os.PowerManager; import android.util.SparseArray; +import com.android.server.backup.BackupAgentTimeoutParameters; import com.android.server.backup.BackupManagerService; import com.android.server.backup.TransportManager; import com.android.server.backup.internal.BackupHandler; @@ -43,7 +44,8 @@ public class BackupManagerServiceTestUtils { TransportManager transportManager, PackageManager packageManager, BackupHandler backupHandler, - PowerManager.WakeLock wakeLock) { + PowerManager.WakeLock wakeLock, + BackupAgentTimeoutParameters agentTimeoutParameters) { when(backupManagerService.getContext()).thenReturn(context); when(backupManagerService.getTransportManager()).thenReturn(transportManager); when(backupManagerService.getPackageManager()).thenReturn(packageManager); @@ -53,6 +55,7 @@ public class BackupManagerServiceTestUtils { when(backupManagerService.getCurrentOperations()).thenReturn(new SparseArray<>()); when(backupManagerService.getActivityManager()).thenReturn(mock(IActivityManager.class)); when(backupManagerService.getWakelock()).thenReturn(wakeLock); + when(backupManagerService.getAgentTimeoutParameters()).thenReturn(agentTimeoutParameters); } public static PowerManager.WakeLock createBackupWakeLock(Application application) { -- GitLab From c159d529422e33dc6233bafafd4aba932b985892 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Wed, 28 Mar 2018 10:54:07 -0600 Subject: [PATCH 022/179] Tidy up users of TRANSPORT constants. Some call sites using explicit TRANSPORT types want to know about the raw underlying transport, and they don't want to know about VPNs that are going over that transport. For example, SettingsLib always wants to know about the actual Wi-Fi network, so it uses NOT_VPN to avoid being confused by VPN networks that are backed by a TRANSPORT_WIFI network. GnssLocationProvider wants to know about any validated internet access, regardless of the underlying transport. Test: atest com.android.settingslib.wifi Bug: 68499889 Change-Id: Ib5897946d856444d9ff3b54c4aeace6baa42f8bf --- .../src/com/android/settingslib/wifi/WifiStatusTracker.java | 4 +++- .../src/com/android/settingslib/wifi/WifiTracker.java | 1 + .../com/android/server/location/GnssLocationProvider.java | 6 +++--- wifi/java/android/net/wifi/WifiManager.java | 1 + 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java index 4cd23f9eac38..9347674ff0ee 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java @@ -50,7 +50,9 @@ public class WifiStatusTracker extends ConnectivityManager.NetworkCallback { } }; private final NetworkRequest mNetworkRequest = new NetworkRequest.Builder() - .clearCapabilities().addTransportType(NetworkCapabilities.TRANSPORT_WIFI).build(); + .clearCapabilities() + .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) + .addTransportType(NetworkCapabilities.TRANSPORT_WIFI).build(); private final ConnectivityManager.NetworkCallback mNetworkCallback = new ConnectivityManager .NetworkCallback() { @Override diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java index 8f80527036ec..a128b542d84e 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java @@ -213,6 +213,7 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro mNetworkRequest = new NetworkRequest.Builder() .clearCapabilities() + .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) .build(); diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java index 3374b30448d4..c445f73e5042 100644 --- a/services/core/java/com/android/server/location/GnssLocationProvider.java +++ b/services/core/java/com/android/server/location/GnssLocationProvider.java @@ -2576,9 +2576,9 @@ public class GnssLocationProvider implements LocationProviderInterface { // register for connectivity change events, this is equivalent to the deprecated way of // registering for CONNECTIVITY_ACTION broadcasts NetworkRequest.Builder networkRequestBuilder = new NetworkRequest.Builder(); - networkRequestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR); - networkRequestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI); - networkRequestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_BLUETOOTH); + networkRequestBuilder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); + networkRequestBuilder.addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED); + networkRequestBuilder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN); NetworkRequest networkRequest = networkRequestBuilder.build(); mConnMgr.registerNetworkCallback(networkRequest, mNetworkConnectivityCallback); diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index c8df08773716..433285bfc702 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -1317,6 +1317,7 @@ public class WifiManager { if (pin) { NetworkRequest request = new NetworkRequest.Builder() .clearCapabilities() + .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) .build(); NetworkPinner.pin(mContext, request); -- GitLab From e3dab2d906ee45954e58826b11cce9219c005cc5 Mon Sep 17 00:00:00 2001 From: Yi Jin Date: Thu, 22 Mar 2018 16:56:39 -0700 Subject: [PATCH 023/179] Use unique_fd with the clear ownership. FdBuffer won't take ownership of the `main` fd. It only enforces transfer ownership in readProcessedDataInStream. Bug: 74021345 Test: atest incidentd_test Change-Id: I6182730241c81c34b3be865b827a2d3e8c10c21c --- cmds/incidentd/src/FdBuffer.cpp | 62 ++++++++++----------- cmds/incidentd/src/FdBuffer.h | 8 +-- cmds/incidentd/src/IncidentService.cpp | 3 +- cmds/incidentd/src/Section.cpp | 17 +++--- cmds/incidentd/tests/FdBuffer_test.cpp | 45 ++++++++------- cmds/incidentd/tests/PrivacyBuffer_test.cpp | 3 +- 6 files changed, 70 insertions(+), 68 deletions(-) diff --git a/cmds/incidentd/src/FdBuffer.cpp b/cmds/incidentd/src/FdBuffer.cpp index 2b85ec08f9a6..c6e561f84052 100644 --- a/cmds/incidentd/src/FdBuffer.cpp +++ b/cmds/incidentd/src/FdBuffer.cpp @@ -34,11 +34,11 @@ FdBuffer::FdBuffer() FdBuffer::~FdBuffer() {} -status_t FdBuffer::read(unique_fd* fd, int64_t timeout) { - struct pollfd pfds = {.fd = fd->get(), .events = POLLIN}; +status_t FdBuffer::read(int fd, int64_t timeout) { + struct pollfd pfds = {.fd = fd, .events = POLLIN}; mStartTime = uptimeMillis(); - fcntl(fd->get(), F_SETFL, fcntl(fd->get(), F_GETFL, 0) | O_NONBLOCK); + fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK); while (true) { if (mBuffer.size() >= MAX_BUFFER_COUNT * BUFFER_SIZE) { @@ -67,16 +67,16 @@ status_t FdBuffer::read(unique_fd* fd, int64_t timeout) { VLOG("return event has error %s", strerror(errno)); return errno != 0 ? -errno : UNKNOWN_ERROR; } else { - ssize_t amt = ::read(fd->get(), mBuffer.writeBuffer(), mBuffer.currentToWrite()); + ssize_t amt = ::read(fd, mBuffer.writeBuffer(), mBuffer.currentToWrite()); if (amt < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK) { continue; } else { - VLOG("Fail to read %d: %s", fd->get(), strerror(errno)); + VLOG("Fail to read %d: %s", fd, strerror(errno)); return -errno; } } else if (amt == 0) { - VLOG("Reached EOF of fd=%d", fd->get()); + VLOG("Reached EOF of fd=%d", fd); break; } mBuffer.wp()->move(amt); @@ -87,7 +87,7 @@ status_t FdBuffer::read(unique_fd* fd, int64_t timeout) { return NO_ERROR; } -status_t FdBuffer::readFully(unique_fd* fd) { +status_t FdBuffer::readFully(int fd) { mStartTime = uptimeMillis(); while (true) { @@ -99,10 +99,10 @@ status_t FdBuffer::readFully(unique_fd* fd) { } if (mBuffer.writeBuffer() == NULL) return NO_MEMORY; - ssize_t amt = TEMP_FAILURE_RETRY( - ::read(fd->get(), mBuffer.writeBuffer(), mBuffer.currentToWrite())); + ssize_t amt = + TEMP_FAILURE_RETRY(::read(fd, mBuffer.writeBuffer(), mBuffer.currentToWrite())); if (amt < 0) { - VLOG("Fail to read %d: %s", fd->get(), strerror(errno)); + VLOG("Fail to read %d: %s", fd, strerror(errno)); return -errno; } else if (amt == 0) { VLOG("Done reading %zu bytes", mBuffer.size()); @@ -116,20 +116,20 @@ status_t FdBuffer::readFully(unique_fd* fd) { return NO_ERROR; } -status_t FdBuffer::readProcessedDataInStream(unique_fd* fd, unique_fd* toFd, unique_fd* fromFd, +status_t FdBuffer::readProcessedDataInStream(int fd, unique_fd toFd, unique_fd fromFd, int64_t timeoutMs, const bool isSysfs) { struct pollfd pfds[] = { - {.fd = fd->get(), .events = POLLIN}, - {.fd = toFd->get(), .events = POLLOUT}, - {.fd = fromFd->get(), .events = POLLIN}, + {.fd = fd, .events = POLLIN}, + {.fd = toFd.get(), .events = POLLOUT}, + {.fd = fromFd.get(), .events = POLLIN}, }; mStartTime = uptimeMillis(); // mark all fds non blocking - fcntl(fd->get(), F_SETFL, fcntl(fd->get(), F_GETFL, 0) | O_NONBLOCK); - fcntl(toFd->get(), F_SETFL, fcntl(toFd->get(), F_GETFL, 0) | O_NONBLOCK); - fcntl(fromFd->get(), F_SETFL, fcntl(fromFd->get(), F_GETFL, 0) | O_NONBLOCK); + fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK); + fcntl(toFd.get(), F_SETFL, fcntl(toFd.get(), F_GETFL, 0) | O_NONBLOCK); + fcntl(fromFd.get(), F_SETFL, fcntl(fromFd.get(), F_GETFL, 0) | O_NONBLOCK); // A circular buffer holds data read from fd and writes to parsing process uint8_t cirBuf[BUFFER_SIZE]; @@ -166,10 +166,10 @@ status_t FdBuffer::readProcessedDataInStream(unique_fd* fd, unique_fd* toFd, uni for (int i = 0; i < 3; ++i) { if ((pfds[i].revents & POLLERR) != 0) { if (i == 0 && isSysfs) { - VLOG("fd %d is sysfs, ignore its POLLERR return value", fd->get()); + VLOG("fd %d is sysfs, ignore its POLLERR return value", fd); continue; } - VLOG("fd[%d]=%d returns error events: %s", i, fd->get(), strerror(errno)); + VLOG("fd[%d]=%d returns error events: %s", i, fd, strerror(errno)); return errno != 0 ? -errno : UNKNOWN_ERROR; } } @@ -178,17 +178,17 @@ status_t FdBuffer::readProcessedDataInStream(unique_fd* fd, unique_fd* toFd, uni if (cirSize != BUFFER_SIZE && pfds[0].fd != -1) { ssize_t amt; if (rpos >= wpos) { - amt = ::read(fd->get(), cirBuf + rpos, BUFFER_SIZE - rpos); + amt = ::read(fd, cirBuf + rpos, BUFFER_SIZE - rpos); } else { - amt = ::read(fd->get(), cirBuf + rpos, wpos - rpos); + amt = ::read(fd, cirBuf + rpos, wpos - rpos); } if (amt < 0) { if (!(errno == EAGAIN || errno == EWOULDBLOCK)) { - VLOG("Fail to read fd %d: %s", fd->get(), strerror(errno)); + VLOG("Fail to read fd %d: %s", fd, strerror(errno)); return -errno; } // otherwise just continue } else if (amt == 0) { - VLOG("Reached EOF of input file %d", fd->get()); + VLOG("Reached EOF of input file %d", fd); pfds[0].fd = -1; // reach EOF so don't have to poll pfds[0]. } else { rpos += amt; @@ -200,13 +200,13 @@ status_t FdBuffer::readProcessedDataInStream(unique_fd* fd, unique_fd* toFd, uni if (cirSize > 0 && pfds[1].fd != -1) { ssize_t amt; if (rpos > wpos) { - amt = ::write(toFd->get(), cirBuf + wpos, rpos - wpos); + amt = ::write(toFd.get(), cirBuf + wpos, rpos - wpos); } else { - amt = ::write(toFd->get(), cirBuf + wpos, BUFFER_SIZE - wpos); + amt = ::write(toFd.get(), cirBuf + wpos, BUFFER_SIZE - wpos); } if (amt < 0) { if (!(errno == EAGAIN || errno == EWOULDBLOCK)) { - VLOG("Fail to write toFd %d: %s", toFd->get(), strerror(errno)); + VLOG("Fail to write toFd.get() %d: %s", toFd.get(), strerror(errno)); return -errno; } // otherwise just continue } else { @@ -217,8 +217,8 @@ status_t FdBuffer::readProcessedDataInStream(unique_fd* fd, unique_fd* toFd, uni // if buffer is empty and fd is closed, close write fd. if (cirSize == 0 && pfds[0].fd == -1 && pfds[1].fd != -1) { - VLOG("Close write pipe %d", toFd->get()); - toFd->reset(); + VLOG("Close write pipe %d", toFd.get()); + toFd.reset(); pfds[1].fd = -1; } @@ -231,14 +231,14 @@ status_t FdBuffer::readProcessedDataInStream(unique_fd* fd, unique_fd* toFd, uni } // read from parsing process - ssize_t amt = ::read(fromFd->get(), mBuffer.writeBuffer(), mBuffer.currentToWrite()); + ssize_t amt = ::read(fromFd.get(), mBuffer.writeBuffer(), mBuffer.currentToWrite()); if (amt < 0) { if (!(errno == EAGAIN || errno == EWOULDBLOCK)) { - VLOG("Fail to read fromFd %d: %s", fromFd->get(), strerror(errno)); + VLOG("Fail to read fromFd.get() %d: %s", fromFd.get(), strerror(errno)); return -errno; } // otherwise just continue } else if (amt == 0) { - VLOG("Reached EOF of fromFd %d", fromFd->get()); + VLOG("Reached EOF of fromFd.get() %d", fromFd.get()); break; } else { mBuffer.wp()->move(amt); diff --git a/cmds/incidentd/src/FdBuffer.h b/cmds/incidentd/src/FdBuffer.h index db3a74b78178..f467da866024 100644 --- a/cmds/incidentd/src/FdBuffer.h +++ b/cmds/incidentd/src/FdBuffer.h @@ -40,13 +40,13 @@ public: * Returns NO_ERROR if there were no errors or if we timed out. * Will mark the file O_NONBLOCK. */ - status_t read(unique_fd* fd, int64_t timeoutMs); + status_t read(int fd, int64_t timeoutMs); /** * Read the data until we hit eof. * Returns NO_ERROR if there were no errors. */ - status_t readFully(unique_fd* fd); + status_t readFully(int fd); /** * Read processed results by streaming data to a parsing process, e.g. incident helper. @@ -58,8 +58,8 @@ public: * * Poll will return POLLERR if fd is from sysfs, handle this edge case. */ - status_t readProcessedDataInStream(unique_fd* fd, unique_fd* toFd, unique_fd* fromFd, - int64_t timeoutMs, const bool isSysfs = false); + status_t readProcessedDataInStream(int fd, unique_fd toFd, unique_fd fromFd, int64_t timeoutMs, + const bool isSysfs = false); /** * Whether we timed out. diff --git a/cmds/incidentd/src/IncidentService.cpp b/cmds/incidentd/src/IncidentService.cpp index aeccefdd15c0..d02b4dd99067 100644 --- a/cmds/incidentd/src/IncidentService.cpp +++ b/cmds/incidentd/src/IncidentService.cpp @@ -352,8 +352,7 @@ status_t IncidentService::cmd_privacy(FILE* in, FILE* out, FILE* err, VectortimeoutMs, mIsSysfs); + status_t readStatus = buffer.readProcessedDataInStream(fd.get(), std::move(p2cPipe.writeFd()), + std::move(c2pPipe.readFd()), + this->timeoutMs, mIsSysfs); if (readStatus != NO_ERROR || buffer.timedOut()) { ALOGW("FileSection '%s' failed to read data from incident helper: %s, timedout: %s", @@ -354,9 +355,9 @@ status_t GZipSection::Execute(ReportRequestSet* requests) const { VLOG("GZipSection '%s' editPos=%zd, dataBeginAt=%zd", this->name.string(), editPos, dataBeginAt); - status_t readStatus = - buffer.readProcessedDataInStream(&fd, &p2cPipe.writeFd(), &c2pPipe.readFd(), - this->timeoutMs, isSysfs(mFilenames[index])); + status_t readStatus = buffer.readProcessedDataInStream( + fd.get(), std::move(p2cPipe.writeFd()), std::move(c2pPipe.readFd()), this->timeoutMs, + isSysfs(mFilenames[index])); if (readStatus != NO_ERROR || buffer.timedOut()) { ALOGW("GZipSection '%s' failed to read data from gzip: %s, timedout: %s", @@ -466,7 +467,7 @@ status_t WorkerThreadSection::Execute(ReportRequestSet* requests) const { pthread_attr_destroy(&attr); // Loop reading until either the timeout or the worker side is done (i.e. eof). - err = buffer.read(&data->pipe.readFd(), this->timeoutMs); + err = buffer.read(data->pipe.readFd().get(), this->timeoutMs); if (err != NO_ERROR) { // TODO: Log this error into the incident report. ALOGW("WorkerThreadSection '%s' reader failed with error '%s'", this->name.string(), @@ -573,7 +574,7 @@ status_t CommandSection::Execute(ReportRequestSet* requests) const { } cmdPipe.writeFd().reset(); - status_t readStatus = buffer.read(&ihPipe.readFd(), this->timeoutMs); + status_t readStatus = buffer.read(ihPipe.readFd().get(), this->timeoutMs); if (readStatus != NO_ERROR || buffer.timedOut()) { ALOGW("CommandSection '%s' failed to read data from incident helper: %s, timedout: %s", this->name.string(), strerror(-readStatus), buffer.timedOut() ? "true" : "false"); @@ -892,7 +893,7 @@ status_t TombstoneSection::BlockingCall(int pipeWriteFd) const { // Parent process. // Read from the pipe concurrently to avoid blocking the child. FdBuffer buffer; - err = buffer.readFully(&dumpPipe.readFd()); + err = buffer.readFully(dumpPipe.readFd().get()); if (err != NO_ERROR) { ALOGW("TombstoneSection '%s' failed to read stack dump: %d", this->name.string(), err); dumpPipe.readFd().reset(); diff --git a/cmds/incidentd/tests/FdBuffer_test.cpp b/cmds/incidentd/tests/FdBuffer_test.cpp index bf770173793f..7a05d7e071d0 100644 --- a/cmds/incidentd/tests/FdBuffer_test.cpp +++ b/cmds/incidentd/tests/FdBuffer_test.cpp @@ -37,7 +37,6 @@ class FdBufferTest : public Test { public: virtual void SetUp() override { ASSERT_NE(tf.fd, -1); - tffd.reset(tf.fd); ASSERT_NE(p2cPipe.init(), -1); ASSERT_NE(c2pPipe.init(), -1); } @@ -57,13 +56,13 @@ public: EXPECT_EQ(expected[i], '\0'); } - bool DoDataStream(unique_fd* rFd, unique_fd* wFd) { + bool DoDataStream(const unique_fd& rFd, const unique_fd& wFd) { char buf[BUFFER_SIZE]; ssize_t nRead; - while ((nRead = read(rFd->get(), buf, BUFFER_SIZE)) > 0) { + while ((nRead = read(rFd.get(), buf, BUFFER_SIZE)) > 0) { ssize_t nWritten = 0; while (nWritten < nRead) { - ssize_t amt = write(wFd->get(), buf + nWritten, nRead - nWritten); + ssize_t amt = write(wFd.get(), buf + nWritten, nRead - nWritten); if (amt < 0) { return false; } @@ -76,7 +75,6 @@ public: protected: FdBuffer buffer; TemporaryFile tf; - unique_fd tffd; Fpipe p2cPipe; Fpipe c2pPipe; @@ -87,7 +85,7 @@ protected: TEST_F(FdBufferTest, ReadAndWrite) { std::string testdata = "FdBuffer test string"; ASSERT_TRUE(WriteStringToFile(testdata, tf.path)); - ASSERT_EQ(NO_ERROR, buffer.read(&tffd, READ_TIMEOUT)); + ASSERT_EQ(NO_ERROR, buffer.read(tf.fd, READ_TIMEOUT)); AssertBufferReadSuccessful(testdata.size()); AssertBufferContent(testdata.c_str()); } @@ -100,7 +98,7 @@ TEST_F(FdBufferTest, IterateEmpty) { TEST_F(FdBufferTest, ReadAndIterate) { std::string testdata = "FdBuffer test string"; ASSERT_TRUE(WriteStringToFile(testdata, tf.path)); - ASSERT_EQ(NO_ERROR, buffer.read(&tffd, READ_TIMEOUT)); + ASSERT_EQ(NO_ERROR, buffer.read(tf.fd, READ_TIMEOUT)); int i = 0; EncodedBuffer::iterator it = buffer.data(); @@ -128,7 +126,7 @@ TEST_F(FdBufferTest, ReadTimeout) { } else { c2pPipe.writeFd().reset(); - status_t status = buffer.read(&c2pPipe.readFd(), QUICK_TIMEOUT_MS); + status_t status = buffer.read(c2pPipe.readFd().get(), QUICK_TIMEOUT_MS); ASSERT_EQ(NO_ERROR, status); EXPECT_TRUE(buffer.timedOut()); @@ -148,7 +146,7 @@ TEST_F(FdBufferTest, ReadInStreamAndWrite) { p2cPipe.writeFd().reset(); c2pPipe.readFd().reset(); ASSERT_TRUE(WriteStringToFd(HEAD, c2pPipe.writeFd())); - ASSERT_TRUE(DoDataStream(&p2cPipe.readFd(), &c2pPipe.writeFd())); + ASSERT_TRUE(DoDataStream(p2cPipe.readFd(), c2pPipe.writeFd())); p2cPipe.readFd().reset(); c2pPipe.writeFd().reset(); // Must exit here otherwise the child process will continue executing the test binary. @@ -157,8 +155,9 @@ TEST_F(FdBufferTest, ReadInStreamAndWrite) { p2cPipe.readFd().reset(); c2pPipe.writeFd().reset(); - ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(&tffd, &p2cPipe.writeFd(), - &c2pPipe.readFd(), READ_TIMEOUT)); + ASSERT_EQ(NO_ERROR, + buffer.readProcessedDataInStream(tf.fd, std::move(p2cPipe.writeFd()), + std::move(c2pPipe.readFd()), READ_TIMEOUT)); AssertBufferReadSuccessful(HEAD.size() + testdata.size()); AssertBufferContent(expected.c_str()); wait(&pid); @@ -189,8 +188,9 @@ TEST_F(FdBufferTest, ReadInStreamAndWriteAllAtOnce) { p2cPipe.readFd().reset(); c2pPipe.writeFd().reset(); - ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(&tffd, &p2cPipe.writeFd(), - &c2pPipe.readFd(), READ_TIMEOUT)); + ASSERT_EQ(NO_ERROR, + buffer.readProcessedDataInStream(tf.fd, std::move(p2cPipe.writeFd()), + std::move(c2pPipe.readFd()), READ_TIMEOUT)); AssertBufferReadSuccessful(HEAD.size() + testdata.size()); AssertBufferContent(expected.c_str()); wait(&pid); @@ -206,7 +206,7 @@ TEST_F(FdBufferTest, ReadInStreamEmpty) { if (pid == 0) { p2cPipe.writeFd().reset(); c2pPipe.readFd().reset(); - ASSERT_TRUE(DoDataStream(&p2cPipe.readFd(), &c2pPipe.writeFd())); + ASSERT_TRUE(DoDataStream(p2cPipe.readFd(), c2pPipe.writeFd())); p2cPipe.readFd().reset(); c2pPipe.writeFd().reset(); _exit(EXIT_SUCCESS); @@ -214,8 +214,9 @@ TEST_F(FdBufferTest, ReadInStreamEmpty) { p2cPipe.readFd().reset(); c2pPipe.writeFd().reset(); - ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(&tffd, &p2cPipe.writeFd(), - &c2pPipe.readFd(), READ_TIMEOUT)); + ASSERT_EQ(NO_ERROR, + buffer.readProcessedDataInStream(tf.fd, std::move(p2cPipe.writeFd()), + std::move(c2pPipe.readFd()), READ_TIMEOUT)); AssertBufferReadSuccessful(0); AssertBufferContent(""); wait(&pid); @@ -233,7 +234,7 @@ TEST_F(FdBufferTest, ReadInStreamMoreThan4MB) { if (pid == 0) { p2cPipe.writeFd().reset(); c2pPipe.readFd().reset(); - ASSERT_TRUE(DoDataStream(&p2cPipe.readFd(), &c2pPipe.writeFd())); + ASSERT_TRUE(DoDataStream(p2cPipe.readFd(), c2pPipe.writeFd())); p2cPipe.readFd().reset(); c2pPipe.writeFd().reset(); _exit(EXIT_SUCCESS); @@ -241,8 +242,9 @@ TEST_F(FdBufferTest, ReadInStreamMoreThan4MB) { p2cPipe.readFd().reset(); c2pPipe.writeFd().reset(); - ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(&fd, &p2cPipe.writeFd(), - &c2pPipe.readFd(), READ_TIMEOUT)); + ASSERT_EQ(NO_ERROR, + buffer.readProcessedDataInStream(fd, std::move(p2cPipe.writeFd()), + std::move(c2pPipe.readFd()), READ_TIMEOUT)); EXPECT_EQ(buffer.size(), fourMB); EXPECT_FALSE(buffer.timedOut()); EXPECT_TRUE(buffer.truncated()); @@ -278,8 +280,9 @@ TEST_F(FdBufferTest, ReadInStreamTimeOut) { p2cPipe.readFd().reset(); c2pPipe.writeFd().reset(); - ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(&tffd, &p2cPipe.writeFd(), - &c2pPipe.readFd(), QUICK_TIMEOUT_MS)); + ASSERT_EQ(NO_ERROR, + buffer.readProcessedDataInStream(tf.fd, std::move(p2cPipe.writeFd()), + std::move(c2pPipe.readFd()), QUICK_TIMEOUT_MS)); EXPECT_TRUE(buffer.timedOut()); kill(pid, SIGKILL); // reap the child process } diff --git a/cmds/incidentd/tests/PrivacyBuffer_test.cpp b/cmds/incidentd/tests/PrivacyBuffer_test.cpp index 5edc0c79785b..c7c69a746f0a 100644 --- a/cmds/incidentd/tests/PrivacyBuffer_test.cpp +++ b/cmds/incidentd/tests/PrivacyBuffer_test.cpp @@ -58,8 +58,7 @@ public: void writeToFdBuffer(string str) { ASSERT_TRUE(WriteStringToFile(str, tf.path)); - unique_fd tffd(tf.fd); - ASSERT_EQ(NO_ERROR, buffer.read(&tffd, 10000)); + ASSERT_EQ(NO_ERROR, buffer.read(tf.fd, 10000)); ASSERT_EQ(str.size(), buffer.size()); } -- GitLab From d778da33d91956f3eb44bb3a6e8bd7570d088315 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Wed, 28 Mar 2018 14:01:55 -0600 Subject: [PATCH 024/179] API council requested tweaks to NetworkRequest. If you put values into the Builder, you should be able to observe those values on the built object. Test: atest android.net.cts.NetworkRequestTest Bug: 74945408 Change-Id: I9aacceb82c98f7881f0eb5e1106d89d469b816a7 --- api/current.txt | 2 ++ core/java/android/net/NetworkRequest.java | 16 ++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/api/current.txt b/api/current.txt index dda00ba8e94d..cf7523702414 100644 --- a/api/current.txt +++ b/api/current.txt @@ -27185,6 +27185,8 @@ package android.net { public class NetworkRequest implements android.os.Parcelable { method public int describeContents(); + method public boolean hasCapability(int); + method public boolean hasTransport(int); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator CREATOR; } diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java index 4f92fa6a7340..caefd896ef16 100644 --- a/core/java/android/net/NetworkRequest.java +++ b/core/java/android/net/NetworkRequest.java @@ -17,6 +17,8 @@ package android.net; import android.annotation.NonNull; +import android.net.NetworkCapabilities.NetCapability; +import android.net.NetworkCapabilities.Transport; import android.os.Parcel; import android.os.Parcelable; import android.os.Process; @@ -427,6 +429,20 @@ public class NetworkRequest implements Parcelable { return type == Type.BACKGROUND_REQUEST; } + /** + * @see Builder#addCapability(int) + */ + public boolean hasCapability(@NetCapability int capability) { + return networkCapabilities.hasCapability(capability); + } + + /** + * @see Builder#addTransportType(int) + */ + public boolean hasTransport(@Transport int transportType) { + return networkCapabilities.hasTransport(transportType); + } + public String toString() { return "NetworkRequest [ " + type + " id=" + requestId + (legacyType != ConnectivityManager.TYPE_NONE ? ", legacyType=" + legacyType : "") + -- GitLab From 1fe10944864f274deac91a49dd24422d7f03577f Mon Sep 17 00:00:00 2001 From: Julia Reynolds Date: Wed, 28 Mar 2018 12:46:51 -0400 Subject: [PATCH 025/179] Allow apps with dnd access to bypass DND That is, to create channels that bypass DND, unless the user has expressed a preference for that channel Change-Id: Ic4593eac726b690946f44b3c61494b629a5ad73a Fixes: 74525735 Test: runtest systemui-notification --- .../statusbar/NotificationDataTest.java | 1 + .../NotificationManagerService.java | 3 +- .../server/notification/RankingConfig.java | 2 +- .../server/notification/RankingHelper.java | 9 +- .../notification/RankingHelperTest.java | 170 ++++++++++-------- 5 files changed, 106 insertions(+), 79 deletions(-) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationDataTest.java index 2000bff7e99a..6a30caa97e5c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationDataTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationDataTest.java @@ -250,6 +250,7 @@ public class NotificationDataTest extends SysuiTestCase { @Test public void testShouldFilterHiddenNotifications() { + initStatusBarNotification(false); // setup when(mFsc.isSystemAlertWarningNeeded(anyInt(), anyString())).thenReturn(false); when(mFsc.isSystemAlertNotification(any())).thenReturn(false); diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 210857e1b097..e930f70fbec3 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -2149,7 +2149,8 @@ public class NotificationManagerService extends SystemService { final NotificationChannel channel = channels.get(i); Preconditions.checkNotNull(channel, "channel in list is null"); mRankingHelper.createNotificationChannel(pkg, uid, channel, - true /* fromTargetApp */); + true /* fromTargetApp */, mConditionProviders.isPackageOrComponentAllowed( + pkg, UserHandle.getUserId(uid))); mListeners.notifyNotificationChannelChanged(pkg, UserHandle.getUserHandleForUid(uid), mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), false), diff --git a/services/core/java/com/android/server/notification/RankingConfig.java b/services/core/java/com/android/server/notification/RankingConfig.java index b1b0bf26d9ee..af6468333ba0 100644 --- a/services/core/java/com/android/server/notification/RankingConfig.java +++ b/services/core/java/com/android/server/notification/RankingConfig.java @@ -38,7 +38,7 @@ public interface RankingConfig { ParceledListSlice getNotificationChannelGroups(String pkg, int uid, boolean includeDeleted, boolean includeNonGrouped); void createNotificationChannel(String pkg, int uid, NotificationChannel channel, - boolean fromTargetApp); + boolean fromTargetApp, boolean hasDndAccess); void updateNotificationChannel(String pkg, int uid, NotificationChannel channel, boolean fromUser); NotificationChannel getNotificationChannel(String pkg, int uid, String channelId, boolean includeDeleted); void deleteNotificationChannel(String pkg, int uid, String channelId); diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java index f16311320972..98d5c9a59f6b 100644 --- a/services/core/java/com/android/server/notification/RankingHelper.java +++ b/services/core/java/com/android/server/notification/RankingHelper.java @@ -569,7 +569,7 @@ public class RankingHelper implements RankingConfig { @Override public void createNotificationChannel(String pkg, int uid, NotificationChannel channel, - boolean fromTargetApp) { + boolean fromTargetApp, boolean hasDndAccess) { Preconditions.checkNotNull(pkg); Preconditions.checkNotNull(channel); Preconditions.checkNotNull(channel.getId()); @@ -610,8 +610,9 @@ public class RankingHelper implements RankingConfig { existing.setImportance(channel.getImportance()); } - // system apps can bypass dnd if the user hasn't changed any fields on the channel yet - if (existing.getUserLockedFields() == 0 & isSystemApp) { + // system apps and dnd access apps can bypass dnd if the user hasn't changed any + // fields on the channel yet + if (existing.getUserLockedFields() == 0 && (isSystemApp || hasDndAccess)) { existing.setBypassDnd(channel.canBypassDnd()); } @@ -624,7 +625,7 @@ public class RankingHelper implements RankingConfig { } // Reset fields that apps aren't allowed to set. - if (fromTargetApp && !isSystemApp) { + if (fromTargetApp && !(isSystemApp || hasDndAccess)) { channel.setBypassDnd(r.priority == Notification.PRIORITY_MAX); } if (fromTargetApp) { diff --git a/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java index 09d88fd8c87c..0815876e5915 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java @@ -367,8 +367,8 @@ public class RankingHelperTest extends UiServiceTestCase { mHelper.createNotificationChannelGroup(PKG, UID, ncg, true); mHelper.createNotificationChannelGroup(PKG, UID, ncg2, true); - mHelper.createNotificationChannel(PKG, UID, channel1, true); - mHelper.createNotificationChannel(PKG, UID, channel2, false); + mHelper.createNotificationChannel(PKG, UID, channel1, true, false); + mHelper.createNotificationChannel(PKG, UID, channel2, false, false); mHelper.setShowBadge(PKG, UID, true); @@ -427,10 +427,10 @@ public class RankingHelperTest extends UiServiceTestCase { mHelper.createNotificationChannelGroup(PKG, UID, ncg, true); mHelper.createNotificationChannelGroup(PKG, UID, ncg2, true); - mHelper.createNotificationChannel(PKG, UID, channel1, true); - mHelper.createNotificationChannel(PKG, UID, channel2, false); - mHelper.createNotificationChannel(PKG, UID, channel3, false); - mHelper.createNotificationChannel(UPDATED_PKG, UID2, getChannel(), true); + mHelper.createNotificationChannel(PKG, UID, channel1, true, false); + mHelper.createNotificationChannel(PKG, UID, channel2, false, false); + mHelper.createNotificationChannel(PKG, UID, channel3, false, false); + mHelper.createNotificationChannel(UPDATED_PKG, UID2, getChannel(), true, false); mHelper.setShowBadge(PKG, UID, true); @@ -481,7 +481,7 @@ public class RankingHelperTest extends UiServiceTestCase { NotificationChannel channel = new NotificationChannel("id", "name", IMPORTANCE_LOW); channel.setSound(SOUND_URI, mAudioAttributes); - mHelper.createNotificationChannel(PKG, UID, channel, true); + mHelper.createNotificationChannel(PKG, UID, channel, true, false); ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, true, channel.getId()); @@ -507,7 +507,7 @@ public class RankingHelperTest extends UiServiceTestCase { NotificationChannel channel = new NotificationChannel("id", "name", IMPORTANCE_LOW); channel.setSound(SOUND_URI, mAudioAttributes); - mHelper.createNotificationChannel(PKG, UID, channel, true); + mHelper.createNotificationChannel(PKG, UID, channel, true, false); ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, true, channel.getId()); loadStreamXml(baos, true); @@ -528,7 +528,7 @@ public class RankingHelperTest extends UiServiceTestCase { NotificationChannel channel = new NotificationChannel("id", "name", IMPORTANCE_LOW); channel.setSound(SOUND_URI, mAudioAttributes); - mHelper.createNotificationChannel(PKG, UID, channel, true); + mHelper.createNotificationChannel(PKG, UID, channel, true, false); ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, true, channel.getId()); loadStreamXml(baos, true); @@ -569,7 +569,7 @@ public class RankingHelperTest extends UiServiceTestCase { NotificationChannel channel = new NotificationChannel("id", "name", IMPORTANCE_LOW); channel.setSound(null, mAudioAttributes); - mHelper.createNotificationChannel(PKG, UID, channel, true); + mHelper.createNotificationChannel(PKG, UID, channel, true, false); ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, true, channel.getId()); loadStreamXml(baos, true); @@ -593,9 +593,9 @@ public class RankingHelperTest extends UiServiceTestCase { mHelper.createNotificationChannelGroup(PKG, UID, ncg, true); mHelper.createNotificationChannelGroup(PKG, UID, ncg2, true); - mHelper.createNotificationChannel(PKG, UID, channel1, true); - mHelper.createNotificationChannel(PKG, UID, channel2, false); - mHelper.createNotificationChannel(PKG, UID, channel3, true); + mHelper.createNotificationChannel(PKG, UID, channel1, true, false); + mHelper.createNotificationChannel(PKG, UID, channel2, false, false); + mHelper.createNotificationChannel(PKG, UID, channel3, true, false); mHelper.deleteNotificationChannel(PKG, UID, channel1.getId()); mHelper.deleteNotificationChannelGroup(PKG, UID, ncg.getId()); @@ -701,7 +701,7 @@ public class RankingHelperTest extends UiServiceTestCase { @Test public void testDeletesDefaultChannelAfterChannelIsCreated() throws Exception { mHelper.createNotificationChannel(PKG, UID, - new NotificationChannel("bananas", "bananas", IMPORTANCE_LOW), true); + new NotificationChannel("bananas", "bananas", IMPORTANCE_LOW), true, false); ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, false, NotificationChannel.DEFAULT_CHANNEL_ID, "bananas"); @@ -721,7 +721,7 @@ public class RankingHelperTest extends UiServiceTestCase { ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, false, NotificationChannel.DEFAULT_CHANNEL_ID, "bananas"); mHelper.createNotificationChannel(PKG, UID, - new NotificationChannel("bananas", "bananas", IMPORTANCE_LOW), true); + new NotificationChannel("bananas", "bananas", IMPORTANCE_LOW), true, false); loadStreamXml(baos, false); @@ -734,36 +734,39 @@ public class RankingHelperTest extends UiServiceTestCase { mHelper.setImportance(PKG, UID, IMPORTANCE_NONE); mHelper.createNotificationChannel(PKG, UID, - new NotificationChannel("bananas", "bananas", IMPORTANCE_LOW), true); + new NotificationChannel("bananas", "bananas", IMPORTANCE_LOW), true, false); } @Test public void testCreateChannel_badImportance() throws Exception { try { mHelper.createNotificationChannel(PKG, UID, - new NotificationChannel("bananas", "bananas", IMPORTANCE_NONE - 1), true); + new NotificationChannel("bananas", "bananas", IMPORTANCE_NONE - 1), + true, false); fail("Was allowed to create a channel with invalid importance"); } catch (IllegalArgumentException e) { // yay } try { mHelper.createNotificationChannel(PKG, UID, - new NotificationChannel("bananas", "bananas", IMPORTANCE_UNSPECIFIED), true); + new NotificationChannel("bananas", "bananas", IMPORTANCE_UNSPECIFIED), + true, false); fail("Was allowed to create a channel with invalid importance"); } catch (IllegalArgumentException e) { // yay } try { mHelper.createNotificationChannel(PKG, UID, - new NotificationChannel("bananas", "bananas", IMPORTANCE_MAX + 1), true); + new NotificationChannel("bananas", "bananas", IMPORTANCE_MAX + 1), + true, false); fail("Was allowed to create a channel with invalid importance"); } catch (IllegalArgumentException e) { // yay } mHelper.createNotificationChannel(PKG, UID, - new NotificationChannel("bananas", "bananas", IMPORTANCE_NONE), true); + new NotificationChannel("bananas", "bananas", IMPORTANCE_NONE), true, false); mHelper.createNotificationChannel(PKG, UID, - new NotificationChannel("bananas", "bananas", IMPORTANCE_MAX), true); + new NotificationChannel("bananas", "bananas", IMPORTANCE_MAX), true, false); } @@ -777,7 +780,7 @@ public class RankingHelperTest extends UiServiceTestCase { channel.setBypassDnd(true); channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET); - mHelper.createNotificationChannel(PKG, UID, channel, false); + mHelper.createNotificationChannel(PKG, UID, channel, false, false); // same id, try to update all fields final NotificationChannel channel2 = @@ -824,7 +827,7 @@ public class RankingHelperTest extends UiServiceTestCase { public void testUpdate_postUpgrade_noUpdateAppFields() throws Exception { final NotificationChannel channel = new NotificationChannel("id2", "name2", IMPORTANCE_LOW); - mHelper.createNotificationChannel(PKG, UID, channel, false); + mHelper.createNotificationChannel(PKG, UID, channel, false, false); assertTrue(mHelper.canShowBadge(PKG, UID)); assertEquals(Notification.PRIORITY_DEFAULT, mHelper.getPackagePriority(PKG, UID)); assertEquals(NotificationManager.VISIBILITY_NO_OVERRIDE, @@ -865,7 +868,7 @@ public class RankingHelperTest extends UiServiceTestCase { } channel.lockFields(lockMask); - mHelper.createNotificationChannel(PKG, UID, channel, true); + mHelper.createNotificationChannel(PKG, UID, channel, true, false); NotificationChannel savedChannel = mHelper.getNotificationChannel(PKG, UID, channel.getId(), false); @@ -894,7 +897,7 @@ public class RankingHelperTest extends UiServiceTestCase { } channel.lockFields(lockMask); - mHelper.createNotificationChannel(PKG, UID, channel, true); + mHelper.createNotificationChannel(PKG, UID, channel, true, false); NotificationChannel savedChannel = mHelper.getNotificationChannel(PKG, UID, channel.getId(), false); @@ -920,7 +923,7 @@ public class RankingHelperTest extends UiServiceTestCase { @Test public void testLockFields_soundAndVibration() throws Exception { - mHelper.createNotificationChannel(PKG, UID, getChannel(), true); + mHelper.createNotificationChannel(PKG, UID, getChannel(), true, false); final NotificationChannel update1 = getChannel(); update1.setSound(new Uri.Builder().scheme("test").build(), @@ -944,7 +947,7 @@ public class RankingHelperTest extends UiServiceTestCase { @Test public void testLockFields_vibrationAndLights() throws Exception { - mHelper.createNotificationChannel(PKG, UID, getChannel(), true); + mHelper.createNotificationChannel(PKG, UID, getChannel(), true, false); final NotificationChannel update1 = getChannel(); update1.setVibrationPattern(new long[]{7945, 46 ,246}); @@ -964,7 +967,7 @@ public class RankingHelperTest extends UiServiceTestCase { @Test public void testLockFields_lightsAndImportance() throws Exception { - mHelper.createNotificationChannel(PKG, UID, getChannel(), true); + mHelper.createNotificationChannel(PKG, UID, getChannel(), true, false); final NotificationChannel update1 = getChannel(); update1.setLightColor(Color.GREEN); @@ -984,7 +987,7 @@ public class RankingHelperTest extends UiServiceTestCase { @Test public void testLockFields_visibilityAndDndAndBadge() throws Exception { - mHelper.createNotificationChannel(PKG, UID, getChannel(), true); + mHelper.createNotificationChannel(PKG, UID, getChannel(), true, false); assertEquals(0, mHelper.getNotificationChannel(PKG, UID, getChannel().getId(), false) .getUserLockedFields()); @@ -1029,7 +1032,7 @@ public class RankingHelperTest extends UiServiceTestCase { channel.enableVibration(true); channel.setVibrationPattern(new long[]{100, 67, 145, 156}); - mHelper.createNotificationChannel(PKG, UID, channel, true); + mHelper.createNotificationChannel(PKG, UID, channel, true, false); mHelper.deleteNotificationChannel(PKG, UID, channel.getId()); // Does not return deleted channel @@ -1058,8 +1061,8 @@ public class RankingHelperTest extends UiServiceTestCase { NotificationChannel channel2 = new NotificationChannel("id4", "a", NotificationManager.IMPORTANCE_HIGH); channelMap.put(channel2.getId(), channel2); - mHelper.createNotificationChannel(PKG, UID, channel, true); - mHelper.createNotificationChannel(PKG, UID, channel2, true); + mHelper.createNotificationChannel(PKG, UID, channel, true, false); + mHelper.createNotificationChannel(PKG, UID, channel2, true, false); mHelper.deleteNotificationChannel(PKG, UID, channel.getId()); @@ -1091,9 +1094,9 @@ public class RankingHelperTest extends UiServiceTestCase { new NotificationChannel("id4", "a", NotificationManager.IMPORTANCE_HIGH); NotificationChannel channel3 = new NotificationChannel("id4", "a", NotificationManager.IMPORTANCE_HIGH); - mHelper.createNotificationChannel(PKG, UID, channel, true); - mHelper.createNotificationChannel(PKG, UID, channel2, true); - mHelper.createNotificationChannel(PKG, UID, channel3, true); + mHelper.createNotificationChannel(PKG, UID, channel, true, false); + mHelper.createNotificationChannel(PKG, UID, channel2, true, false); + mHelper.createNotificationChannel(PKG, UID, channel3, true, false); mHelper.deleteNotificationChannel(PKG, UID, channel.getId()); mHelper.deleteNotificationChannel(PKG, UID, channel3.getId()); @@ -1109,14 +1112,14 @@ public class RankingHelperTest extends UiServiceTestCase { new NotificationChannel("id2", "name2", IMPORTANCE_LOW); channel.setVibrationPattern(vibration); - mHelper.createNotificationChannel(PKG, UID, channel, true); + mHelper.createNotificationChannel(PKG, UID, channel, true, false); mHelper.deleteNotificationChannel(PKG, UID, channel.getId()); NotificationChannel newChannel = new NotificationChannel( channel.getId(), channel.getName(), NotificationManager.IMPORTANCE_HIGH); newChannel.setVibrationPattern(new long[]{100}); - mHelper.createNotificationChannel(PKG, UID, newChannel, true); + mHelper.createNotificationChannel(PKG, UID, newChannel, true, false); // No long deleted, using old settings compareChannels(channel, @@ -1128,7 +1131,7 @@ public class RankingHelperTest extends UiServiceTestCase { assertTrue(mHelper.onlyHasDefaultChannel(PKG, UID)); assertFalse(mHelper.onlyHasDefaultChannel(UPDATED_PKG, UID2)); - mHelper.createNotificationChannel(PKG, UID, getChannel(), true); + mHelper.createNotificationChannel(PKG, UID, getChannel(), true, false); assertFalse(mHelper.onlyHasDefaultChannel(PKG, UID)); } @@ -1136,7 +1139,7 @@ public class RankingHelperTest extends UiServiceTestCase { public void testCreateChannel_defaultChannelId() throws Exception { try { mHelper.createNotificationChannel(PKG, UID, new NotificationChannel( - NotificationChannel.DEFAULT_CHANNEL_ID, "ha", IMPORTANCE_HIGH), true); + NotificationChannel.DEFAULT_CHANNEL_ID, "ha", IMPORTANCE_HIGH), true, false); fail("Allowed to create default channel"); } catch (IllegalArgumentException e) { // pass @@ -1150,13 +1153,13 @@ public class RankingHelperTest extends UiServiceTestCase { new NotificationChannel("id2", "name2", IMPORTANCE_LOW); channel.setVibrationPattern(vibration); - mHelper.createNotificationChannel(PKG, UID, channel, true); + mHelper.createNotificationChannel(PKG, UID, channel, true, false); NotificationChannel newChannel = new NotificationChannel( channel.getId(), channel.getName(), NotificationManager.IMPORTANCE_HIGH); newChannel.setVibrationPattern(new long[]{100}); - mHelper.createNotificationChannel(PKG, UID, newChannel, true); + mHelper.createNotificationChannel(PKG, UID, newChannel, true, false); // Old settings not overridden compareChannels(channel, @@ -1169,7 +1172,7 @@ public class RankingHelperTest extends UiServiceTestCase { final NotificationChannel channel = new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_DEFAULT); channel.setSound(sound, mAudioAttributes); - mHelper.createNotificationChannel(PKG, UID, channel, true); + mHelper.createNotificationChannel(PKG, UID, channel, true, false); assertEquals(sound, mHelper.getNotificationChannel( PKG, UID, channel.getId(), false).getSound()); } @@ -1181,8 +1184,8 @@ public class RankingHelperTest extends UiServiceTestCase { NotificationChannel channel2 = new NotificationChannel("id2", "name2", IMPORTANCE_LOW); - mHelper.createNotificationChannel(PKG, UID, channel1, true); - mHelper.createNotificationChannel(PKG, UID, channel2, false); + mHelper.createNotificationChannel(PKG, UID, channel1, true, false); + mHelper.createNotificationChannel(PKG, UID, channel2, false, false); mHelper.permanentlyDeleteNotificationChannels(PKG, UID); @@ -1205,9 +1208,9 @@ public class RankingHelperTest extends UiServiceTestCase { mHelper.createNotificationChannelGroup(PKG, UID, notDeleted, true); mHelper.createNotificationChannelGroup(PKG, UID, deleted, true); - mHelper.createNotificationChannel(PKG, UID, nonGroupedNonDeletedChannel, true); - mHelper.createNotificationChannel(PKG, UID, groupedAndDeleted, true); - mHelper.createNotificationChannel(PKG, UID, groupedButNotDeleted, true); + mHelper.createNotificationChannel(PKG, UID, nonGroupedNonDeletedChannel, true, false); + mHelper.createNotificationChannel(PKG, UID, groupedAndDeleted, true, false); + mHelper.createNotificationChannel(PKG, UID, groupedButNotDeleted, true, false); mHelper.deleteNotificationChannelGroup(PKG, UID, deleted.getId()); @@ -1264,14 +1267,14 @@ public class RankingHelperTest extends UiServiceTestCase { // Deleted NotificationChannel channel1 = new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); - mHelper.createNotificationChannel(PKG, UID, channel1, true); + mHelper.createNotificationChannel(PKG, UID, channel1, true, false); mHelper.onPackagesChanged(true, UserHandle.USER_SYSTEM, new String[]{PKG}, new int[]{UID}); assertEquals(0, mHelper.getNotificationChannels(PKG, UID, true).getList().size()); // Not deleted - mHelper.createNotificationChannel(PKG, UID, channel1, true); + mHelper.createNotificationChannel(PKG, UID, channel1, true, false); mHelper.onPackagesChanged(false, UserHandle.USER_SYSTEM, new String[]{PKG}, new int[]{UID}); assertEquals(2, mHelper.getNotificationChannels(PKG, UID, false).getList().size()); @@ -1302,7 +1305,7 @@ public class RankingHelperTest extends UiServiceTestCase { @Test public void testOnPackageChange_downgradeTargetSdk() throws Exception { // create channel as api 26 - mHelper.createNotificationChannel(UPDATED_PKG, UID2, getChannel(), true); + mHelper.createNotificationChannel(UPDATED_PKG, UID2, getChannel(), true, false); // install new app version targeting 25 final ApplicationInfo legacy = new ApplicationInfo(); @@ -1338,7 +1341,7 @@ public class RankingHelperTest extends UiServiceTestCase { new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); channel1.setGroup("garbage"); try { - mHelper.createNotificationChannel(PKG, UID, channel1, true); + mHelper.createNotificationChannel(PKG, UID, channel1, true, false); fail("Created a channel with a bad group"); } catch (IllegalArgumentException e) { } @@ -1351,7 +1354,7 @@ public class RankingHelperTest extends UiServiceTestCase { NotificationChannel channel1 = new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); channel1.setGroup(ncg.getId()); - mHelper.createNotificationChannel(PKG, UID, channel1, true); + mHelper.createNotificationChannel(PKG, UID, channel1, true, false); assertEquals(ncg.getId(), mHelper.getNotificationChannel(PKG, UID, channel1.getId(), false).getGroup()); @@ -1369,20 +1372,20 @@ public class RankingHelperTest extends UiServiceTestCase { NotificationChannel channel1 = new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); channel1.setGroup(ncg.getId()); - mHelper.createNotificationChannel(PKG, UID, channel1, true); + mHelper.createNotificationChannel(PKG, UID, channel1, true, false); NotificationChannel channel1a = new NotificationChannel("id1a", "name1", NotificationManager.IMPORTANCE_HIGH); channel1a.setGroup(ncg.getId()); - mHelper.createNotificationChannel(PKG, UID, channel1a, true); + mHelper.createNotificationChannel(PKG, UID, channel1a, true, false); NotificationChannel channel2 = new NotificationChannel("id2", "name1", NotificationManager.IMPORTANCE_HIGH); channel2.setGroup(ncg2.getId()); - mHelper.createNotificationChannel(PKG, UID, channel2, true); + mHelper.createNotificationChannel(PKG, UID, channel2, true, false); NotificationChannel channel3 = new NotificationChannel("id3", "name1", NotificationManager.IMPORTANCE_HIGH); - mHelper.createNotificationChannel(PKG, UID, channel3, true); + mHelper.createNotificationChannel(PKG, UID, channel3, true, false); List actual = mHelper.getNotificationChannelGroups(PKG, UID, true, true).getList(); @@ -1416,7 +1419,7 @@ public class RankingHelperTest extends UiServiceTestCase { NotificationChannel channel1 = new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); channel1.setGroup(ncg.getId()); - mHelper.createNotificationChannel(PKG, UID, channel1, true); + mHelper.createNotificationChannel(PKG, UID, channel1, true, false); mHelper.getNotificationChannelGroups(PKG, UID, true, true).getList(); channel1.setImportance(IMPORTANCE_LOW); @@ -1436,12 +1439,12 @@ public class RankingHelperTest extends UiServiceTestCase { @Test public void testCreateChannel_updateName() throws Exception { NotificationChannel nc = new NotificationChannel("id", "hello", IMPORTANCE_DEFAULT); - mHelper.createNotificationChannel(PKG, UID, nc, true); + mHelper.createNotificationChannel(PKG, UID, nc, true, false); NotificationChannel actual = mHelper.getNotificationChannel(PKG, UID, "id", false); assertEquals("hello", actual.getName()); nc = new NotificationChannel("id", "goodbye", IMPORTANCE_HIGH); - mHelper.createNotificationChannel(PKG, UID, nc, true); + mHelper.createNotificationChannel(PKG, UID, nc, true, false); actual = mHelper.getNotificationChannel(PKG, UID, "id", false); assertEquals("goodbye", actual.getName()); @@ -1455,13 +1458,13 @@ public class RankingHelperTest extends UiServiceTestCase { NotificationChannelGroup group = new NotificationChannelGroup("group", ""); mHelper.createNotificationChannelGroup(PKG, UID, group, true); NotificationChannel nc = new NotificationChannel("id", "hello", IMPORTANCE_DEFAULT); - mHelper.createNotificationChannel(PKG, UID, nc, true); + mHelper.createNotificationChannel(PKG, UID, nc, true, false); NotificationChannel actual = mHelper.getNotificationChannel(PKG, UID, "id", false); assertNull(actual.getGroup()); nc = new NotificationChannel("id", "hello", IMPORTANCE_HIGH); nc.setGroup(group.getId()); - mHelper.createNotificationChannel(PKG, UID, nc, true); + mHelper.createNotificationChannel(PKG, UID, nc, true, false); actual = mHelper.getNotificationChannel(PKG, UID, "id", false); assertNotNull(actual.getGroup()); @@ -1486,7 +1489,7 @@ public class RankingHelperTest extends UiServiceTestCase { int numChannels = ThreadLocalRandom.current().nextInt(1, 10); for (int j = 0; j < numChannels; j++) { mHelper.createNotificationChannel(pkgName, UID, - new NotificationChannel("" + j, "a", IMPORTANCE_HIGH), true); + new NotificationChannel("" + j, "a", IMPORTANCE_HIGH), true, false); } expectedChannels.put(pkgName, numChannels); } @@ -1621,10 +1624,10 @@ public class RankingHelperTest extends UiServiceTestCase { c.setGroup(group.getId()); NotificationChannel d = new NotificationChannel("d", "d", IMPORTANCE_DEFAULT); - mHelper.createNotificationChannel(PKG, UID, a, true); - mHelper.createNotificationChannel(PKG, UID, b, true); - mHelper.createNotificationChannel(PKG, UID, c, true); - mHelper.createNotificationChannel(PKG, UID, d, true); + mHelper.createNotificationChannel(PKG, UID, a, true, false); + mHelper.createNotificationChannel(PKG, UID, b, true, false); + mHelper.createNotificationChannel(PKG, UID, c, true, false); + mHelper.createNotificationChannel(PKG, UID, d, true, false); mHelper.deleteNotificationChannel(PKG, UID, c.getId()); NotificationChannelGroup retrieved = mHelper.getNotificationChannelGroupWithChannels( @@ -1641,22 +1644,31 @@ public class RankingHelperTest extends UiServiceTestCase { @Test public void testAndroidPkgCanBypassDnd_creation() { - NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW); test.setBypassDnd(true); - mHelper.createNotificationChannel(SYSTEM_PKG, SYSTEM_UID, test, true); + mHelper.createNotificationChannel(SYSTEM_PKG, SYSTEM_UID, test, true, false); assertTrue(mHelper.getNotificationChannel(SYSTEM_PKG, SYSTEM_UID, "A", false) .canBypassDnd()); } + @Test + public void testDndPkgCanBypassDnd_creation() { + NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW); + test.setBypassDnd(true); + + mHelper.createNotificationChannel(PKG, UID, test, true, true); + + assertTrue(mHelper.getNotificationChannel(PKG, UID, "A", false).canBypassDnd()); + } + @Test public void testNormalPkgCannotBypassDnd_creation() { NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW); test.setBypassDnd(true); - mHelper.createNotificationChannel(PKG, 1000, test, true); + mHelper.createNotificationChannel(PKG, 1000, test, true, false); assertFalse(mHelper.getNotificationChannel(PKG, 1000, "A", false).canBypassDnd()); } @@ -1664,11 +1676,11 @@ public class RankingHelperTest extends UiServiceTestCase { @Test public void testAndroidPkgCanBypassDnd_update() throws Exception { NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW); - mHelper.createNotificationChannel(SYSTEM_PKG, SYSTEM_UID, test, true); + mHelper.createNotificationChannel(SYSTEM_PKG, SYSTEM_UID, test, true, false); NotificationChannel update = new NotificationChannel("A", "a", IMPORTANCE_LOW); update.setBypassDnd(true); - mHelper.createNotificationChannel(SYSTEM_PKG, SYSTEM_UID, update, true); + mHelper.createNotificationChannel(SYSTEM_PKG, SYSTEM_UID, update, true, false); assertTrue(mHelper.getNotificationChannel(SYSTEM_PKG, SYSTEM_UID, "A", false) .canBypassDnd()); @@ -1677,13 +1689,25 @@ public class RankingHelperTest extends UiServiceTestCase { verify(mPm, times(2)).getPackageInfoAsUser(any(), anyInt(), anyInt()); } + @Test + public void testDndPkgCanBypassDnd_update() throws Exception { + NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW); + mHelper.createNotificationChannel(PKG, UID, test, true, true); + + NotificationChannel update = new NotificationChannel("A", "a", IMPORTANCE_LOW); + update.setBypassDnd(true); + mHelper.createNotificationChannel(PKG, UID, update, true, true); + + assertTrue(mHelper.getNotificationChannel(PKG, UID, "A", false).canBypassDnd()); + } + @Test public void testNormalPkgCannotBypassDnd_update() { NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW); - mHelper.createNotificationChannel(PKG, 1000, test, true); + mHelper.createNotificationChannel(PKG, 1000, test, true, false); NotificationChannel update = new NotificationChannel("A", "a", IMPORTANCE_LOW); update.setBypassDnd(true); - mHelper.createNotificationChannel(PKG, 1000, update, true); + mHelper.createNotificationChannel(PKG, 1000, update, true, false); assertFalse(mHelper.getNotificationChannel(PKG, 1000, "A", false).canBypassDnd()); } } -- GitLab From 67b51d46918e5d42e9784289aefe2f47d10ac544 Mon Sep 17 00:00:00 2001 From: Alan Viverette Date: Wed, 28 Mar 2018 17:10:20 -0400 Subject: [PATCH 026/179] Federate platform docs against AndroidX Bug: 76692459 Test: make docs Change-Id: If1523ee47bcc58151a641938ac6f4a6e7ae1af0b --- Android.mk | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Android.mk b/Android.mk index e219661b19f1..d7d9c900e3bf 100644 --- a/Android.mk +++ b/Android.mk @@ -252,6 +252,11 @@ framework_docs_LOCAL_DROIDDOC_OPTIONS += \ -federate SupportLib https://developer.android.com \ -federationapi SupportLib prebuilts/sdk/current/support-api.txt +# Federate AndroidX references against local API file. +framework_docs_LOCAL_DROIDDOC_OPTIONS += \ + -federate AndroidX https://developer.android.com \ + -federationapi AndroidX prebuilts/sdk/current/androidx-api.txt + # ==== Public API diff =========================== include $(CLEAR_VARS) -- GitLab From 20d30e522654d26a30b2afc3a03410e9bc0219ce Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Wed, 28 Mar 2018 14:14:17 -0700 Subject: [PATCH 027/179] Improved documentation of AutofillFieldClassificationService.onGetScores() Test: echo 'In TH we trust!' Fixes: 74830976 Change-Id: Ia1c002fa3b340810789b9cca9d7c4b71ea083230 --- .../AutofillFieldClassificationService.java | 60 ++++++++++++++++--- 1 file changed, 52 insertions(+), 8 deletions(-) diff --git a/core/java/android/service/autofill/AutofillFieldClassificationService.java b/core/java/android/service/autofill/AutofillFieldClassificationService.java index cf1674989fe5..99d45f40c26a 100644 --- a/core/java/android/service/autofill/AutofillFieldClassificationService.java +++ b/core/java/android/service/autofill/AutofillFieldClassificationService.java @@ -113,23 +113,67 @@ public abstract class AutofillFieldClassificationService extends Service { /** * Calculates field classification scores in a batch. * - *

    See {@link AutofillFieldClassificationService} for more info about field classification - * scores. + *

    A field classification score is a {@code float} representing how well an + * {@link AutofillValue} filled matches a expected value predicted by an autofill service + * —a full-match is {@code 1.0} (representing 100%), while a full mismatch is {@code 0.0}. * - * @param algorithm name of the algorithm to be used to calculate the scores. If invalid, the - * default algorithm will be used instead. - * @param args optional arguments to be passed to the algorithm. + *

    The exact score depends on the algorithm used to calculate it— the service must + * provide at least one default algorithm (which is used when the algorithm is not specified + * or is invalid), but it could provide more (in which case the algorithm name should be + * specifiied by the caller when calculating the scores). + * + *

    For example, if the service provides an algorithm named {@code EXACT_MATCH} that + * returns {@code 1.0} if all characters in match or {@code 0.0} otherwise, a call to: + * + *

    +     * service.onGetScores("EXACT_MATCH", null,
    +     *   Arrays.asList(AutofillValue.forText("email1"), AutofillValue.forText("PHONE1")),
    +     *   Arrays.asList("email1", "phone1"));
    +     * 
    + * + *

    Returns: + * + *

    +     * [
    +     *   [1.0, 0.0], // "email1" compared against ["email1", "phone1"]
    +     *   [0.0, 0.0]  // "PHONE1" compared against ["email1", "phone1"]
    +     * ];
    +     * 
    + * + *

    If the same algorithm allows the caller to specify whether the comparisons should be + * case sensitive by passing a boolean option named {@code "case_sensitive"}, then a call to: + * + *

    +     * Bundle algorithmOptions = new Bundle();
    +     * algorithmOptions.putBoolean("case_sensitive", false);
    +     *
    +     * service.onGetScores("EXACT_MATCH", algorithmOptions,
    +     *   Arrays.asList(AutofillValue.forText("email1"), AutofillValue.forText("PHONE1")),
    +     *   Arrays.asList("email1", "phone1"));
    +     * 
    + * + *

    Returns: + * + *

    +     * [
    +     *   [1.0, 0.0], // "email1" compared against ["email1", "phone1"]
    +     *   [0.0, 1.0]  // "PHONE1" compared against ["email1", "phone1"]
    +     * ];
    +     * 
    + * + * @param algorithm name of the algorithm to be used to calculate the scores. If invalid or + * {@code null}, the default algorithm is used instead. + * @param algorithmOptions optional arguments to be passed to the algorithm. * @param actualValues values entered by the user. * @param userDataValues values predicted from the user data. - * @return the calculated scores, with the first dimension representing actual values and the - * second dimension values from {@link UserData}. + * @return the calculated scores of {@code actualValues} x {@code userDataValues}. * * {@hide} */ @Nullable @SystemApi public float[][] onGetScores(@Nullable String algorithm, - @Nullable Bundle args, @NonNull List actualValues, + @Nullable Bundle algorithmOptions, @NonNull List actualValues, @NonNull List userDataValues) { Log.e(TAG, "service implementation (" + getClass() + " does not implement onGetScore()"); return null; -- GitLab From 205d83e108e4ff0442547cb30a8c2d83f69afa15 Mon Sep 17 00:00:00 2001 From: John Reck Date: Wed, 28 Mar 2018 14:36:58 -0700 Subject: [PATCH 028/179] Move Path to NAR Bug: 74686528 Test: PathTest#testUseAfterFinalize Change-Id: Ic1c9df6f1b63ea5795a6c3a54b8fc50fdaf0a5f4 --- core/jni/android/graphics/Path.cpp | 23 ++++++++++++++--------- graphics/java/android/graphics/Path.java | 23 +++++++++++------------ 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/core/jni/android/graphics/Path.cpp b/core/jni/android/graphics/Path.cpp index d3d68826affe..97abd82eaac5 100644 --- a/core/jni/android/graphics/Path.cpp +++ b/core/jni/android/graphics/Path.cpp @@ -37,6 +37,14 @@ namespace android { class SkPathGlue { public: + static void finalizer(SkPath* obj) { + // Purge entries from the HWUI path cache if this path's data is unique + if (obj->unique() && android::uirenderer::Caches::hasInstance()) { + android::uirenderer::Caches::getInstance().pathCache.removeDeferred(obj); + } + delete obj; + } + // ---------------- Regular JNI ----------------------------- static jlong init(JNIEnv* env, jclass clazz) { @@ -48,13 +56,8 @@ public: return reinterpret_cast(new SkPath(*val)); } - static void finalize(JNIEnv* env, jclass clazz, jlong objHandle) { - SkPath* obj = reinterpret_cast(objHandle); - // Purge entries from the HWUI path cache if this path's data is unique - if (obj->unique() && android::uirenderer::Caches::hasInstance()) { - android::uirenderer::Caches::getInstance().pathCache.removeDeferred(obj); - } - delete obj; + static jlong getFinalizer(JNIEnv* env, jclass clazz) { + return static_cast(reinterpret_cast(&finalizer)); } static void set(JNIEnv* env, jclass clazz, jlong dstHandle, jlong srcHandle) { @@ -469,7 +472,9 @@ public: SkRect rect; SkPath* obj = reinterpret_cast(objHandle); jboolean result = obj->isRect(&rect); - GraphicsJNI::rect_to_jrectf(rect, env, jrect); + if (jrect) { + GraphicsJNI::rect_to_jrectf(rect, env, jrect); + } return result; } @@ -510,7 +515,7 @@ public: static const JNINativeMethod methods[] = { {"nInit","()J", (void*) SkPathGlue::init}, {"nInit","(J)J", (void*) SkPathGlue::init_Path}, - {"nFinalize", "(J)V", (void*) SkPathGlue::finalize}, + {"nGetFinalizer", "()J", (void*) SkPathGlue::getFinalizer}, {"nSet","(JJ)V", (void*) SkPathGlue::set}, {"nComputeBounds","(JLandroid/graphics/RectF;)V", (void*) SkPathGlue::computeBounds}, {"nIncReserve","(JI)V", (void*) SkPathGlue::incReserve}, diff --git a/graphics/java/android/graphics/Path.java b/graphics/java/android/graphics/Path.java index 098cdc67555d..cd0862cd13fe 100644 --- a/graphics/java/android/graphics/Path.java +++ b/graphics/java/android/graphics/Path.java @@ -24,6 +24,8 @@ import android.annotation.Size; import dalvik.annotation.optimization.CriticalNative; import dalvik.annotation.optimization.FastNative; +import libcore.util.NativeAllocationRegistry; + /** * The Path class encapsulates compound (multiple contour) geometric paths * consisting of straight line segments, quadratic curves, and cubic curves. @@ -32,10 +34,14 @@ import dalvik.annotation.optimization.FastNative; * text on a path. */ public class Path { + + private static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry( + Path.class.getClassLoader(), nGetFinalizer(), 48 /* dummy size */); + /** * @hide */ - public long mNativePath; + public final long mNativePath; /** * @hide @@ -52,6 +58,7 @@ public class Path { */ public Path() { mNativePath = nInit(); + sRegistry.registerNativeAllocation(this, mNativePath); } /** @@ -69,6 +76,7 @@ public class Path { } } mNativePath = nInit(valNative); + sRegistry.registerNativeAllocation(this, mNativePath); } /** @@ -297,7 +305,7 @@ public class Path { * a rectangle * @return true if the path specifies a rectangle */ - public boolean isRect(RectF rect) { + public boolean isRect(@Nullable RectF rect) { return nIsRect(mNativePath, rect); } @@ -771,15 +779,6 @@ public class Path { nTransform(mNativePath, matrix.native_instance); } - protected void finalize() throws Throwable { - try { - nFinalize(mNativePath); - mNativePath = 0; // Other finalizers can still call us. - } finally { - super.finalize(); - } - } - /** @hide */ public final long readOnlyNI() { return mNativePath; @@ -820,7 +819,7 @@ public class Path { private static native long nInit(); private static native long nInit(long nPath); - private static native void nFinalize(long nPath); + private static native long nGetFinalizer(); private static native void nSet(long native_dst, long nSrc); private static native void nComputeBounds(long nPath, RectF bounds); private static native void nIncReserve(long nPath, int extraPtCount); -- GitLab From 5f6dc61c10dc06e669dfc05c94fffddd15e4e742 Mon Sep 17 00:00:00 2001 From: jovanak Date: Tue, 27 Mar 2018 11:59:22 -0700 Subject: [PATCH 029/179] Bouncer should not show over the full screen user switcher on boot. Full screen switcher is only used in auto. Fixes: 77142022 Test: Some unit tests + Refreshing sys ui and making sure full screen switcher shows first. Change-Id: I726a79af274c2443fca0ece007ecac0f3c42a439 --- .../systemui/statusbar/phone/StatusBar.java | 11 ++- .../phone/StatusBarKeyguardViewManager.java | 4 +- .../statusbar/phone/StatusBarTest.java | 67 ++++++++++++++++--- 3 files changed, 68 insertions(+), 14 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index c03ecb306226..beeba83b9c25 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -562,7 +562,7 @@ public class StatusBar extends SystemUI implements DemoMode, }; private KeyguardUserSwitcher mKeyguardUserSwitcher; - private UserSwitcherController mUserSwitcherController; + protected UserSwitcherController mUserSwitcherController; private NetworkController mNetworkController; private KeyguardMonitorImpl mKeyguardMonitor = (KeyguardMonitorImpl) Dependency.get(KeyguardMonitor.class); @@ -588,7 +588,7 @@ public class StatusBar extends SystemUI implements DemoMode, } }; private boolean mNoAnimationOnNextBarModeChange; - private FalsingManager mFalsingManager; + protected FalsingManager mFalsingManager; private final KeyguardUpdateMonitorCallback mUpdateCallback = new KeyguardUpdateMonitorCallback() { @@ -3448,6 +3448,13 @@ public class StatusBar extends SystemUI implements DemoMode, return updateIsKeyguard(); } + /** + * @return True if StatusBar state is FULLSCREEN_USER_SWITCHER. + */ + public boolean isFullScreenUserSwitcherState() { + return mState == StatusBarState.FULLSCREEN_USER_SWITCHER; + } + private boolean updateIsKeyguard() { boolean wakeAndUnlocking = mFingerprintUnlockController.getMode() == FingerprintUnlockController.MODE_WAKE_AND_UNLOCK; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index 597560823824..4e782de96449 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -145,9 +145,11 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb // conserve the original animation. // • The user quickly taps on the display and we show "swipe up to unlock." // • Keyguard will be dismissed by an action. a.k.a: FLAG_DISMISS_KEYGUARD_ACTIVITY + // • Full-screen user switcher is displayed. final boolean noLongerTracking = mLastTracking != tracking && !tracking; if (mOccluded || mNotificationPanelView.isUnlockHintRunning() - || mBouncer.willDismissWithAction()) { + || mBouncer.willDismissWithAction() + || mStatusBar.isFullScreenUserSwitcherState()) { mBouncer.setExpansion(0); } else if (mShowing && mStatusBar.isKeyguardCurrentlySecure() && !mDozing) { mBouncer.setExpansion(expansion); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java index 4a66bb7deca0..b31a2dc1af04 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java @@ -41,6 +41,7 @@ import android.app.Notification; import android.app.StatusBarManager; import android.app.trust.TrustManager; import android.content.Context; +import android.content.pm.UserInfo; import android.hardware.fingerprint.FingerprintManager; import android.metrics.LogMaker; import android.os.Binder; @@ -71,6 +72,7 @@ import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.assist.AssistManager; import com.android.systemui.keyguard.KeyguardViewMediator; +import com.android.systemui.classifier.FalsingManager; import com.android.systemui.keyguard.WakefulnessLifecycle; import com.android.systemui.recents.misc.SystemServicesProxy; import com.android.systemui.statusbar.ActivatableNotificationView; @@ -91,6 +93,7 @@ import com.android.systemui.statusbar.NotificationLogger; import com.android.systemui.statusbar.NotificationMediaManager; import com.android.systemui.statusbar.NotificationPresenter; import com.android.systemui.statusbar.NotificationRemoteInputManager; +import com.android.systemui.statusbar.NotificationShelf; import com.android.systemui.statusbar.NotificationViewHierarchyManager; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.notification.ActivityLaunchAnimator; @@ -98,6 +101,7 @@ import com.android.systemui.statusbar.notification.VisualStabilityManager; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.KeyguardMonitor; import com.android.systemui.statusbar.policy.KeyguardMonitorImpl; +import com.android.systemui.statusbar.policy.UserSwitcherController; import com.android.systemui.statusbar.stack.NotificationStackScrollLayout; import org.junit.Before; @@ -134,6 +138,7 @@ public class StatusBarTest extends SysuiTestCase { @Mock private VisualStabilityManager mVisualStabilityManager; @Mock private NotificationListener mNotificationListener; @Mock private KeyguardViewMediator mKeyguardViewMediator; + @Mock private NotificationLockscreenUserManager mLockscreenUserManager; private TestableStatusBar mStatusBar; private FakeMetricsLogger mMetricsLogger; @@ -146,9 +151,7 @@ public class StatusBarTest extends SysuiTestCase { MockitoAnnotations.initMocks(this); mDependency.injectMockDependency(AssistManager.class); mDependency.injectMockDependency(DeviceProvisionedController.class); - mDependency.injectMockDependency(NotificationGroupManager.class); mDependency.injectMockDependency(NotificationGutsManager.class); - mDependency.injectMockDependency(NotificationRemoteInputManager.class); mDependency.injectMockDependency(NotificationMediaManager.class); mDependency.injectMockDependency(ForegroundServiceController.class); mDependency.injectTestDependency(NotificationViewHierarchyManager.class, @@ -202,7 +205,12 @@ public class StatusBarTest extends SysuiTestCase { mPowerManager, mNotificationPanelView, mBarService, mNotificationListener, mNotificationLogger, mVisualStabilityManager, mViewHierarchyManager, mEntryManager, mScrimController, mFingerprintUnlockController, - mock(ActivityLaunchAnimator.class), mKeyguardViewMediator); + mock(ActivityLaunchAnimator.class), mKeyguardViewMediator, + mock(NotificationRemoteInputManager.class), mock(NotificationGroupManager.class), + mock(FalsingManager.class), mock(StatusBarWindowManager.class), + mock(NotificationIconAreaController.class), mock(DozeScrimController.class), + mock(NotificationShelf.class), mLockscreenUserManager, + mock(CommandQueue.class)); mStatusBar.mContext = mContext; mStatusBar.mComponents = mContext.getComponents(); mEntryManager.setUpForTest(mStatusBar, mStackScroller, mStatusBar, mHeadsUpManager, @@ -529,11 +537,7 @@ public class StatusBarTest extends SysuiTestCase { @Test @RunWithLooper(setAsMainLooper = true) public void testUpdateKeyguardState_DoesNotCrash() { - mStatusBar.mStatusBarWindow = mock(StatusBarWindowView.class); mStatusBar.mState = StatusBarState.KEYGUARD; - mStatusBar.mDozeScrimController = mock(DozeScrimController.class); - mStatusBar.mNotificationIconAreaController = mock(NotificationIconAreaController.class); - mStatusBar.mLockscreenUserManager = mock(NotificationLockscreenUserManager.class); when(mStatusBar.mLockscreenUserManager.getCurrentProfiles()).thenReturn( new SparseArray<>()); mStatusBar.updateKeyguardState(false, false); @@ -541,9 +545,6 @@ public class StatusBarTest extends SysuiTestCase { @Test public void testFingerprintNotification_UpdatesScrims() { - mStatusBar.mStatusBarWindowManager = mock(StatusBarWindowManager.class); - mStatusBar.mDozeScrimController = mock(DozeScrimController.class); - mStatusBar.mNotificationIconAreaController = mock(NotificationIconAreaController.class); mStatusBar.notifyFpAuthModeChanged(); verify(mScrimController).transitionTo(any(), any()); } @@ -629,6 +630,32 @@ public class StatusBarTest extends SysuiTestCase { verify(mStackScroller).changeViewPosition(any(FooterView.class), eq(-1 /* end */)); } + @Test + public void testSetState_changesIsFullScreenUserSwitcherState() { + mStatusBar.setBarStateForTest(StatusBarState.KEYGUARD); + assertFalse(mStatusBar.isFullScreenUserSwitcherState()); + + mStatusBar.setBarStateForTest(StatusBarState.FULLSCREEN_USER_SWITCHER); + assertTrue(mStatusBar.isFullScreenUserSwitcherState()); + } + + @Test + public void testShowKeyguardImplementation_setsState() { + when(mLockscreenUserManager.getCurrentProfiles()).thenReturn(new SparseArray<>()); + + mStatusBar.setBarStateForTest(StatusBarState.SHADE); + + // By default, showKeyguardImpl sets state to KEYGUARD. + mStatusBar.showKeyguardImpl(); + assertTrue(mStatusBar.mState == StatusBarState.KEYGUARD); + + // If useFullscreenUserSwitcher is true, state is set to FULLSCREEN_USER_SWITCHER. + mStatusBar.mUserSwitcherController = mock(UserSwitcherController.class); + when(mStatusBar.mUserSwitcherController.useFullscreenUserSwitcher()).thenReturn(true); + mStatusBar.showKeyguardImpl(); + assertTrue(mStatusBar.mState == StatusBarState.FULLSCREEN_USER_SWITCHER); + } + static class TestableStatusBar extends StatusBar { public TestableStatusBar(StatusBarKeyguardViewManager man, UnlockMethodCache unlock, KeyguardIndicationController key, @@ -640,7 +667,16 @@ public class StatusBarTest extends SysuiTestCase { NotificationViewHierarchyManager viewHierarchyManager, TestableNotificationEntryManager entryManager, ScrimController scrimController, FingerprintUnlockController fingerprintUnlockController, - ActivityLaunchAnimator launchAnimator, KeyguardViewMediator keyguardViewMediator) { + ActivityLaunchAnimator launchAnimator, KeyguardViewMediator keyguardViewMediator, + NotificationRemoteInputManager notificationRemoteInputManager, + NotificationGroupManager notificationGroupManager, + FalsingManager falsingManager, + StatusBarWindowManager statusBarWindowManager, + NotificationIconAreaController notificationIconAreaController, + DozeScrimController dozeScrimController, + NotificationShelf notificationShelf, + NotificationLockscreenUserManager notificationLockscreenUserManager, + CommandQueue commandQueue) { mStatusBarKeyguardViewManager = man; mUnlockMethodCache = unlock; mKeyguardIndicationController = key; @@ -660,6 +696,15 @@ public class StatusBarTest extends SysuiTestCase { mActivityLaunchAnimator = launchAnimator; mKeyguardViewMediator = keyguardViewMediator; mClearAllEnabled = true; + mRemoteInputManager = notificationRemoteInputManager; + mGroupManager = notificationGroupManager; + mFalsingManager = falsingManager; + mStatusBarWindowManager = statusBarWindowManager; + mNotificationIconAreaController = notificationIconAreaController; + mDozeScrimController = dozeScrimController; + mNotificationShelf = notificationShelf; + mLockscreenUserManager = notificationLockscreenUserManager; + mCommandQueue = commandQueue; } private WakefulnessLifecycle createAwakeWakefulnessLifecycle() { -- GitLab From 17a879db4f1a2b763b0767eddcfc156f26a2ef8b Mon Sep 17 00:00:00 2001 From: Bookatz Date: Wed, 28 Mar 2018 15:05:28 -0700 Subject: [PATCH 030/179] Update BleScanStateChanged comment Bug: 71607284 Test: none; it's just a comment Change-Id: Ie290bef146bf326cc6965b32fe74076761a10bd7 --- cmds/statsd/src/atoms.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index 5e75359f111e..cfb9d87df87b 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -245,7 +245,7 @@ message ProcessLifeCycleStateChanged { * Logs when the ble scan state changes. * * Logged from: - * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java + * packages/apps/Bluetooth/src/com/android/bluetooth/gatt/AppScanStats.java */ // TODO: Consider changing to tracking per-scanner-id (log from AppScanStats). message BleScanStateChanged { -- GitLab From ef5ce1c300ab496efc3fd87d29d6790f81a6a771 Mon Sep 17 00:00:00 2001 From: Andrii Kulian Date: Tue, 20 Mar 2018 19:27:24 -0700 Subject: [PATCH 031/179] Prefer default orientation for secondary displays For existing use-cases secondary displays should not be influenced by things like orientation sensors, docking mode, etc. This CL makes WindowManagerPolicy prefer default orientation when calculating rotation for non-default displays. Bug: 72447212 Test: Rotate phone to landscape, start Android Auto Projected. Change-Id: I1934085d32096aa9c1a2b8f7f62c26b7480dd13d --- .../server/policy/PhoneWindowManager.java | 8 +++-- .../server/policy/WindowManagerPolicy.java | 5 ++- .../com/android/server/wm/DisplayContent.java | 33 ++++++++++++------- .../server/wm/WindowManagerService.java | 4 +-- .../server/wm/TestWindowManagerPolicy.java | 3 +- 5 files changed, 35 insertions(+), 18 deletions(-) diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 4dc68ac72557..dc63ab68d4d0 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -7175,7 +7175,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } @Override - public int rotationForOrientationLw(int orientation, int lastRotation) { + public int rotationForOrientationLw(int orientation, int lastRotation, boolean defaultDisplay) { if (false) { Slog.v(TAG, "rotationForOrientationLw(orient=" + orientation + ", last=" + lastRotation @@ -7196,7 +7196,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { } final int preferredRotation; - if (mLidState == LID_OPEN && mLidOpenRotation >= 0) { + if (!defaultDisplay) { + // For secondary displays we ignore things like displays sensors, docking mode and + // rotation lock, and always prefer a default rotation. + preferredRotation = Surface.ROTATION_0; + } else if (mLidState == LID_OPEN && mLidOpenRotation >= 0) { // Ignore sensor when lid switch is open and rotation is forced. preferredRotation = mLidOpenRotation; } else if (mDockMode == Intent.EXTRA_DOCK_STATE_CAR diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java index ec0521dda40d..afff8b592194 100644 --- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java +++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java @@ -1426,10 +1426,13 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { * @param orientation An orientation constant, such as * {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_LANDSCAPE}. * @param lastRotation The most recently used rotation. + * @param defaultDisplay Flag indicating whether the rotation is computed for the default + * display. Currently for all non-default displays sensors, docking mode, + * rotation lock and other factors are ignored. * @return The surface rotation to use. */ public int rotationForOrientationLw(@ActivityInfo.ScreenOrientation int orientation, - int lastRotation); + int lastRotation, boolean defaultDisplay); /** * Given an orientation constant and a rotation, returns true if the rotation diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 2ffdbfd4c646..c9ff9e3ba35b 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -909,6 +909,7 @@ class DisplayContent extends WindowContainer keySet = bundle.keySet(); - builder.append("[Bundle with ").append(keySet.size()).append(" extras:"); - for (String key : keySet) { - final Object value = bundle.get(key); - builder.append(' ').append(key).append('='); - builder.append((value instanceof Object[]) - ? Arrays.toString((Objects[]) value) : value); - } - builder.append(']'); - } - - static String bundleToString(Bundle bundle) { - final StringBuilder builder = new StringBuilder(); - append(builder, bundle); - return builder.toString(); - } - @Nullable static AutofillId[] toArray(@Nullable ArraySet set) { if (set == null) return null; diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java index 706fb1a72491..706a6ab8436f 100644 --- a/services/autofill/java/com/android/server/autofill/Session.java +++ b/services/autofill/java/com/android/server/autofill/Session.java @@ -2502,8 +2502,10 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } pw.print(prefix); pw.print("mHasCallback: "); pw.println(mHasCallback); - pw.print(prefix); pw.print("mClientState: "); pw.println( - Helper.bundleToString(mClientState)); + if (mClientState != null) { + pw.print(prefix); pw.println("mClientState: "); pw.print(mClientState.getSize()); pw + .println(" items"); + } pw.print(prefix); pw.print("mCompatMode: "); pw.println(mCompatMode); pw.print(prefix); pw.print("mUrlBar: "); if (mUrlBar == null) { -- GitLab From 10b6c41a763ff29243b1e4fcc2598432c404322c Mon Sep 17 00:00:00 2001 From: Matthew Ng Date: Mon, 26 Mar 2018 18:01:37 -0700 Subject: [PATCH 033/179] Fixes OpaLayoutTest to pass by adding SysuiTestCase (1/2) Copied SysuiTestCase to systemui Google to be able to inflate KeyButtonView that is dependent on StatusBar. Also fixed the connection failure catch exception when proxy cannot connect to service in tests. Test: atest com.google.android.systemui.OpaLayoutTest Change-Id: Ica2a894ce92e06af30c208afcc6a22adeac3a843 Fixes: 76416916 --- .../com/android/systemui/OverviewProxyService.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java index 2983df6ec937..90d1d948d44d 100644 --- a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java +++ b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java @@ -227,9 +227,14 @@ public class OverviewProxyService implements CallbackController Date: Wed, 28 Mar 2018 16:49:47 -0700 Subject: [PATCH 034/179] Root (uid=0) should be core. Fix UserHandle.isCore(). Bug: 77240427 Change-Id: I057e8f50370fb1cd74ff2ebdab41990a682cec6f Fix: 77240427 Test: build & boot Test: "am set-standby-bucket com.google.android.apps.docs 40" will override ACTIVE --- core/java/android/os/UserHandle.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java index 5be72bc5c54b..094f0046649b 100644 --- a/core/java/android/os/UserHandle.java +++ b/core/java/android/os/UserHandle.java @@ -158,7 +158,7 @@ public final class UserHandle implements Parcelable { * @hide */ public static boolean isCore(int uid) { - if (uid > 0) { + if (uid >= 0) { final int appId = getAppId(uid); return appId < Process.FIRST_APPLICATION_UID; } else { -- GitLab From 33c5a847079ba1b33f03ab1f1901b0e9f45c4659 Mon Sep 17 00:00:00 2001 From: Mady Mellor Date: Mon, 19 Mar 2018 16:23:15 -0700 Subject: [PATCH 035/179] Add permission hint, update permission slice structure Test: atest cts/tests/tests/slices Bug: 75500766 Change-Id: Ic26dbaa121a3745174a6e21171f35abad69c61de --- api/current.txt | 1 + core/java/android/app/slice/Slice.java | 6 ++++++ .../java/android/app/slice/SliceProvider.java | 20 ++++++++++--------- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/api/current.txt b/api/current.txt index 85f238c1113d..7251e8fb9f1d 100644 --- a/api/current.txt +++ b/api/current.txt @@ -7213,6 +7213,7 @@ package android.app.slice { field public static final java.lang.String HINT_LIST_ITEM = "list_item"; field public static final java.lang.String HINT_NO_TINT = "no_tint"; field public static final java.lang.String HINT_PARTIAL = "partial"; + field public static final java.lang.String HINT_PERMISSION_REQUEST = "permission_request"; field public static final java.lang.String HINT_SEE_MORE = "see_more"; field public static final java.lang.String HINT_SELECTED = "selected"; field public static final java.lang.String HINT_SHORTCUT = "shortcut"; diff --git a/core/java/android/app/slice/Slice.java b/core/java/android/app/slice/Slice.java index 95bb1f682701..fc3b38d2bcfb 100644 --- a/core/java/android/app/slice/Slice.java +++ b/core/java/android/app/slice/Slice.java @@ -70,6 +70,7 @@ public final class Slice implements Parcelable { HINT_ERROR, HINT_TTL, HINT_LAST_UPDATED, + HINT_PERMISSION_REQUEST, }) @Retention(RetentionPolicy.SOURCE) public @interface SliceHint {} @@ -183,6 +184,11 @@ public final class Slice implements Parcelable { * Hint indicating an item representing when the content was created or last updated. */ public static final String HINT_LAST_UPDATED = "last_updated"; + /** + * A hint to indicate that this slice represents a permission request for showing + * slices. + */ + public static final String HINT_PERMISSION_REQUEST = "permission_request"; /** * Key to retrieve an extra added to an intent when a control is changed. */ diff --git a/core/java/android/app/slice/SliceProvider.java b/core/java/android/app/slice/SliceProvider.java index bf856b74f067..bbeb3849be78 100644 --- a/core/java/android/app/slice/SliceProvider.java +++ b/core/java/android/app/slice/SliceProvider.java @@ -428,15 +428,17 @@ public abstract class SliceProvider extends ContentProvider { } finally { Handler.getMain().removeCallbacks(mAnr); } - return new Slice.Builder(sliceUri) - .addAction(action, - new Slice.Builder(sliceUri.buildUpon().appendPath("permission").build()) - .addText(getPermissionString(context, callingPackage), null, - Collections.emptyList()) - .build(), - null) - .addHints(Arrays.asList(Slice.HINT_LIST_ITEM)) - .build(); + Slice.Builder parent = new Slice.Builder(sliceUri); + Slice.Builder childAction = new Slice.Builder(parent) + .addHints(Arrays.asList(Slice.HINT_TITLE, Slice.HINT_SHORTCUT)) + .addAction(action, new Slice.Builder(parent).build(), null); + + parent.addSubSlice(new Slice.Builder(sliceUri.buildUpon().appendPath("permission").build()) + .addText(getPermissionString(context, callingPackage), null, + Collections.emptyList()) + .addSubSlice(childAction.build(), null) + .build(), null); + return parent.addHints(Arrays.asList(Slice.HINT_PERMISSION_REQUEST)).build(); } /** -- GitLab From ec2bb18c92dc489a0b54bfc96118007261e3e7be Mon Sep 17 00:00:00 2001 From: Jean-Michel Trivi Date: Fri, 23 Mar 2018 18:04:00 -0700 Subject: [PATCH 036/179] NotificationManagerService: don't play notif in SILENT mode Fix the test for playing a notification sound: play sound when 1/ no exclusive focus AND 2/ volume not 0 Previous test would play a notification if device was in SILENT mode (volume was 0, but ringer mode was != VIBRATE) Bug: 75043398 Test: enter silent mode, play notification, verify no ducking Change-Id: I0e19d068f719a89c7a8a3c239da86c1dfce701ec --- .../notification/NotificationManagerService.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 210857e1b097..4e8150792b44 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -4691,11 +4691,12 @@ public class NotificationManagerService extends SystemService { private boolean playSound(final NotificationRecord record, Uri soundUri) { boolean looping = (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0; - // do not play notifications if there is a user of exclusive audio focus - // or the device is in vibrate mode - if (!mAudioManager.isAudioFocusExclusive() && (mAudioManager.getRingerModeInternal() - != AudioManager.RINGER_MODE_VIBRATE || mAudioManager.getStreamVolume( - AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) != 0)) { + // play notifications if there is no user of exclusive audio focus + // and the stream volume is not 0 (non-zero volume implies not silenced by SILENT or + // VIBRATE ringer mode) + if (!mAudioManager.isAudioFocusExclusive() + && (mAudioManager.getStreamVolume( + AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) != 0)) { final long identity = Binder.clearCallingIdentity(); try { final IRingtonePlayer player = mAudioManager.getRingtonePlayer(); -- GitLab From 4c2aa390125dc699f020155c9f65ed1a796ac7af Mon Sep 17 00:00:00 2001 From: Lucas Dupin Date: Wed, 28 Mar 2018 18:00:45 -0700 Subject: [PATCH 037/179] Avoid clock and challenge overlap Test: combination of - keyboard, pin, pattern - and different font and display sizes Fixes: 74758659 Change-Id: Iaa851d863cd1771c6d9fd9120e4bb743fef776e1 --- .../systemui/statusbar/phone/KeyguardBouncer.java | 14 ++++++++++++++ .../phone/KeyguardClockPositionAlgorithm.java | 14 +++++++++++--- .../statusbar/phone/NotificationPanelView.java | 9 ++++++++- .../phone/StatusBarKeyguardViewManager.java | 8 +++++++- 4 files changed, 40 insertions(+), 5 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java index fcd4e8f3669f..df2b817101ab 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java @@ -334,6 +334,20 @@ public class KeyguardBouncer { return mKeyguardView != null && mKeyguardView.hasDismissActions(); } + public int getTop() { + if (mKeyguardView == null) { + return 0; + } + + int top = mKeyguardView.getTop(); + // The password view has an extra top padding that should be ignored. + if (mKeyguardView.getCurrentSecurityMode() == SecurityMode.Password) { + View messageArea = mKeyguardView.findViewById(R.id.keyguard_message_area); + top += messageArea.getTop(); + } + return top; + } + protected void ensureView() { // Removal of the view might be deferred to reduce unlock latency, // in this case we need to force the removal, otherwise we'll diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java index 19e829592f79..3d7067d1d799 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java @@ -113,6 +113,11 @@ public class KeyguardClockPositionAlgorithm { */ private boolean mTracking; + /** + * Distance in pixels between the top of the screen and the first view of the bouncer. + */ + private int mBouncerTop; + /** * Refreshes the dimension values. */ @@ -129,7 +134,7 @@ public class KeyguardClockPositionAlgorithm { public void setup(int minTopMargin, int maxShadeBottom, int notificationStackHeight, float expandedHeight, float maxPanelHeight, int parentHeight, int keyguardStatusHeight, - float dark, boolean secure, boolean tracking) { + float dark, boolean secure, boolean tracking, int bouncerTop) { mMinTopMargin = minTopMargin + mContainerTopPadding; mMaxShadeBottom = maxShadeBottom; mNotificationStackHeight = notificationStackHeight; @@ -140,6 +145,7 @@ public class KeyguardClockPositionAlgorithm { mDarkAmount = dark; mCurrentlySecure = secure; mTracking = tracking; + mBouncerTop = bouncerTop; } public void run(Result result) { @@ -189,8 +195,10 @@ public class KeyguardClockPositionAlgorithm { private int getClockY() { // Dark: Align the bottom edge of the clock at about half of the screen: final float clockYDark = getMaxClockY() + burnInPreventionOffsetY(); - float clockYRegular = getExpandedClockPosition(); - float clockYTarget = mCurrentlySecure ? mMinTopMargin : -mKeyguardStatusHeight; + final float clockYRegular = getExpandedClockPosition(); + final boolean hasEnoughSpace = mMinTopMargin + mKeyguardStatusHeight < mBouncerTop; + float clockYTarget = mCurrentlySecure && hasEnoughSpace ? + mMinTopMargin : -mKeyguardStatusHeight; // Move clock up while collapsing the shade float shadeExpansion = mExpandedHeight / mMaxPanelHeight; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java index cccda90c20a8..27ca0d11ee28 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -160,6 +160,7 @@ public class NotificationPanelView extends PanelView implements protected int mQsMinExpansionHeight; protected int mQsMaxExpansionHeight; private int mQsPeekHeight; + private int mBouncerTop; private boolean mStackScrollerOverscrolling; private boolean mQsExpansionFromOverscroll; private float mLastOverscroll; @@ -476,7 +477,8 @@ public class NotificationPanelView extends PanelView implements mKeyguardStatusView.getHeight(), mDarkAmount, mStatusBar.isKeyguardCurrentlySecure(), - mTracking); + mTracking, + mBouncerTop); mClockPositionAlgorithm.run(mClockPositionResult); if (animate || mClockAnimator != null) { startClockAnimation(mClockPositionResult.clockX, mClockPositionResult.clockY); @@ -550,6 +552,11 @@ public class NotificationPanelView extends PanelView implements return count; } + public void setBouncerTop(int bouncerTop) { + mBouncerTop = bouncerTop; + positionClockAndNotifications(); + } + private void startClockAnimation(int x, int y) { if (mClockAnimationTargetX == x && mClockAnimationTargetY == y) { return; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index 597560823824..30685af62a94 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -135,10 +135,16 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb mFingerprintUnlockController = fingerprintUnlockController; mBouncer = SystemUIFactory.getInstance().createKeyguardBouncer(mContext, mViewMediatorCallback, mLockPatternUtils, container, dismissCallbackRegistry); + mContainer.addOnLayoutChangeListener(this::onContainerLayout); mNotificationPanelView = notificationPanelView; notificationPanelView.setExpansionListener(this::onPanelExpansionChanged); } + private void onContainerLayout(View v, int left, int top, int right, int bottom, + int oldLeft, int oldTop, int oldRight, int oldBottom) { + mNotificationPanelView.setBouncerTop(mBouncer.getTop()); + } + private void onPanelExpansionChanged(float expansion, boolean tracking) { // We don't want to translate the bounce when: // • Keyguard is occluded, because we're in a FLAG_SHOW_WHEN_LOCKED activity and need to @@ -154,7 +160,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb if (expansion == 1) { mBouncer.onFullyHidden(); } else if (!mBouncer.isShowing() && !mBouncer.isAnimatingAway()) { - mBouncer.show(false /* resetSecuritySelection */, false /* notifyFalsing */); + mBouncer.show(false /* resetSecuritySelection */, false /* animated */); } else if (noLongerTracking) { // Notify that falsing manager should stop its session when user stops touching, // even before the animation ends, to guarantee that we're not recording sensitive -- GitLab From ab49fc46e57436f3232337839570a477aabae52e Mon Sep 17 00:00:00 2001 From: Calin Juravle Date: Wed, 28 Mar 2018 19:00:18 -0700 Subject: [PATCH 038/179] Add the compilation reason to the dexopt dumps Knowing why we compiled a package will make some investigations easier. Test: adb shell dumpsys package dexopt Bug: 76425903 Change-Id: I67b5bc980d198340aa52affb24fb3ce7e3080d67 --- .../com/android/server/pm/PackageDexOptimizer.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java index 77bf67daa478..eb9162bb7caf 100644 --- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java +++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java @@ -446,13 +446,15 @@ public class PackageDexOptimizer { pw.increaseIndent(); for (String isa : dexCodeInstructionSets) { - String status = null; try { - status = DexFile.getDexFileStatus(path, isa); + String[] status = DexFile.getDexFileOptimizationStatus(path, isa); + String compilationStatus = status[0]; + String compilationReason = status[1]; + pw.println(isa + ": [status=" + compilationStatus + +"] reason=[" + compilationReason + "]"); } catch (IOException ioe) { - status = "[Exception]: " + ioe.getMessage(); + pw.println(isa + ": [Exception]: " + ioe.getMessage()); } - pw.println(isa + ": " + status); } if (useInfo.isUsedByOtherApps(path)) { -- GitLab From 224b5b39a274623e92e9238e112181eb086379ad Mon Sep 17 00:00:00 2001 From: Brad Stenning Date: Wed, 28 Mar 2018 21:26:57 -0700 Subject: [PATCH 039/179] Allow for the different nav bars before the device is provisioned Split window creation from content creation so I could remove and add new content once the provisioned state changed. Bug: 68808310 Test: Go through the setup wizard on a clean deploy Change-Id: I409c1cd92552846c7317d713fb16ef8bac8b9ee4 --- packages/SystemUI/res/values/dimens_car.xml | 2 + .../car/CarFacetButtonController.java | 6 + .../systemui/statusbar/car/CarStatusBar.java | 218 +++++++++++------- .../statusbar/car/hvac/HvacController.java | 8 + 4 files changed, 150 insertions(+), 84 deletions(-) diff --git a/packages/SystemUI/res/values/dimens_car.xml b/packages/SystemUI/res/values/dimens_car.xml index 5679dd2f1fb0..6caed61f11a7 100644 --- a/packages/SystemUI/res/values/dimens_car.xml +++ b/packages/SystemUI/res/values/dimens_car.xml @@ -32,6 +32,8 @@ 64dp 760dp + 96dp + 96dp 12dp 24dp diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarFacetButtonController.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarFacetButtonController.java index 284113624cc1..b7d501e7f745 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarFacetButtonController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarFacetButtonController.java @@ -46,6 +46,12 @@ public class CarFacetButtonController { } } + public void removeAll() { + mButtonsByCategory.clear(); + mButtonsByPackage.clear(); + mSelectedFacetButton = null; + } + /** * This will unselect the currently selected CarFacetButton and determine which one should be * selected next. It does this by reading the properties on the CarFacetButton and seeing if diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java index a95d0a4dc7b8..3530e0b84664 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java @@ -45,6 +45,7 @@ import com.android.systemui.statusbar.car.hvac.HvacController; import com.android.systemui.statusbar.phone.CollapsedStatusBarFragment; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.policy.BatteryController; +import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.UserSwitcherController; import java.io.FileDescriptor; @@ -80,12 +81,16 @@ public class CarStatusBar extends StatusBar implements private boolean mShowRight; private boolean mShowBottom; private CarFacetButtonController mCarFacetButtonController; + private ActivityManagerWrapper mActivityManagerWrapper; + private DeviceProvisionedController mDeviceProvisionedController; + private boolean mDeviceIsProvisioned = true; @Override public void start() { super.start(); mTaskStackListener = new TaskStackListenerImpl(); - ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener); + mActivityManagerWrapper = ActivityManagerWrapper.getInstance(); + mActivityManagerWrapper.registerTaskStackListener(mTaskStackListener); mStackScroller.setScrollingEnabled(true); @@ -96,12 +101,54 @@ public class CarStatusBar extends StatusBar implements Log.d(TAG, "Connecting to HVAC service"); Dependency.get(HvacController.class).connectToCarService(); } + mCarFacetButtonController = Dependency.get(CarFacetButtonController.class); + mDeviceProvisionedController = Dependency.get(DeviceProvisionedController.class); + mDeviceIsProvisioned = mDeviceProvisionedController.isDeviceProvisioned(); + if (!mDeviceIsProvisioned) { + mDeviceProvisionedController.addCallback( + new DeviceProvisionedController.DeviceProvisionedListener() { + @Override + public void onDeviceProvisionedChanged() { + mDeviceIsProvisioned = + mDeviceProvisionedController.isDeviceProvisioned(); + restartNavBars(); + } + }); + } + } + + /** + * Remove all content from navbars and rebuild them. Used to allow for different nav bars + * before and after the device is provisioned + */ + private void restartNavBars() { + mCarFacetButtonController.removeAll(); + if (ENABLE_HVAC_CONNECTION) { + Dependency.get(HvacController.class).removeAllComponents(); + } + if (mNavigationBarWindow != null) { + mNavigationBarWindow.removeAllViews(); + mNavigationBarView = null; + } + + if (mLeftNavigationBarWindow != null) { + mLeftNavigationBarWindow.removeAllViews(); + mLeftNavigationBarView = null; + } + + if (mRightNavigationBarWindow != null) { + mRightNavigationBarWindow.removeAllViews(); + mRightNavigationBarView = null; + } + buildNavBarContent(); } + @Override public void destroy() { mCarBatteryController.stopListening(); mConnectedDeviceSignalController.stopListening(); + mActivityManagerWrapper.unregisterTaskStackListener(mTaskStackListener); if (mNavigationBarWindow != null) { mWindowManager.removeViewImmediate(mNavigationBarWindow); @@ -117,10 +164,10 @@ public class CarStatusBar extends StatusBar implements mWindowManager.removeViewImmediate(mRightNavigationBarWindow); mRightNavigationBarView = null; } - super.destroy(); } + @Override protected void makeStatusBarView() { super.makeStatusBarView(); @@ -167,129 +214,132 @@ public class CarStatusBar extends StatusBar implements @Override protected void createNavigationBar() { - mCarFacetButtonController = Dependency.get(CarFacetButtonController.class); - if (mNavigationBarView != null) { - return; - } - mShowBottom = mContext.getResources().getBoolean(R.bool.config_enableBottomNavigationBar); + mShowLeft = mContext.getResources().getBoolean(R.bool.config_enableLeftNavigationBar); + mShowRight = mContext.getResources().getBoolean(R.bool.config_enableRightNavigationBar); + + buildNavBarWindows(); + buildNavBarContent(); + attachNavBarWindows(); + } + + private void buildNavBarContent() { if (mShowBottom) { - buildBottomBar(); + buildBottomBar((mDeviceIsProvisioned) ? R.layout.car_navigation_bar : + R.layout.car_navigation_bar_unprovisioned); } - int widthForSides = mContext.getResources().getDimensionPixelSize( - R.dimen.navigation_bar_height_car_mode); + if (mShowLeft) { + buildLeft((mDeviceIsProvisioned) ? R.layout.car_left_navigation_bar : + R.layout.car_left_navigation_bar_unprovisioned); + } + if (mShowRight) { + buildRight((mDeviceIsProvisioned) ? R.layout.car_right_navigation_bar : + R.layout.car_right_navigation_bar_unprovisioned); + } + } - mShowLeft = mContext.getResources().getBoolean(R.bool.config_enableLeftNavigationBar); + private void buildNavBarWindows() { + if (mShowBottom) { + mNavigationBarWindow = (ViewGroup) View.inflate(mContext, + R.layout.navigation_bar_window, null); + } if (mShowLeft) { - buildLeft(widthForSides); + mLeftNavigationBarWindow = (ViewGroup) View.inflate(mContext, + R.layout.navigation_bar_window, null); + } + if (mShowRight) { + mRightNavigationBarWindow = (ViewGroup) View.inflate(mContext, + R.layout.navigation_bar_window, null); } - mShowRight = mContext.getResources().getBoolean(R.bool.config_enableRightNavigationBar); + } + + private void attachNavBarWindows() { + if (mShowBottom) { + WindowManager.LayoutParams lp = new WindowManager.LayoutParams( + LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, + WindowManager.LayoutParams.TYPE_NAVIGATION_BAR, + WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE + | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL + | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH + | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH, + PixelFormat.TRANSLUCENT); + lp.setTitle("CarNavigationBar"); + lp.windowAnimations = 0; + mWindowManager.addView(mNavigationBarWindow, lp); + } + if (mShowLeft) { + int width = mContext.getResources().getDimensionPixelSize( + R.dimen.car_left_navigation_bar_width); + WindowManager.LayoutParams leftlp = new WindowManager.LayoutParams( + width, LayoutParams.MATCH_PARENT, + WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL, + WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE + | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL + | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH + | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH, + PixelFormat.TRANSLUCENT); + leftlp.setTitle("LeftCarNavigationBar"); + leftlp.windowAnimations = 0; + leftlp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR; + leftlp.gravity = Gravity.LEFT; + mWindowManager.addView(mLeftNavigationBarWindow, leftlp); + } if (mShowRight) { - buildRight(widthForSides); + int width = mContext.getResources().getDimensionPixelSize( + R.dimen.car_right_navigation_bar_width); + WindowManager.LayoutParams rightlp = new WindowManager.LayoutParams( + width, LayoutParams.MATCH_PARENT, + WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL, + WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE + | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL + | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH + | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH, + PixelFormat.TRANSLUCENT); + rightlp.setTitle("RightCarNavigationBar"); + rightlp.windowAnimations = 0; + rightlp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR; + rightlp.gravity = Gravity.RIGHT; + mWindowManager.addView(mRightNavigationBarWindow, rightlp); } } - - private void buildBottomBar() { + private void buildBottomBar(int layout) { // SystemUI requires that the navigation bar view have a parent. Since the regular // StatusBar inflates navigation_bar_window as this parent view, use the same view for the // CarNavigationBarView. - mNavigationBarWindow = (ViewGroup) View.inflate(mContext, - R.layout.navigation_bar_window, null); - if (mNavigationBarWindow == null) { - Log.e(TAG, "CarStatusBar failed inflate for R.layout.navigation_bar_window"); - } - - - View.inflate(mContext, R.layout.car_navigation_bar, mNavigationBarWindow); + View.inflate(mContext, layout, mNavigationBarWindow); mNavigationBarView = (CarNavigationBarView) mNavigationBarWindow.getChildAt(0); if (mNavigationBarView == null) { Log.e(TAG, "CarStatusBar failed inflate for R.layout.car_navigation_bar"); throw new RuntimeException("Unable to build botom nav bar due to missing layout"); } mNavigationBarView.setStatusBar(this); - - - WindowManager.LayoutParams lp = new WindowManager.LayoutParams( - LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, - WindowManager.LayoutParams.TYPE_NAVIGATION_BAR, - WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE - | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL - | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH - | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH, - PixelFormat.TRANSLUCENT); - lp.setTitle("CarNavigationBar"); - lp.windowAnimations = 0; - - - mWindowManager.addView(mNavigationBarWindow, lp); } - private void buildLeft(int widthForSides) { - mLeftNavigationBarWindow = (ViewGroup) View.inflate(mContext, - R.layout.navigation_bar_window, null); - if (mLeftNavigationBarWindow == null) { - Log.e(TAG, "CarStatusBar failed inflate for R.layout.navigation_bar_window"); - } - - View.inflate(mContext, R.layout.car_left_navigation_bar, mLeftNavigationBarWindow); + private void buildLeft(int layout) { + View.inflate(mContext, layout, mLeftNavigationBarWindow); mLeftNavigationBarView = (CarNavigationBarView) mLeftNavigationBarWindow.getChildAt(0); if (mLeftNavigationBarView == null) { Log.e(TAG, "CarStatusBar failed inflate for R.layout.car_navigation_bar"); throw new RuntimeException("Unable to build left nav bar due to missing layout"); } mLeftNavigationBarView.setStatusBar(this); - - WindowManager.LayoutParams leftlp = new WindowManager.LayoutParams( - widthForSides, LayoutParams.MATCH_PARENT, - WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL, - WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE - | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL - | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH - | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH, - PixelFormat.TRANSLUCENT); - leftlp.setTitle("LeftCarNavigationBar"); - leftlp.windowAnimations = 0; - leftlp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR; - leftlp.gravity = Gravity.LEFT; - mWindowManager.addView(mLeftNavigationBarWindow, leftlp); } - private void buildRight(int widthForSides) { - mRightNavigationBarWindow = (ViewGroup) View.inflate(mContext, - R.layout.navigation_bar_window, null); - if (mRightNavigationBarWindow == null) { - Log.e(TAG, "CarStatusBar failed inflate for R.layout.navigation_bar_window"); - } - - View.inflate(mContext, R.layout.car_right_navigation_bar, mRightNavigationBarWindow); + private void buildRight(int layout) { + View.inflate(mContext, layout, mRightNavigationBarWindow); mRightNavigationBarView = (CarNavigationBarView) mRightNavigationBarWindow.getChildAt(0); if (mRightNavigationBarView == null) { Log.e(TAG, "CarStatusBar failed inflate for R.layout.car_navigation_bar"); throw new RuntimeException("Unable to build right nav bar due to missing layout"); } - mRightNavigationBarView.setStatusBar(this); - - WindowManager.LayoutParams rightlp = new WindowManager.LayoutParams( - widthForSides, LayoutParams.MATCH_PARENT, - WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL, - WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE - | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL - | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH - | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH, - PixelFormat.TRANSLUCENT); - rightlp.setTitle("RightCarNavigationBar"); - rightlp.windowAnimations = 0; - rightlp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR; - rightlp.gravity = Gravity.RIGHT; - mWindowManager.addView(mRightNavigationBarWindow, rightlp); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/hvac/HvacController.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/hvac/HvacController.java index 23bf88796da3..7d283d9fde9d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/car/hvac/HvacController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/hvac/HvacController.java @@ -175,6 +175,14 @@ public class HvacController { } }; + /** + * Removes all registered components. This is useful if you need to rebuild the UI since + * components self register. + */ + public void removeAllComponents() { + mTempComponents.clear(); + } + /** * Key for storing {@link TemperatureView}s in a hash map */ -- GitLab From 1a0a941c20eb746868d0de52e3806f69c74d335f Mon Sep 17 00:00:00 2001 From: Chenjie Yu Date: Wed, 28 Mar 2018 10:07:22 -0700 Subject: [PATCH 040/179] Fix StatsCompanionService pull on bucket ends + change StatsPullerManager internal time units to be consistent + use series of alarms for pullers, instead of use setRepeating Bug: 76223345 Bug: 75970648 Test: cts test Change-Id: I9e6ac0ce06541f5ceabd2a8fa444e13d40e36983 --- cmds/statsd/src/StatsLogProcessor.cpp | 4 +- cmds/statsd/src/StatsService.cpp | 2 +- cmds/statsd/src/external/StatsPuller.cpp | 29 +-- cmds/statsd/src/external/StatsPuller.h | 10 +- cmds/statsd/src/external/StatsPullerManager.h | 21 +-- .../src/external/StatsPullerManagerImpl.cpp | 175 ++++++++++++------ .../src/external/StatsPullerManagerImpl.h | 22 +-- .../src/metrics/GaugeMetricProducer.cpp | 5 +- .../src/metrics/ValueMetricProducer.cpp | 25 ++- cmds/statsd/src/metrics/ValueMetricProducer.h | 2 +- cmds/statsd/src/stats_log_util.cpp | 3 +- .../metrics/GaugeMetricProducer_test.cpp | 25 +-- .../metrics/ValueMetricProducer_test.cpp | 19 +- .../tests/metrics/metrics_test_helper.h | 6 +- .../android/os/IStatsCompanionService.aidl | 4 +- .../server/stats/StatsCompanionService.java | 50 +++-- 16 files changed, 235 insertions(+), 167 deletions(-) diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp index a458c07394a7..c1ff27545401 100644 --- a/cmds/statsd/src/StatsLogProcessor.cpp +++ b/cmds/statsd/src/StatsLogProcessor.cpp @@ -79,8 +79,6 @@ StatsLogProcessor::StatsLogProcessor(const sp& uidMap, mSendBroadcast(sendBroadcast), mTimeBaseSec(timeBaseSec), mLastLogTimestamp(0) { - StatsPullerManager statsPullerManager; - statsPullerManager.SetTimeBaseSec(mTimeBaseSec); } StatsLogProcessor::~StatsLogProcessor() { @@ -177,7 +175,7 @@ void StatsLogProcessor::OnLogEvent(LogEvent* event) { uint64_t curTimeSec = getElapsedRealtimeSec(); if (curTimeSec - mLastPullerCacheClearTimeSec > StatsdStats::kPullerCacheClearIntervalSec) { - mStatsPullerManager.ClearPullerCacheIfNecessary(curTimeSec); + mStatsPullerManager.ClearPullerCacheIfNecessary(curTimeSec * NS_PER_SEC); mLastPullerCacheClearTimeSec = curTimeSec; } diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp index b03b4b4a942c..9f70c75d66e9 100644 --- a/cmds/statsd/src/StatsService.cpp +++ b/cmds/statsd/src/StatsService.cpp @@ -595,7 +595,7 @@ status_t StatsService::cmd_log_app_breadcrumb(FILE* out, const Vector& status_t StatsService::cmd_print_pulled_metrics(FILE* out, const Vector& args) { int s = atoi(args[1].c_str()); vector > stats; - if (mStatsPullerManager.Pull(s, &stats)) { + if (mStatsPullerManager.Pull(s, getElapsedRealtimeNs(), &stats)) { for (const auto& it : stats) { fprintf(out, "Pull from %d: %s\n", s, it->ToString().c_str()); } diff --git a/cmds/statsd/src/external/StatsPuller.cpp b/cmds/statsd/src/external/StatsPuller.cpp index 3b0cd349168d..ec5a5d6f3724 100644 --- a/cmds/statsd/src/external/StatsPuller.cpp +++ b/cmds/statsd/src/external/StatsPuller.cpp @@ -35,26 +35,31 @@ void StatsPuller::SetUidMap(const sp& uidMap) { mUidMap = uidMap; } // ValueMetric has a minimum bucket size of 10min so that we don't pull too frequently StatsPuller::StatsPuller(const int tagId) : mTagId(tagId) { - mCoolDownSec = StatsPullerManagerImpl::kAllPullAtomInfo.find(tagId)->second.coolDownSec; - VLOG("Puller for tag %d created. Cooldown set to %ld", mTagId, mCoolDownSec); + mCoolDownNs = StatsPullerManagerImpl::kAllPullAtomInfo.find(tagId)->second.coolDownNs; + VLOG("Puller for tag %d created. Cooldown set to %lld", mTagId, (long long)mCoolDownNs); } -bool StatsPuller::Pull(std::vector>* data) { +bool StatsPuller::Pull(const int64_t elapsedTimeNs, std::vector>* data) { lock_guard lock(mLock); + int64_t wallClockTimeNs = getWallClockNs(); StatsdStats::getInstance().notePull(mTagId); - long curTime = getElapsedRealtimeSec(); - if (curTime - mLastPullTimeSec < mCoolDownSec) { + if (elapsedTimeNs - mLastPullTimeNs < mCoolDownNs) { (*data) = mCachedData; StatsdStats::getInstance().notePullFromCache(mTagId); return true; } - if (mMinPullIntervalSec > curTime - mLastPullTimeSec) { - mMinPullIntervalSec = curTime - mLastPullTimeSec; - StatsdStats::getInstance().updateMinPullIntervalSec(mTagId, mMinPullIntervalSec); + if (mMinPullIntervalNs > elapsedTimeNs - mLastPullTimeNs) { + mMinPullIntervalNs = elapsedTimeNs - mLastPullTimeNs; + StatsdStats::getInstance().updateMinPullIntervalSec(mTagId, + mMinPullIntervalNs / NS_PER_SEC); } mCachedData.clear(); - mLastPullTimeSec = curTime; + mLastPullTimeNs = elapsedTimeNs; bool ret = PullInternal(&mCachedData); + for (const shared_ptr& data : mCachedData) { + data->setElapsedTimestampNs(elapsedTimeNs); + data->setLogdWallClockTimestampNs(wallClockTimeNs); + } if (ret) { mergeIsolatedUidsToHostUid(mCachedData, mUidMap, mTagId); (*data) = mCachedData; @@ -70,12 +75,12 @@ int StatsPuller::clearCache() { lock_guard lock(mLock); int ret = mCachedData.size(); mCachedData.clear(); - mLastPullTimeSec = 0; + mLastPullTimeNs = 0; return ret; } -int StatsPuller::ClearCacheIfNecessary(long timestampSec) { - if (timestampSec - mLastPullTimeSec > mCoolDownSec) { +int StatsPuller::ClearCacheIfNecessary(int64_t timestampNs) { + if (timestampNs - mLastPullTimeNs > mCoolDownNs) { return clearCache(); } else { return 0; diff --git a/cmds/statsd/src/external/StatsPuller.h b/cmds/statsd/src/external/StatsPuller.h index 936c47e92f2c..caac677ee215 100644 --- a/cmds/statsd/src/external/StatsPuller.h +++ b/cmds/statsd/src/external/StatsPuller.h @@ -37,13 +37,13 @@ public: virtual ~StatsPuller() {} - bool Pull(std::vector>* data); + bool Pull(const int64_t timeNs, std::vector>* data); // Clear cache immediately int ForceClearCache(); // Clear cache if elapsed time is more than cooldown time - int ClearCacheIfNecessary(long timestampSec); + int ClearCacheIfNecessary(int64_t timestampNs); static void SetUidMap(const sp& uidMap); @@ -59,9 +59,9 @@ private: // If a pull request comes before cooldown, a cached version from purevious pull // will be returned. // The actual value should be determined by individual pullers. - long mCoolDownSec; + int64_t mCoolDownNs; // For puller stats - long mMinPullIntervalSec = LONG_MAX; + int64_t mMinPullIntervalNs = LONG_MAX; virtual bool PullInternal(std::vector>* data) = 0; @@ -69,7 +69,7 @@ private: // cached data will be returned. std::vector> mCachedData; - long mLastPullTimeSec; + int64_t mLastPullTimeNs; int clearCache(); diff --git a/cmds/statsd/src/external/StatsPullerManager.h b/cmds/statsd/src/external/StatsPullerManager.h index 2717d5c2de9c..83d59c0a5830 100644 --- a/cmds/statsd/src/external/StatsPullerManager.h +++ b/cmds/statsd/src/external/StatsPullerManager.h @@ -26,10 +26,9 @@ class StatsPullerManager { public: virtual ~StatsPullerManager() {} - virtual void RegisterReceiver(int tagId, - wp receiver, - long intervalMs) { - mPullerManager.RegisterReceiver(tagId, receiver, intervalMs); + virtual void RegisterReceiver(int tagId, wp receiver, int64_t nextPullTimeNs, + int64_t intervalNs) { + mPullerManager.RegisterReceiver(tagId, receiver, nextPullTimeNs, intervalNs); }; virtual void UnRegisterReceiver(int tagId, wp receiver) { @@ -45,13 +44,9 @@ class StatsPullerManager { mPullerManager.OnAlarmFired(); } - virtual bool - Pull(const int tagId, vector>* data) { - return mPullerManager.Pull(tagId, data); - } - - void SetTimeBaseSec(const long timeBaseSec) { - mPullerManager.SetTimeBaseSec(timeBaseSec); + virtual bool Pull(const int tagId, const int64_t timesNs, + vector>* data) { + return mPullerManager.Pull(tagId, timesNs, data); } int ForceClearPullerCache() { @@ -62,8 +57,8 @@ class StatsPullerManager { mPullerManager.SetStatsCompanionService(statsCompanionService); } - int ClearPullerCacheIfNecessary(long timestampSec) { - return mPullerManager.ClearPullerCacheIfNecessary(timestampSec); + int ClearPullerCacheIfNecessary(int64_t timestampNs) { + return mPullerManager.ClearPullerCacheIfNecessary(timestampNs); } private: diff --git a/cmds/statsd/src/external/StatsPullerManagerImpl.cpp b/cmds/statsd/src/external/StatsPullerManagerImpl.cpp index dd6406bb90ca..0e23bf01074c 100644 --- a/cmds/statsd/src/external/StatsPullerManagerImpl.cpp +++ b/cmds/statsd/src/external/StatsPullerManagerImpl.cpp @@ -19,15 +19,17 @@ #include #include +#include #include #include +#include "../StatsService.h" #include "../logd/LogEvent.h" #include "../stats_log_util.h" #include "../statscompanion_util.h" #include "ResourceHealthManagerPuller.h" #include "ResourceThermalManagerPuller.h" #include "StatsCompanionServicePuller.h" -#include "StatsService.h" +#include "StatsPullerManagerImpl.h" #include "SubsystemSleepStatePuller.h" #include "statslog.h" @@ -47,89 +49,136 @@ namespace statsd { const std::map StatsPullerManagerImpl::kAllPullAtomInfo = { // wifi_bytes_transfer {android::util::WIFI_BYTES_TRANSFER, - {{2, 3, 4, 5}, {}, 1, + {{2, 3, 4, 5}, + {}, + 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::WIFI_BYTES_TRANSFER)}}, // wifi_bytes_transfer_by_fg_bg {android::util::WIFI_BYTES_TRANSFER_BY_FG_BG, - {{3, 4, 5, 6}, {2}, 1, + {{3, 4, 5, 6}, + {2}, + 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::WIFI_BYTES_TRANSFER_BY_FG_BG)}}, // mobile_bytes_transfer {android::util::MOBILE_BYTES_TRANSFER, - {{2, 3, 4, 5}, {}, 1, + {{2, 3, 4, 5}, + {}, + 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::MOBILE_BYTES_TRANSFER)}}, // mobile_bytes_transfer_by_fg_bg {android::util::MOBILE_BYTES_TRANSFER_BY_FG_BG, - {{3, 4, 5, 6}, {2}, 1, + {{3, 4, 5, 6}, + {2}, + 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::MOBILE_BYTES_TRANSFER_BY_FG_BG)}}, // bluetooth_bytes_transfer {android::util::BLUETOOTH_BYTES_TRANSFER, - {{2, 3}, {}, 1, new StatsCompanionServicePuller(android::util::BLUETOOTH_BYTES_TRANSFER)}}, + {{2, 3}, + {}, + 1 * NS_PER_SEC, + new StatsCompanionServicePuller(android::util::BLUETOOTH_BYTES_TRANSFER)}}, // kernel_wakelock {android::util::KERNEL_WAKELOCK, - {{}, {}, 1, new StatsCompanionServicePuller(android::util::KERNEL_WAKELOCK)}}, + {{}, {}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::KERNEL_WAKELOCK)}}, // subsystem_sleep_state {android::util::SUBSYSTEM_SLEEP_STATE, - {{}, {}, 1, new SubsystemSleepStatePuller()}}, + {{}, {}, 1 * NS_PER_SEC, new SubsystemSleepStatePuller()}}, // cpu_time_per_freq {android::util::CPU_TIME_PER_FREQ, - {{3}, {2}, 1, new StatsCompanionServicePuller(android::util::CPU_TIME_PER_FREQ)}}, + {{3}, + {2}, + 1 * NS_PER_SEC, + new StatsCompanionServicePuller(android::util::CPU_TIME_PER_FREQ)}}, // cpu_time_per_uid {android::util::CPU_TIME_PER_UID, - {{2, 3}, {}, 1, new StatsCompanionServicePuller(android::util::CPU_TIME_PER_UID)}}, + {{2, 3}, + {}, + 1 * NS_PER_SEC, + new StatsCompanionServicePuller(android::util::CPU_TIME_PER_UID)}}, // cpu_time_per_uid_freq - // the throttling is 3sec, handled in frameworks/base/core/java/com/android/internal/os/KernelCpuProcReader + // the throttling is 3sec, handled in + // frameworks/base/core/java/com/android/internal/os/KernelCpuProcReader {android::util::CPU_TIME_PER_UID_FREQ, - {{4}, {2,3}, 0, new StatsCompanionServicePuller(android::util::CPU_TIME_PER_UID_FREQ)}}, + {{4}, + {2, 3}, + 1 * NS_PER_SEC, + new StatsCompanionServicePuller(android::util::CPU_TIME_PER_UID_FREQ)}}, // cpu_active_time - // the throttling is 3sec, handled in frameworks/base/core/java/com/android/internal/os/KernelCpuProcReader + // the throttling is 3sec, handled in + // frameworks/base/core/java/com/android/internal/os/KernelCpuProcReader {android::util::CPU_ACTIVE_TIME, - {{2}, {}, 0, new StatsCompanionServicePuller(android::util::CPU_ACTIVE_TIME)}}, + {{2}, + {}, + 1 * NS_PER_SEC, + new StatsCompanionServicePuller(android::util::CPU_ACTIVE_TIME)}}, // cpu_cluster_time - // the throttling is 3sec, handled in frameworks/base/core/java/com/android/internal/os/KernelCpuProcReader + // the throttling is 3sec, handled in + // frameworks/base/core/java/com/android/internal/os/KernelCpuProcReader {android::util::CPU_CLUSTER_TIME, - {{3}, {2}, 0, new StatsCompanionServicePuller(android::util::CPU_CLUSTER_TIME)}}, + {{3}, + {2}, + 1 * NS_PER_SEC, + new StatsCompanionServicePuller(android::util::CPU_CLUSTER_TIME)}}, // wifi_activity_energy_info {android::util::WIFI_ACTIVITY_ENERGY_INFO, - {{}, {}, 1, new StatsCompanionServicePuller(android::util::WIFI_ACTIVITY_ENERGY_INFO)}}, + {{}, + {}, + 1 * NS_PER_SEC, + new StatsCompanionServicePuller(android::util::WIFI_ACTIVITY_ENERGY_INFO)}}, // modem_activity_info {android::util::MODEM_ACTIVITY_INFO, - {{}, {}, 1, new StatsCompanionServicePuller(android::util::MODEM_ACTIVITY_INFO)}}, + {{}, + {}, + 1 * NS_PER_SEC, + new StatsCompanionServicePuller(android::util::MODEM_ACTIVITY_INFO)}}, // bluetooth_activity_info {android::util::BLUETOOTH_ACTIVITY_INFO, - {{}, {}, 1, new StatsCompanionServicePuller(android::util::BLUETOOTH_ACTIVITY_INFO)}}, + {{}, + {}, + 1 * NS_PER_SEC, + new StatsCompanionServicePuller(android::util::BLUETOOTH_ACTIVITY_INFO)}}, // system_elapsed_realtime {android::util::SYSTEM_ELAPSED_REALTIME, - {{}, {}, 1, new StatsCompanionServicePuller(android::util::SYSTEM_ELAPSED_REALTIME)}}, + {{}, + {}, + 1 * NS_PER_SEC, + new StatsCompanionServicePuller(android::util::SYSTEM_ELAPSED_REALTIME)}}, // system_uptime {android::util::SYSTEM_UPTIME, - {{}, {}, 1, new StatsCompanionServicePuller(android::util::SYSTEM_UPTIME)}}, + {{}, {}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::SYSTEM_UPTIME)}}, // disk_space {android::util::DISK_SPACE, - {{}, {}, 1, new StatsCompanionServicePuller(android::util::DISK_SPACE)}}, + {{}, {}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::DISK_SPACE)}}, // remaining_battery_capacity {android::util::REMAINING_BATTERY_CAPACITY, - {{}, {}, 1, new ResourceHealthManagerPuller(android::util::REMAINING_BATTERY_CAPACITY)}}, + {{}, + {}, + 1 * NS_PER_SEC, + new ResourceHealthManagerPuller(android::util::REMAINING_BATTERY_CAPACITY)}}, // full_battery_capacity {android::util::FULL_BATTERY_CAPACITY, - {{}, {}, 1, new ResourceHealthManagerPuller(android::util::FULL_BATTERY_CAPACITY)}}, + {{}, + {}, + 1 * NS_PER_SEC, + new ResourceHealthManagerPuller(android::util::FULL_BATTERY_CAPACITY)}}, // process_memory_state {android::util::PROCESS_MEMORY_STATE, - {{4,5,6,7,8}, - {2,3}, - 0, + {{4, 5, 6, 7, 8}, + {2, 3}, + 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_STATE)}}, // temperature {android::util::TEMPERATURE, {{}, {}, 1, new ResourceThermalManagerPuller()}}}; -StatsPullerManagerImpl::StatsPullerManagerImpl() - : mCurrentPullingInterval(LONG_MAX) { +StatsPullerManagerImpl::StatsPullerManagerImpl() : mNextPullTimeNs(LONG_MAX) { } -bool StatsPullerManagerImpl::Pull(int tagId, vector>* data) { +bool StatsPullerManagerImpl::Pull(const int tagId, const int64_t timeNs, + vector>* data) { VLOG("Initiating pulling %d", tagId); if (kAllPullAtomInfo.find(tagId) != kAllPullAtomInfo.end()) { - bool ret = kAllPullAtomInfo.find(tagId)->second.puller->Pull(data); + bool ret = kAllPullAtomInfo.find(tagId)->second.puller->Pull(timeNs, data); VLOG("pulled %d items", (int)data->size()); return ret; } else { @@ -148,12 +197,14 @@ bool StatsPullerManagerImpl::PullerForMatcherExists(int tagId) const { } void StatsPullerManagerImpl::updateAlarmLocked() { - long currentTimeMs = getElapsedRealtimeMillis(); - long nextAlarmTimeMs = currentTimeMs + mCurrentPullingInterval - - (currentTimeMs - mTimeBaseSec * 1000) % mCurrentPullingInterval; + if (mNextPullTimeNs == LONG_MAX) { + VLOG("No need to set alarms. Skipping"); + return; + } + sp statsCompanionServiceCopy = mStatsCompanionService; if (statsCompanionServiceCopy != nullptr) { - statsCompanionServiceCopy->setPullingAlarms(nextAlarmTimeMs, mCurrentPullingInterval); + statsCompanionServiceCopy->setPullingAlarm(mNextPullTimeNs / 1000000); } else { VLOG("StatsCompanionService not available. Alarm not set."); } @@ -174,7 +225,7 @@ void StatsPullerManagerImpl::SetStatsCompanionService( } void StatsPullerManagerImpl::RegisterReceiver(int tagId, wp receiver, - long intervalMs) { + int64_t nextPullTimeNs, int64_t intervalNs) { AutoMutex _l(mLock); auto& receivers = mReceivers[tagId]; for (auto it = receivers.begin(); it != receivers.end(); it++) { @@ -185,21 +236,24 @@ void StatsPullerManagerImpl::RegisterReceiver(int tagId, wp re } ReceiverInfo receiverInfo; receiverInfo.receiver = receiver; - receiverInfo.timeInfo.first = intervalMs; - receivers.push_back(receiverInfo); // Round it to the nearest minutes. This is the limit of alarm manager. - // In practice, we should limit it higher. - long roundedIntervalMs = intervalMs/1000/60 * 1000 * 60; + // In practice, we should always have larger buckets. + int64_t roundedIntervalNs = intervalNs / NS_PER_SEC / 60 * NS_PER_SEC * 60; // Scheduled pulling should be at least 1 min apart. // This can be lower in cts tests, in which case we round it to 1 min. - if (roundedIntervalMs < 60 * 1000) { - roundedIntervalMs = 60 * 1000; + if (roundedIntervalNs < 60 * (int64_t)NS_PER_SEC) { + roundedIntervalNs = 60 * (int64_t)NS_PER_SEC; } + + receiverInfo.intervalNs = roundedIntervalNs; + receiverInfo.nextPullTimeNs = nextPullTimeNs; + receivers.push_back(receiverInfo); + // There is only one alarm for all pulled events. So only set it to the smallest denom. - if (roundedIntervalMs < mCurrentPullingInterval) { - VLOG("Updating pulling interval %ld", intervalMs); - mCurrentPullingInterval = roundedIntervalMs; + if (nextPullTimeNs < mNextPullTimeNs) { + VLOG("Updating next pull time %lld", (long long)mNextPullTimeNs); + mNextPullTimeNs = nextPullTimeNs; updateAlarmLocked(); } VLOG("Puller for tagId %d registered of %d", tagId, (int)receivers.size()); @@ -224,16 +278,22 @@ void StatsPullerManagerImpl::UnRegisterReceiver(int tagId, wp void StatsPullerManagerImpl::OnAlarmFired() { AutoMutex _l(mLock); - uint64_t currentTimeMs = getElapsedRealtimeMillis(); + int64_t currentTimeNs = getElapsedRealtimeNs(); + + int64_t minNextPullTimeNs = LONG_MAX; vector>> needToPull = vector>>(); for (auto& pair : mReceivers) { vector receivers = vector(); if (pair.second.size() != 0) { - for (auto& receiverInfo : pair.second) { - if (receiverInfo.timeInfo.first + receiverInfo.timeInfo.second > currentTimeMs) { + for (ReceiverInfo& receiverInfo : pair.second) { + if (receiverInfo.nextPullTimeNs < currentTimeNs) { receivers.push_back(&receiverInfo); + } else { + if (receiverInfo.nextPullTimeNs < minNextPullTimeNs) { + minNextPullTimeNs = receiverInfo.nextPullTimeNs; + } } } if (receivers.size() > 0) { @@ -244,18 +304,29 @@ void StatsPullerManagerImpl::OnAlarmFired() { for (const auto& pullInfo : needToPull) { vector> data; - if (Pull(pullInfo.first, &data)) { + if (Pull(pullInfo.first, currentTimeNs, &data)) { for (const auto& receiverInfo : pullInfo.second) { sp receiverPtr = receiverInfo->receiver.promote(); if (receiverPtr != nullptr) { receiverPtr->onDataPulled(data); - receiverInfo->timeInfo.second = currentTimeMs; + // we may have just come out of a coma, compute next pull time + receiverInfo->nextPullTimeNs = + ceil((double_t)(currentTimeNs - receiverInfo->nextPullTimeNs) / + receiverInfo->intervalNs) * + receiverInfo->intervalNs + + receiverInfo->nextPullTimeNs; + if (receiverInfo->nextPullTimeNs < minNextPullTimeNs) { + minNextPullTimeNs = receiverInfo->nextPullTimeNs; + } } else { VLOG("receiver already gone."); } } } } + + mNextPullTimeNs = minNextPullTimeNs; + updateAlarmLocked(); } int StatsPullerManagerImpl::ForceClearPullerCache() { @@ -266,10 +337,10 @@ int StatsPullerManagerImpl::ForceClearPullerCache() { return totalCleared; } -int StatsPullerManagerImpl::ClearPullerCacheIfNecessary(long timestampSec) { +int StatsPullerManagerImpl::ClearPullerCacheIfNecessary(int64_t timestampNs) { int totalCleared = 0; for (const auto& pulledAtom : kAllPullAtomInfo) { - totalCleared += pulledAtom.second.puller->ClearCacheIfNecessary(timestampSec); + totalCleared += pulledAtom.second.puller->ClearCacheIfNecessary(timestampNs); } return totalCleared; } diff --git a/cmds/statsd/src/external/StatsPullerManagerImpl.h b/cmds/statsd/src/external/StatsPullerManagerImpl.h index 682ad33a8749..8c771f31fdc5 100644 --- a/cmds/statsd/src/external/StatsPullerManagerImpl.h +++ b/cmds/statsd/src/external/StatsPullerManagerImpl.h @@ -41,7 +41,7 @@ typedef struct { std::vector nonAdditiveFields; // How long should the puller wait before doing an actual pull again. Default // 1 sec. Set this to 0 if this is handled elsewhere. - long coolDownSec = 1; + int64_t coolDownNs = 1 * NS_PER_SEC; // The actual puller sp puller; } PullAtomInfo; @@ -50,7 +50,8 @@ class StatsPullerManagerImpl : public virtual RefBase { public: static StatsPullerManagerImpl& GetInstance(); - void RegisterReceiver(int tagId, wp receiver, long intervalMs); + void RegisterReceiver(int tagId, wp receiver, int64_t nextPullTimeNs, + int64_t intervalNs); void UnRegisterReceiver(int tagId, wp receiver); @@ -59,13 +60,11 @@ public: void OnAlarmFired(); - bool Pull(const int tagId, vector>* data); - - void SetTimeBaseSec(long timeBaseSec) {mTimeBaseSec = timeBaseSec;}; + bool Pull(const int tagId, const int64_t timeNs, vector>* data); int ForceClearPullerCache(); - int ClearPullerCacheIfNecessary(long timestampSec); + int ClearPullerCacheIfNecessary(int64_t timestampNs); void SetStatsCompanionService(sp statsCompanionService); @@ -77,8 +76,8 @@ public: sp mStatsCompanionService = nullptr; typedef struct { - // pull_interval_sec : last_pull_time_sec - std::pair timeInfo; + int64_t nextPullTimeNs; + int64_t intervalNs; wp receiver; } ReceiverInfo; @@ -90,12 +89,7 @@ public: void updateAlarmLocked(); - long mCurrentPullingInterval; - - // for pulled metrics, it is important for the buckets to be aligned to multiple of smallest - // bucket size. All pulled metrics start pulling based on this time, so that they can be - // correctly attributed to the correct buckets. - long mTimeBaseSec; + int64_t mNextPullTimeNs; }; } // namespace statsd diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp index f0e0df18693a..b13c3e7a0487 100644 --- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp +++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp @@ -112,7 +112,8 @@ GaugeMetricProducer::GaugeMetricProducer(const ConfigKey& key, const GaugeMetric // Kicks off the puller immediately. if (mPullTagId != -1 && mSamplingType == GaugeMetric::RANDOM_ONE_SAMPLE) { - mStatsPullerManager->RegisterReceiver(mPullTagId, this, bucketSizeMills); + mStatsPullerManager->RegisterReceiver( + mPullTagId, this, mCurrentBucketStartTimeNs + mBucketSizeNs, mBucketSizeNs); } VLOG("Gauge metric %lld created. bucket size %lld start_time: %lld sliced %d", @@ -255,7 +256,7 @@ void GaugeMetricProducer::pullLocked() { } vector> allData; - if (!mStatsPullerManager->Pull(mPullTagId, &allData)) { + if (!mStatsPullerManager->Pull(mPullTagId, getElapsedRealtimeNs(), &allData)) { ALOGE("Gauge Stats puller failed for tag: %d", mPullTagId); return; } diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp index e19e2368f751..bd3c78ce839d 100644 --- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp +++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp @@ -110,10 +110,12 @@ ValueMetricProducer::ValueMetricProducer(const ConfigKey& key, const ValueMetric } mConditionSliced = (metric.links().size() > 0) || (mDimensionsInCondition.size() > 0); - if (!metric.has_condition() && mPullTagId != -1) { - VLOG("Setting up periodic pulling for %d", mPullTagId); - mStatsPullerManager->RegisterReceiver(mPullTagId, this, bucketSizeMills); + // Kicks off the puller immediately. + if (mPullTagId != -1) { + mStatsPullerManager->RegisterReceiver( + mPullTagId, this, mCurrentBucketStartTimeNs + mBucketSizeNs, mBucketSizeNs); } + VLOG("value metric %lld created. bucket size %lld start_time: %lld", (long long)metric.id(), (long long)mBucketSizeNs, (long long)mStartTimeNs); } @@ -194,26 +196,21 @@ void ValueMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs, // TODO: Clear mDimensionKeyMap once the report is dumped. } -void ValueMetricProducer::onConditionChangedLocked(const bool condition, const uint64_t eventTime) { +void ValueMetricProducer::onConditionChangedLocked(const bool condition, + const uint64_t eventTimeNs) { mCondition = condition; - if (eventTime < mCurrentBucketStartTimeNs) { - VLOG("Skip event due to late arrival: %lld vs %lld", (long long)eventTime, + if (eventTimeNs < mCurrentBucketStartTimeNs) { + VLOG("Skip event due to late arrival: %lld vs %lld", (long long)eventTimeNs, (long long)mCurrentBucketStartTimeNs); return; } - flushIfNeededLocked(eventTime); + flushIfNeededLocked(eventTimeNs); if (mPullTagId != -1) { - if (mCondition == true) { - mStatsPullerManager->RegisterReceiver(mPullTagId, this, mBucketSizeNs / 1000 / 1000); - } else if (mCondition == false) { - mStatsPullerManager->UnRegisterReceiver(mPullTagId, this); - } - vector> allData; - if (mStatsPullerManager->Pull(mPullTagId, &allData)) { + if (mStatsPullerManager->Pull(mPullTagId, eventTimeNs, &allData)) { if (allData.size() == 0) { return; } diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h index 796e83af4f1d..ebc6e81d22c9 100644 --- a/cmds/statsd/src/metrics/ValueMetricProducer.h +++ b/cmds/statsd/src/metrics/ValueMetricProducer.h @@ -53,7 +53,7 @@ public: if (mPullTagId != -1) { vector> allData; - mStatsPullerManager->Pull(mPullTagId, &allData); + mStatsPullerManager->Pull(mPullTagId, eventTimeNs, &allData); if (allData.size() == 0) { // This shouldn't happen since this valuemetric is not useful now. } diff --git a/cmds/statsd/src/stats_log_util.cpp b/cmds/statsd/src/stats_log_util.cpp index cab61e9787c6..efd810f01140 100644 --- a/cmds/statsd/src/stats_log_util.cpp +++ b/cmds/statsd/src/stats_log_util.cpp @@ -221,7 +221,8 @@ void writeFieldValueTreeToStream(int tagId, const std::vector& value int64_t TimeUnitToBucketSizeInMillisGuardrailed(int uid, TimeUnit unit) { int64_t bucketSizeMillis = TimeUnitToBucketSizeInMillis(unit); - if (bucketSizeMillis > 1000 && bucketSizeMillis < 5 * 60 * 1000LL && uid != AID_SHELL) { + if (bucketSizeMillis > 1000 && bucketSizeMillis < 5 * 60 * 1000LL && uid != AID_SHELL && + uid != AID_ROOT) { bucketSizeMillis = 5 * 60 * 1000LL; } return bucketSizeMillis; diff --git a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp index 2583c95b2016..7ca66fd361c2 100644 --- a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp +++ b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp @@ -63,7 +63,7 @@ TEST(GaugeMetricProducerTest, TestNoCondition) { // For now we still need this so that it doesn't do real pulling. shared_ptr pullerManager = make_shared>(); - EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _)).WillOnce(Return()); + EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return()); EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return()); GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard, @@ -213,10 +213,11 @@ TEST(GaugeMetricProducerTest, TestPulledWithUpgrade) { shared_ptr pullerManager = make_shared>(); - EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _)).WillOnce(Return()); + EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return()); EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return()); - EXPECT_CALL(*pullerManager, Pull(tagId, _)) - .WillOnce(Invoke([](int tagId, vector>* data) { + EXPECT_CALL(*pullerManager, Pull(tagId, _, _)) + .WillOnce(Invoke([](int tagId, int64_t timeNs, + vector>* data) { data->clear(); shared_ptr event = make_shared(tagId, eventUpgradeTimeNs); event->write("some value"); @@ -281,10 +282,11 @@ TEST(GaugeMetricProducerTest, TestWithCondition) { shared_ptr pullerManager = make_shared>(); - EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _)).WillOnce(Return()); + EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return()); EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return()); - EXPECT_CALL(*pullerManager, Pull(tagId, _)) - .WillOnce(Invoke([](int tagId, vector>* data) { + EXPECT_CALL(*pullerManager, Pull(tagId, _, _)) + .WillOnce(Invoke([](int tagId, int64_t timeNs, + vector>* data) { data->clear(); shared_ptr event = make_shared(tagId, bucketStartTimeNs + 10); event->write("some value"); @@ -372,10 +374,11 @@ TEST(GaugeMetricProducerTest, TestWithSlicedCondition) { shared_ptr pullerManager = make_shared>(); - EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _)).WillOnce(Return()); + EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return()); EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return()); - EXPECT_CALL(*pullerManager, Pull(tagId, _)) - .WillOnce(Invoke([](int tagId, vector>* data) { + EXPECT_CALL(*pullerManager, Pull(tagId, _, _)) + .WillOnce(Invoke([](int tagId, int64_t timeNs, + vector>* data) { data->clear(); shared_ptr event = make_shared(tagId, bucketStartTimeNs + 10); event->write(1000); @@ -420,7 +423,7 @@ TEST(GaugeMetricProducerTest, TestAnomalyDetection) { shared_ptr pullerManager = make_shared>(); - EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _)).WillOnce(Return()); + EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return()); EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return()); GaugeMetric metric; diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp index a8eb27037ebf..a0224ec17a78 100644 --- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp +++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp @@ -62,7 +62,7 @@ TEST(ValueMetricProducerTest, TestNonDimensionalEvents) { // For now we still need this so that it doesn't do real pulling. shared_ptr pullerManager = make_shared>(); - EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _)).WillOnce(Return()); + EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return()); EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return()); ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard, @@ -141,11 +141,12 @@ TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition) { sp wizard = new NaggyMock(); shared_ptr pullerManager = make_shared>(); - EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _)).WillOnce(Return()); + EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return()); EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return()); - EXPECT_CALL(*pullerManager, Pull(tagId, _)) - .WillOnce(Invoke([](int tagId, vector>* data) { + EXPECT_CALL(*pullerManager, Pull(tagId, _, _)) + .WillOnce(Invoke([](int tagId, int64_t timeNs, + vector>* data) { data->clear(); shared_ptr event = make_shared(tagId, bucketStartTimeNs + 10); event->write(tagId); @@ -154,7 +155,8 @@ TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition) { data->push_back(event); return true; })) - .WillOnce(Invoke([](int tagId, vector>* data) { + .WillOnce(Invoke([](int tagId, int64_t timeNs, + vector>* data) { data->clear(); shared_ptr event = make_shared(tagId, bucket2StartTimeNs + 10); event->write(tagId); @@ -260,10 +262,11 @@ TEST(ValueMetricProducerTest, TestPulledValueWithUpgrade) { sp wizard = new NaggyMock(); shared_ptr pullerManager = make_shared>(); - EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _)).WillOnce(Return()); + EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return()); EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return()); - EXPECT_CALL(*pullerManager, Pull(tagId, _)) - .WillOnce(Invoke([](int tagId, vector>* data) { + EXPECT_CALL(*pullerManager, Pull(tagId, _, _)) + .WillOnce(Invoke([](int tagId, int64_t timeNs, + vector>* data) { data->clear(); shared_ptr event = make_shared(tagId, bucketStartTimeNs + 10); event->write(tagId); diff --git a/cmds/statsd/tests/metrics/metrics_test_helper.h b/cmds/statsd/tests/metrics/metrics_test_helper.h index f040bf9f37ae..5afaba6671fa 100644 --- a/cmds/statsd/tests/metrics/metrics_test_helper.h +++ b/cmds/statsd/tests/metrics/metrics_test_helper.h @@ -35,9 +35,11 @@ public: class MockStatsPullerManager : public StatsPullerManager { public: - MOCK_METHOD3(RegisterReceiver, void(int tagId, wp receiver, long intervalMs)); + MOCK_METHOD4(RegisterReceiver, void(int tagId, wp receiver, + int64_t nextPulltimeNs, int64_t intervalNs)); MOCK_METHOD2(UnRegisterReceiver, void(int tagId, wp receiver)); - MOCK_METHOD2(Pull, bool(const int pullCode, vector>* data)); + MOCK_METHOD3(Pull, bool(const int pullCode, const int64_t timeNs, + vector>* data)); }; class MockUidMap : public UidMap { diff --git a/core/java/android/os/IStatsCompanionService.aidl b/core/java/android/os/IStatsCompanionService.aidl index 402c995452e8..116262e347de 100644 --- a/core/java/android/os/IStatsCompanionService.aidl +++ b/core/java/android/os/IStatsCompanionService.aidl @@ -47,10 +47,10 @@ interface IStatsCompanionService { * Uses AlarmManager.setRepeating API, so if the timestamp is in past, alarm fires immediately, * and alarm is inexact. */ - oneway void setPullingAlarms(long timestampMs, long intervalMs); + oneway void setPullingAlarm(long nextPullTimeMs); /** Cancel any repeating pulling alarm. */ - oneway void cancelPullingAlarms(); + oneway void cancelPullingAlarm(); /** * Register an alarm when we want to trigger subscribers at the given diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java index b3d28fcbc4f1..d252a56ddf6b 100644 --- a/services/core/java/com/android/server/stats/StatsCompanionService.java +++ b/services/core/java/com/android/server/stats/StatsCompanionService.java @@ -466,34 +466,32 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { } @Override // Binder call - public void setPullingAlarms(long timestampMs, long intervalMs) { - enforceCallingPermission(); - if (DEBUG) - Slog.d(TAG, "Setting pulling alarm for " + timestampMs + " every " + intervalMs + "ms"); - final long callingToken = Binder.clearCallingIdentity(); - try { - // using ELAPSED_REALTIME, not ELAPSED_REALTIME_WAKEUP, so if device is asleep, will - // only fire when it awakens. - // This alarm is inexact, leaving its exactness completely up to the OS optimizations. - // TODO: totally inexact means that stats per bucket could be quite off. Is this okay? - mAlarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME, timestampMs, intervalMs, - mPullingAlarmIntent); - } finally { - Binder.restoreCallingIdentity(callingToken); - } + public void setPullingAlarm(long nextPullTimeMs) { + enforceCallingPermission(); + if (DEBUG) + Slog.d(TAG, + "Setting pulling alarm in about " + (nextPullTimeMs - SystemClock.elapsedRealtime())); + final long callingToken = Binder.clearCallingIdentity(); + try { + // using ELAPSED_REALTIME, not ELAPSED_REALTIME_WAKEUP, so if device is asleep, will + // only fire when it awakens. + mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME, nextPullTimeMs, mPullingAlarmIntent); + } finally { + Binder.restoreCallingIdentity(callingToken); + } } @Override // Binder call - public void cancelPullingAlarms() { - enforceCallingPermission(); - if (DEBUG) - Slog.d(TAG, "Cancelling pulling alarm"); - final long callingToken = Binder.clearCallingIdentity(); - try { - mAlarmManager.cancel(mPullingAlarmIntent); - } finally { - Binder.restoreCallingIdentity(callingToken); - } + public void cancelPullingAlarm() { + enforceCallingPermission(); + if (DEBUG) + Slog.d(TAG, "Cancelling pulling alarm"); + final long callingToken = Binder.clearCallingIdentity(); + try { + mAlarmManager.cancel(mPullingAlarmIntent); + } finally { + Binder.restoreCallingIdentity(callingToken); + } } private void addNetworkStats( @@ -1109,7 +1107,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { mContext.unregisterReceiver(mUserUpdateReceiver); mContext.unregisterReceiver(mShutdownEventReceiver); cancelAnomalyAlarm(); - cancelPullingAlarms(); + cancelPullingAlarm(); } } -- GitLab From 6f2e97e235f428ccf4a0a7c930ec82e0f573356c Mon Sep 17 00:00:00 2001 From: Tony Mak Date: Mon, 26 Mar 2018 20:43:06 +0100 Subject: [PATCH 041/179] Not allow shell to dump screen by using ui-automator if... DISALLOW_DEBUGGING_FEATURES is set (adb unroot first) Test: Turn on DISALLOW_DEBUGGING_FEATURES in work profile. Can dump personal window + Cannot dump work window by using adb shell uiautomator dump Test: Turn off DISALLOW_DEBUGGING_FEATURES in work profile. Can dump window in both profiles Test: atest CtsAccessibilityServiceTestCases Test: Enable talkback, try launching a few apps and interact with them. Fixes: 73147467 Change-Id: I044a1546f9b568b0d19714154d6e7e5ab7232d26 --- .../AccessibilityManagerService.java | 44 +++++++++++++++---- .../server/wm/WindowManagerInternal.java | 6 +++ .../server/wm/WindowManagerService.java | 11 +++++ 3 files changed, 53 insertions(+), 8 deletions(-) diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index 8941b4926584..de112f94f743 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -853,11 +853,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub if (mSecurityPolicy.findA11yWindowInfoById(windowId) == null) { return null; } - IBinder token = mGlobalWindowTokens.get(windowId); - if (token != null) { - return token; - } - return getCurrentUserStateLocked().mWindowTokens.get(windowId); + return findWindowTokenLocked(windowId); } } @@ -2527,6 +2523,14 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub getInteractionBridge().clearAccessibilityFocusNotLocked(windowId); } + private IBinder findWindowTokenLocked(int windowId) { + IBinder token = mGlobalWindowTokens.get(windowId); + if (token != null) { + return token; + } + return getCurrentUserStateLocked().mWindowTokens.get(windowId); + } + private int findWindowIdLocked(IBinder token) { final int globalIndex = mGlobalWindowTokens.indexOfValue(token); if (globalIndex >= 0) { @@ -2986,7 +2990,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub // the accessibility layer reports which are windows // that a sighted user can touch. default: { - return isRetrievalAllowingWindow(event.getWindowId()); + return isRetrievalAllowingWindowLocked(event.getWindowId()); } } } @@ -3438,7 +3442,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub public boolean canGetAccessibilityNodeInfoLocked( AbstractAccessibilityServiceConnection service, int windowId) { - return canRetrieveWindowContentLocked(service) && isRetrievalAllowingWindow(windowId); + return canRetrieveWindowContentLocked(service) + && isRetrievalAllowingWindowLocked(windowId); } public boolean canRetrieveWindowsLocked(AbstractAccessibilityServiceConnection service) { @@ -3523,17 +3528,40 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub || userId == UserHandle.USER_CURRENT_OR_SELF); } - private boolean isRetrievalAllowingWindow(int windowId) { + private boolean isRetrievalAllowingWindowLocked(int windowId) { // The system gets to interact with any window it wants. if (Binder.getCallingUid() == Process.SYSTEM_UID) { return true; } + if (Binder.getCallingUid() == Process.SHELL_UID) { + if (!isShellAllowedToRetrieveWindowLocked(windowId)) { + return false; + } + } if (windowId == mActiveWindowId) { return true; } return findA11yWindowInfoById(windowId) != null; } + private boolean isShellAllowedToRetrieveWindowLocked(int windowId) { + long token = Binder.clearCallingIdentity(); + try { + IBinder windowToken = findWindowTokenLocked(windowId); + if (windowToken == null) { + return false; + } + int userId = mWindowManagerService.getWindowOwnerUserId(windowToken); + if (userId == UserHandle.USER_NULL) { + return false; + } + return !mUserManager.hasUserRestriction( + UserManager.DISALLOW_DEBUGGING_FEATURES, UserHandle.of(userId)); + } finally { + Binder.restoreCallingIdentity(token); + } + } + public AccessibilityWindowInfo findA11yWindowInfoById(int windowId) { return mA11yWindowInfoById.get(windowId); } diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java index 6bceda5ae3bc..6686b80d1e18 100644 --- a/services/core/java/com/android/server/wm/WindowManagerInternal.java +++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java @@ -419,4 +419,10 @@ public abstract class WindowManagerInternal { * @see android.view.IWindowManager#lockNow */ public abstract void lockNow(); + + /** + * Return the user that owns the given window, {@link android.os.UserHandle#USER_NULL} if + * the window token is not found. + */ + public abstract int getWindowOwnerUserId(IBinder windowToken); } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 56b314f18e79..f664ab07f8b5 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -7354,6 +7354,17 @@ public class WindowManagerService extends IWindowManager.Stub public void lockNow() { WindowManagerService.this.lockNow(null); } + + @Override + public int getWindowOwnerUserId(IBinder token) { + synchronized (mWindowMap) { + WindowState window = mWindowMap.get(token); + if (window != null) { + return UserHandle.getUserId(window.mOwnerUid); + } + return UserHandle.USER_NULL; + } + } } void registerAppFreezeListener(AppFreezeListener listener) { -- GitLab From f15d4f4dc5de372f10ce530f3d1ce3cb0355ebbe Mon Sep 17 00:00:00 2001 From: Eran Messeri Date: Fri, 23 Mar 2018 13:32:17 +0000 Subject: [PATCH 042/179] DPM: API review for installKeyPair Per API council review, make installKeyPair take a single, integer flags argument rather than two boolean ones. Bug: 71818124 Test: cts-tradefed run commandAndExit cts-dev -a armeabi-v7a -m CtsDevicePolicyManagerTestCases -t com.android.cts.devicepolicy.DeviceOwnerTest#testKeyManagement -l DEBUG Change-Id: Ia04f8d617ae0d1db028bd9bcef3a4bf486449468 --- api/current.txt | 4 +- .../app/admin/DevicePolicyManager.java | 43 ++++++++++++++----- 2 files changed, 36 insertions(+), 11 deletions(-) diff --git a/api/current.txt b/api/current.txt index 406ebac6c5eb..83069008800c 100644 --- a/api/current.txt +++ b/api/current.txt @@ -6501,7 +6501,7 @@ package android.app.admin { method public boolean installExistingPackage(android.content.ComponentName, java.lang.String); method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate, java.lang.String); method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate[], java.lang.String, boolean); - method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate[], java.lang.String, boolean, boolean); + method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate[], java.lang.String, int); method public boolean isActivePasswordSufficient(); method public boolean isAdminActive(android.content.ComponentName); method public boolean isAffiliatedUser(); @@ -6685,6 +6685,8 @@ package android.app.admin { field public static final int ID_TYPE_IMEI = 4; // 0x4 field public static final int ID_TYPE_MEID = 8; // 0x8 field public static final int ID_TYPE_SERIAL = 2; // 0x2 + field public static final int INSTALLKEY_REQUEST_CREDENTIALS_ACCESS = 1; // 0x1 + field public static final int INSTALLKEY_SET_USER_SELECTABLE = 2; // 0x2 field public static final int KEYGUARD_DISABLE_BIOMETRICS = 416; // 0x1a0 field public static final int KEYGUARD_DISABLE_FACE = 128; // 0x80 field public static final int KEYGUARD_DISABLE_FEATURES_ALL = 2147483647; // 0x7fffffff diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 106b42fba40d..9b4036fc8d0a 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -124,6 +124,7 @@ import java.util.concurrent.Executor; @SystemService(Context.DEVICE_POLICY_SERVICE) @RequiresFeature(PackageManager.FEATURE_DEVICE_ADMIN) public class DevicePolicyManager { + private static String TAG = "DevicePolicyManager"; private final Context mContext; @@ -1750,6 +1751,25 @@ public class DevicePolicyManager { */ public static final int ID_TYPE_MEID = 8; + /** + * Specifies that the calling app should be granted access to the installed credentials + * immediately. Otherwise, access to the credentials will be gated by user approval. + * For use with {@link #installKeyPair(ComponentName, PrivateKey, Certificate[], String, int)} + * + * @see #installKeyPair(ComponentName, PrivateKey, Certificate[], String, int) + */ + public static final int INSTALLKEY_REQUEST_CREDENTIALS_ACCESS = 1; + + /** + * Specifies that a user can select the key via the Certificate Selection prompt. + * If this flag is not set when calling {@link #installKeyPair}, the key can only be granted + * access by implementing {@link android.app.admin.DeviceAdminReceiver#onChoosePrivateKeyAlias}. + * For use with {@link #installKeyPair(ComponentName, PrivateKey, Certificate[], String, int)} + * + * @see #installKeyPair(ComponentName, PrivateKey, Certificate[], String, int) + */ + public static final int INSTALLKEY_SET_USER_SELECTABLE = 2; + /** * Broadcast action: sent when the profile owner is set, changed or cleared. * @@ -4126,7 +4146,11 @@ public class DevicePolicyManager { */ public boolean installKeyPair(@Nullable ComponentName admin, @NonNull PrivateKey privKey, @NonNull Certificate[] certs, @NonNull String alias, boolean requestAccess) { - return installKeyPair(admin, privKey, certs, alias, requestAccess, true); + int flags = INSTALLKEY_SET_USER_SELECTABLE; + if (requestAccess) { + flags |= INSTALLKEY_REQUEST_CREDENTIALS_ACCESS; + } + return installKeyPair(admin, privKey, certs, alias, flags); } /** @@ -4150,13 +4174,9 @@ public class DevicePolicyManager { * {@link android.security.KeyChain#getCertificateChain}. * @param alias The private key alias under which to install the certificate. If a certificate * with that alias already exists, it will be overwritten. - * @param requestAccess {@code true} to request that the calling app be granted access to the - * credentials immediately. Otherwise, access to the credentials will be gated by user - * approval. - * @param isUserSelectable {@code true} to indicate that a user can select this key via the - * Certificate Selection prompt, false to indicate that this key can only be granted - * access by implementing - * {@link android.app.admin.DeviceAdminReceiver#onChoosePrivateKeyAlias}. + * @param flags Flags to request that the calling app be granted access to the credentials + * and set the key to be user-selectable. See {@link #INSTALLKEY_SET_USER_SELECTABLE} and + * {@link #INSTALLKEY_REQUEST_CREDENTIALS_ACCESS}. * @return {@code true} if the keys were installed, {@code false} otherwise. * @throws SecurityException if {@code admin} is not {@code null} and not a device or profile * owner. @@ -4165,9 +4185,12 @@ public class DevicePolicyManager { * @see #DELEGATION_CERT_INSTALL */ public boolean installKeyPair(@Nullable ComponentName admin, @NonNull PrivateKey privKey, - @NonNull Certificate[] certs, @NonNull String alias, boolean requestAccess, - boolean isUserSelectable) { + @NonNull Certificate[] certs, @NonNull String alias, int flags) { throwIfParentInstance("installKeyPair"); + boolean requestAccess = (flags & INSTALLKEY_REQUEST_CREDENTIALS_ACCESS) + == INSTALLKEY_REQUEST_CREDENTIALS_ACCESS; + boolean isUserSelectable = (flags & INSTALLKEY_SET_USER_SELECTABLE) + == INSTALLKEY_SET_USER_SELECTABLE; try { final byte[] pemCert = Credentials.convertToPem(certs[0]); byte[] pemChain = null; -- GitLab From 52c15f1699e60c0701cc21a69847a005efe87bc9 Mon Sep 17 00:00:00 2001 From: Robert Berry Date: Thu, 29 Mar 2018 10:21:50 +0100 Subject: [PATCH 043/179] Add warning comment about serialization As it's important we do not break serialization of KeyChainSnapshot (as it could fail in weird and mysterious ways if we did), add comments warning anybody editing those files to also update the serializer and deserializer, as well as appropriate tests. Test: none, just adding comments Bug: 73921897 Change-Id: If73162b8fb2a0b44fd954b72c9030cd9e042282b --- .../recovery/KeyChainProtectionParams.java | 16 ++++++++++++++++ .../keystore/recovery/KeyChainSnapshot.java | 16 ++++++++++++++++ .../keystore/recovery/KeyDerivationParams.java | 16 ++++++++++++++++ .../keystore/recovery/WrappedApplicationKey.java | 15 +++++++++++++++ 4 files changed, 63 insertions(+) diff --git a/core/java/android/security/keystore/recovery/KeyChainProtectionParams.java b/core/java/android/security/keystore/recovery/KeyChainProtectionParams.java index 2a66206e805e..4af1af5f90cf 100644 --- a/core/java/android/security/keystore/recovery/KeyChainProtectionParams.java +++ b/core/java/android/security/keystore/recovery/KeyChainProtectionParams.java @@ -50,6 +50,22 @@ import java.util.Arrays; */ @SystemApi public final class KeyChainProtectionParams implements Parcelable { + + // IMPORTANT! PLEASE READ! + // ----------------------- + // If you edit this file (e.g., to add new fields), please MAKE SURE to also do the following: + // - Update the #writeToParcel(Parcel) method below + // - Update the #(Parcel) constructor below + // - Update android.security.keystore.recovery.KeyChainSnapshotTest to make sure nobody + // accidentally breaks your fields in the Parcel in the future. + // - Update com.android.server.locksettings.recoverablekeystore.serialization + // .KeyChainSnapshotSerializer to correctly serialize your new field + // - Update com.android.server.locksettings.recoverablekeystore.serialization + // .KeyChainSnapshotSerializer to correctly deserialize your new field + // - Update com.android.server.locksettings.recoverablekeystore.serialization + // .KeychainSnapshotSerializerTest to make sure nobody breaks serialization of your field + // in the future. + /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = {"TYPE_"}, value = {TYPE_LOCKSCREEN}) diff --git a/core/java/android/security/keystore/recovery/KeyChainSnapshot.java b/core/java/android/security/keystore/recovery/KeyChainSnapshot.java index 24ff182ab4bd..e46c34c85d55 100644 --- a/core/java/android/security/keystore/recovery/KeyChainSnapshot.java +++ b/core/java/android/security/keystore/recovery/KeyChainSnapshot.java @@ -48,6 +48,22 @@ import java.util.List; */ @SystemApi public final class KeyChainSnapshot implements Parcelable { + + // IMPORTANT! PLEASE READ! + // ----------------------- + // If you edit this file (e.g., to add new fields), please MAKE SURE to also do the following: + // - Update the #writeToParcel(Parcel) method below + // - Update the #(Parcel) constructor below + // - Update android.security.keystore.recovery.KeyChainSnapshotTest to make sure nobody + // accidentally breaks your fields in the Parcel in the future. + // - Update com.android.server.locksettings.recoverablekeystore.serialization + // .KeyChainSnapshotSerializer to correctly serialize your new field + // - Update com.android.server.locksettings.recoverablekeystore.serialization + // .KeyChainSnapshotSerializer to correctly deserialize your new field + // - Update com.android.server.locksettings.recoverablekeystore.serialization + // .KeychainSnapshotSerializerTest to make sure nobody breaks serialization of your field + // in the future. + private static final int DEFAULT_MAX_ATTEMPTS = 10; private static final long DEFAULT_COUNTER_ID = 1L; diff --git a/core/java/android/security/keystore/recovery/KeyDerivationParams.java b/core/java/android/security/keystore/recovery/KeyDerivationParams.java index 225b592d7595..d16f3ea317cf 100644 --- a/core/java/android/security/keystore/recovery/KeyDerivationParams.java +++ b/core/java/android/security/keystore/recovery/KeyDerivationParams.java @@ -35,6 +35,22 @@ import java.lang.annotation.RetentionPolicy; */ @SystemApi public final class KeyDerivationParams implements Parcelable { + + // IMPORTANT! PLEASE READ! + // ----------------------- + // If you edit this file (e.g., to add new fields), please MAKE SURE to also do the following: + // - Update the #writeToParcel(Parcel) method below + // - Update the #(Parcel) constructor below + // - Update android.security.keystore.recovery.KeyChainSnapshotTest to make sure nobody + // accidentally breaks your fields in the Parcel in the future. + // - Update com.android.server.locksettings.recoverablekeystore.serialization + // .KeyChainSnapshotSerializer to correctly serialize your new field + // - Update com.android.server.locksettings.recoverablekeystore.serialization + // .KeyChainSnapshotSerializer to correctly deserialize your new field + // - Update com.android.server.locksettings.recoverablekeystore.serialization + // .KeychainSnapshotSerializerTest to make sure nobody breaks serialization of your field + // in the future. + private final int mAlgorithm; private final byte[] mSalt; private final int mMemoryDifficulty; diff --git a/core/java/android/security/keystore/recovery/WrappedApplicationKey.java b/core/java/android/security/keystore/recovery/WrappedApplicationKey.java index 714e35a2e6fc..32952db7037d 100644 --- a/core/java/android/security/keystore/recovery/WrappedApplicationKey.java +++ b/core/java/android/security/keystore/recovery/WrappedApplicationKey.java @@ -42,6 +42,21 @@ public final class WrappedApplicationKey implements Parcelable { // The only supported format is AES-256 symmetric key. private byte[] mEncryptedKeyMaterial; + // IMPORTANT! PLEASE READ! + // ----------------------- + // If you edit this file (e.g., to add new fields), please MAKE SURE to also do the following: + // - Update the #writeToParcel(Parcel) method below + // - Update the #(Parcel) constructor below + // - Update android.security.keystore.recovery.KeyChainSnapshotTest to make sure nobody + // accidentally breaks your fields in the Parcel in the future. + // - Update com.android.server.locksettings.recoverablekeystore.serialization + // .KeyChainSnapshotSerializer to correctly serialize your new field + // - Update com.android.server.locksettings.recoverablekeystore.serialization + // .KeyChainSnapshotSerializer to correctly deserialize your new field + // - Update com.android.server.locksettings.recoverablekeystore.serialization + // .KeychainSnapshotSerializerTest to make sure nobody breaks serialization of your field + // in the future. + /** * Builder for creating {@link WrappedApplicationKey}. */ -- GitLab From 25f5135551f2db2e979ee26353c72e303abf16e5 Mon Sep 17 00:00:00 2001 From: Robert Berry Date: Wed, 28 Mar 2018 20:26:57 +0100 Subject: [PATCH 044/179] Persist KeyChainSnapshot to XML Adds parser and serializer, and round trip test. Bug: 73921897 Test: runtest frameworks-services -p \ com.android.server.locksettings.recoverablekeystore Change-Id: I8259ec398ee076823ac8bbf847534738514de8dc --- .../KeyChainSnapshotDeserializer.java | 401 ++++++++++++++++++ .../KeyChainSnapshotParserException.java | 32 ++ .../serialization/KeyChainSnapshotSchema.java | 57 +++ .../KeyChainSnapshotSerializer.java | 196 +++++++++ .../KeyChainSnapshotSerializerTest.java | 218 ++++++++++ 5 files changed, 904 insertions(+) create mode 100644 services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotDeserializer.java create mode 100644 services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotParserException.java create mode 100644 services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSchema.java create mode 100644 services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSerializer.java create mode 100644 services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSerializerTest.java diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotDeserializer.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotDeserializer.java new file mode 100644 index 000000000000..dcaa0b4785cc --- /dev/null +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotDeserializer.java @@ -0,0 +1,401 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.locksettings.recoverablekeystore.serialization; + +import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.CERTIFICATE_FACTORY_TYPE; +import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.NAMESPACE; +import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.OUTPUT_ENCODING; +import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_ALGORITHM; +import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_ALIAS; +import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_APPLICATION_KEY; +import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_APPLICATION_KEYS; +import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_COUNTER_ID; +import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_RECOVERY_KEY_MATERIAL; +import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_KEY_CHAIN_PROTECTION_PARAMS; +import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_KEY_CHAIN_PROTECTION_PARAMS_LIST; +import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_KEY_CHAIN_SNAPSHOT; +import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_KEY_DERIVATION_PARAMS; +import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_KEY_MATERIAL; +import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_LOCK_SCREEN_UI_TYPE; +import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_MAX_ATTEMPTS; +import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_MEMORY_DIFFICULTY; +import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_SALT; +import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_SERVER_PARAMS; +import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_SNAPSHOT_VERSION; +import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_TRUSTED_HARDWARE_CERT_PATH; +import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_USER_SECRET_TYPE; + +import android.security.keystore.recovery.KeyChainProtectionParams; +import android.security.keystore.recovery.KeyChainSnapshot; +import android.security.keystore.recovery.KeyDerivationParams; +import android.security.keystore.recovery.WrappedApplicationKey; +import android.util.Base64; +import android.util.Xml; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.security.cert.CertPath; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +/** + * Deserializes a {@link android.security.keystore.recovery.KeyChainSnapshot} instance from XML. + */ +public class KeyChainSnapshotDeserializer { + + /** + * Deserializes a {@link KeyChainSnapshot} instance from the XML in the {@code inputStream}. + * + * @throws IOException if there is an IO error reading from the stream. + * @throws KeyChainSnapshotParserException if the XML does not conform to the expected XML for + * a snapshot. + */ + public static KeyChainSnapshot deserialize(InputStream inputStream) + throws KeyChainSnapshotParserException, IOException { + try { + return deserializeInternal(inputStream); + } catch (XmlPullParserException e) { + throw new KeyChainSnapshotParserException("Malformed KeyChainSnapshot XML", e); + } + } + + private static KeyChainSnapshot deserializeInternal(InputStream inputStream) throws IOException, + XmlPullParserException, KeyChainSnapshotParserException { + XmlPullParser parser = Xml.newPullParser(); + parser.setInput(inputStream, OUTPUT_ENCODING); + + parser.nextTag(); + parser.require(XmlPullParser.START_TAG, NAMESPACE, TAG_KEY_CHAIN_SNAPSHOT); + + KeyChainSnapshot.Builder builder = new KeyChainSnapshot.Builder(); + while (parser.next() != XmlPullParser.END_TAG) { + if (parser.getEventType() != XmlPullParser.START_TAG) { + continue; + } + + String name = parser.getName(); + + switch (name) { + case TAG_SNAPSHOT_VERSION: + builder.setSnapshotVersion(readIntTag(parser, TAG_SNAPSHOT_VERSION)); + break; + + case TAG_RECOVERY_KEY_MATERIAL: + builder.setEncryptedRecoveryKeyBlob( + readBlobTag(parser, TAG_RECOVERY_KEY_MATERIAL)); + break; + + case TAG_COUNTER_ID: + builder.setCounterId(readLongTag(parser, TAG_COUNTER_ID)); + break; + + case TAG_SERVER_PARAMS: + builder.setServerParams(readBlobTag(parser, TAG_SERVER_PARAMS)); + break; + + case TAG_MAX_ATTEMPTS: + builder.setMaxAttempts(readIntTag(parser, TAG_MAX_ATTEMPTS)); + break; + + case TAG_TRUSTED_HARDWARE_CERT_PATH: + try { + builder.setTrustedHardwareCertPath( + readCertPathTag(parser, TAG_TRUSTED_HARDWARE_CERT_PATH)); + } catch (CertificateException e) { + throw new KeyChainSnapshotParserException( + "Could not set trustedHardwareCertPath", e); + } + break; + + case TAG_KEY_CHAIN_PROTECTION_PARAMS_LIST: + builder.setKeyChainProtectionParams(readKeyChainProtectionParamsList(parser)); + break; + + case TAG_APPLICATION_KEYS: + builder.setWrappedApplicationKeys(readWrappedApplicationKeys(parser)); + break; + + default: + throw new KeyChainSnapshotParserException(String.format( + Locale.US, "Unexpected tag %s in keyChainSnapshot", name)); + } + } + + parser.require(XmlPullParser.END_TAG, NAMESPACE, TAG_KEY_CHAIN_SNAPSHOT); + try { + return builder.build(); + } catch (NullPointerException e) { + throw new KeyChainSnapshotParserException("Failed to build KeyChainSnapshot", e); + } + } + + private static List readWrappedApplicationKeys(XmlPullParser parser) + throws IOException, XmlPullParserException, KeyChainSnapshotParserException { + parser.require(XmlPullParser.START_TAG, NAMESPACE, TAG_APPLICATION_KEYS); + ArrayList keys = new ArrayList<>(); + while (parser.next() != XmlPullParser.END_TAG) { + if (parser.getEventType() != XmlPullParser.START_TAG) { + continue; + } + keys.add(readWrappedApplicationKey(parser)); + } + parser.require(XmlPullParser.END_TAG, NAMESPACE, TAG_APPLICATION_KEYS); + return keys; + } + + private static WrappedApplicationKey readWrappedApplicationKey(XmlPullParser parser) + throws IOException, XmlPullParserException, KeyChainSnapshotParserException { + parser.require(XmlPullParser.START_TAG, NAMESPACE, TAG_APPLICATION_KEY); + WrappedApplicationKey.Builder builder = new WrappedApplicationKey.Builder(); + while (parser.next() != XmlPullParser.END_TAG) { + if (parser.getEventType() != XmlPullParser.START_TAG) { + continue; + } + + String name = parser.getName(); + + switch (name) { + case TAG_ALIAS: + builder.setAlias(readStringTag(parser, TAG_ALIAS)); + break; + + case TAG_KEY_MATERIAL: + builder.setEncryptedKeyMaterial(readBlobTag(parser, TAG_KEY_MATERIAL)); + break; + + default: + throw new KeyChainSnapshotParserException(String.format( + Locale.US, "Unexpected tag %s in wrappedApplicationKey", name)); + } + } + parser.require(XmlPullParser.END_TAG, NAMESPACE, TAG_APPLICATION_KEY); + + try { + return builder.build(); + } catch (NullPointerException e) { + throw new KeyChainSnapshotParserException("Failed to build WrappedApplicationKey", e); + } + } + + private static List readKeyChainProtectionParamsList( + XmlPullParser parser) throws IOException, XmlPullParserException, + KeyChainSnapshotParserException { + parser.require(XmlPullParser.START_TAG, NAMESPACE, TAG_KEY_CHAIN_PROTECTION_PARAMS_LIST); + + ArrayList keyChainProtectionParamsList = new ArrayList<>(); + while (parser.next() != XmlPullParser.END_TAG) { + if (parser.getEventType() != XmlPullParser.START_TAG) { + continue; + } + keyChainProtectionParamsList.add(readKeyChainProtectionParams(parser)); + } + + parser.require(XmlPullParser.END_TAG, NAMESPACE, TAG_KEY_CHAIN_PROTECTION_PARAMS_LIST); + return keyChainProtectionParamsList; + } + + private static KeyChainProtectionParams readKeyChainProtectionParams(XmlPullParser parser) + throws IOException, XmlPullParserException, KeyChainSnapshotParserException { + parser.require(XmlPullParser.START_TAG, NAMESPACE, TAG_KEY_CHAIN_PROTECTION_PARAMS); + + KeyChainProtectionParams.Builder builder = new KeyChainProtectionParams.Builder(); + while (parser.next() != XmlPullParser.END_TAG) { + if (parser.getEventType() != XmlPullParser.START_TAG) { + continue; + } + + String name = parser.getName(); + + switch (name) { + case TAG_LOCK_SCREEN_UI_TYPE: + builder.setLockScreenUiFormat(readIntTag(parser, TAG_LOCK_SCREEN_UI_TYPE)); + break; + + case TAG_USER_SECRET_TYPE: + builder.setUserSecretType(readIntTag(parser, TAG_USER_SECRET_TYPE)); + break; + + case TAG_KEY_DERIVATION_PARAMS: + builder.setKeyDerivationParams(readKeyDerivationParams(parser)); + break; + + default: + throw new KeyChainSnapshotParserException(String.format( + Locale.US, + "Unexpected tag %s in keyChainProtectionParams", + name)); + + } + } + + parser.require(XmlPullParser.END_TAG, NAMESPACE, TAG_KEY_CHAIN_PROTECTION_PARAMS); + + try { + return builder.build(); + } catch (NullPointerException e) { + throw new KeyChainSnapshotParserException( + "Failed to build KeyChainProtectionParams", e); + } + } + + private static KeyDerivationParams readKeyDerivationParams(XmlPullParser parser) + throws XmlPullParserException, IOException, KeyChainSnapshotParserException { + parser.require(XmlPullParser.START_TAG, NAMESPACE, TAG_KEY_DERIVATION_PARAMS); + + int memoryDifficulty = -1; + int algorithm = -1; + byte[] salt = null; + + while (parser.next() != XmlPullParser.END_TAG) { + if (parser.getEventType() != XmlPullParser.START_TAG) { + continue; + } + + String name = parser.getName(); + + switch (name) { + case TAG_MEMORY_DIFFICULTY: + memoryDifficulty = readIntTag(parser, TAG_MEMORY_DIFFICULTY); + break; + + case TAG_ALGORITHM: + algorithm = readIntTag(parser, TAG_ALGORITHM); + break; + + case TAG_SALT: + salt = readBlobTag(parser, TAG_SALT); + break; + + default: + throw new KeyChainSnapshotParserException( + String.format( + Locale.US, + "Unexpected tag %s in keyDerivationParams", + name)); + } + } + + if (salt == null) { + throw new KeyChainSnapshotParserException("salt was not set in keyDerivationParams"); + } + + KeyDerivationParams keyDerivationParams = null; + + switch (algorithm) { + case KeyDerivationParams.ALGORITHM_SHA256: + keyDerivationParams = KeyDerivationParams.createSha256Params(salt); + break; + + case KeyDerivationParams.ALGORITHM_SCRYPT: + keyDerivationParams = KeyDerivationParams.createScryptParams( + salt, memoryDifficulty); + break; + + default: + throw new KeyChainSnapshotParserException( + "Unknown algorithm in keyDerivationParams"); + } + + parser.require(XmlPullParser.END_TAG, NAMESPACE, TAG_KEY_DERIVATION_PARAMS); + return keyDerivationParams; + } + + private static int readIntTag(XmlPullParser parser, String tagName) + throws IOException, XmlPullParserException, KeyChainSnapshotParserException { + parser.require(XmlPullParser.START_TAG, NAMESPACE, tagName); + String text = readText(parser); + parser.require(XmlPullParser.END_TAG, NAMESPACE, tagName); + try { + return Integer.valueOf(text); + } catch (NumberFormatException e) { + throw new KeyChainSnapshotParserException( + String.format( + Locale.US, "%s expected int but got '%s'", tagName, text), e); + } + } + + private static long readLongTag(XmlPullParser parser, String tagName) + throws IOException, XmlPullParserException, KeyChainSnapshotParserException { + parser.require(XmlPullParser.START_TAG, NAMESPACE, tagName); + String text = readText(parser); + parser.require(XmlPullParser.END_TAG, NAMESPACE, tagName); + try { + return Long.valueOf(text); + } catch (NumberFormatException e) { + throw new KeyChainSnapshotParserException( + String.format( + Locale.US, "%s expected long but got '%s'", tagName, text), e); + } + } + + private static String readStringTag(XmlPullParser parser, String tagName) + throws IOException, XmlPullParserException { + parser.require(XmlPullParser.START_TAG, NAMESPACE, tagName); + String text = readText(parser); + parser.require(XmlPullParser.END_TAG, NAMESPACE, tagName); + return text; + } + + private static byte[] readBlobTag(XmlPullParser parser, String tagName) + throws IOException, XmlPullParserException, KeyChainSnapshotParserException { + parser.require(XmlPullParser.START_TAG, NAMESPACE, tagName); + String text = readText(parser); + parser.require(XmlPullParser.END_TAG, NAMESPACE, tagName); + + try { + return Base64.decode(text, /*flags=*/ Base64.DEFAULT); + } catch (IllegalArgumentException e) { + throw new KeyChainSnapshotParserException( + String.format( + Locale.US, + "%s expected base64 encoded bytes but got '%s'", + tagName, text), e); + } + } + + private static CertPath readCertPathTag(XmlPullParser parser, String tagName) + throws IOException, XmlPullParserException, KeyChainSnapshotParserException { + byte[] bytes = readBlobTag(parser, tagName); + try { + return CertificateFactory.getInstance(CERTIFICATE_FACTORY_TYPE) + .generateCertPath(new ByteArrayInputStream(bytes)); + } catch (CertificateException e) { + throw new KeyChainSnapshotParserException("Could not parse CertPath in tag " + tagName, + e); + } + } + + private static String readText(XmlPullParser parser) + throws IOException, XmlPullParserException { + String result = ""; + if (parser.next() == XmlPullParser.TEXT) { + result = parser.getText(); + parser.nextTag(); + } + return result; + } + + // Statics only + private KeyChainSnapshotDeserializer() {} +} diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotParserException.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotParserException.java new file mode 100644 index 000000000000..a3208afddf9b --- /dev/null +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotParserException.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.locksettings.recoverablekeystore.serialization; + +/** + * Error thrown when parsing invalid XML, while trying to read a + * {@link android.security.keystore.recovery.KeyChainSnapshot}. + */ +public class KeyChainSnapshotParserException extends Exception { + + public KeyChainSnapshotParserException(String message, Throwable cause) { + super(message, cause); + } + + public KeyChainSnapshotParserException(String message) { + super(message); + } +} diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSchema.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSchema.java new file mode 100644 index 000000000000..ee8b2cfd18f5 --- /dev/null +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSchema.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.locksettings.recoverablekeystore.serialization; + +/** + * Describes the XML schema of the {@link android.security.keystore.recovery.KeyChainSnapshot} file. + */ +class KeyChainSnapshotSchema { + static final String NAMESPACE = null; + + static final String OUTPUT_ENCODING = "UTF-8"; + + static final String CERTIFICATE_FACTORY_TYPE = "X.509"; + static final String CERT_PATH_ENCODING = "PkiPath"; + + static final String TAG_KEY_CHAIN_SNAPSHOT = "keyChainSnapshot"; + + static final String TAG_SNAPSHOT_VERSION = "snapshotVersion"; + static final String TAG_COUNTER_ID = "counterId"; + static final String TAG_MAX_ATTEMPTS = "maxAttempts"; + static final String TAG_RECOVERY_KEY_MATERIAL = "recoveryKeyMaterial"; + static final String TAG_SERVER_PARAMS = "serverParams"; + static final String TAG_TRUSTED_HARDWARE_CERT_PATH = "thmCertPath"; + + static final String TAG_KEY_CHAIN_PROTECTION_PARAMS_LIST = + "keyChainProtectionParamsList"; + static final String TAG_KEY_CHAIN_PROTECTION_PARAMS = "keyChainProtectionParams"; + static final String TAG_USER_SECRET_TYPE = "userSecretType"; + static final String TAG_LOCK_SCREEN_UI_TYPE = "lockScreenUiType"; + + static final String TAG_KEY_DERIVATION_PARAMS = "keyDerivationParams"; + static final String TAG_ALGORITHM = "algorithm"; + static final String TAG_MEMORY_DIFFICULTY = "memoryDifficulty"; + static final String TAG_SALT = "salt"; + + static final String TAG_APPLICATION_KEYS = "applicationKeysList"; + static final String TAG_APPLICATION_KEY = "applicationKey"; + static final String TAG_ALIAS = "alias"; + static final String TAG_KEY_MATERIAL = "keyMaterial"; + + // Statics only + private KeyChainSnapshotSchema() {} +} diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSerializer.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSerializer.java new file mode 100644 index 000000000000..f817a8fb02e4 --- /dev/null +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSerializer.java @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.locksettings.recoverablekeystore.serialization; + + +import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.CERT_PATH_ENCODING; +import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.NAMESPACE; +import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.OUTPUT_ENCODING; +import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_ALGORITHM; +import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_ALIAS; +import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_APPLICATION_KEY; +import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_APPLICATION_KEYS; +import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_COUNTER_ID; +import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_RECOVERY_KEY_MATERIAL; +import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_KEY_CHAIN_PROTECTION_PARAMS; +import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_KEY_CHAIN_PROTECTION_PARAMS_LIST; +import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_KEY_CHAIN_SNAPSHOT; +import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_KEY_DERIVATION_PARAMS; +import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_KEY_MATERIAL; +import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_LOCK_SCREEN_UI_TYPE; +import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_MAX_ATTEMPTS; +import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_MEMORY_DIFFICULTY; +import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_SALT; +import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_SERVER_PARAMS; +import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_SNAPSHOT_VERSION; +import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_TRUSTED_HARDWARE_CERT_PATH; +import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_USER_SECRET_TYPE; + +import android.security.keystore.recovery.KeyChainProtectionParams; +import android.security.keystore.recovery.KeyChainSnapshot; +import android.security.keystore.recovery.KeyDerivationParams; +import android.security.keystore.recovery.WrappedApplicationKey; +import android.util.Base64; +import android.util.Xml; + +import org.xmlpull.v1.XmlSerializer; + +import java.io.IOException; +import java.io.OutputStream; +import java.security.cert.CertPath; +import java.security.cert.CertificateEncodingException; +import java.util.List; + +/** + * Serializes a {@link KeyChainSnapshot} instance to XML. + */ +public class KeyChainSnapshotSerializer { + + /** + * Serializes {@code keyChainSnapshot} to XML, writing to {@code outputStream}. + * + * @throws IOException if there was an IO error writing to the stream. + * @throws CertificateEncodingException if the {@link CertPath} from + * {@link KeyChainSnapshot#getTrustedHardwareCertPath()} is not encoded correctly. + */ + public static void serialize(KeyChainSnapshot keyChainSnapshot, OutputStream outputStream) + throws IOException, CertificateEncodingException { + XmlSerializer xmlSerializer = Xml.newSerializer(); + xmlSerializer.setOutput(outputStream, OUTPUT_ENCODING); + xmlSerializer.startDocument( + /*encoding=*/ null, + /*standalone=*/ null); + xmlSerializer.startTag(NAMESPACE, TAG_KEY_CHAIN_SNAPSHOT); + writeKeyChainSnapshotProperties(xmlSerializer, keyChainSnapshot); + writeKeyChainProtectionParams(xmlSerializer, + keyChainSnapshot.getKeyChainProtectionParams()); + writeApplicationKeys(xmlSerializer, + keyChainSnapshot.getWrappedApplicationKeys()); + xmlSerializer.endTag(NAMESPACE, TAG_KEY_CHAIN_SNAPSHOT); + xmlSerializer.endDocument(); + } + + private static void writeApplicationKeys( + XmlSerializer xmlSerializer, List wrappedApplicationKeys) + throws IOException { + xmlSerializer.startTag(NAMESPACE, TAG_APPLICATION_KEYS); + for (WrappedApplicationKey key : wrappedApplicationKeys) { + xmlSerializer.startTag(NAMESPACE, TAG_APPLICATION_KEY); + writeApplicationKeyProperties(xmlSerializer, key); + xmlSerializer.endTag(NAMESPACE, TAG_APPLICATION_KEY); + } + xmlSerializer.endTag(NAMESPACE, TAG_APPLICATION_KEYS); + } + + private static void writeApplicationKeyProperties( + XmlSerializer xmlSerializer, WrappedApplicationKey applicationKey) throws IOException { + writePropertyTag(xmlSerializer, TAG_ALIAS, applicationKey.getAlias()); + writePropertyTag(xmlSerializer, TAG_KEY_MATERIAL, applicationKey.getEncryptedKeyMaterial()); + } + + private static void writeKeyChainProtectionParams( + XmlSerializer xmlSerializer, + List keyChainProtectionParamsList) throws IOException { + xmlSerializer.startTag(NAMESPACE, TAG_KEY_CHAIN_PROTECTION_PARAMS_LIST); + for (KeyChainProtectionParams keyChainProtectionParams : keyChainProtectionParamsList) { + xmlSerializer.startTag(NAMESPACE, TAG_KEY_CHAIN_PROTECTION_PARAMS); + writeKeyChainProtectionParamsProperties(xmlSerializer, keyChainProtectionParams); + xmlSerializer.endTag(NAMESPACE, TAG_KEY_CHAIN_PROTECTION_PARAMS); + } + xmlSerializer.endTag(NAMESPACE, TAG_KEY_CHAIN_PROTECTION_PARAMS_LIST); + } + + private static void writeKeyChainProtectionParamsProperties( + XmlSerializer xmlSerializer, KeyChainProtectionParams keyChainProtectionParams) + throws IOException { + writePropertyTag(xmlSerializer, TAG_USER_SECRET_TYPE, + keyChainProtectionParams.getUserSecretType()); + writePropertyTag(xmlSerializer, TAG_LOCK_SCREEN_UI_TYPE, + keyChainProtectionParams.getLockScreenUiFormat()); + + // NOTE: Do not serialize the 'secret' field. It should never be set anyway for snapshots + // we generate. + + writeKeyDerivationParams(xmlSerializer, keyChainProtectionParams.getKeyDerivationParams()); + } + + private static void writeKeyDerivationParams( + XmlSerializer xmlSerializer, KeyDerivationParams keyDerivationParams) + throws IOException { + xmlSerializer.startTag(NAMESPACE, TAG_KEY_DERIVATION_PARAMS); + writeKeyDerivationParamsProperties( + xmlSerializer, keyDerivationParams); + xmlSerializer.endTag(NAMESPACE, TAG_KEY_DERIVATION_PARAMS); + } + + private static void writeKeyDerivationParamsProperties( + XmlSerializer xmlSerializer, KeyDerivationParams keyDerivationParams) + throws IOException { + writePropertyTag(xmlSerializer, TAG_ALGORITHM, keyDerivationParams.getAlgorithm()); + writePropertyTag(xmlSerializer, TAG_SALT, keyDerivationParams.getSalt()); + writePropertyTag(xmlSerializer, TAG_MEMORY_DIFFICULTY, + keyDerivationParams.getMemoryDifficulty()); + } + + private static void writeKeyChainSnapshotProperties( + XmlSerializer xmlSerializer, KeyChainSnapshot keyChainSnapshot) + throws IOException, CertificateEncodingException { + + writePropertyTag(xmlSerializer, TAG_SNAPSHOT_VERSION, + keyChainSnapshot.getSnapshotVersion()); + writePropertyTag(xmlSerializer, TAG_MAX_ATTEMPTS, keyChainSnapshot.getMaxAttempts()); + writePropertyTag(xmlSerializer, TAG_COUNTER_ID, keyChainSnapshot.getCounterId()); + writePropertyTag(xmlSerializer, TAG_RECOVERY_KEY_MATERIAL, + keyChainSnapshot.getEncryptedRecoveryKeyBlob()); + writePropertyTag(xmlSerializer, TAG_SERVER_PARAMS, keyChainSnapshot.getServerParams()); + writePropertyTag(xmlSerializer, TAG_TRUSTED_HARDWARE_CERT_PATH, + keyChainSnapshot.getTrustedHardwareCertPath()); + } + + private static void writePropertyTag( + XmlSerializer xmlSerializer, String propertyName, long propertyValue) + throws IOException { + xmlSerializer.startTag(NAMESPACE, propertyName); + xmlSerializer.text(Long.toString(propertyValue)); + xmlSerializer.endTag(NAMESPACE, propertyName); + } + + private static void writePropertyTag( + XmlSerializer xmlSerializer, String propertyName, String propertyValue) + throws IOException { + xmlSerializer.startTag(NAMESPACE, propertyName); + xmlSerializer.text(propertyValue); + xmlSerializer.endTag(NAMESPACE, propertyName); + } + + private static void writePropertyTag( + XmlSerializer xmlSerializer, String propertyName, byte[] propertyValue) + throws IOException { + xmlSerializer.startTag(NAMESPACE, propertyName); + xmlSerializer.text(Base64.encodeToString(propertyValue, /*flags=*/ Base64.DEFAULT)); + xmlSerializer.endTag(NAMESPACE, propertyName); + } + + private static void writePropertyTag( + XmlSerializer xmlSerializer, String propertyName, CertPath certPath) + throws IOException, CertificateEncodingException { + writePropertyTag(xmlSerializer, propertyName, certPath.getEncoded(CERT_PATH_ENCODING)); + } + + // Statics only + private KeyChainSnapshotSerializer() {} +} diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSerializerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSerializerTest.java new file mode 100644 index 000000000000..6c2958e4f456 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSerializerTest.java @@ -0,0 +1,218 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.locksettings.recoverablekeystore.serialization; + +import static com.google.common.truth.Truth.assertThat; + +import android.security.keystore.recovery.KeyChainProtectionParams; +import android.security.keystore.recovery.KeyChainSnapshot; +import android.security.keystore.recovery.KeyDerivationParams; +import android.security.keystore.recovery.WrappedApplicationKey; +import android.support.test.InstrumentationRegistry; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; + +import com.android.server.locksettings.recoverablekeystore.TestData; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.security.cert.CertPath; +import java.util.ArrayList; +import java.util.List; + +@SmallTest +@RunWith(AndroidJUnit4.class) +public class KeyChainSnapshotSerializerTest { + private static final int COUNTER_ID = 2134; + private static final int SNAPSHOT_VERSION = 125; + private static final int MAX_ATTEMPTS = 21; + private static final byte[] SERVER_PARAMS = new byte[] { 8, 2, 4 }; + private static final byte[] KEY_BLOB = new byte[] { 124, 53, 53, 53 }; + private static final CertPath CERT_PATH = TestData.CERT_PATH_1; + private static final int SECRET_TYPE = KeyChainProtectionParams.TYPE_LOCKSCREEN; + private static final int LOCK_SCREEN_UI = KeyChainProtectionParams.UI_FORMAT_PASSWORD; + private static final byte[] SALT = new byte[] { 5, 4, 3, 2, 1 }; + private static final int MEMORY_DIFFICULTY = 45; + private static final int ALGORITHM = KeyDerivationParams.ALGORITHM_SCRYPT; + private static final byte[] SECRET = new byte[] { 1, 2, 3, 4 }; + + private static final String TEST_KEY_1_ALIAS = "key1"; + private static final byte[] TEST_KEY_1_BYTES = new byte[] { 66, 77, 88 }; + + private static final String TEST_KEY_2_ALIAS = "key2"; + private static final byte[] TEST_KEY_2_BYTES = new byte[] { 99, 33, 11 }; + + private static final String TEST_KEY_3_ALIAS = "key3"; + private static final byte[] TEST_KEY_3_BYTES = new byte[] { 2, 8, 100 }; + + @Test + public void roundTrip_persistsCounterId() throws Exception { + assertThat(roundTrip().getCounterId()).isEqualTo(COUNTER_ID); + } + + @Test + public void roundTrip_persistsSnapshotVersion() throws Exception { + assertThat(roundTrip().getSnapshotVersion()).isEqualTo(SNAPSHOT_VERSION); + } + + @Test + public void roundTrip_persistsMaxAttempts() throws Exception { + assertThat(roundTrip().getMaxAttempts()).isEqualTo(MAX_ATTEMPTS); + } + + @Test + public void roundTrip_persistsRecoveryKey() throws Exception { + assertThat(roundTrip().getEncryptedRecoveryKeyBlob()).isEqualTo(KEY_BLOB); + } + + @Test + public void roundTrip_persistsServerParams() throws Exception { + assertThat(roundTrip().getServerParams()).isEqualTo(SERVER_PARAMS); + } + + @Test + public void roundTrip_persistsCertPath() throws Exception { + assertThat(roundTrip().getTrustedHardwareCertPath()).isEqualTo(CERT_PATH); + } + + @Test + public void roundTrip_persistsParamsList() throws Exception { + assertThat(roundTrip().getKeyChainProtectionParams()).hasSize(1); + } + + @Test + public void roundTripParams_persistsUserSecretType() throws Exception { + assertThat(roundTripParams().getUserSecretType()).isEqualTo(SECRET_TYPE); + } + + @Test + public void roundTripParams_persistsLockScreenUi() throws Exception { + assertThat(roundTripParams().getLockScreenUiFormat()).isEqualTo(LOCK_SCREEN_UI); + } + + @Test + public void roundTripParams_persistsSalt() throws Exception { + assertThat(roundTripParams().getKeyDerivationParams().getSalt()).isEqualTo(SALT); + } + + @Test + public void roundTripParams_persistsAlgorithm() throws Exception { + assertThat(roundTripParams().getKeyDerivationParams().getAlgorithm()).isEqualTo(ALGORITHM); + } + + @Test + public void roundTripParams_persistsMemoryDifficulty() throws Exception { + assertThat(roundTripParams().getKeyDerivationParams().getMemoryDifficulty()) + .isEqualTo(MEMORY_DIFFICULTY); + } + + @Test + public void roundTripParams_doesNotPersistSecret() throws Exception { + assertThat(roundTripParams().getSecret()).isEmpty(); + } + + @Test + public void roundTripKeys_hasCorrectLength() throws Exception { + assertThat(roundTripKeys()).hasSize(3); + } + + @Test + public void roundTripKeys_0_persistsAlias() throws Exception { + assertThat(roundTripKeys().get(0).getAlias()).isEqualTo(TEST_KEY_1_ALIAS); + } + + @Test + public void roundTripKeys_0_persistsKeyBytes() throws Exception { + assertThat(roundTripKeys().get(0).getEncryptedKeyMaterial()).isEqualTo(TEST_KEY_1_BYTES); + } + + @Test + public void roundTripKeys_1_persistsAlias() throws Exception { + assertThat(roundTripKeys().get(1).getAlias()).isEqualTo(TEST_KEY_2_ALIAS); + } + + @Test + public void roundTripKeys_1_persistsKeyBytes() throws Exception { + assertThat(roundTripKeys().get(1).getEncryptedKeyMaterial()).isEqualTo(TEST_KEY_2_BYTES); + } + + @Test + public void roundTripKeys_2_persistsAlias() throws Exception { + assertThat(roundTripKeys().get(2).getAlias()).isEqualTo(TEST_KEY_3_ALIAS); + } + + @Test + public void roundTripKeys_2_persistsKeyBytes() throws Exception { + assertThat(roundTripKeys().get(2).getEncryptedKeyMaterial()).isEqualTo(TEST_KEY_3_BYTES); + } + + private static List roundTripKeys() throws Exception { + return roundTrip().getWrappedApplicationKeys(); + } + + private static KeyChainProtectionParams roundTripParams() throws Exception { + return roundTrip().getKeyChainProtectionParams().get(0); + } + + public static KeyChainSnapshot roundTrip() throws Exception { + KeyChainSnapshot snapshot = createTestKeyChainSnapshot(); + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + KeyChainSnapshotSerializer.serialize(snapshot, byteArrayOutputStream); + return KeyChainSnapshotDeserializer.deserialize( + new ByteArrayInputStream(byteArrayOutputStream.toByteArray())); + } + + private static KeyChainSnapshot createTestKeyChainSnapshot() throws Exception { + KeyDerivationParams keyDerivationParams = + KeyDerivationParams.createScryptParams(SALT, MEMORY_DIFFICULTY); + KeyChainProtectionParams keyChainProtectionParams = new KeyChainProtectionParams.Builder() + .setKeyDerivationParams(keyDerivationParams) + .setUserSecretType(SECRET_TYPE) + .setLockScreenUiFormat(LOCK_SCREEN_UI) + .setSecret(SECRET) + .build(); + ArrayList keyChainProtectionParamsList = + new ArrayList<>(1); + keyChainProtectionParamsList.add(keyChainProtectionParams); + + ArrayList keyList = new ArrayList<>(); + keyList.add(createKey(TEST_KEY_1_ALIAS, TEST_KEY_1_BYTES)); + keyList.add(createKey(TEST_KEY_2_ALIAS, TEST_KEY_2_BYTES)); + keyList.add(createKey(TEST_KEY_3_ALIAS, TEST_KEY_3_BYTES)); + + return new KeyChainSnapshot.Builder() + .setCounterId(COUNTER_ID) + .setSnapshotVersion(SNAPSHOT_VERSION) + .setServerParams(SERVER_PARAMS) + .setMaxAttempts(MAX_ATTEMPTS) + .setEncryptedRecoveryKeyBlob(KEY_BLOB) + .setKeyChainProtectionParams(keyChainProtectionParamsList) + .setWrappedApplicationKeys(keyList) + .setTrustedHardwareCertPath(CERT_PATH) + .build(); + } + + private static WrappedApplicationKey createKey(String alias, byte[] bytes) { + return new WrappedApplicationKey.Builder() + .setAlias(alias) + .setEncryptedKeyMaterial(bytes) + .build(); + } +} -- GitLab From 924b550151cd0338fc8a9e9af29eb52279b6eb37 Mon Sep 17 00:00:00 2001 From: Robert Berry Date: Thu, 29 Mar 2018 10:09:03 +0100 Subject: [PATCH 045/179] Remove unused KeyChainSnapshot tables This will be persisted as an XML file instead. Bug: 73921897 Test: none, it's just removing unused consts Change-Id: Idaeb437d0a7258d03418932d4aba75189092b3fe --- .../RecoverableKeyStoreDbContract.java | 115 ------------------ 1 file changed, 115 deletions(-) diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbContract.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbContract.java index 1eff2d472144..7ee809aa3865 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbContract.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbContract.java @@ -69,121 +69,6 @@ class RecoverableKeyStoreDbContract { static final String COLUMN_NAME_RECOVERY_STATUS = "recovery_status"; } - /** - * Table holding encrypted snapshots of the recoverable key store. - */ - static class SnapshotsEntry implements BaseColumns { - static final String TABLE_NAME = "snapshots"; - - /** - * The version number of the snapshot. - */ - static final String COLUMN_NAME_VERSION = "version"; - - /** - * The ID of the user whose keystore was snapshotted. - */ - static final String COLUMN_NAME_USER_ID = "user_id"; - - /** - * The UID of the app that owns the snapshot (i.e., the recovery agent). - */ - static final String COLUMN_NAME_UID = "uid"; - - /** - * The maximum number of attempts allowed to attempt to decrypt the recovery key. - */ - static final String COLUMN_NAME_MAX_ATTEMPTS = "max_attempts"; - - /** - * The ID of the counter in the trusted hardware module. - */ - static final String COLUMN_NAME_COUNTER_ID = "counter_id"; - - /** - * Server parameters used to help identify the device (during recovery). - */ - static final String SERVER_PARAMS = "server_params"; - - /** - * The public key of the trusted hardware module. This key has been used to encrypt the - * snapshot, to ensure that it can only be read by the trusted module. - */ - static final String TRUSTED_HARDWARE_PUBLIC_KEY = "thm_public_key"; - - /** - * {@link java.security.cert.CertPath} signing the trusted hardware module to whose public - * key this snapshot is encrypted. - */ - static final String CERT_PATH = "cert_path"; - - /** - * The recovery key, encrypted with the user's lock screen and the trusted hardware module's - * public key. - */ - static final String ENCRYPTED_RECOVERY_KEY = "encrypted_recovery_key"; - } - - /** - * Table holding encrypted keys belonging to a particular snapshot. - */ - static class SnapshotKeysEntry implements BaseColumns { - static final String TABLE_NAME = "snapshot_keys"; - - /** - * ID of the associated snapshot entry in {@link SnapshotsEntry}. - */ - static final String COLUMN_NAME_SNAPSHOT_ID = "snapshot_id"; - - /** - * Alias of the key. - */ - static final String COLUMN_NAME_ALIAS = "alias"; - - /** - * Key material, encrypted with the recovery key from the snapshot. - */ - static final String COLUMN_NAME_ENCRYPTED_BYTES = "encrypted_key_bytes"; - } - - /** - * A layer of protection associated with a snapshot. - */ - static class SnapshotProtectionParams implements BaseColumns { - static final String TABLE_NAME = "snapshot_protection_params"; - - /** - * ID of the associated snapshot entry in {@link SnapshotsEntry}. - */ - static final String COLUMN_NAME_SNAPSHOT_ID = "snapshot_id"; - - /** - * Type of secret used to generate recovery key. One of - * {@link android.security.keystore.recovery.KeyChainProtectionParams#TYPE_LOCKSCREEN} or - */ - static final String COLUMN_NAME_SECRET_TYPE = "secret_type"; - - /** - * If a lock screen, the type of UI used. One of - * {@link android.security.keystore.recovery.KeyChainProtectionParams#UI_FORMAT_PATTERN}, - * {@link android.security.keystore.recovery.KeyChainProtectionParams#UI_FORMAT_PIN}, or - * {@link android.security.keystore.recovery.KeyChainProtectionParams#UI_FORMAT_PASSWORD}. - */ - static final String COLUMN_NAME_LOCKSCREEN_UI_TYPE = "lock_screen_ui_type"; - - /** - * The algorithm used to derive cryptographic material from the key and salt. One of - * {@link android.security.keystore.recovery.KeyDerivationParams#ALGORITHM_SHA256} or - * {@link android.security.keystore.recovery.KeyDerivationParams#ALGORITHM_SCRYPT}. - */ - static final String COLUMN_NAME_KEY_DERIVATION_ALGORITHM = "key_derivation_algorithm"; - - /** - * The salt used along with the secret to generate cryptographic material. - */ - static final String COLUMN_NAME_KEY_DERIVATION_SALT = "key_derivation_salt"; - } - /** * Recoverable KeyStore metadata for a specific user profile. */ -- GitLab From 11115e9c9ae07c9027c4e2fc31168c0db6448210 Mon Sep 17 00:00:00 2001 From: Robert Berry Date: Thu, 29 Mar 2018 10:30:29 +0100 Subject: [PATCH 046/179] Remove unused KeyStore field in RecoverableKeyStoreManager Test: runtest frameworks-services -p \ com.android.server.locksettings.recoverablekeystore Bug: 74944591 Change-Id: Ibe0167adb103beded9eb0138825f4a975f12c29e --- .../recoverablekeystore/RecoverableKeyStoreManager.java | 4 ---- .../recoverablekeystore/RecoverableKeyStoreManagerTest.java | 1 - 2 files changed, 5 deletions(-) diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java index 30125f8199de..8a79e4c680d2 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java @@ -100,7 +100,6 @@ public class RecoverableKeyStoreManager { private final RecoverableKeyGenerator mRecoverableKeyGenerator; private final RecoverySnapshotStorage mSnapshotStorage; private final PlatformKeyManager mPlatformKeyManager; - private final KeyStore mKeyStore; private final ApplicationKeyStorage mApplicationKeyStorage; /** @@ -126,7 +125,6 @@ public class RecoverableKeyStoreManager { mInstance = new RecoverableKeyStoreManager( context.getApplicationContext(), - keystore, db, new RecoverySessionStorage(), Executors.newSingleThreadExecutor(), @@ -141,7 +139,6 @@ public class RecoverableKeyStoreManager { @VisibleForTesting RecoverableKeyStoreManager( Context context, - KeyStore keystore, RecoverableKeyStoreDb recoverableKeyStoreDb, RecoverySessionStorage recoverySessionStorage, ExecutorService executorService, @@ -150,7 +147,6 @@ public class RecoverableKeyStoreManager { PlatformKeyManager platformKeyManager, ApplicationKeyStorage applicationKeyStorage) { mContext = context; - mKeyStore = keystore; mDatabase = recoverableKeyStoreDb; mRecoverySessionStorage = recoverySessionStorage; mExecutorService = executorService; diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java index f5f5027da771..18a3885aea6a 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java @@ -189,7 +189,6 @@ public class RecoverableKeyStoreManagerTest { mRecoverableKeyStoreManager = new RecoverableKeyStoreManager( mMockContext, - KeyStore.getInstance(), mRecoverableKeyStoreDb, mRecoverySessionStorage, Executors.newSingleThreadExecutor(), -- GitLab From 6169239b942fc2f6e8721b219f84b506c106fbe1 Mon Sep 17 00:00:00 2001 From: Eran Messeri Date: Mon, 26 Mar 2018 16:43:14 +0100 Subject: [PATCH 047/179] Utilize verbose KeyChain errors As KeyChain reports detailed error codes about failure to generate keys or attestation records for them, log these detailed errors and throw an exception if the hardware does not support Device ID attestation. Bug: 72642093 Bug: 73448533 Test: cts-tradefed run commandAndExit cts-dev -s 127.0.0.1:50487 -a x86_64 -m CtsDevicePolicyManagerTestCases -t com.android.cts.devicepolicy.DeviceOwnerTest#testKeyManagement -l DEBUG Change-Id: Ib12efcf48c158373e1fc28cc51d67e70282d029e --- .../app/admin/DevicePolicyManager.java | 2 + .../android/security/IKeyChainService.aidl | 4 +- keystore/java/android/security/KeyChain.java | 76 +++++++++++++++++++ keystore/java/android/security/KeyStore.java | 1 + .../DevicePolicyManagerService.java | 18 +++-- 5 files changed, 93 insertions(+), 8 deletions(-) diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 106b42fba40d..5c55e4fa3fc7 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -4246,6 +4246,8 @@ public class DevicePolicyManager { * algorithm specification in {@code keySpec} is not {@code RSAKeyGenParameterSpec} * or {@code ECGenParameterSpec}, or if Device ID attestation was requested but the * {@code keySpec} does not contain an attestation challenge. + * @throws UnsupportedOperationException if Device ID attestation was requested but the + * underlying hardware does not support it. * @see KeyGenParameterSpec.Builder#setAttestationChallenge(byte[]) */ public AttestedKeyPair generateKeyPair(@Nullable ComponentName admin, diff --git a/keystore/java/android/security/IKeyChainService.aidl b/keystore/java/android/security/IKeyChainService.aidl index 5a8fa0700328..0d32075d20d2 100644 --- a/keystore/java/android/security/IKeyChainService.aidl +++ b/keystore/java/android/security/IKeyChainService.aidl @@ -33,8 +33,8 @@ interface IKeyChainService { boolean isUserSelectable(String alias); void setUserSelectable(String alias, boolean isUserSelectable); - boolean generateKeyPair(in String algorithm, in ParcelableKeyGenParameterSpec spec); - boolean attestKey(in String alias, in byte[] challenge, in int[] idAttestationFlags, + int generateKeyPair(in String algorithm, in ParcelableKeyGenParameterSpec spec); + int attestKey(in String alias, in byte[] challenge, in int[] idAttestationFlags, out KeymasterCertificateChain chain); boolean setKeyPairCertificate(String alias, in byte[] userCert, in byte[] certChain); diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java index 2daf733d057f..46a7fa8d5e28 100644 --- a/keystore/java/android/security/KeyChain.java +++ b/keystore/java/android/security/KeyChain.java @@ -245,6 +245,82 @@ public final class KeyChain { */ public static final String EXTRA_KEY_ACCESSIBLE = "android.security.extra.KEY_ACCESSIBLE"; + /** + * Indicates that a call to {@link #generateKeyPair} was successful. + * @hide + */ + public static final int KEY_GEN_SUCCESS = 0; + + /** + * An alias was missing from the key specifications when calling {@link #generateKeyPair}. + * @hide + */ + public static final int KEY_GEN_MISSING_ALIAS = 1; + + /** + * A key attestation challenge was provided to {@link #generateKeyPair}, but it shouldn't + * have been provided. + * @hide + */ + public static final int KEY_GEN_SUPERFLUOUS_ATTESTATION_CHALLENGE = 2; + + /** + * Algorithm not supported by {@link #generateKeyPair} + * @hide + */ + public static final int KEY_GEN_NO_SUCH_ALGORITHM = 3; + + /** + * Invalid algorithm parameters when calling {@link #generateKeyPair} + * @hide + */ + public static final int KEY_GEN_INVALID_ALGORITHM_PARAMETERS = 4; + + /** + * Keystore is not available when calling {@link #generateKeyPair} + * @hide + */ + public static final int KEY_GEN_NO_KEYSTORE_PROVIDER = 5; + + /** + * General failure while calling {@link #generateKeyPair} + * @hide + */ + public static final int KEY_GEN_FAILURE = 6; + + /** + * Successful call to {@link #attestKey} + * @hide + */ + public static final int KEY_ATTESTATION_SUCCESS = 0; + + /** + * Attestation challenge missing when calling {@link #attestKey} + * @hide + */ + public static final int KEY_ATTESTATION_MISSING_CHALLENGE = 1; + + /** + * The caller requested Device ID attestation when calling {@link #attestKey}, but has no + * permissions to get device identifiers. + * @hide + */ + public static final int KEY_ATTESTATION_CANNOT_COLLECT_DATA = 2; + + /** + * The underlying hardware does not support Device ID attestation or cannot attest to the + * identifiers that are stored on the device. This indicates permanent inability + * to get attestation records on the device. + * @hide + */ + public static final int KEY_ATTESTATION_CANNOT_ATTEST_IDS = 3; + + /** + * General failure when calling {@link #attestKey} + * @hide + */ + public static final int KEY_ATTESTATION_FAILURE = 4; + /** * Returns an {@code Intent} that can be used for credential * installation. The intent may be used without any extras, in diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java index 1924bbe764c7..1e2ebf894f99 100644 --- a/keystore/java/android/security/KeyStore.java +++ b/keystore/java/android/security/KeyStore.java @@ -66,6 +66,7 @@ public class KeyStore { public static final int VALUE_CORRUPTED = 8; public static final int UNDEFINED_ACTION = 9; public static final int WRONG_PASSWORD = 10; + public static final int CANNOT_ATTEST_IDS = -66; public static final int HARDWARE_TYPE_UNAVAILABLE = -68; /** diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 5cfba22d2c66..02cd3b6572ef 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -5533,10 +5533,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { .setAttestationChallenge(null) .build(); - final boolean generationResult = keyChain.generateKeyPair(algorithm, + final int generationResult = keyChain.generateKeyPair(algorithm, new ParcelableKeyGenParameterSpec(noAttestationSpec)); - if (!generationResult) { - Log.e(LOG_TAG, "KeyChain failed to generate a keypair."); + if (generationResult != KeyChain.KEY_GEN_SUCCESS) { + Log.e(LOG_TAG, String.format( + "KeyChain failed to generate a keypair, error %d.", generationResult)); return false; } @@ -5549,12 +5550,17 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { final byte[] attestationChallenge = keySpec.getAttestationChallenge(); if (attestationChallenge != null) { - final boolean attestationResult = keyChain.attestKey( + final int attestationResult = keyChain.attestKey( alias, attestationChallenge, attestationUtilsFlags, attestationChain); - if (!attestationResult) { + if (attestationResult != KeyChain.KEY_ATTESTATION_SUCCESS) { Log.e(LOG_TAG, String.format( - "Attestation for %s failed, deleting key.", alias)); + "Attestation for %s failed (rc=%d), deleting key.", + alias, attestationResult)); keyChain.removeKeyPair(alias); + if (attestationResult == KeyChain.KEY_ATTESTATION_CANNOT_ATTEST_IDS) { + throw new UnsupportedOperationException( + "Device does not support Device ID attestation."); + } return false; } } -- GitLab From 5b53875fdc24c041d198838bce294aa6e631b2e2 Mon Sep 17 00:00:00 2001 From: Artem Iglikov Date: Tue, 27 Mar 2018 15:12:18 +0100 Subject: [PATCH 048/179] Clear app data before full restore for specified packages In some cases (deferred restore) the app data needs to be cleared even if the app has implemented backup agent. As a quick fix introduce PACKAGES_TO_CLEAR_DATA_BEFORE_FULL_RESTORE secure setting, which transport can fill prior to restore. Bug: 69069240 Test: adb shell settings put secure packages_to_clear_data_before_full_restore com.google.android.apps.nexuslauncher && adb shell bmgr restore com.google.android.apps.nexuslauncher Change-Id: I2a4651365d9cf4747f32d2ba69312f54cd03d118 --- core/java/android/provider/Settings.java | 8 ++++ .../android/providers/settings/secure.proto | 1 + .../android/provider/SettingsBackupTest.java | 3 +- .../settings/SettingsProtoDumpUtil.java | 3 ++ .../backup/restore/FullRestoreEngine.java | 38 ++++++++++++++++--- 5 files changed, 47 insertions(+), 6 deletions(-) diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 70f343ee5f57..b7f6cdef20ed 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -7808,6 +7808,14 @@ public final class Settings { public static final String SUPPRESS_AUTO_BATTERY_SAVER_SUGGESTION = "suppress_auto_battery_saver_suggestion"; + /** + * List of packages, which data need to be unconditionally cleared before full restore. + * Type: string + * @hide + */ + public static final String PACKAGES_TO_CLEAR_DATA_BEFORE_FULL_RESTORE = + "packages_to_clear_data_before_full_restore"; + /** * This are the settings to be backed up. * diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto index cfb89808b1b2..593747df4ee3 100644 --- a/core/proto/android/providers/settings/secure.proto +++ b/core/proto/android/providers/settings/secure.proto @@ -145,6 +145,7 @@ message SecureSettingsProto { optional SettingProto transport = 4 [ (android.privacy).dest = DEST_AUTOMATIC ]; optional SettingProto manager_constants = 5; optional SettingProto local_transport_parameters = 6; + optional SettingProto packages_to_clear_data_before_full_restore = 7; } optional Backup backup = 10; diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java index 2a3fcadb5144..4b9465d24fc9 100644 --- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java +++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java @@ -587,7 +587,8 @@ public class SettingsBackupTest { Settings.Secure.BLUETOOTH_ON_WHILE_DRIVING, Settings.Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, Settings.Secure.LOW_POWER_WARNING_ACKNOWLEDGED, - Settings.Secure.SUPPRESS_AUTO_BATTERY_SAVER_SUGGESTION); + Settings.Secure.SUPPRESS_AUTO_BATTERY_SAVER_SUGGESTION, + Settings.Secure.PACKAGES_TO_CLEAR_DATA_BEFORE_FULL_RESTORE); @Test public void systemSettingsBackedUpOrBlacklisted() { diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java index a444ac8090d6..f43e719d47a3 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java @@ -1724,6 +1724,9 @@ class SettingsProtoDumpUtil { dumpSetting(s, p, Settings.Secure.BACKUP_LOCAL_TRANSPORT_PARAMETERS, SecureSettingsProto.Backup.LOCAL_TRANSPORT_PARAMETERS); + dumpSetting(s, p, + Settings.Secure.PACKAGES_TO_CLEAR_DATA_BEFORE_FULL_RESTORE, + SecureSettingsProto.Backup.PACKAGES_TO_CLEAR_DATA_BEFORE_FULL_RESTORE); p.end(backupToken); // Settings.Secure.BLUETOOTH_ON intentionally excluded since it's deprecated. diff --git a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java index c1a1c1dc10e7..9607d2496ef0 100644 --- a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java +++ b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java @@ -40,6 +40,8 @@ import android.content.pm.PackageManagerInternal; import android.content.pm.Signature; import android.os.ParcelFileDescriptor; import android.os.RemoteException; +import android.provider.Settings; +import android.text.TextUtils; import android.util.Slog; import com.android.server.LocalServices; @@ -56,8 +58,11 @@ import com.android.server.backup.utils.TarBackupReader; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; +import java.util.List; /** * Full restore engine, used by both adb restore and transport-based full restore. @@ -320,12 +325,17 @@ public class FullRestoreEngine extends RestoreEngine { pkg, 0); // If we haven't sent any data to this app yet, we probably - // need to clear it first. Check that. + // need to clear it first. Check that. if (!mClearedPackages.contains(pkg)) { - // apps with their own backup agents are - // responsible for coherently managing a full - // restore. - if (mTargetApp.backupAgentName == null) { + // Apps with their own backup agents are responsible for coherently + // managing a full restore. + // In some rare cases they can't, especially in case of deferred + // restore. In this case check whether this app should be forced to + // clear up. + // TODO: Fix this properly with manifest parameter. + boolean forceClear = shouldForceClearAppDataOnFullRestore( + mTargetApp.packageName); + if (mTargetApp.backupAgentName == null || forceClear) { if (DEBUG) { Slog.d(TAG, "Clearing app data preparatory to full restore"); @@ -623,6 +633,24 @@ public class FullRestoreEngine extends RestoreEngine { return true; } + /** + * Returns whether the package is in the list of the packages for which clear app data should + * be called despite the fact that they have backup agent. + * + *

    The list is read from {@link Settings.Secure.PACKAGES_TO_CLEAR_DATA_BEFORE_FULL_RESTORE}. + */ + private boolean shouldForceClearAppDataOnFullRestore(String packageName) { + String packageListString = Settings.Secure.getString( + mBackupManagerService.getContext().getContentResolver(), + Settings.Secure.PACKAGES_TO_CLEAR_DATA_BEFORE_FULL_RESTORE); + if (TextUtils.isEmpty(packageListString)) { + return false; + } + + List packages = Arrays.asList(packageListString.split(";")); + return packages.contains(packageName); + } + void sendOnRestorePackage(String name) { if (mObserver != null) { try { -- GitLab From 981ae652c98000bb96450b6950c8736078707b4b Mon Sep 17 00:00:00 2001 From: Nicolas Geoffray Date: Wed, 28 Mar 2018 23:15:54 +0100 Subject: [PATCH 049/179] Move graphics APIs to the light grey. The APIs have just started being removed in public APIs, and some non-vendor apps are using them. bug: 77224796 Test: m Change-Id: I5c3afd18244a888ec77f14eaa6d839faf4f6d2be --- config/hiddenapi-light-greylist.txt | 5 +++++ config/hiddenapi-vendor-list.txt | 5 ----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt index 3af610592732..0ded5159aa35 100644 --- a/config/hiddenapi-light-greylist.txt +++ b/config/hiddenapi-light-greylist.txt @@ -609,6 +609,11 @@ Landroid/graphics/Bitmap;->reinit(IIZ)V Landroid/graphics/Camera;->native_instance:J Landroid/graphics/Canvas;->(J)V Landroid/graphics/Canvas;->release()V +Landroid/graphics/Canvas;->save(I)I +Landroid/graphics/Canvas;->saveLayer(Landroid/graphics/RectF;Landroid/graphics/Paint;I)I +Landroid/graphics/Canvas;->saveLayer(FFFFLandroid/graphics/Paint;I)I +Landroid/graphics/Canvas;->saveLayerAlpha(Landroid/graphics/RectF;II)I +Landroid/graphics/Canvas;->saveLayerAlpha(FFFFII)I Landroid/graphics/ColorMatrixColorFilter;->setColorMatrix(Landroid/graphics/ColorMatrix;)V Landroid/graphics/drawable/AnimatedImageDrawable;->onAnimationEnd()V Landroid/graphics/drawable/AnimatedStateListDrawable$AnimatedStateListState;->mStateIds:Landroid/util/SparseIntArray; diff --git a/config/hiddenapi-vendor-list.txt b/config/hiddenapi-vendor-list.txt index 77bb0bb3d7ab..6b528508a8bb 100644 --- a/config/hiddenapi-vendor-list.txt +++ b/config/hiddenapi-vendor-list.txt @@ -108,11 +108,6 @@ Landroid/graphics/Bitmap;->createGraphicBufferHandle()Landroid/graphics/GraphicB Landroid/graphics/Bitmap;->createHardwareBitmap(Landroid/graphics/GraphicBuffer;)Landroid/graphics/Bitmap; Landroid/graphics/Canvas;->clipRegion(Landroid/graphics/Region;Landroid/graphics/Region$Op;)Z Landroid/graphics/Canvas;->clipRegion(Landroid/graphics/Region;)Z -Landroid/graphics/Canvas;->save(I)I -Landroid/graphics/Canvas;->saveLayerAlpha(FFFFII)I -Landroid/graphics/Canvas;->saveLayerAlpha(Landroid/graphics/RectF;II)I -Landroid/graphics/Canvas;->saveLayer(FFFFLandroid/graphics/Paint;I)I -Landroid/graphics/Canvas;->saveLayer(Landroid/graphics/RectF;Landroid/graphics/Paint;I)I Landroid/graphics/drawable/Drawable;->isProjected()Z Landroid/graphics/drawable/Drawable;->updateTintFilter(Landroid/graphics/PorterDuffColorFilter;Landroid/content/res/ColorStateList;Landroid/graphics/PorterDuff$Mode;)Landroid/graphics/PorterDuffColorFilter; Landroid/hardware/camera2/CaptureRequest$Key;->(Ljava/lang/String;Ljava/lang/Class;)V -- GitLab From 842e788ffc7f2964d6d5877511e3762d4908bb95 Mon Sep 17 00:00:00 2001 From: Adrian Roos Date: Mon, 26 Mar 2018 17:34:06 +0200 Subject: [PATCH 050/179] RemoteAnimations: Add failsafe Adds failsafe mechanisms to RemoteAnimation and RecentsAnimation: - cancel animations on binder death - schedule a short timeout for RecentsAnimation after HOME and POWER events Also enables RemoteAnimationControllerTest for presubmit, since it's turned out to be reliable. Change-Id: Id0bfdbee7d36f662eb386727195da8de2ed1684a Fixes: 73496879 Test: kill / suspend launcher during animations; verify animations get aborted as expected. Test: atest RemoteAnimationControllerTest --- .../android/server/am/RecentsAnimation.java | 17 ---------- .../server/policy/PhoneWindowManager.java | 6 ++++ .../server/policy/WindowManagerPolicy.java | 6 ++++ .../server/wm/RecentsAnimationController.java | 24 ++++++++++++- .../server/wm/RemoteAnimationController.java | 34 ++++++++++++++----- .../server/wm/WindowManagerService.java | 17 ++++++++-- .../wm/RemoteAnimationControllerTest.java | 22 +++++++++--- 7 files changed, 91 insertions(+), 35 deletions(-) diff --git a/services/core/java/com/android/server/am/RecentsAnimation.java b/services/core/java/com/android/server/am/RecentsAnimation.java index 73a7c3eb32a5..9df321c64c9a 100644 --- a/services/core/java/com/android/server/am/RecentsAnimation.java +++ b/services/core/java/com/android/server/am/RecentsAnimation.java @@ -42,18 +42,13 @@ import com.android.server.wm.WindowManagerService; class RecentsAnimation implements RecentsAnimationCallbacks { private static final String TAG = RecentsAnimation.class.getSimpleName(); - private static final int RECENTS_ANIMATION_TIMEOUT = 10 * 1000; - private final ActivityManagerService mService; private final ActivityStackSupervisor mStackSupervisor; private final ActivityStartController mActivityStartController; private final WindowManagerService mWindowManager; private final UserController mUserController; - private final Handler mHandler; private final int mCallingPid; - private final Runnable mCancelAnimationRunnable; - // The stack to restore the home stack behind when the animation is finished private ActivityStack mRestoreHomeBehindStack; @@ -63,16 +58,9 @@ class RecentsAnimation implements RecentsAnimationCallbacks { mService = am; mStackSupervisor = stackSupervisor; mActivityStartController = activityStartController; - mHandler = new Handler(mStackSupervisor.mLooper); mWindowManager = wm; mUserController = userController; mCallingPid = callingPid; - - mCancelAnimationRunnable = () -> { - // The caller has not finished the animation in a predefined amount of time, so - // force-cancel the animation - mWindowManager.cancelRecentsAnimation(); - }; } void startRecentsActivity(Intent intent, IRecentsAnimationRunner recentsAnimationRunner, @@ -133,10 +121,6 @@ class RecentsAnimation implements RecentsAnimationCallbacks { // duration of the gesture that is driven by the recents component homeActivity.mLaunchTaskBehind = true; - // Post a timeout for the animation. This needs to happen before initializing the - // recents animation on the WM side since we may decide to cancel the animation there - mHandler.postDelayed(mCancelAnimationRunnable, RECENTS_ANIMATION_TIMEOUT); - // Fetch all the surface controls and pass them to the client to get the animation // started mWindowManager.cancelRecentsAnimation(); @@ -157,7 +141,6 @@ class RecentsAnimation implements RecentsAnimationCallbacks { @Override public void onAnimationFinished(boolean moveHomeToTop) { - mHandler.removeCallbacks(mCancelAnimationRunnable); synchronized (mService) { if (mWindowManager.getRecentsAnimationController() == null) return; diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 2e6e348c51a4..e8d6540baaee 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -1330,6 +1330,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { mHandler.post(mHiddenNavPanic); } + // Abort possibly stuck animations. + mHandler.post(mWindowManagerFuncs::triggerAnimationFailsafe); + // Latch power key state to detect screenshot chord. if (interactive && !mScreenshotChordPowerKeyTriggered && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) { @@ -4362,6 +4365,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { * given the situation with the keyguard. */ void launchHomeFromHotKey(final boolean awakenFromDreams, final boolean respectKeyguard) { + // Abort possibly stuck animations. + mHandler.post(mWindowManagerFuncs::triggerAnimationFailsafe); + if (respectKeyguard) { if (isKeyguardShowingAndNotOccluded()) { // don't launch home if keyguard showing diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java index ec0521dda40d..49d3588eb24c 100644 --- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java +++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java @@ -649,6 +649,12 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { return Integer.toString(lens); } } + + /** + * Hint to window manager that the user has started a navigation action that should + * abort animations that have no timeout, in case they got stuck. + */ + void triggerAnimationFailsafe(); } /** Window has been added to the screen. */ diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java index 10188487fd9b..7274aee3c987 100644 --- a/services/core/java/com/android/server/wm/RecentsAnimationController.java +++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java @@ -34,6 +34,7 @@ import android.app.WindowConfiguration; import android.graphics.Point; import android.graphics.Rect; import android.os.Binder; +import android.os.IBinder.DeathRecipient; import android.os.RemoteException; import android.os.SystemClock; import android.util.ArraySet; @@ -61,15 +62,17 @@ import java.util.ArrayList; * window manager when the animation is completed. In addition, window manager may also notify the * app if it requires the animation to be canceled at any time (ie. due to timeout, etc.) */ -public class RecentsAnimationController { +public class RecentsAnimationController implements DeathRecipient { private static final String TAG = TAG_WITH_CLASS_NAME ? "RecentsAnimationController" : TAG_WM; private static final boolean DEBUG = false; + private static final long FAILSAFE_DELAY = 1000; private final WindowManagerService mService; private final IRecentsAnimationRunner mRunner; private final RecentsAnimationCallbacks mCallbacks; private final ArrayList mPendingAnimations = new ArrayList<>(); private final int mDisplayId; + private final Runnable mFailsafeRunnable = this::cancelAnimation; // The recents component app token that is shown behind the visibile tasks private AppWindowToken mHomeAppToken; @@ -223,6 +226,13 @@ public class RecentsAnimationController { return; } + try { + mRunner.asBinder().linkToDeath(this, 0); + } catch (RemoteException e) { + cancelAnimation(); + return; + } + // Adjust the wallpaper visibility for the showing home activity final AppWindowToken recentsComponentAppToken = dc.getHomeStack().getTopChild().getTopFullscreenAppToken(); @@ -296,6 +306,7 @@ public class RecentsAnimationController { // We've already canceled the animation return; } + mService.mH.removeCallbacks(mFailsafeRunnable); mCanceled = true; try { mRunner.onAnimationCanceled(); @@ -321,10 +332,21 @@ public class RecentsAnimationController { } mPendingAnimations.clear(); + mRunner.asBinder().unlinkToDeath(this, 0); + mService.mInputMonitor.updateInputWindowsLw(true /*force*/); mService.destroyInputConsumer(INPUT_CONSUMER_RECENTS_ANIMATION); } + void scheduleFailsafe() { + mService.mH.postDelayed(mFailsafeRunnable, FAILSAFE_DELAY); + } + + @Override + public void binderDied() { + cancelAnimation(); + } + void checkAnimationReady(WallpaperController wallpaperController) { if (mPendingStart) { final boolean wallpaperReady = !isHomeAppOverWallpaper() diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java index 379a1a1528b4..3be7b23590e5 100644 --- a/services/core/java/com/android/server/wm/RemoteAnimationController.java +++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java @@ -26,6 +26,7 @@ import android.graphics.Point; import android.graphics.Rect; import android.os.Binder; import android.os.Handler; +import android.os.IBinder.DeathRecipient; import android.os.RemoteException; import android.os.SystemClock; import android.util.Slog; @@ -47,7 +48,7 @@ import java.util.ArrayList; /** * Helper class to run app animations in a remote process. */ -class RemoteAnimationController { +class RemoteAnimationController implements DeathRecipient { private static final String TAG = TAG_WITH_CLASS_NAME ? "RemoteAnimationController" : TAG_WM; private static final long TIMEOUT_MS = 2000; @@ -56,12 +57,10 @@ class RemoteAnimationController { private final ArrayList mPendingAnimations = new ArrayList<>(); private final Rect mTmpRect = new Rect(); private final Handler mHandler; - private FinishedCallback mFinishedCallback; + private final Runnable mTimeoutRunnable = this::cancelAnimation; - private final Runnable mTimeoutRunnable = () -> { - onAnimationFinished(); - invokeAnimationCancelled(); - }; + private FinishedCallback mFinishedCallback; + private boolean mCanceled; RemoteAnimationController(WindowManagerService service, RemoteAnimationAdapter remoteAnimationAdapter, Handler handler) { @@ -90,7 +89,7 @@ class RemoteAnimationController { * Called when the transition is ready to be started, and all leashes have been set up. */ void goodToGo() { - if (mPendingAnimations.isEmpty()) { + if (mPendingAnimations.isEmpty() || mCanceled) { onAnimationFinished(); return; } @@ -107,8 +106,8 @@ class RemoteAnimationController { } mService.mAnimator.addAfterPrepareSurfacesRunnable(() -> { try { - mRemoteAnimationAdapter.getRunner().onAnimationStart(animations, - mFinishedCallback); + mRemoteAnimationAdapter.getRunner().asBinder().linkToDeath(this, 0); + mRemoteAnimationAdapter.getRunner().onAnimationStart(animations, mFinishedCallback); } catch (RemoteException e) { Slog.e(TAG, "Failed to start remote animation", e); onAnimationFinished(); @@ -120,6 +119,17 @@ class RemoteAnimationController { } } + private void cancelAnimation() { + synchronized (mService.getWindowManagerLock()) { + if (mCanceled) { + return; + } + mCanceled = true; + } + onAnimationFinished(); + invokeAnimationCancelled(); + } + private void writeStartDebugStatement() { Slog.i(TAG, "Starting remote animation"); final StringWriter sw = new StringWriter(); @@ -154,6 +164,7 @@ class RemoteAnimationController { private void onAnimationFinished() { mHandler.removeCallbacks(mTimeoutRunnable); + mRemoteAnimationAdapter.getRunner().asBinder().unlinkToDeath(this, 0); synchronized (mService.mWindowMap) { releaseFinishedCallback(); mService.openSurfaceTransaction(); @@ -193,6 +204,11 @@ class RemoteAnimationController { mService.sendSetRunningRemoteAnimation(pid, running); } + @Override + public void binderDied() { + cancelAnimation(); + } + private static final class FinishedCallback extends IRemoteAnimationFinishedCallback.Stub { RemoteAnimationController mOuter; diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 0b5c0064d40f..22375375bc00 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -25,12 +25,10 @@ import static android.app.ActivityManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT; import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW; import static android.app.StatusBarManager.DISABLE_MASK; import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED; -import static android.content.Intent.EXTRA_USER_HANDLE; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.os.Process.SYSTEM_UID; import static android.os.Process.myPid; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; -import static android.os.UserHandle.USER_NULL; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; import static android.view.WindowManager.DOCKED_INVALID; @@ -181,7 +179,6 @@ import android.util.Log; import android.util.MergedConfiguration; import android.util.Pair; import android.util.Slog; -import android.util.SparseArray; import android.util.SparseBooleanArray; import android.util.SparseIntArray; import android.util.TimeUtils; @@ -2793,6 +2790,11 @@ public class WindowManagerService extends IWindowManager.Stub mTaskSnapshotController.screenTurningOff(listener); } + @Override + public void triggerAnimationFailsafe() { + mH.sendEmptyMessage(H.ANIMATION_FAILSAFE); + } + /** * Starts deferring layout passes. Useful when doing multiple changes but to optimize * performance, only one layout pass should be done. This can be called multiple times, and @@ -4566,6 +4568,7 @@ public class WindowManagerService extends IWindowManager.Stub public static final int NOTIFY_KEYGUARD_TRUSTED_CHANGED = 57; public static final int SET_HAS_OVERLAY_UI = 58; public static final int SET_RUNNING_REMOTE_ANIMATION = 59; + public static final int ANIMATION_FAILSAFE = 60; /** * Used to denote that an integer field in a message will not be used. @@ -4984,6 +4987,14 @@ public class WindowManagerService extends IWindowManager.Stub mAmInternal.setRunningRemoteAnimation(msg.arg1, msg.arg2 == 1); } break; + case ANIMATION_FAILSAFE: { + synchronized (mWindowMap) { + if (mRecentsAnimationController != null) { + mRecentsAnimationController.scheduleFailsafe(); + } + } + } + break; } if (DEBUG_WINDOW_TRACE) { Slog.v(TAG_WM, "handleMessage: exit"); diff --git a/services/tests/servicestests/src/com/android/server/wm/RemoteAnimationControllerTest.java b/services/tests/servicestests/src/com/android/server/wm/RemoteAnimationControllerTest.java index 553d65824c54..95361f03fe4b 100644 --- a/services/tests/servicestests/src/com/android/server/wm/RemoteAnimationControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/wm/RemoteAnimationControllerTest.java @@ -17,14 +17,20 @@ package com.android.server.wm; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; + import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; import android.graphics.Point; import android.graphics.Rect; +import android.os.Binder; +import android.os.IInterface; +import android.platform.test.annotations.Presubmit; import android.support.test.filters.FlakyTest; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; @@ -50,7 +56,7 @@ import org.mockito.MockitoAnnotations; * atest FrameworksServicesTests:com.android.server.wm.RemoteAnimationControllerTest */ @SmallTest -@FlakyTest(detail = "Promote to presubmit if non-flakyness is established") +@Presubmit @RunWith(AndroidJUnit4.class) public class RemoteAnimationControllerTest extends WindowTestsBase { @@ -67,6 +73,7 @@ public class RemoteAnimationControllerTest extends WindowTestsBase { public void setUp() throws Exception { super.setUp(); MockitoAnnotations.initMocks(this); + when(mMockRunner.asBinder()).thenReturn(new Binder()); mAdapter = new RemoteAnimationAdapter(mMockRunner, 100, 50); mAdapter.setCallingPid(123); sWm.mH.runWithScissors(() -> { @@ -166,7 +173,7 @@ public class RemoteAnimationControllerTest extends WindowTestsBase { @Test public void testZeroAnimations() throws Exception { mController.goodToGo(); - verifyZeroInteractions(mMockRunner); + verifyNoMoreInteractionsExceptAsBinder(mMockRunner); } @Test @@ -175,7 +182,7 @@ public class RemoteAnimationControllerTest extends WindowTestsBase { mController.createAnimationAdapter(win.mAppToken, new Point(50, 100), new Rect(50, 100, 150, 150)); mController.goodToGo(); - verifyZeroInteractions(mMockRunner); + verifyNoMoreInteractionsExceptAsBinder(mMockRunner); } @Test @@ -206,7 +213,12 @@ public class RemoteAnimationControllerTest extends WindowTestsBase { adapter.startAnimation(mMockLeash, mMockTransaction, mFinishedCallback); win.mAppToken.removeImmediately(); mController.goodToGo(); - verifyZeroInteractions(mMockRunner); + verifyNoMoreInteractionsExceptAsBinder(mMockRunner); verify(mFinishedCallback).onAnimationFinished(eq(adapter)); } + + private static void verifyNoMoreInteractionsExceptAsBinder(IInterface binder) { + verify(binder, atLeast(0)).asBinder(); + verifyNoMoreInteractions(binder); + } } -- GitLab From 5bbb6dac0a51f1b6df419d725defacf0477b554b Mon Sep 17 00:00:00 2001 From: Julia Reynolds Date: Wed, 28 Mar 2018 10:48:37 -0400 Subject: [PATCH 051/179] Exempt some notis from DND visual suppression Specifically, foreground service notifications and media notifications. Fixes: 75261156 Test: atest SystemUITests Change-Id: I2f1fddbf748a274177d2c8dddb1b72fce82c8c4c --- .../systemui/statusbar/NotificationData.java | 69 ++++++++----------- .../statusbar/NotificationEntryManager.java | 10 +-- .../phone/NotificationIconAreaController.java | 2 +- .../statusbar/NotificationDataTest.java | 37 ++++++++++ 4 files changed, 73 insertions(+), 45 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java index 402d9fddc825..4b6ab64ab624 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java @@ -18,25 +18,21 @@ package com.android.systemui.statusbar; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT; -import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR; +import android.Manifest; import android.app.AppGlobals; -import android.app.AppOpsManager; import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; +import android.content.Context; import android.content.pm.IPackageManager; import android.content.pm.PackageManager; -import android.content.Context; import android.graphics.drawable.Icon; -import android.os.AsyncTask; -import android.os.Bundle; import android.os.RemoteException; import android.os.SystemClock; -import android.service.notification.NotificationListenerService; import android.service.notification.NotificationListenerService.Ranking; import android.service.notification.NotificationListenerService.RankingMap; import android.service.notification.SnoozeCriterion; @@ -46,10 +42,8 @@ import android.util.ArraySet; import android.view.View; import android.widget.ImageView; import android.widget.RemoteViews; -import android.Manifest; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.messages.nano.SystemMessageProto; import com.android.internal.statusbar.StatusBarIcon; import com.android.internal.util.NotificationColorUtil; import com.android.systemui.Dependency; @@ -454,47 +448,44 @@ public class NotificationData { return Ranking.VISIBILITY_NO_OVERRIDE; } - public boolean shouldSuppressFullScreenIntent(String key) { - if (mRankingMap != null) { - getRanking(key, mTmpRanking); - return (mTmpRanking.getSuppressedVisualEffects() - & SUPPRESSED_EFFECT_FULL_SCREEN_INTENT) != 0; - } - return false; + public boolean shouldSuppressFullScreenIntent(StatusBarNotification sbn) { + return shouldSuppressVisualEffect(sbn, SUPPRESSED_EFFECT_FULL_SCREEN_INTENT); } - public boolean shouldSuppressPeek(String key) { - if (mRankingMap != null) { - getRanking(key, mTmpRanking); - return (mTmpRanking.getSuppressedVisualEffects() - & SUPPRESSED_EFFECT_PEEK) != 0; - } - return false; + public boolean shouldSuppressPeek(StatusBarNotification sbn) { + return shouldSuppressVisualEffect(sbn, SUPPRESSED_EFFECT_PEEK); } - public boolean shouldSuppressStatusBar(String key) { - if (mRankingMap != null) { - getRanking(key, mTmpRanking); - return (mTmpRanking.getSuppressedVisualEffects() - & SUPPRESSED_EFFECT_STATUS_BAR) != 0; - } - return false; + public boolean shouldSuppressStatusBar(StatusBarNotification sbn) { + return shouldSuppressVisualEffect(sbn, SUPPRESSED_EFFECT_STATUS_BAR); + } + + public boolean shouldSuppressAmbient(StatusBarNotification sbn) { + return shouldSuppressVisualEffect(sbn, SUPPRESSED_EFFECT_AMBIENT); + } + + public boolean shouldSuppressNotificationList(StatusBarNotification sbn) { + return shouldSuppressVisualEffect(sbn, SUPPRESSED_EFFECT_NOTIFICATION_LIST); } - public boolean shouldSuppressAmbient(String key) { + private boolean shouldSuppressVisualEffect(StatusBarNotification sbn, int effect) { + if (isExemptFromDndVisualSuppression(sbn)) { + return false; + } + String key = sbn.getKey(); if (mRankingMap != null) { getRanking(key, mTmpRanking); - return (mTmpRanking.getSuppressedVisualEffects() - & SUPPRESSED_EFFECT_AMBIENT) != 0; + return (mTmpRanking.getSuppressedVisualEffects() & effect) != 0; } return false; } - public boolean shouldSuppressNotificationList(String key) { - if (mRankingMap != null) { - getRanking(key, mTmpRanking); - return (mTmpRanking.getSuppressedVisualEffects() - & SUPPRESSED_EFFECT_NOTIFICATION_LIST) != 0; + protected boolean isExemptFromDndVisualSuppression(StatusBarNotification sbn) { + if ((sbn.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) { + return true; + } + if (sbn.getNotification().isMediaNotification()) { + return true; } return false; } @@ -620,11 +611,11 @@ public class NotificationData { return true; } - if (mEnvironment.isDozing() && shouldSuppressAmbient(sbn.getKey())) { + if (mEnvironment.isDozing() && shouldSuppressAmbient(sbn)) { return true; } - if (!mEnvironment.isDozing() && shouldSuppressNotificationList(sbn.getKey())) { + if (!mEnvironment.isDozing() && shouldSuppressNotificationList(sbn)) { return true; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java index 7a7cc99eb44d..45df4505fac2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java @@ -299,12 +299,12 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. updateNotifications(); } - private boolean shouldSuppressFullScreenIntent(String key) { + private boolean shouldSuppressFullScreenIntent(StatusBarNotification sbn) { if (mPresenter.isDeviceInVrMode()) { return true; } - return mNotificationData.shouldSuppressFullScreenIntent(key); + return mNotificationData.shouldSuppressFullScreenIntent(sbn); } private void inflateViews(NotificationData.Entry entry, ViewGroup parent) { @@ -690,7 +690,7 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. NotificationData.Entry shadeEntry = createNotificationViews(notification); boolean isHeadsUped = shouldPeek(shadeEntry); if (!isHeadsUped && notification.getNotification().fullScreenIntent != null) { - if (shouldSuppressFullScreenIntent(key)) { + if (shouldSuppressFullScreenIntent(notification)) { if (DEBUG) { Log.d(TAG, "No Fullscreen intent: suppressed by DND: " + key); } @@ -846,13 +846,13 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. return false; } - if (!mPresenter.isDozing() && mNotificationData.shouldSuppressPeek(sbn.getKey())) { + if (!mPresenter.isDozing() && mNotificationData.shouldSuppressPeek(sbn)) { if (DEBUG) Log.d(TAG, "No peeking: suppressed by DND: " + sbn.getKey()); return false; } // Peeking triggers an ambient display pulse, so disable peek is ambient is active - if (mPresenter.isDozing() && mNotificationData.shouldSuppressAmbient(sbn.getKey())) { + if (mPresenter.isDozing() && mNotificationData.shouldSuppressAmbient(sbn)) { if (DEBUG) Log.d(TAG, "No peeking: suppressed by DND: " + sbn.getKey()); return false; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java index 9063dea584b1..b6a11f71f251 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java @@ -150,7 +150,7 @@ public class NotificationIconAreaController implements DarkReceiver { // showAmbient == show in shade but not shelf if (!showAmbient && mEntryManager.getNotificationData().shouldSuppressStatusBar( - entry.key)) { + entry.notification)) { return false; } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationDataTest.java index c43702119e91..5e27fde04441 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationDataTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationDataTest.java @@ -35,6 +35,7 @@ import android.app.Notification; import android.app.NotificationChannel; import android.content.pm.IPackageManager; import android.content.pm.PackageManager; +import android.media.session.MediaSession; import android.os.Bundle; import android.service.notification.NotificationListenerService; import android.service.notification.StatusBarNotification; @@ -61,6 +62,7 @@ public class NotificationDataTest extends SysuiTestCase { private static final int UID_NORMAL = 123; private static final int UID_ALLOW_DURING_SETUP = 456; private static final String TEST_HIDDEN_NOTIFICATION_KEY = "testHiddenNotificationKey"; + private static final String TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY = "exempt"; private final StatusBarNotification mMockStatusBarNotification = mock(StatusBarNotification.class); @@ -275,6 +277,7 @@ public class NotificationDataTest extends SysuiTestCase { @Test public void testShouldFilterHiddenNotifications() { + initStatusBarNotification(false); // setup when(mFsc.isSystemAlertWarningNeeded(anyInt(), anyString())).thenReturn(false); when(mFsc.isSystemAlertNotification(any())).thenReturn(false); @@ -289,6 +292,33 @@ public class NotificationDataTest extends SysuiTestCase { assertFalse(mNotificationData.shouldFilterOut(mMockStatusBarNotification)); } + @Test + public void testIsExemptFromDndVisualSuppression_foreground() { + initStatusBarNotification(false); + when(mMockStatusBarNotification.getKey()).thenReturn( + TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY); + Notification n = mMockStatusBarNotification.getNotification(); + n.flags = Notification.FLAG_FOREGROUND_SERVICE; + + assertTrue(mNotificationData.isExemptFromDndVisualSuppression(mMockStatusBarNotification)); + assertFalse(mNotificationData.shouldSuppressAmbient(mMockStatusBarNotification)); + } + + @Test + public void testIsExemptFromDndVisualSuppression_media() { + initStatusBarNotification(false); + when(mMockStatusBarNotification.getKey()).thenReturn( + TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY); + Notification n = mMockStatusBarNotification.getNotification(); + Notification.Builder nb = Notification.Builder.recoverBuilder(mContext, n); + nb.setStyle(new Notification.MediaStyle().setMediaSession(mock(MediaSession.Token.class))); + n = nb.build(); + when(mMockStatusBarNotification.getNotification()).thenReturn(n); + + assertTrue(mNotificationData.isExemptFromDndVisualSuppression(mMockStatusBarNotification)); + assertFalse(mNotificationData.shouldSuppressAmbient(mMockStatusBarNotification)); + } + private void initStatusBarNotification(boolean allowDuringSetup) { Bundle bundle = new Bundle(); bundle.putBoolean(Notification.EXTRA_ALLOW_DURING_SETUP, allowDuringSetup); @@ -318,6 +348,13 @@ public class NotificationDataTest extends SysuiTestCase { outRanking.getImportance(), outRanking.getImportanceExplanation(), outRanking.getOverrideGroupKey(), outRanking.getChannel(), null, null, outRanking.canShowBadge(), outRanking.getUserSentiment(), true); + } else if (key.equals(TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY)) { + outRanking.populate(key, outRanking.getRank(), + outRanking.matchesInterruptionFilter(), + outRanking.getVisibilityOverride(), 255, + outRanking.getImportance(), outRanking.getImportanceExplanation(), + outRanking.getOverrideGroupKey(), outRanking.getChannel(), null, null, + outRanking.canShowBadge(), outRanking.getUserSentiment(), true); } else { outRanking.populate(key, outRanking.getRank(), outRanking.matchesInterruptionFilter(), -- GitLab From 4af1781776f304c848e1a0ece34a0f5f3b5780ff Mon Sep 17 00:00:00 2001 From: Paul Jensen Date: Wed, 28 Mar 2018 09:19:58 -0400 Subject: [PATCH 052/179] Add Network.fromNetworkHandle() This is the counterpart to Network.getNetworkHandle() and facilitates native code calling back to Java with network handle values from getNetworkHandle. Bug: 77210159 Bug: 64148938 Test: make CtsNetTestCases Change-Id: I032b959d84180c063a79ddd97c35e7384b0f50a1 --- api/current.txt | 1 + core/java/android/net/Network.java | 30 +++++++++++++++++++++++++----- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/api/current.txt b/api/current.txt index dda00ba8e94d..f7c8143964dc 100644 --- a/api/current.txt +++ b/api/current.txt @@ -27086,6 +27086,7 @@ package android.net { method public void bindSocket(java.net.Socket) throws java.io.IOException; method public void bindSocket(java.io.FileDescriptor) throws java.io.IOException; method public int describeContents(); + method public static android.net.Network fromNetworkHandle(long); method public java.net.InetAddress[] getAllByName(java.lang.String) throws java.net.UnknownHostException; method public java.net.InetAddress getByName(java.lang.String) throws java.net.UnknownHostException; method public long getNetworkHandle(); diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java index 5df168d20586..d24c131242d6 100644 --- a/core/java/android/net/Network.java +++ b/core/java/android/net/Network.java @@ -77,6 +77,11 @@ public class Network implements Parcelable { httpKeepAlive ? Integer.parseInt(System.getProperty("http.maxConnections", "5")) : 0; private static final long httpKeepAliveDurationMs = Long.parseLong(System.getProperty("http.keepAliveDuration", "300000")); // 5 minutes. + // Value used to obfuscate network handle longs. + // The HANDLE_MAGIC value MUST be kept in sync with the corresponding + // value in the native/android/net.c NDK implementation. + private static final long HANDLE_MAGIC = 0xcafed00dL; + private static final int HANDLE_MAGIC_SIZE = 32; /** * @hide @@ -334,6 +339,25 @@ public class Network implements Parcelable { } } + /** + * Returns a {@link Network} object given a handle returned from {@link #getNetworkHandle}. + * + * @param networkHandle a handle returned from {@link #getNetworkHandle}. + * @return A {@link Network} object derived from {@code networkHandle}. + */ + public static Network fromNetworkHandle(long networkHandle) { + if (networkHandle == 0) { + throw new IllegalArgumentException( + "Network.fromNetworkHandle refusing to instantiate NETID_UNSET Network."); + } + if ((networkHandle & ((1L << HANDLE_MAGIC_SIZE) - 1)) != HANDLE_MAGIC + || networkHandle < 0) { + throw new IllegalArgumentException( + "Value passed to fromNetworkHandle() is not a network handle."); + } + return new Network((int) (networkHandle >> HANDLE_MAGIC_SIZE)); + } + /** * Returns a handle representing this {@code Network}, for use with the NDK API. */ @@ -356,14 +380,10 @@ public class Network implements Parcelable { // At some future date it may be desirable to realign the handle with // Multiple Provisioning Domains API recommendations, as made by the // IETF mif working group. - // - // The handleMagic value MUST be kept in sync with the corresponding - // value in the native/android/net.c NDK implementation. if (netId == 0) { return 0L; // make this zero condition obvious for debugging } - final long handleMagic = 0xcafed00dL; - return (((long) netId) << 32) | handleMagic; + return (((long) netId) << HANDLE_MAGIC_SIZE) | HANDLE_MAGIC; } // implement the Parcelable interface -- GitLab From 89bb993293f0d7a524d1404184a55584b59bb67c Mon Sep 17 00:00:00 2001 From: Paul Jensen Date: Thu, 29 Mar 2018 07:41:43 -0400 Subject: [PATCH 053/179] Fix socket leaks in various android.net.Network methods. Bug: 72124526 Test: make CtsNetTestCases Change-Id: I3398b67272360f894e01a8cdfbc47b17d77c2330 --- core/java/android/net/Network.java | 40 ++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java index 5df168d20586..bc2e10df3e21 100644 --- a/core/java/android/net/Network.java +++ b/core/java/android/net/Network.java @@ -26,6 +26,8 @@ import android.util.proto.ProtoOutputStream; import com.android.okhttp.internalandroidapi.Dns; import com.android.okhttp.internalandroidapi.HttpURLConnectionFactory; +import libcore.io.IoUtils; + import java.io.FileDescriptor; import java.io.IOException; import java.net.DatagramSocket; @@ -137,9 +139,15 @@ public class Network implements Parcelable { for (int i = 0; i < hostAddresses.length; i++) { try { Socket socket = createSocket(); - if (localAddress != null) socket.bind(localAddress); - socket.connect(new InetSocketAddress(hostAddresses[i], port)); - return socket; + boolean failed = true; + try { + if (localAddress != null) socket.bind(localAddress); + socket.connect(new InetSocketAddress(hostAddresses[i], port)); + failed = false; + return socket; + } finally { + if (failed) IoUtils.closeQuietly(socket); + } } catch (IOException e) { if (i == (hostAddresses.length - 1)) throw e; } @@ -156,15 +164,27 @@ public class Network implements Parcelable { public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException { Socket socket = createSocket(); - socket.bind(new InetSocketAddress(localAddress, localPort)); - socket.connect(new InetSocketAddress(address, port)); + boolean failed = true; + try { + socket.bind(new InetSocketAddress(localAddress, localPort)); + socket.connect(new InetSocketAddress(address, port)); + failed = false; + } finally { + if (failed) IoUtils.closeQuietly(socket); + } return socket; } @Override public Socket createSocket(InetAddress host, int port) throws IOException { Socket socket = createSocket(); - socket.connect(new InetSocketAddress(host, port)); + boolean failed = true; + try { + socket.connect(new InetSocketAddress(host, port)); + failed = false; + } finally { + if (failed) IoUtils.closeQuietly(socket); + } return socket; } @@ -176,7 +196,13 @@ public class Network implements Parcelable { @Override public Socket createSocket() throws IOException { Socket socket = new Socket(); - bindSocket(socket); + boolean failed = true; + try { + bindSocket(socket); + failed = false; + } finally { + if (failed) IoUtils.closeQuietly(socket); + } return socket; } } -- GitLab From 3b8e61e5ecf98725785cc8d657ce8c5ef0197701 Mon Sep 17 00:00:00 2001 From: Nicolas Geoffray Date: Thu, 29 Mar 2018 00:00:12 +0100 Subject: [PATCH 054/179] Add three more wifi APIs. bug: 74066078 Test: m Change-Id: I2c9a7499094c743de3923226bbcea3c1cd147d5f --- config/hiddenapi-light-greylist.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt index 3af610592732..5f10a33f67c0 100644 --- a/config/hiddenapi-light-greylist.txt +++ b/config/hiddenapi-light-greylist.txt @@ -1111,6 +1111,8 @@ Landroid/net/wifi/p2p/WifiP2pManager;->deletePersistentGroup(Landroid/net/wifi/p Landroid/net/wifi/p2p/WifiP2pManager;->requestPersistentGroupInfo(Landroid/net/wifi/p2p/WifiP2pManager$Channel;Landroid/net/wifi/p2p/WifiP2pManager$PersistentGroupInfoListener;)V Landroid/net/wifi/p2p/WifiP2pManager;->setDeviceName(Landroid/net/wifi/p2p/WifiP2pManager$Channel;Ljava/lang/String;Landroid/net/wifi/p2p/WifiP2pManager$ActionListener;)V Landroid/net/wifi/p2p/WifiP2pManager;->setWifiP2pChannels(Landroid/net/wifi/p2p/WifiP2pManager$Channel;IILandroid/net/wifi/p2p/WifiP2pManager$ActionListener;)V +Landroid/net/wifi/p2p/WifiP2pManager$Channel;->mAsyncChannel:Lcom/android/internal/util/AsyncChannel; +Landroid/net/wifi/p2p/WifiP2pManager$Channel;->putListener(Ljava/lang/Object;)I Landroid/net/wifi/ScanResult;->anqpDomainId:I Landroid/net/wifi/ScanResult;->anqpLines:Ljava/util/List; Landroid/net/wifi/ScanResult;->distanceCm:I @@ -2779,6 +2781,7 @@ Lcom/android/internal/telephony/ITelephony$Stub$Proxy;->endCall()Z Lcom/android/internal/telephony/ITelephony$Stub$Proxy;->(Landroid/os/IBinder;)V Lcom/android/internal/telephony/ITelephony$Stub;->TRANSACTION_getDeviceId:I Lcom/android/internal/textservice/ITextServicesManager$Stub$Proxy;->(Landroid/os/IBinder;)V +Lcom/android/internal/util/AsyncChannel;->sendMessage(III)V Lcom/android/internal/util/FastPrintWriter;->(Ljava/io/OutputStream;)V Lcom/android/internal/util/XmlUtils;->readMapXml(Ljava/io/InputStream;)Ljava/util/HashMap; Lcom/android/internal/view/IInputMethodManager$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/view/IInputMethodManager; -- GitLab From dc8021507457dbfc8f1dd5d449c2c2199f4f3491 Mon Sep 17 00:00:00 2001 From: David Brazdil Date: Thu, 29 Mar 2018 14:21:48 +0100 Subject: [PATCH 055/179] Add more hidden API uses to light greylist Bug: 76443991 Bug: 64382372 Test: make Change-Id: I5ec60bbf9b747230ab1a5ae539d7d014b24605b0 --- config/hiddenapi-light-greylist.txt | 19 +++++++++++++++++++ config/hiddenapi-vendor-list.txt | 1 - 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt index 0ded5159aa35..e560dade9fde 100644 --- a/config/hiddenapi-light-greylist.txt +++ b/config/hiddenapi-light-greylist.txt @@ -1,4 +1,5 @@ Landroid/accounts/AccountManager;->mContext:Landroid/content/Context; +Landroid/accounts/IAccountAuthenticatorResponse$Stub;->()V Landroid/accounts/IAccountManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/accounts/IAccountManager; Landroid/accounts/IAccountManager$Stub$Proxy;->(Landroid/os/IBinder;)V Landroid/animation/LayoutTransition;->cancel()V @@ -236,6 +237,7 @@ Landroid/app/IActivityManager;->getLaunchedFromPackage(Landroid/os/IBinder;)Ljav Landroid/app/IActivityManager;->getTaskForActivity(Landroid/os/IBinder;Z)I Landroid/app/IActivityManager;->moveTaskToFront(IILandroid/os/Bundle;)V Landroid/app/IActivityManager;->publishContentProviders(Landroid/app/IApplicationThread;Ljava/util/List;)V +Landroid/app/IActivityManager;->requestBugReport(I)V Landroid/app/IActivityManager;->resumeAppSwitches()V Landroid/app/IActivityManager;->setRequestedOrientation(Landroid/os/IBinder;I)V Landroid/app/IActivityManager;->setTaskResizeable(II)V @@ -948,6 +950,7 @@ Landroid/media/IAudioService;->getStreamVolume(I)I Landroid/media/IAudioService;->setStreamVolume(IIILjava/lang/String;)V Landroid/media/IAudioService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/media/IAudioService; Landroid/media/IAudioService$Stub$Proxy;->(Landroid/os/IBinder;)V +Landroid/media/IRemoteDisplayCallback;->onStateChanged(Landroid/media/RemoteDisplayState;)V Landroid/media/IVolumeController$Stub;->asInterface(Landroid/os/IBinder;)Landroid/media/IVolumeController; Landroid/media/JetPlayer;->mNativePlayerInJavaObj:J Landroid/media/JetPlayer;->postEventFromNative(Ljava/lang/Object;III)V @@ -1000,6 +1003,8 @@ Landroid/media/PlaybackParams;->SET_SPEED:I Landroid/media/RemoteDisplay;->notifyDisplayConnected(Landroid/view/Surface;IIII)V Landroid/media/RemoteDisplay;->notifyDisplayDisconnected()V Landroid/media/RemoteDisplay;->notifyDisplayError(I)V +Landroid/media/RemoteDisplayState;->displays:Ljava/util/ArrayList; +Landroid/media/RemoteDisplayState;->()V Landroid/media/RingtoneManager;->getRingtone(Landroid/content/Context;Landroid/net/Uri;I)Landroid/media/Ringtone; Landroid/media/session/MediaSessionLegacyHelper;->getHelper(Landroid/content/Context;)Landroid/media/session/MediaSessionLegacyHelper; Landroid/media/session/MediaSession;->mCallback:Landroid/media/session/MediaSession$CallbackMessageHandler; @@ -1011,6 +1016,11 @@ Landroid/media/soundtrigger/SoundTriggerManager;->startRecognition(Ljava/util/UU Landroid/media/soundtrigger/SoundTriggerManager;->stopRecognition(Ljava/util/UUID;)I Landroid/media/soundtrigger/SoundTriggerManager;->unloadSoundModel(Ljava/util/UUID;)I Landroid/media/SubtitleController;->mHandler:Landroid/os/Handler; +Landroid/media/SubtitleTrack$RenderingWidget;->draw(Landroid/graphics/Canvas;)V +Landroid/media/SubtitleTrack$RenderingWidget;->onAttachedToWindow()V +Landroid/media/SubtitleTrack$RenderingWidget;->onDetachedFromWindow()V +Landroid/media/SubtitleTrack$RenderingWidget;->setOnChangedListener(Landroid/media/SubtitleTrack$RenderingWidget$OnChangedListener;)V +Landroid/media/SubtitleTrack$RenderingWidget;->setSize(II)V Landroid/media/ThumbnailUtils;->createImageThumbnail(Ljava/lang/String;I)Landroid/graphics/Bitmap; Landroid/media/ToneGenerator;->mNativeContext:J Landroid/media/VolumeShaper$Configuration;->(IIIDI[F[F)V @@ -1966,6 +1976,7 @@ Landroid/util/Rational;->mDenominator:I Landroid/util/Rational;->mNumerator:I Landroid/util/Singleton;->mInstance:Ljava/lang/Object; Landroid/util/Slog;->d(Ljava/lang/String;Ljava/lang/String;)I +Landroid/util/Slog;->w(Ljava/lang/String;Ljava/lang/String;)I Landroid/util/SparseIntArray;->mKeys:[I Landroid/util/SparseIntArray;->mSize:I Landroid/util/SparseIntArray;->mValues:[I @@ -2285,6 +2296,7 @@ Landroid/view/Window;->mHardwareAccelerated:Z Landroid/webkit/IWebViewUpdateService$Stub$Proxy;->(Landroid/os/IBinder;)V Landroid/webkit/WebResourceResponse;->mImmutable:Z Landroid/webkit/WebSyncManager;->mHandler:Landroid/os/Handler; +Landroid/webkit/WebViewClient;->onUnhandledInputEvent(Landroid/webkit/WebView;Landroid/view/InputEvent;)V Landroid/webkit/WebView;->debugDump()V Landroid/webkit/WebView;->disablePlatformNotifications()V Landroid/webkit/WebView;->emulateShiftHeld()V @@ -2714,11 +2726,15 @@ Lcom/android/internal/R$styleable;->CheckBoxPreference_summaryOff:I Lcom/android/internal/R$styleable;->CheckBoxPreference_summaryOn:I Lcom/android/internal/R$styleable;->CompoundButton_button:I Lcom/android/internal/R$styleable;->CompoundButton:[I +Lcom/android/internal/R$styleable;->DialogPreference_dialogTitle:I +Lcom/android/internal/R$styleable;->DialogPreference:[I Lcom/android/internal/R$styleable;->EdgeEffect_colorEdgeEffect:I Lcom/android/internal/R$styleable;->EdgeEffect:[I Lcom/android/internal/R$styleable;->IconMenuView:[I Lcom/android/internal/R$styleable;->ImageView:[I Lcom/android/internal/R$styleable;->ImageView_src:I +Lcom/android/internal/R$styleable;->ListPreference_entries:I +Lcom/android/internal/R$styleable;->ListPreference:[I Lcom/android/internal/R$styleable;->Preference_defaultValue:I Lcom/android/internal/R$styleable;->Preference_dependency:I Lcom/android/internal/R$styleable;->Preference_enabled:I @@ -2960,6 +2976,7 @@ Ljava/lang/Runtime;->load(Ljava/lang/String;Ljava/lang/ClassLoader;)V Ljava/lang/Runtime;->nativeLoad(Ljava/lang/String;Ljava/lang/ClassLoader;)Ljava/lang/String; Ljava/lang/Short;->value:S Ljava/lang/String;->(II[C)V +Ljava/lang/System;->arraycopy([II[III)V Ljava/lang/System;->()V Ljava/lang/Thread;->daemon:Z Ljava/lang/Thread;->dispatchUncaughtException(Ljava/lang/Throwable;)V @@ -3071,5 +3088,7 @@ Llibcore/util/ZoneInfo;->mTransitions:[J Lorg/apache/http/conn/ssl/SSLSocketFactory;->(Ljavax/net/ssl/SSLSocketFactory;)V Lorg/apache/http/conn/ssl/SSLSocketFactory;->()V Lorg/json/JSONArray;->values:Ljava/util/List; +Lorg/json/JSONObject;->append(Ljava/lang/String;Ljava/lang/Object;)Lorg/json/JSONObject; +Lorg/json/JSONObject;->keySet()Ljava/util/Set; Lorg/json/JSONObject;->writeTo(Lorg/json/JSONStringer;)V Lsun/misc/Unsafe;->theUnsafe:Lsun/misc/Unsafe; diff --git a/config/hiddenapi-vendor-list.txt b/config/hiddenapi-vendor-list.txt index 6b528508a8bb..61ae6e77cbfd 100644 --- a/config/hiddenapi-vendor-list.txt +++ b/config/hiddenapi-vendor-list.txt @@ -32,7 +32,6 @@ Landroid/app/IActivityManager;->getRunningAppProcesses()Ljava/util/List; Landroid/app/IActivityManager;->getTaskSnapshot(IZ)Landroid/app/ActivityManager$TaskSnapshot; Landroid/app/IActivityManager;->registerTaskStackListener(Landroid/app/ITaskStackListener;)V Landroid/app/IActivityManager;->removeTask(I)Z -Landroid/app/IActivityManager;->requestBugReport(I)V Landroid/app/IActivityManager;->startActivityAsUser(Landroid/app/IApplicationThread;Ljava/lang/String;Landroid/content/Intent;Ljava/lang/String;Landroid/os/IBinder;Ljava/lang/String;IILandroid/app/ProfilerInfo;Landroid/os/Bundle;I)I Landroid/app/IActivityManager;->startActivityFromRecents(ILandroid/os/Bundle;)I Landroid/app/IActivityManager;->startActivity(Landroid/app/IApplicationThread;Ljava/lang/String;Landroid/content/Intent;Ljava/lang/String;Landroid/os/IBinder;Ljava/lang/String;IILandroid/app/ProfilerInfo;Landroid/os/Bundle;)I -- GitLab From 5658837b464275b7ae87fec5529c7344bf21b733 Mon Sep 17 00:00:00 2001 From: Robert Berry Date: Thu, 29 Mar 2018 12:07:17 +0100 Subject: [PATCH 056/179] Save KeyChainSnapshots to disk Bug: 73921897 Test: runtest frameworks-services -p \ com.android.server.locksettings.recoverablekeystore Change-Id: I909f2f7f289d4e2a0cdff6a3f7184747e5deeae2 --- .../RecoverableKeyStoreManager.java | 3 +- .../KeyChainSnapshotDeserializer.java | 8 + .../serialization/KeyChainSnapshotSchema.java | 1 + .../KeyChainSnapshotSerializer.java | 7 + .../storage/RecoverySnapshotStorage.java | 122 +++++++++- .../recoverablekeystore/KeySyncTaskTest.java | 11 +- .../KeyChainSnapshotSerializerTest.java | 64 ++++-- .../storage/RecoverySnapshotStorageTest.java | 209 ++++++++++++++++-- 8 files changed, 384 insertions(+), 41 deletions(-) diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java index 8a79e4c680d2..77d7c3cfdbf2 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java @@ -31,7 +31,6 @@ import android.annotation.Nullable; import android.app.PendingIntent; import android.content.Context; import android.os.Binder; -import android.os.Process; import android.os.RemoteException; import android.os.ServiceSpecificException; import android.os.UserHandle; @@ -128,7 +127,7 @@ public class RecoverableKeyStoreManager { db, new RecoverySessionStorage(), Executors.newSingleThreadExecutor(), - new RecoverySnapshotStorage(), + RecoverySnapshotStorage.newInstance(), new RecoverySnapshotListenersStorage(), platformKeyManager, applicationKeyStorage); diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotDeserializer.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotDeserializer.java index dcaa0b4785cc..f789155cee52 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotDeserializer.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotDeserializer.java @@ -23,6 +23,9 @@ import static com.android.server.locksettings.recoverablekeystore.serialization. import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_ALIAS; import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_APPLICATION_KEY; import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_APPLICATION_KEYS; + +import static com.android.server.locksettings.recoverablekeystore.serialization + .KeyChainSnapshotSchema.TAG_BACKEND_PUBLIC_KEY; import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_COUNTER_ID; import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_RECOVERY_KEY_MATERIAL; import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_KEY_CHAIN_PROTECTION_PARAMS; @@ -128,6 +131,11 @@ public class KeyChainSnapshotDeserializer { } break; + case TAG_BACKEND_PUBLIC_KEY: + builder.setTrustedHardwarePublicKey( + readBlobTag(parser, TAG_BACKEND_PUBLIC_KEY)); + break; + case TAG_KEY_CHAIN_PROTECTION_PARAMS_LIST: builder.setKeyChainProtectionParams(readKeyChainProtectionParamsList(parser)); break; diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSchema.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSchema.java index ee8b2cfd18f5..ff30ecd7d3a7 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSchema.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSchema.java @@ -35,6 +35,7 @@ class KeyChainSnapshotSchema { static final String TAG_RECOVERY_KEY_MATERIAL = "recoveryKeyMaterial"; static final String TAG_SERVER_PARAMS = "serverParams"; static final String TAG_TRUSTED_HARDWARE_CERT_PATH = "thmCertPath"; + static final String TAG_BACKEND_PUBLIC_KEY = "backendPublicKey"; static final String TAG_KEY_CHAIN_PROTECTION_PARAMS_LIST = "keyChainProtectionParamsList"; diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSerializer.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSerializer.java index f817a8fb02e4..17a16bf5906b 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSerializer.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSerializer.java @@ -24,6 +24,9 @@ import static com.android.server.locksettings.recoverablekeystore.serialization. import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_ALIAS; import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_APPLICATION_KEY; import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_APPLICATION_KEYS; + +import static com.android.server.locksettings.recoverablekeystore.serialization + .KeyChainSnapshotSchema.TAG_BACKEND_PUBLIC_KEY; import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_COUNTER_ID; import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_RECOVERY_KEY_MATERIAL; import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_KEY_CHAIN_PROTECTION_PARAMS; @@ -159,6 +162,10 @@ public class KeyChainSnapshotSerializer { writePropertyTag(xmlSerializer, TAG_SERVER_PARAMS, keyChainSnapshot.getServerParams()); writePropertyTag(xmlSerializer, TAG_TRUSTED_HARDWARE_CERT_PATH, keyChainSnapshot.getTrustedHardwareCertPath()); + if (keyChainSnapshot.getTrustedHardwarePublicKey() != null) { + writePropertyTag(xmlSerializer, TAG_BACKEND_PUBLIC_KEY, + keyChainSnapshot.getTrustedHardwarePublicKey()); + } } private static void writePropertyTag( diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverySnapshotStorage.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverySnapshotStorage.java index 3f93cc6f5f88..c02b103f1d33 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverySnapshotStorage.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverySnapshotStorage.java @@ -17,13 +17,28 @@ package com.android.server.locksettings.recoverablekeystore.storage; import android.annotation.Nullable; +import android.os.Environment; import android.security.keystore.recovery.KeyChainSnapshot; +import android.util.Log; import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; +import com.android.server.locksettings.recoverablekeystore.serialization + .KeyChainSnapshotDeserializer; +import com.android.server.locksettings.recoverablekeystore.serialization + .KeyChainSnapshotParserException; +import com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSerializer; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.security.cert.CertificateEncodingException; +import java.util.Locale; /** - * In-memory storage for recovery snapshots. + * Storage for recovery snapshots. Stores snapshots in memory, backed by disk storage. * *

    Recovery snapshots are generated after a successful screen unlock. They are only generated if * the recoverable keystore has been mutated since the previous snapshot. This class stores only the @@ -33,14 +48,46 @@ import com.android.internal.annotations.GuardedBy; * {@link com.android.server.locksettings.recoverablekeystore.KeySyncTask} thread. */ public class RecoverySnapshotStorage { + + private static final String TAG = "RecoverySnapshotStorage"; + + private static final String ROOT_PATH = "system"; + private static final String STORAGE_PATH = "recoverablekeystore/snapshots/"; + @GuardedBy("this") private final SparseArray mSnapshotByUid = new SparseArray<>(); + private final File rootDirectory; + + /** + * A new instance, storing snapshots in /data/system/recoverablekeystore/snapshots. + * + *

    NOTE: calling this multiple times DOES NOT return the same instance, so will NOT be backed + * by the same in-memory store. + */ + public static RecoverySnapshotStorage newInstance() { + return new RecoverySnapshotStorage( + new File(Environment.getDataDirectory(), ROOT_PATH)); + } + + @VisibleForTesting + public RecoverySnapshotStorage(File rootDirectory) { + this.rootDirectory = rootDirectory; + } + /** * Sets the latest {@code snapshot} for the recovery agent {@code uid}. */ public synchronized void put(int uid, KeyChainSnapshot snapshot) { mSnapshotByUid.put(uid, snapshot); + + try { + writeToDisk(uid, snapshot); + } catch (IOException | CertificateEncodingException e) { + Log.e(TAG, + String.format(Locale.US, "Error persisting snapshot for %d to disk", uid), + e); + } } /** @@ -48,7 +95,17 @@ public class RecoverySnapshotStorage { */ @Nullable public synchronized KeyChainSnapshot get(int uid) { - return mSnapshotByUid.get(uid); + KeyChainSnapshot snapshot = mSnapshotByUid.get(uid); + if (snapshot != null) { + return snapshot; + } + + try { + return readFromDisk(uid); + } catch (IOException | KeyChainSnapshotParserException e) { + Log.e(TAG, String.format(Locale.US, "Error reading snapshot for %d from disk", uid), e); + return null; + } } /** @@ -56,5 +113,66 @@ public class RecoverySnapshotStorage { */ public synchronized void remove(int uid) { mSnapshotByUid.remove(uid); + getSnapshotFile(uid).delete(); + } + + /** + * Writes the snapshot for recovery agent {@code uid} to disk. + * + * @throws IOException if an IO error occurs writing to disk. + */ + private void writeToDisk(int uid, KeyChainSnapshot snapshot) + throws IOException, CertificateEncodingException { + File snapshotFile = getSnapshotFile(uid); + + try ( + FileOutputStream fileOutputStream = new FileOutputStream(snapshotFile) + ) { + KeyChainSnapshotSerializer.serialize(snapshot, fileOutputStream); + } catch (IOException | CertificateEncodingException e) { + // If we fail to write the latest snapshot, we should delete any older snapshot that + // happens to be around. Otherwise snapshot syncs might end up going 'back in time'. + snapshotFile.delete(); + throw e; + } + } + + /** + * Reads the last snapshot for recovery agent {@code uid} from disk. + * + * @return The snapshot, or null if none existed. + * @throws IOException if an IO error occurs reading from disk. + */ + @Nullable + private KeyChainSnapshot readFromDisk(int uid) + throws IOException, KeyChainSnapshotParserException { + File snapshotFile = getSnapshotFile(uid); + + try ( + FileInputStream fileInputStream = new FileInputStream(snapshotFile) + ) { + return KeyChainSnapshotDeserializer.deserialize(fileInputStream); + } catch (IOException | KeyChainSnapshotParserException e) { + // If we fail to read the latest snapshot, we should delete it in case it is in some way + // corrupted. We can regenerate snapshots anyway. + snapshotFile.delete(); + throw e; + } + } + + private File getSnapshotFile(int uid) { + File folder = getStorageFolder(); + String fileName = getSnapshotFileName(uid); + return new File(folder, fileName); + } + + private String getSnapshotFileName(int uid) { + return String.format(Locale.US, "%d.xml", uid); + } + + private File getStorageFolder() { + File folder = new File(rootDirectory, STORAGE_PATH); + folder.mkdirs(); + return folder; } } diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java index 9ae45ea15ca2..81a73efd94ad 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java @@ -38,6 +38,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; +import android.os.FileUtils; import android.security.keystore.AndroidKeyStoreSecretKey; import android.security.keystore.KeyGenParameterSpec; import android.security.keystore.KeyProperties; @@ -49,7 +50,6 @@ import android.support.test.InstrumentationRegistry; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; -import android.util.Log; import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDb; import com.android.server.locksettings.recoverablekeystore.storage.RecoverySnapshotStorage; @@ -72,6 +72,9 @@ import javax.crypto.SecretKey; @SmallTest @RunWith(AndroidJUnit4.class) public class KeySyncTaskTest { + + private static final String SNAPSHOT_TOP_LEVEL_DIRECTORY = "recoverablekeystore"; + private static final String KEY_ALGORITHM = "AES"; private static final String ANDROID_KEY_STORE_PROVIDER = "AndroidKeyStore"; private static final String TEST_ROOT_CERT_ALIAS = "trusted_root"; @@ -117,7 +120,7 @@ public class KeySyncTaskTest { TEST_ROOT_CERT_ALIAS); mRecoverableKeyStoreDb.setActiveRootOfTrust(TEST_USER_ID, TEST_RECOVERY_AGENT_UID2, TEST_ROOT_CERT_ALIAS); - mRecoverySnapshotStorage = new RecoverySnapshotStorage(); + mRecoverySnapshotStorage = new RecoverySnapshotStorage(context.getFilesDir()); mKeySyncTask = new KeySyncTask( mRecoverableKeyStoreDb, @@ -139,6 +142,10 @@ public class KeySyncTaskTest { public void tearDown() { mRecoverableKeyStoreDb.close(); mDatabaseFile.delete(); + + File file = new File(InstrumentationRegistry.getTargetContext().getFilesDir(), + SNAPSHOT_TOP_LEVEL_DIRECTORY); + FileUtils.deleteContentsAndDir(file); } @Test diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSerializerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSerializerTest.java index 6c2958e4f456..2f4da86bf38f 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSerializerTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSerializerTest.java @@ -45,6 +45,7 @@ public class KeyChainSnapshotSerializerTest { private static final int MAX_ATTEMPTS = 21; private static final byte[] SERVER_PARAMS = new byte[] { 8, 2, 4 }; private static final byte[] KEY_BLOB = new byte[] { 124, 53, 53, 53 }; + private static final byte[] PUBLIC_KEY_BLOB = new byte[] { 6, 6, 6, 6, 6, 6, 7 }; private static final CertPath CERT_PATH = TestData.CERT_PATH_1; private static final int SECRET_TYPE = KeyChainProtectionParams.TYPE_LOCKSCREEN; private static final int LOCK_SCREEN_UI = KeyChainProtectionParams.UI_FORMAT_PASSWORD; @@ -92,6 +93,11 @@ public class KeyChainSnapshotSerializerTest { assertThat(roundTrip().getTrustedHardwareCertPath()).isEqualTo(CERT_PATH); } + @Test + public void roundTrip_persistsBackendPublicKey() throws Exception { + assertThat(roundTrip().getTrustedHardwarePublicKey()).isEqualTo(PUBLIC_KEY_BLOB); + } + @Test public void roundTrip_persistsParamsList() throws Exception { assertThat(roundTrip().getKeyChainProtectionParams()).hasSize(1); @@ -163,6 +169,12 @@ public class KeyChainSnapshotSerializerTest { assertThat(roundTripKeys().get(2).getEncryptedKeyMaterial()).isEqualTo(TEST_KEY_3_BYTES); } + @Test + public void serialize_doesNotThrowForNullPublicKey() throws Exception { + KeyChainSnapshotSerializer.serialize( + createTestKeyChainSnapshotNoPublicKey(), new ByteArrayOutputStream()); + } + private static List roundTripKeys() throws Exception { return roundTrip().getWrappedApplicationKeys(); } @@ -180,6 +192,41 @@ public class KeyChainSnapshotSerializerTest { } private static KeyChainSnapshot createTestKeyChainSnapshot() throws Exception { + return new KeyChainSnapshot.Builder() + .setCounterId(COUNTER_ID) + .setSnapshotVersion(SNAPSHOT_VERSION) + .setServerParams(SERVER_PARAMS) + .setMaxAttempts(MAX_ATTEMPTS) + .setEncryptedRecoveryKeyBlob(KEY_BLOB) + .setKeyChainProtectionParams(createKeyChainProtectionParamsList()) + .setWrappedApplicationKeys(createKeys()) + .setTrustedHardwareCertPath(CERT_PATH) + .setTrustedHardwarePublicKey(PUBLIC_KEY_BLOB) + .build(); + } + + private static KeyChainSnapshot createTestKeyChainSnapshotNoPublicKey() throws Exception { + return new KeyChainSnapshot.Builder() + .setCounterId(COUNTER_ID) + .setSnapshotVersion(SNAPSHOT_VERSION) + .setServerParams(SERVER_PARAMS) + .setMaxAttempts(MAX_ATTEMPTS) + .setEncryptedRecoveryKeyBlob(KEY_BLOB) + .setKeyChainProtectionParams(createKeyChainProtectionParamsList()) + .setWrappedApplicationKeys(createKeys()) + .setTrustedHardwareCertPath(CERT_PATH) + .build(); + } + + private static List createKeys() { + ArrayList keyList = new ArrayList<>(); + keyList.add(createKey(TEST_KEY_1_ALIAS, TEST_KEY_1_BYTES)); + keyList.add(createKey(TEST_KEY_2_ALIAS, TEST_KEY_2_BYTES)); + keyList.add(createKey(TEST_KEY_3_ALIAS, TEST_KEY_3_BYTES)); + return keyList; + } + + private static List createKeyChainProtectionParamsList() { KeyDerivationParams keyDerivationParams = KeyDerivationParams.createScryptParams(SALT, MEMORY_DIFFICULTY); KeyChainProtectionParams keyChainProtectionParams = new KeyChainProtectionParams.Builder() @@ -191,22 +238,7 @@ public class KeyChainSnapshotSerializerTest { ArrayList keyChainProtectionParamsList = new ArrayList<>(1); keyChainProtectionParamsList.add(keyChainProtectionParams); - - ArrayList keyList = new ArrayList<>(); - keyList.add(createKey(TEST_KEY_1_ALIAS, TEST_KEY_1_BYTES)); - keyList.add(createKey(TEST_KEY_2_ALIAS, TEST_KEY_2_BYTES)); - keyList.add(createKey(TEST_KEY_3_ALIAS, TEST_KEY_3_BYTES)); - - return new KeyChainSnapshot.Builder() - .setCounterId(COUNTER_ID) - .setSnapshotVersion(SNAPSHOT_VERSION) - .setServerParams(SERVER_PARAMS) - .setMaxAttempts(MAX_ATTEMPTS) - .setEncryptedRecoveryKeyBlob(KEY_BLOB) - .setKeyChainProtectionParams(keyChainProtectionParamsList) - .setWrappedApplicationKeys(keyList) - .setTrustedHardwareCertPath(CERT_PATH) - .build(); + return keyChainProtectionParamsList; } private static WrappedApplicationKey createKey(String alias, byte[] bytes) { diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverySnapshotStorageTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverySnapshotStorageTest.java index c7729566b353..ad14c3a8adef 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverySnapshotStorageTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverySnapshotStorageTest.java @@ -1,27 +1,82 @@ package com.android.server.locksettings.recoverablekeystore.storage; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import android.content.Context; +import android.os.FileUtils; +import android.security.keystore.recovery.KeyChainProtectionParams; import android.security.keystore.recovery.KeyChainSnapshot; +import android.security.keystore.recovery.KeyDerivationParams; +import android.security.keystore.recovery.WrappedApplicationKey; +import android.support.test.InstrumentationRegistry; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; import com.android.server.locksettings.recoverablekeystore.TestData; +import com.google.common.io.Files; + +import org.junit.After; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import java.io.File; +import java.nio.charset.StandardCharsets; +import java.security.cert.CertPath; import java.security.cert.CertificateException; import java.util.ArrayList; +import java.util.List; @SmallTest @RunWith(AndroidJUnit4.class) public class RecoverySnapshotStorageTest { + private static final int COUNTER_ID = 432546; + private static final int MAX_ATTEMPTS = 10; + private static final byte[] SERVER_PARAMS = new byte[] { 12, 8, 2, 4, 15, 64 }; + private static final byte[] KEY_BLOB = new byte[] { 124, 56, 53, 99, 0, 0, 1 }; + private static final CertPath CERT_PATH = TestData.CERT_PATH_2; + private static final int SECRET_TYPE = KeyChainProtectionParams.TYPE_LOCKSCREEN; + private static final int LOCK_SCREEN_UI = KeyChainProtectionParams.UI_FORMAT_PATTERN; + private static final byte[] SALT = new byte[] { 1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1 }; + private static final int MEMORY_DIFFICULTY = 12; + private static final byte[] SECRET = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0 }; + + private static final String TEST_KEY_1_ALIAS = "alias1"; + private static final byte[] TEST_KEY_1_BYTES = new byte[] { 100, 32, 43, 66, 77, 88 }; + + private static final String TEST_KEY_2_ALIAS = "alias11"; + private static final byte[] TEST_KEY_2_BYTES = new byte[] { 100, 0, 0, 99, 33, 11 }; + + private static final String TEST_KEY_3_ALIAS = "alias111"; + private static final byte[] TEST_KEY_3_BYTES = new byte[] { 1, 1, 1, 0, 2, 8, 100 }; + + private static final int TEST_UID = 1000; + private static final String SNAPSHOT_DIRECTORY = "recoverablekeystore/snapshots"; + private static final String SNAPSHOT_FILE_PATH = "1000.xml"; + private static final String SNAPSHOT_TOP_LEVEL_DIRECTORY = "recoverablekeystore"; + private static final KeyChainSnapshot MINIMAL_KEYCHAIN_SNAPSHOT = - createMinimalKeyChainSnapshot(); + createTestKeyChainSnapshot(1); - private final RecoverySnapshotStorage mRecoverySnapshotStorage = new RecoverySnapshotStorage(); + private Context mContext; + private RecoverySnapshotStorage mRecoverySnapshotStorage; + + @Before + public void setUp() { + mContext = InstrumentationRegistry.getTargetContext(); + mRecoverySnapshotStorage = new RecoverySnapshotStorage(mContext.getFilesDir()); + } + + @After + public void tearDown() { + File file = new File(mContext.getFilesDir(), SNAPSHOT_TOP_LEVEL_DIRECTORY); + FileUtils.deleteContentsAndDir(file); + } @Test public void get_isNullForNonExistentSnapshot() { @@ -30,37 +85,153 @@ public class RecoverySnapshotStorageTest { @Test public void get_returnsSetSnapshot() { - int userId = 1000; + mRecoverySnapshotStorage.put(TEST_UID, MINIMAL_KEYCHAIN_SNAPSHOT); - mRecoverySnapshotStorage.put(userId, MINIMAL_KEYCHAIN_SNAPSHOT); + assertEquals(MINIMAL_KEYCHAIN_SNAPSHOT, mRecoverySnapshotStorage.get(TEST_UID)); + } + + @Test + public void get_readsFromDiskIfNoneInMemory() { + mRecoverySnapshotStorage.put(TEST_UID, MINIMAL_KEYCHAIN_SNAPSHOT); + RecoverySnapshotStorage storage = new RecoverySnapshotStorage(mContext.getFilesDir()); - assertEquals(MINIMAL_KEYCHAIN_SNAPSHOT, mRecoverySnapshotStorage.get(userId)); + assertKeyChainSnapshotsAreEqual(MINIMAL_KEYCHAIN_SNAPSHOT, storage.get(TEST_UID)); } @Test - public void remove_removesSnapshots() { - int userId = 1000; + public void get_deletesFileIfItIsInvalidSnapshot() throws Exception { + File folder = new File(mContext.getFilesDir(), SNAPSHOT_DIRECTORY); + folder.mkdirs(); + File file = new File(folder, SNAPSHOT_FILE_PATH); + byte[] fileContents = "".getBytes( + StandardCharsets.UTF_8); + Files.write(fileContents, file); + assertTrue(file.exists()); - mRecoverySnapshotStorage.put(userId, MINIMAL_KEYCHAIN_SNAPSHOT); - mRecoverySnapshotStorage.remove(userId); + assertNull(mRecoverySnapshotStorage.get(TEST_UID)); - assertNull(mRecoverySnapshotStorage.get(1000)); + assertFalse(file.exists()); + } + + @Test + public void put_overwritesOldFiles() { + int snapshotVersion = 2; + mRecoverySnapshotStorage.put(TEST_UID, MINIMAL_KEYCHAIN_SNAPSHOT); + + mRecoverySnapshotStorage.put(TEST_UID, createTestKeyChainSnapshot(snapshotVersion)); + + KeyChainSnapshot snapshot = new RecoverySnapshotStorage(mContext.getFilesDir()) + .get(TEST_UID); + assertEquals(snapshotVersion, snapshot.getSnapshotVersion()); } - private static KeyChainSnapshot createMinimalKeyChainSnapshot() { + @Test + public void put_doesNotThrowIfCannotCreateFiles() throws Exception { + File evilFile = new File(mContext.getFilesDir(), "recoverablekeystore"); + Files.write(new byte[] { 1 }, evilFile); + + mRecoverySnapshotStorage.put(TEST_UID, MINIMAL_KEYCHAIN_SNAPSHOT); + + assertNull(new RecoverySnapshotStorage(mContext.getFilesDir()).get(TEST_UID)); + } + + @Test + public void remove_removesSnapshotsFromMemory() { + mRecoverySnapshotStorage.put(TEST_UID, MINIMAL_KEYCHAIN_SNAPSHOT); + mRecoverySnapshotStorage.remove(TEST_UID); + + assertNull(mRecoverySnapshotStorage.get(TEST_UID)); + } + + @Test + public void remove_removesSnapshotsFromDisk() { + mRecoverySnapshotStorage.put(TEST_UID, MINIMAL_KEYCHAIN_SNAPSHOT); + + new RecoverySnapshotStorage(mContext.getFilesDir()).remove(TEST_UID); + + assertNull(new RecoverySnapshotStorage(mContext.getFilesDir()).get(TEST_UID)); + } + + private void assertKeyChainSnapshotsAreEqual(KeyChainSnapshot a, KeyChainSnapshot b) { + assertEquals(b.getCounterId(), a.getCounterId()); + assertEquals(b.getSnapshotVersion(), a.getSnapshotVersion()); + assertArrayEquals(b.getServerParams(), a.getServerParams()); + assertEquals(b.getMaxAttempts(), a.getMaxAttempts()); + assertArrayEquals(b.getEncryptedRecoveryKeyBlob(), a.getEncryptedRecoveryKeyBlob()); + assertEquals(b.getTrustedHardwareCertPath(), a.getTrustedHardwareCertPath()); + + List aKeys = a.getWrappedApplicationKeys(); + List bKeys = b.getWrappedApplicationKeys(); + assertEquals(bKeys.size(), aKeys.size()); + for (int i = 0; i < aKeys.size(); i++) { + assertWrappedApplicationKeysAreEqual(aKeys.get(i), bKeys.get(i)); + } + + List aParams = a.getKeyChainProtectionParams(); + List bParams = b.getKeyChainProtectionParams(); + assertEquals(bParams.size(), aParams.size()); + for (int i = 0; i < aParams.size(); i++) { + assertKeyChainProtectionParamsAreEqual(aParams.get(i), bParams.get(i)); + } + } + + private void assertWrappedApplicationKeysAreEqual( + WrappedApplicationKey a, WrappedApplicationKey b) { + assertEquals(b.getAlias(), a.getAlias()); + assertArrayEquals(b.getEncryptedKeyMaterial(), a.getEncryptedKeyMaterial()); + } + + private void assertKeyChainProtectionParamsAreEqual( + KeyChainProtectionParams a, KeyChainProtectionParams b) { + assertEquals(b.getUserSecretType(), a.getUserSecretType()); + assertEquals(b.getLockScreenUiFormat(), a.getLockScreenUiFormat()); + assertKeyDerivationParamsAreEqual(a.getKeyDerivationParams(), b.getKeyDerivationParams()); + } + + private void assertKeyDerivationParamsAreEqual(KeyDerivationParams a, KeyDerivationParams b) { + assertEquals(b.getAlgorithm(), a.getAlgorithm()); + assertEquals(b.getMemoryDifficulty(), a.getMemoryDifficulty()); + assertArrayEquals(b.getSalt(), a.getSalt()); + } + + private static KeyChainSnapshot createTestKeyChainSnapshot(int snapshotVersion) { + KeyDerivationParams keyDerivationParams = + KeyDerivationParams.createScryptParams(SALT, MEMORY_DIFFICULTY); + KeyChainProtectionParams keyChainProtectionParams = new KeyChainProtectionParams.Builder() + .setKeyDerivationParams(keyDerivationParams) + .setUserSecretType(SECRET_TYPE) + .setLockScreenUiFormat(LOCK_SCREEN_UI) + .setSecret(SECRET) + .build(); + ArrayList keyChainProtectionParamsList = + new ArrayList<>(1); + keyChainProtectionParamsList.add(keyChainProtectionParams); + + ArrayList keyList = new ArrayList<>(); + keyList.add(createKey(TEST_KEY_1_ALIAS, TEST_KEY_1_BYTES)); + keyList.add(createKey(TEST_KEY_2_ALIAS, TEST_KEY_2_BYTES)); + keyList.add(createKey(TEST_KEY_3_ALIAS, TEST_KEY_3_BYTES)); + try { return new KeyChainSnapshot.Builder() - .setCounterId(1) - .setSnapshotVersion(1) - .setServerParams(new byte[0]) - .setMaxAttempts(10) - .setEncryptedRecoveryKeyBlob(new byte[0]) - .setKeyChainProtectionParams(new ArrayList<>()) - .setWrappedApplicationKeys(new ArrayList<>()) - .setTrustedHardwareCertPath(TestData.CERT_PATH_1) + .setCounterId(COUNTER_ID) + .setSnapshotVersion(snapshotVersion) + .setServerParams(SERVER_PARAMS) + .setMaxAttempts(MAX_ATTEMPTS) + .setEncryptedRecoveryKeyBlob(KEY_BLOB) + .setKeyChainProtectionParams(keyChainProtectionParamsList) + .setWrappedApplicationKeys(keyList) + .setTrustedHardwareCertPath(CERT_PATH) .build(); } catch (CertificateException e) { throw new RuntimeException(e); } } + + private static WrappedApplicationKey createKey(String alias, byte[] bytes) { + return new WrappedApplicationKey.Builder() + .setAlias(alias) + .setEncryptedKeyMaterial(bytes) + .build(); + } } -- GitLab From 856939fa2b5954c30d14b3cdb84b3d0d9fd5c218 Mon Sep 17 00:00:00 2001 From: Amin Shaikh Date: Thu, 29 Mar 2018 09:41:45 -0400 Subject: [PATCH 057/179] Change alarm/ringer status QS separator. Change-Id: Ib305e65e45a78f1db6091bb978e086c46205db5f Fixes: 76208830 Test: visual --- .../res/drawable/qs_header_status_dot.xml | 19 ------------------- .../res/layout/quick_settings_header_info.xml | 15 +++++++-------- 2 files changed, 7 insertions(+), 27 deletions(-) delete mode 100644 packages/SystemUI/res/drawable/qs_header_status_dot.xml diff --git a/packages/SystemUI/res/drawable/qs_header_status_dot.xml b/packages/SystemUI/res/drawable/qs_header_status_dot.xml deleted file mode 100644 index 69bfd49255fc..000000000000 --- a/packages/SystemUI/res/drawable/qs_header_status_dot.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - diff --git a/packages/SystemUI/res/layout/quick_settings_header_info.xml b/packages/SystemUI/res/layout/quick_settings_header_info.xml index 03e8451e59dc..54baa4a82a0b 100644 --- a/packages/SystemUI/res/layout/quick_settings_header_info.xml +++ b/packages/SystemUI/res/layout/quick_settings_header_info.xml @@ -54,15 +54,14 @@ android:layout_marginStart="@dimen/qs_header_alarm_text_margin_start" android:textAppearance="@style/TextAppearance.QS.TileLabel" /> - + android:layout_width="1dp" + android:layout_height="match_parent" + android:layout_marginStart="10dp" + android:layout_marginEnd="10dp" + android:background="@android:color/white" + android:backgroundTint="?android:attr/textColorPrimary" /> Date: Wed, 28 Mar 2018 18:01:22 +0200 Subject: [PATCH 058/179] Fix letterbox insets when starting app Showing the letterbox with checking on HAS_DRAWN is too late. We also need to show it in READY_TO_SHOW such that we have it available when starting the transition. Test: Open letterboxed app. Observe no flicker Test: Capture winscope trace and make sure content insets when reopening app are correct. Bug: 76220728 Change-Id: I20ed8b1b5a90cc0a878d3eb1512e1aa1e4cd37f3 --- .../java/com/android/server/policy/WindowManagerPolicy.java | 3 +++ services/core/java/com/android/server/wm/AppWindowToken.java | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java index ec0521dda40d..7a6b53e93917 100644 --- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java +++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java @@ -407,7 +407,10 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { /** * Returns true if this window has been shown on screen at some time in * the past. Must be called with the window manager lock held. + * + * @deprecated Use {@link #isDrawnLw} or any of the other drawn/visibility methods. */ + @Deprecated public boolean hasDrawnLw(); /** diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index 56c9e51d5d3a..f19c554ace97 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -1485,7 +1485,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree if (w == null || winHint != null && w != winHint) { return; } - final boolean surfaceReady = w.hasDrawnLw() // Regular case + final boolean surfaceReady = w.isDrawnLw() // Regular case || w.mWinAnimator.mSurfaceDestroyDeferred // The preserved surface is still ready. || w.isDragResizeChanged(); // Waiting for relayoutWindow to call preserveSurface. final boolean needsLetterbox = w.isLetterboxedAppWindow() && fillsParent() && surfaceReady; -- GitLab From e3264ba6cf7df5b33b10dd6a15ac5010c78bac6e Mon Sep 17 00:00:00 2001 From: Alan Viverette Date: Fri, 23 Mar 2018 14:33:43 -0400 Subject: [PATCH 059/179] Migrate to AAPT2 Bug: 73128633 Test: make checkbuild Change-Id: I4b6b73299d1cae61994c34ebb77ca587c5ee64ff --- packages/SettingsLib/Android.mk | 2 ++ packages/SettingsLib/common.mk | 42 --------------------------------- 2 files changed, 2 insertions(+), 42 deletions(-) diff --git a/packages/SettingsLib/Android.mk b/packages/SettingsLib/Android.mk index 859f86faecbe..5a8be3192b0c 100644 --- a/packages/SettingsLib/Android.mk +++ b/packages/SettingsLib/Android.mk @@ -3,6 +3,8 @@ include $(CLEAR_VARS) LOCAL_USE_AAPT2 := true +LOCAL_AAPT2_ONLY := true + LOCAL_MODULE := SettingsLib LOCAL_JAVA_LIBRARIES := \ diff --git a/packages/SettingsLib/common.mk b/packages/SettingsLib/common.mk index 28f97d1948bd..5de3a6e99440 100644 --- a/packages/SettingsLib/common.mk +++ b/packages/SettingsLib/common.mk @@ -13,7 +13,6 @@ # include frameworks/base/packages/SettingsLib/common.mk # -ifeq ($(LOCAL_USE_AAPT2),true) LOCAL_STATIC_JAVA_LIBRARIES += \ android-support-annotations \ android-arch-lifecycle-common @@ -26,45 +25,4 @@ LOCAL_STATIC_ANDROID_LIBRARIES += \ android-support-v7-appcompat \ android-support-v14-preference \ SettingsLib -else -LOCAL_RESOURCE_DIR += $(call my-dir)/res - -## Include transitive dependencies below - -# Include support-v7-appcompat, if not already included -ifeq (,$(findstring android-support-v7-appcompat,$(LOCAL_STATIC_JAVA_LIBRARIES))) -LOCAL_RESOURCE_DIR += prebuilts/sdk/current/support/v7/appcompat/res -LOCAL_AAPT_FLAGS += --extra-packages android.support.v7.appcompat -LOCAL_STATIC_JAVA_LIBRARIES += android-support-v7-appcompat -endif - -# Include support-v7-recyclerview, if not already included -ifeq (,$(findstring android-support-v7-recyclerview,$(LOCAL_STATIC_JAVA_LIBRARIES))) -LOCAL_RESOURCE_DIR += prebuilts/sdk/current/support/v7/recyclerview/res -LOCAL_AAPT_FLAGS += --extra-packages android.support.v7.recyclerview -LOCAL_STATIC_JAVA_LIBRARIES += android-support-v7-recyclerview -endif - -# Include android-support-v7-preference, if not already included -ifeq (,$(findstring android-support-v7-preference,$(LOCAL_STATIC_JAVA_LIBRARIES))) -LOCAL_RESOURCE_DIR += prebuilts/sdk/current/support/v7/preference/res -LOCAL_AAPT_FLAGS += --extra-packages android.support.v7.preference -LOCAL_STATIC_JAVA_LIBRARIES += android-support-v7-preference -endif - -# Include android-support-v14-preference, if not already included -ifeq (,$(findstring android-support-v14-preference,$(LOCAL_STATIC_JAVA_LIBRARIES))) -LOCAL_AAPT_FLAGS += --extra-packages android.support.v14.preference -LOCAL_STATIC_JAVA_LIBRARIES += android-support-v14-preference -endif - -LOCAL_AAPT_FLAGS += --auto-add-overlay --extra-packages com.android.settingslib - -LOCAL_STATIC_JAVA_LIBRARIES += \ - android-support-annotations \ - android-support-v4 \ - android-arch-lifecycle-runtime \ - android-arch-lifecycle-common \ - SettingsLib -endif -- GitLab From 27926edc3b737823bd6bc3146b6e73a69f8dfe3a Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Tue, 27 Mar 2018 13:28:42 -0700 Subject: [PATCH 060/179] Indicate whether BandConfig initialization is required or not. The broadcastradio HAL 1.x requires waiting for onConfigChanged callback to indicate the initialization is done, while HAL 2.0 does not have the config setting (at the tuner session level) at all. This change makes it possible to cleanly workaround race condition in the radio app retaining support for both HAL revisions. Future versions of the RadioManager will provide a method to open a session without taking care about these nuances. Bug: 74353024 Test: manual Change-Id: I5de2d5e5c33626fcf0cfbbaf121d0b13e53d0bae --- api/system-current.txt | 1 + .../android/hardware/radio/RadioManager.java | 25 ++++++++++++++++--- .../server/broadcastradio/hal2/Convert.java | 1 + services/core/jni/BroadcastRadio/convert.cpp | 9 ++++--- 4 files changed, 29 insertions(+), 7 deletions(-) diff --git a/api/system-current.txt b/api/system-current.txt index e049f5316c72..84d874bfd9f9 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -2103,6 +2103,7 @@ package android.hardware.radio { method public java.lang.String getVersion(); method public boolean isBackgroundScanningSupported(); method public boolean isCaptureSupported(); + method public boolean isInitializationRequired(); method public boolean isProgramIdentifierSupported(int); method public boolean isProgramTypeSupported(int); method public void writeToParcel(android.os.Parcel, int); diff --git a/core/java/android/hardware/radio/RadioManager.java b/core/java/android/hardware/radio/RadioManager.java index 8fde82ef2012..8263bb8dfd2d 100644 --- a/core/java/android/hardware/radio/RadioManager.java +++ b/core/java/android/hardware/radio/RadioManager.java @@ -211,6 +211,7 @@ public class RadioManager { private final String mSerial; private final int mNumTuners; private final int mNumAudioSources; + private final boolean mIsInitializationRequired; private final boolean mIsCaptureSupported; private final BandDescriptor[] mBands; private final boolean mIsBgScanSupported; @@ -222,7 +223,8 @@ public class RadioManager { /** @hide */ public ModuleProperties(int id, String serviceName, int classId, String implementor, String product, String version, String serial, int numTuners, int numAudioSources, - boolean isCaptureSupported, BandDescriptor[] bands, boolean isBgScanSupported, + boolean isInitializationRequired, boolean isCaptureSupported, + BandDescriptor[] bands, boolean isBgScanSupported, @ProgramSelector.ProgramType int[] supportedProgramTypes, @ProgramSelector.IdentifierType int[] supportedIdentifierTypes, @Nullable Map dabFrequencyTable, @@ -236,6 +238,7 @@ public class RadioManager { mSerial = serial; mNumTuners = numTuners; mNumAudioSources = numAudioSources; + mIsInitializationRequired = isInitializationRequired; mIsCaptureSupported = isCaptureSupported; mBands = bands; mIsBgScanSupported = isBgScanSupported; @@ -329,6 +332,18 @@ public class RadioManager { return mNumAudioSources; } + /** + * Checks, if BandConfig initialization (after {@link RadioManager#openTuner}) + * is required to be done before other operations or not. + * + * If it is, the client has to wait for {@link RadioTuner.Callback#onConfigurationChanged} + * callback before executing any other operations. Otherwise, such operation will fail + * returning {@link RadioManager#STATUS_INVALID_OPERATION} error code. + */ + public boolean isInitializationRequired() { + return mIsInitializationRequired; + } + /** {@code true} if audio capture is possible from radio tuner output. * This indicates if routing to audio devices not connected to the same HAL as the FM radio * is possible (e.g. to USB) or DAR (Digital Audio Recorder) feature can be implemented. @@ -419,6 +434,7 @@ public class RadioManager { mSerial = in.readString(); mNumTuners = in.readInt(); mNumAudioSources = in.readInt(); + mIsInitializationRequired = in.readInt() == 1; mIsCaptureSupported = in.readInt() == 1; Parcelable[] tmp = in.readParcelableArray(BandDescriptor.class.getClassLoader()); mBands = new BandDescriptor[tmp.length]; @@ -454,6 +470,7 @@ public class RadioManager { dest.writeString(mSerial); dest.writeInt(mNumTuners); dest.writeInt(mNumAudioSources); + dest.writeInt(mIsInitializationRequired ? 1 : 0); dest.writeInt(mIsCaptureSupported ? 1 : 0); dest.writeParcelableArray(mBands, flags); dest.writeInt(mIsBgScanSupported ? 1 : 0); @@ -476,6 +493,7 @@ public class RadioManager { + ", mVersion=" + mVersion + ", mSerial=" + mSerial + ", mNumTuners=" + mNumTuners + ", mNumAudioSources=" + mNumAudioSources + + ", mIsInitializationRequired=" + mIsInitializationRequired + ", mIsCaptureSupported=" + mIsCaptureSupported + ", mIsBgScanSupported=" + mIsBgScanSupported + ", mBands=" + Arrays.toString(mBands) + "]"; @@ -484,8 +502,8 @@ public class RadioManager { @Override public int hashCode() { return Objects.hash(mId, mServiceName, mClassId, mImplementor, mProduct, mVersion, - mSerial, mNumTuners, mNumAudioSources, mIsCaptureSupported, mBands, - mIsBgScanSupported, mDabFrequencyTable, mVendorInfo); + mSerial, mNumTuners, mNumAudioSources, mIsInitializationRequired, + mIsCaptureSupported, mBands, mIsBgScanSupported, mDabFrequencyTable, mVendorInfo); } @Override @@ -503,6 +521,7 @@ public class RadioManager { if (!Objects.equals(mSerial, other.mSerial)) return false; if (mNumTuners != other.mNumTuners) return false; if (mNumAudioSources != other.mNumAudioSources) return false; + if (mIsInitializationRequired != other.mIsInitializationRequired) return false; if (mIsCaptureSupported != other.mIsCaptureSupported) return false; if (!Objects.equals(mBands, other.mBands)) return false; if (mIsBgScanSupported != other.mIsBgScanSupported) return false; diff --git a/services/core/java/com/android/server/broadcastradio/hal2/Convert.java b/services/core/java/com/android/server/broadcastradio/hal2/Convert.java index 6919282054ed..248151ca2bd3 100644 --- a/services/core/java/com/android/server/broadcastradio/hal2/Convert.java +++ b/services/core/java/com/android/server/broadcastradio/hal2/Convert.java @@ -232,6 +232,7 @@ class Convert { * HAL implementation instance. */ 1, // numTuners 1, // numAudioSources + false, // isInitializationRequired false, // isCaptureSupported amfmConfigToBands(amfmConfig), diff --git a/services/core/jni/BroadcastRadio/convert.cpp b/services/core/jni/BroadcastRadio/convert.cpp index 847222ae4ba1..61b48c2e9316 100644 --- a/services/core/jni/BroadcastRadio/convert.cpp +++ b/services/core/jni/BroadcastRadio/convert.cpp @@ -380,6 +380,7 @@ static JavaRef ModulePropertiesFromHal(JNIEnv *env, const V1_0::Propert auto jProduct = make_javastr(env, prop10.product); auto jVersion = make_javastr(env, prop10.version); auto jSerial = make_javastr(env, prop10.serial); + constexpr bool isInitializationRequired = true; bool isBgScanSupported = prop11 ? prop11->supportsBackgroundScanning : false; auto jVendorInfo = prop11 ? VendorInfoFromHal(env, prop11->vendorInfo) : nullptr; @@ -394,9 +395,9 @@ static JavaRef ModulePropertiesFromHal(JNIEnv *env, const V1_0::Propert return make_javaref(env, env->NewObject(gjni.ModuleProperties.clazz, gjni.ModuleProperties.cstor, moduleId, jServiceName.get(), prop10.classId, jImplementor.get(), jProduct.get(), jVersion.get(), jSerial.get(), prop10.numTuners, - prop10.numAudioSources, prop10.supportsCapture, jBands.get(), isBgScanSupported, - jSupportedProgramTypes.get(), jSupportedIdentifierTypes.get(), nullptr, - jVendorInfo.get())); + prop10.numAudioSources, isInitializationRequired, prop10.supportsCapture, jBands.get(), + isBgScanSupported, jSupportedProgramTypes.get(), jSupportedIdentifierTypes.get(), + nullptr, jVendorInfo.get())); } JavaRef ModulePropertiesFromHal(JNIEnv *env, const V1_0::Properties &properties, @@ -712,7 +713,7 @@ void register_android_server_broadcastradio_convert(JNIEnv *env) { gjni.ModuleProperties.clazz = MakeGlobalRefOrDie(env, modulePropertiesClass); gjni.ModuleProperties.cstor = GetMethodIDOrDie(env, modulePropertiesClass, "", "(ILjava/lang/String;ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;" - "Ljava/lang/String;IIZ[Landroid/hardware/radio/RadioManager$BandDescriptor;Z" + "Ljava/lang/String;IIZZ[Landroid/hardware/radio/RadioManager$BandDescriptor;Z" "[I[ILjava/util/Map;Ljava/util/Map;)V"); auto programInfoClass = FindClassOrDie(env, "android/hardware/radio/RadioManager$ProgramInfo"); -- GitLab From e71df98e507f4ef85fa2640bfa35e4995045b2e9 Mon Sep 17 00:00:00 2001 From: Patrick Baumann Date: Wed, 28 Mar 2018 21:25:57 +0000 Subject: [PATCH 061/179] Revert "Install for all on replace" This reverts commit dccef33d901398b1f39a8fea4dd919d57c5643f2. Reason for revert: Breaks ADB install disabled setting Change-Id: Icad438c592eb8e3be2a321e41fd75f9d577b002f (cherry picked from commit d7b6815d2ca97e06de1594bc91ad7433c3165fe1) Fixes: 73948872 Bug: 64472557 --- .../java/com/android/server/pm/PackageManagerService.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index e08ec556c68f..a4b10d245d99 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -16810,12 +16810,6 @@ public class PackageManagerService extends IPackageManager.Stub if (userId != UserHandle.USER_ALL) { ps.setInstalled(true, userId); ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, userId, installerPackageName); - } else { - for (int currentUserId : sUserManager.getUserIds()) { - ps.setInstalled(true, currentUserId); - ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, currentUserId, - installerPackageName); - } } // When replacing an existing package, preserve the original install reason for all -- GitLab From a66e6385ee324e12b5b998631268fa78b18d57b9 Mon Sep 17 00:00:00 2001 From: Roshan Pius Date: Wed, 14 Mar 2018 16:10:16 -0700 Subject: [PATCH 062/179] wifi metrics(proto): Add new metrics for wifi native failures a) Add new metrics for supplicant & hostapd crash numbers. Also, create new failure metrics for softap turn on. b) Add metrics for unexpected interface down events. Bug: 71720421 Bug: 68716726 Test: Unit tests Change-Id: I9fd6e8bf8f42174a9d6a4ef8249656f804238408 --- proto/src/wifi.proto | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/proto/src/wifi.proto b/proto/src/wifi.proto index 9c74188d671e..160525294c0f 100644 --- a/proto/src/wifi.proto +++ b/proto/src/wifi.proto @@ -249,12 +249,12 @@ message WifiLog { optional int32 num_wificond_crashes = 54; // Indicates the number of times an error was encountered in - // Wifi HAL when wifi was turned on. - optional int32 num_wifi_on_failure_due_to_hal = 55; + // Wifi HAL on |WifiNative.setupInterfaceForClientMode|. + optional int32 num_setup_client_interface_failure_due_to_hal = 55; // Indicates the number of times an error was encountered in - // Wificond when wifi was turned on. - optional int32 num_wifi_on_failure_due_to_wificond = 56; + // Wificond on |WifiNative.setupInterfaceForClientMode|. + optional int32 num_setup_client_interface_failure_due_to_wificond = 56; // Wi-Fi Aware metrics optional WifiAwareLog wifi_aware_log = 57; @@ -385,6 +385,34 @@ message WifiLog { // Histogram counting instances of scans with N many 802.11mc (RTT) supporting APs repeated NumConnectableNetworksBucket observed_80211mc_supporting_aps_in_scan_histogram = 95; + + // Total number of times supplicant crashed. + optional int32 num_supplicant_crashes = 96; + + // Total number of times hostapd crashed. + optional int32 num_hostapd_crashes = 97; + + // Indicates the number of times an error was encountered in + // supplicant on |WifiNative.setupInterfaceForClientMode|. + optional int32 num_setup_client_interface_failure_due_to_supplicant = 98; + + // Indicates the number of times an error was encountered in + // Wifi HAL on |WifiNative.setupInterfaceForSoftApMode|. + optional int32 num_setup_soft_ap_interface_failure_due_to_hal = 99; + + // Indicates the number of times an error was encountered in + // Wifi HAL on |WifiNative.setupInterfaceForSoftApMode|. + optional int32 num_setup_soft_ap_interface_failure_due_to_wificond = 100; + + // Indicates the number of times an error was encountered in + // Wifi HAL on |WifiNative.setupInterfaceForSoftApMode|. + optional int32 num_setup_soft_ap_interface_failure_due_to_hostapd = 101; + + // Indicates the number of times we got an interface down in client mode. + optional int32 num_client_interface_down = 102; + + // Indicates the number of times we got an interface down in softap mode. + optional int32 num_soft_ap_interface_down = 103; } // Information that gets logged for every WiFi connection. -- GitLab From d903074ea80e70bb02a433ecbcef5b3d72a7c6c9 Mon Sep 17 00:00:00 2001 From: Anton Philippov Date: Mon, 26 Mar 2018 19:12:08 +0100 Subject: [PATCH 063/179] Add FLAG_INCREMENTAL support to LocalTransport. Implement performBackup() with flags argument: 1. If FLAG_INCREMENTAL is passed and transport has no data for this package or supports only non-incremental backups, request a non-incremental retry. 2. If FLAG_NON_INCREMENTAL is passed, but transport has data, discard that data and continue. Bug: 72212840 Test: GTS test in the same topic Change-Id: I4c4a1dbfa1a807e4d4c523f42bb6a404a39731e9 --- .../internal/backup/LocalTransport.java | 43 +++++++++++++++++-- .../backup/LocalTransportParameters.java | 7 +++ 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/core/java/com/android/internal/backup/LocalTransport.java b/core/java/com/android/internal/backup/LocalTransport.java index b049db379341..f4b7032a774c 100644 --- a/core/java/com/android/internal/backup/LocalTransport.java +++ b/core/java/com/android/internal/backup/LocalTransport.java @@ -187,11 +187,27 @@ public class LocalTransport extends BackupTransport { @Override public int performBackup(PackageInfo packageInfo, ParcelFileDescriptor data) { + return performBackup(packageInfo, data, /*flags=*/ 0); + } + + @Override + public int performBackup(PackageInfo packageInfo, ParcelFileDescriptor data, int flags) { + boolean isIncremental = (flags & FLAG_INCREMENTAL) != 0; + boolean isNonIncremental = (flags & FLAG_NON_INCREMENTAL) != 0; + + if (isIncremental) { + Log.i(TAG, "Performing incremental backup for " + packageInfo.packageName); + } else if (isNonIncremental) { + Log.i(TAG, "Performing non-incremental backup for " + packageInfo.packageName); + } else { + Log.i(TAG, "Performing backup for " + packageInfo.packageName); + } + if (DEBUG) { try { - StructStat ss = Os.fstat(data.getFileDescriptor()); - Log.v(TAG, "performBackup() pkg=" + packageInfo.packageName - + " size=" + ss.st_size); + StructStat ss = Os.fstat(data.getFileDescriptor()); + Log.v(TAG, "performBackup() pkg=" + packageInfo.packageName + + " size=" + ss.st_size + " flags=" + flags); } catch (ErrnoException e) { Log.w(TAG, "Unable to stat input file in performBackup() on " + packageInfo.packageName); @@ -199,7 +215,26 @@ public class LocalTransport extends BackupTransport { } File packageDir = new File(mCurrentSetIncrementalDir, packageInfo.packageName); - packageDir.mkdirs(); + boolean hasDataForPackage = !packageDir.mkdirs(); + + if (isIncremental) { + if (mParameters.isNonIncrementalOnly() || !hasDataForPackage) { + if (mParameters.isNonIncrementalOnly()) { + Log.w(TAG, "Transport is in non-incremental only mode."); + + } else { + Log.w(TAG, + "Requested incremental, but transport currently stores no data for the " + + "package, requesting non-incremental retry."); + } + return TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED; + } + } + if (isNonIncremental && hasDataForPackage) { + Log.w(TAG, "Requested non-incremental, deleting existing data."); + clearBackupData(packageInfo); + packageDir.mkdirs(); + } // Each 'record' in the restore set is kept in its own file, named by // the record key. Wind through the data file, extracting individual diff --git a/core/java/com/android/internal/backup/LocalTransportParameters.java b/core/java/com/android/internal/backup/LocalTransportParameters.java index 154e79d4f7ef..2427d39fd65e 100644 --- a/core/java/com/android/internal/backup/LocalTransportParameters.java +++ b/core/java/com/android/internal/backup/LocalTransportParameters.java @@ -26,8 +26,10 @@ class LocalTransportParameters extends KeyValueSettingObserver { private static final String TAG = "LocalTransportParams"; private static final String SETTING = Settings.Secure.BACKUP_LOCAL_TRANSPORT_PARAMETERS; private static final String KEY_FAKE_ENCRYPTION_FLAG = "fake_encryption_flag"; + private static final String KEY_NON_INCREMENTAL_ONLY = "non_incremental_only"; private boolean mFakeEncryptionFlag; + private boolean mIsNonIncrementalOnly; LocalTransportParameters(Handler handler, ContentResolver resolver) { super(handler, resolver, Settings.Secure.getUriFor(SETTING)); @@ -37,11 +39,16 @@ class LocalTransportParameters extends KeyValueSettingObserver { return mFakeEncryptionFlag; } + boolean isNonIncrementalOnly() { + return mIsNonIncrementalOnly; + } + public String getSettingValue(ContentResolver resolver) { return Settings.Secure.getString(resolver, SETTING); } public void update(KeyValueListParser parser) { mFakeEncryptionFlag = parser.getBoolean(KEY_FAKE_ENCRYPTION_FLAG, false); + mIsNonIncrementalOnly = parser.getBoolean(KEY_NON_INCREMENTAL_ONLY, false); } } -- GitLab From 306ccc2d6bbb396e53f1a250da32003989a24b42 Mon Sep 17 00:00:00 2001 From: Yangster-mac Date: Sat, 24 Mar 2018 15:03:40 -0700 Subject: [PATCH 064/179] Guardrail for dimension in condition in duration tracker. Test: statsd test BUG: b/74437017 Change-Id: I349528e419ede817904f1e3884260c06651c6d0b --- cmds/statsd/src/guardrail/StatsdStats.cpp | 23 ++++++++ cmds/statsd/src/guardrail/StatsdStats.h | 19 ++++++ .../src/metrics/DurationMetricProducer.cpp | 59 ++++++++++++++----- cmds/statsd/src/stats_log.proto | 1 + 4 files changed, 87 insertions(+), 15 deletions(-) diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp index ef637df68ed3..22ff9428c83a 100644 --- a/cmds/statsd/src/guardrail/StatsdStats.cpp +++ b/cmds/statsd/src/guardrail/StatsdStats.cpp @@ -76,6 +76,7 @@ const int FIELD_ID_CONFIG_STATS_MATCHER_STATS = 13; const int FIELD_ID_CONFIG_STATS_CONDITION_STATS = 14; const int FIELD_ID_CONFIG_STATS_METRIC_STATS = 15; const int FIELD_ID_CONFIG_STATS_ALERT_STATS = 16; +const int FIELD_ID_CONFIG_STATS_METRIC_DIMENSION_IN_CONDITION_STATS = 17; const int FIELD_ID_MATCHER_STATS_ID = 1; const int FIELD_ID_MATCHER_STATS_COUNT = 2; @@ -255,6 +256,20 @@ void StatsdStats::noteMetricDimensionSize(const ConfigKey& key, const int64_t& i } } +void StatsdStats::noteMetricDimensionInConditionSize( + const ConfigKey& key, const int64_t& id, int size) { + lock_guard lock(mLock); + // if name doesn't exist before, it will create the key with count 0. + auto statsIt = mConfigStats.find(key); + if (statsIt == mConfigStats.end()) { + return; + } + auto& metricsDimensionMap = statsIt->second->metric_dimension_in_condition_stats; + if (size > metricsDimensionMap[id]) { + metricsDimensionMap[id] = size; + } +} + void StatsdStats::noteMatcherMatched(const ConfigKey& key, const int64_t& id) { lock_guard lock(mLock); @@ -339,6 +354,7 @@ void StatsdStats::resetInternalLocked() { config.second->matcher_stats.clear(); config.second->condition_stats.clear(); config.second->metric_stats.clear(); + config.second->metric_dimension_in_condition_stats.clear(); config.second->alert_stats.clear(); } } @@ -504,6 +520,13 @@ void addConfigStatsToProto(const ConfigStats& configStats, ProtoOutputStream* pr proto->write(FIELD_TYPE_INT32 | FIELD_ID_METRIC_STATS_COUNT, pair.second); proto->end(tmpToken); } + for (const auto& pair : configStats.metric_dimension_in_condition_stats) { + uint64_t tmpToken = proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | + FIELD_ID_CONFIG_STATS_METRIC_DIMENSION_IN_CONDITION_STATS); + proto->write(FIELD_TYPE_INT64 | FIELD_ID_METRIC_STATS_ID, (long long)pair.first); + proto->write(FIELD_TYPE_INT32 | FIELD_ID_METRIC_STATS_COUNT, pair.second); + proto->end(tmpToken); + } for (const auto& pair : configStats.alert_stats) { uint64_t tmpToken = proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h index 7f8755b8c1e0..bd395c4c232b 100644 --- a/cmds/statsd/src/guardrail/StatsdStats.h +++ b/cmds/statsd/src/guardrail/StatsdStats.h @@ -57,6 +57,12 @@ struct ConfigStats { // it means some data has been dropped. The map size is capped by kMaxConfigCount. std::map metric_stats; + // Stores the max number of output tuple of dimensions in condition across dimensions in what + // when it's bigger than kDimensionKeySizeSoftLimit. When you see the number is + // kDimensionKeySizeHardLimit +1, it means some data has been dropped. The map size is capped by + // kMaxConfigCount. + std::map metric_dimension_in_condition_stats; + // Stores the number of times an anomaly detection alert has been declared. // The map size is capped by kMaxConfigCount. std::map alert_stats; @@ -183,6 +189,19 @@ public: */ void noteMetricDimensionSize(const ConfigKey& key, const int64_t& id, int size); + + /** + * Report the max size of output tuple of dimension in condition across dimensions in what. + * + * Note: only report when the metric has an output dimension in condition, and the max tuple + * count > kDimensionKeySizeSoftLimit. + * + * [key]: The config key that this metric belongs to. + * [id]: The id of the metric. + * [size]: The output tuple size. + */ + void noteMetricDimensionInConditionSize(const ConfigKey& key, const int64_t& id, int size); + /** * Report a matcher has been matched. * diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp index c28bb8800e20..f02f30756b2d 100644 --- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp +++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp @@ -308,11 +308,14 @@ void DurationMetricProducer::onSlicedConditionMayChangeLocked_opt2(bool conditio if (mMetric2ConditionLinks.size() == 0 || trueDim.contains(linkedConditionDimensionKey)) { if (!whatIt.second.empty()) { + auto newEventKey = MetricDimensionKey(whatIt.first, trueDim); + if (hitGuardRailLocked(newEventKey)) { + continue; + } unique_ptr newTracker = whatIt.second.begin()->second->clone(eventTime); if (newTracker != nullptr) { - newTracker->setEventKey( - MetricDimensionKey(whatIt.first, trueDim)); + newTracker->setEventKey(newEventKey); newTracker->onConditionChanged(true, eventTime); whatIt.second[trueDim] = std::move(newTracker); } @@ -370,11 +373,14 @@ void DurationMetricProducer::onSlicedConditionMayChangeLocked(bool overallCondit for (const auto& conditionDimension : conditionDimensionsKeySet) { for (auto& whatIt : mCurrentSlicedDurationTrackerMap) { if (!whatIt.second.empty()) { + auto newEventKey = MetricDimensionKey(whatIt.first, conditionDimension); + if (hitGuardRailLocked(newEventKey)) { + continue; + } unique_ptr newTracker = whatIt.second.begin()->second->clone(eventTime); if (newTracker != nullptr) { - newTracker->setEventKey(MetricDimensionKey( - whatIt.first, conditionDimension)); + newTracker->setEventKey(MetricDimensionKey(newEventKey)); newTracker->onSlicedConditionMayChange(overallCondition, eventTime); whatIt.second[conditionDimension] = std::move(newTracker); } @@ -397,10 +403,13 @@ void DurationMetricProducer::onSlicedConditionMayChangeLocked(bool overallCondit for (const auto& conditionDimension : conditionDimensionsKeys) { if (!whatIt.second.empty() && whatIt.second.find(conditionDimension) == whatIt.second.end()) { + auto newEventKey = MetricDimensionKey(whatIt.first, conditionDimension); + if (hitGuardRailLocked(newEventKey)) { + continue; + } auto newTracker = whatIt.second.begin()->second->clone(eventTime); if (newTracker != nullptr) { - newTracker->setEventKey( - MetricDimensionKey(whatIt.first, conditionDimension)); + newTracker->setEventKey(newEventKey); newTracker->onSlicedConditionMayChange(overallCondition, eventTime); whatIt.second[conditionDimension] = std::move(newTracker); } @@ -552,15 +561,35 @@ void DurationMetricProducer::dumpStatesLocked(FILE* out, bool verbose) const { } bool DurationMetricProducer::hitGuardRailLocked(const MetricDimensionKey& newKey) { - // 1. Report the tuple count if the tuple count > soft limit - if (mCurrentSlicedDurationTrackerMap.size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) { - size_t newTupleCount = mCurrentSlicedDurationTrackerMap.size() + 1; - StatsdStats::getInstance().noteMetricDimensionSize(mConfigKey, mMetricId, newTupleCount); - // 2. Don't add more tuples, we are above the allowed threshold. Drop the data. - if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) { - ALOGE("DurationMetric %lld dropping data for dimension key %s", - (long long)mMetricId, newKey.toString().c_str()); - return true; + auto whatIt = mCurrentSlicedDurationTrackerMap.find(newKey.getDimensionKeyInWhat()); + if (whatIt != mCurrentSlicedDurationTrackerMap.end()) { + auto condIt = whatIt->second.find(newKey.getDimensionKeyInCondition()); + if (condIt != whatIt->second.end()) { + return false; + } + if (whatIt->second.size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) { + size_t newTupleCount = whatIt->second.size() + 1; + StatsdStats::getInstance().noteMetricDimensionInConditionSize( + mConfigKey, mMetricId, newTupleCount); + // 2. Don't add more tuples, we are above the allowed threshold. Drop the data. + if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) { + ALOGE("DurationMetric %lld dropping data for condition dimension key %s", + (long long)mMetricId, newKey.getDimensionKeyInCondition().toString().c_str()); + return true; + } + } + } else { + // 1. Report the tuple count if the tuple count > soft limit + if (mCurrentSlicedDurationTrackerMap.size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) { + size_t newTupleCount = mCurrentSlicedDurationTrackerMap.size() + 1; + StatsdStats::getInstance().noteMetricDimensionSize( + mConfigKey, mMetricId, newTupleCount); + // 2. Don't add more tuples, we are above the allowed threshold. Drop the data. + if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) { + ALOGE("DurationMetric %lld dropping data for what dimension key %s", + (long long)mMetricId, newKey.getDimensionKeyInWhat().toString().c_str()); + return true; + } } } return false; diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto index dd3b37c8c2d7..a25df3fc4c09 100644 --- a/cmds/statsd/src/stats_log.proto +++ b/cmds/statsd/src/stats_log.proto @@ -241,6 +241,7 @@ message StatsdStatsReport { repeated ConditionStats condition_stats = 14; repeated MetricStats metric_stats = 15; repeated AlertStats alert_stats = 16; + repeated MetricStats metric_dimension_in_condition_stats = 17; } repeated ConfigStats config_stats = 3; -- GitLab From a1652cfcce547183a426cc710691c740b2e46aa7 Mon Sep 17 00:00:00 2001 From: Jan Althaus Date: Thu, 29 Mar 2018 17:51:57 +0200 Subject: [PATCH 065/179] Switch reference time to ZonedDateTime Bug: 74838195 Test: atest FrameworksCoreTests:TextClassificationManagerTest Test: atest FrameworksCoreTests:TextClassificationTest Test: atest CtsViewTestCases:TextClassificationManagerTest Test: atest CtsViewTestCases:TextClassifierValueObjectsTest Change-Id: I0df9dddf415fa558435553336a8a0a15621e9b05 --- api/current.txt | 4 +- .../textclassifier/TextClassification.java | 12 ++-- .../textclassifier/TextClassifierImpl.java | 62 ++++++++++--------- .../TextClassificationTest.java | 10 +-- 4 files changed, 46 insertions(+), 42 deletions(-) diff --git a/api/current.txt b/api/current.txt index af042fb49630..29dbf62a86c1 100644 --- a/api/current.txt +++ b/api/current.txt @@ -50411,9 +50411,9 @@ package android.view.textclassifier { ctor public TextClassification.Options(); method public int describeContents(); method public android.os.LocaleList getDefaultLocales(); - method public java.util.Calendar getReferenceTime(); + method public java.time.ZonedDateTime getReferenceTime(); method public android.view.textclassifier.TextClassification.Options setDefaultLocales(android.os.LocaleList); - method public android.view.textclassifier.TextClassification.Options setReferenceTime(java.util.Calendar); + method public android.view.textclassifier.TextClassification.Options setReferenceTime(java.time.ZonedDateTime); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator CREATOR; } diff --git a/core/java/android/view/textclassifier/TextClassification.java b/core/java/android/view/textclassifier/TextClassification.java index 630007bad9b1..b413d48c6c78 100644 --- a/core/java/android/view/textclassifier/TextClassification.java +++ b/core/java/android/view/textclassifier/TextClassification.java @@ -43,8 +43,8 @@ import com.android.internal.util.Preconditions; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.time.ZonedDateTime; import java.util.ArrayList; -import java.util.Calendar; import java.util.Collections; import java.util.List; import java.util.Locale; @@ -512,7 +512,7 @@ public final class TextClassification implements Parcelable { public static final class Options implements Parcelable { private @Nullable LocaleList mDefaultLocales; - private @Nullable Calendar mReferenceTime; + private @Nullable ZonedDateTime mReferenceTime; public Options() {} @@ -531,7 +531,7 @@ public final class TextClassification implements Parcelable { * be interpreted. This should usually be the time when the text was originally * composed. If no reference time is set, now is used. */ - public Options setReferenceTime(Calendar referenceTime) { + public Options setReferenceTime(ZonedDateTime referenceTime) { mReferenceTime = referenceTime; return this; } @@ -550,7 +550,7 @@ public final class TextClassification implements Parcelable { * interpreted. */ @Nullable - public Calendar getReferenceTime() { + public ZonedDateTime getReferenceTime() { return mReferenceTime; } @@ -567,7 +567,7 @@ public final class TextClassification implements Parcelable { } dest.writeInt(mReferenceTime != null ? 1 : 0); if (mReferenceTime != null) { - dest.writeSerializable(mReferenceTime); + dest.writeString(mReferenceTime.toString()); } } @@ -589,7 +589,7 @@ public final class TextClassification implements Parcelable { mDefaultLocales = LocaleList.CREATOR.createFromParcel(in); } if (in.readInt() > 0) { - mReferenceTime = (Calendar) in.readSerializable(); + mReferenceTime = ZonedDateTime.parse(in.readString()); } } } diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java index 5ba470afd961..8d1ed0eb68cb 100644 --- a/core/java/android/view/textclassifier/TextClassifierImpl.java +++ b/core/java/android/view/textclassifier/TextClassifierImpl.java @@ -16,6 +16,8 @@ package android.view.textclassifier; +import static java.time.temporal.ChronoUnit.MILLIS; + import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.WorkerThread; @@ -45,9 +47,10 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; +import java.time.Instant; +import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.Arrays; -import java.util.Calendar; import java.util.Collection; import java.util.Collections; import java.util.HashMap; @@ -119,7 +122,7 @@ public final class TextClassifierImpl implements TextClassifier { && rangeLength <= mSettings.getSuggestSelectionMaxRangeLength()) { final LocaleList locales = (options == null) ? null : options.getDefaultLocales(); final String localesString = concatenateLocales(locales); - final Calendar refTime = Calendar.getInstance(); + final ZonedDateTime refTime = ZonedDateTime.now(); final boolean darkLaunchAllowed = options != null && options.isDarkLaunchAllowed(); final TextClassifierImplNative nativeImpl = getNative(locales); final String string = text.toString(); @@ -143,8 +146,8 @@ public final class TextClassifierImpl implements TextClassifier { nativeImpl.classifyText( string, start, end, new TextClassifierImplNative.ClassificationOptions( - refTime.getTimeInMillis(), - refTime.getTimeZone().getID(), + refTime.toInstant().toEpochMilli(), + refTime.getZone().getId(), localesString)); final int size = results.length; for (int i = 0; i < size; i++) { @@ -183,19 +186,20 @@ public final class TextClassifierImpl implements TextClassifier { final String string = text.toString(); final LocaleList locales = (options == null) ? null : options.getDefaultLocales(); final String localesString = concatenateLocales(locales); - final Calendar refTime = (options != null && options.getReferenceTime() != null) - ? options.getReferenceTime() : Calendar.getInstance(); + final ZonedDateTime refTime = + (options != null && options.getReferenceTime() != null) + ? options.getReferenceTime() : ZonedDateTime.now(); final TextClassifierImplNative.ClassificationResult[] results = getNative(locales) .classifyText(string, startIndex, endIndex, new TextClassifierImplNative.ClassificationOptions( - refTime.getTimeInMillis(), - refTime.getTimeZone().getID(), + refTime.toInstant().toEpochMilli(), + refTime.getZone().getId(), localesString)); if (results.length > 0) { return createClassificationResult( - results, string, startIndex, endIndex, refTime); + results, string, startIndex, endIndex, refTime.toInstant()); } } } catch (Throwable t) { @@ -224,7 +228,7 @@ public final class TextClassifierImpl implements TextClassifier { try { final long startTimeMs = System.currentTimeMillis(); final LocaleList defaultLocales = options != null ? options.getDefaultLocales() : null; - final Calendar refTime = Calendar.getInstance(); + final ZonedDateTime refTime = ZonedDateTime.now(); final Collection entitiesToIdentify = options != null && options.getEntityConfig() != null ? options.getEntityConfig().resolveEntityListModifications( @@ -236,8 +240,8 @@ public final class TextClassifierImpl implements TextClassifier { nativeImpl.annotate( textString, new TextClassifierImplNative.AnnotationOptions( - refTime.getTimeInMillis(), - refTime.getTimeZone().getID(), + refTime.toInstant().toEpochMilli(), + refTime.getZone().getId(), concatenateLocales(defaultLocales))); for (TextClassifierImplNative.AnnotatedSpan span : annotations) { final TextClassifierImplNative.ClassificationResult[] results = @@ -416,7 +420,7 @@ public final class TextClassifierImpl implements TextClassifier { private TextClassification createClassificationResult( TextClassifierImplNative.ClassificationResult[] classifications, - String text, int start, int end, @Nullable Calendar referenceTime) { + String text, int start, int end, @Nullable Instant referenceTime) { final String classifiedText = text.substring(start, end); final TextClassification.Builder builder = new TextClassification.Builder() .setText(classifiedText); @@ -646,7 +650,7 @@ public final class TextClassifierImpl implements TextClassifier { @NonNull public static List create( Context context, - @Nullable Calendar referenceTime, + @Nullable Instant referenceTime, TextClassifierImplNative.ClassificationResult classification, String text) { final String type = classification.getCollection().trim().toLowerCase(Locale.ENGLISH); @@ -663,10 +667,9 @@ public final class TextClassifierImpl implements TextClassifier { case TextClassifier.TYPE_DATE: case TextClassifier.TYPE_DATE_TIME: if (classification.getDatetimeResult() != null) { - Calendar eventTime = Calendar.getInstance(); - eventTime.setTimeInMillis( + final Instant parsedTime = Instant.ofEpochMilli( classification.getDatetimeResult().getTimeMsUtc()); - return createForDatetime(context, type, referenceTime, eventTime); + return createForDatetime(context, type, referenceTime, parsedTime); } else { return new ArrayList<>(); } @@ -758,18 +761,17 @@ public final class TextClassifierImpl implements TextClassifier { @NonNull private static List createForDatetime( - Context context, String type, @Nullable Calendar referenceTime, - Calendar eventTime) { + Context context, String type, @Nullable Instant referenceTime, + Instant parsedTime) { if (referenceTime == null) { // If no reference time was given, use now. - referenceTime = Calendar.getInstance(); + referenceTime = Instant.now(); } List actions = new ArrayList<>(); - actions.add(createCalendarViewIntent(context, eventTime)); - final long millisSinceReference = - eventTime.getTimeInMillis() - referenceTime.getTimeInMillis(); - if (millisSinceReference > MIN_EVENT_FUTURE_MILLIS) { - actions.add(createCalendarCreateEventIntent(context, eventTime, type)); + actions.add(createCalendarViewIntent(context, parsedTime)); + final long millisUntilEvent = referenceTime.until(parsedTime, MILLIS); + if (millisUntilEvent > MIN_EVENT_FUTURE_MILLIS) { + actions.add(createCalendarCreateEventIntent(context, parsedTime, type)); } return actions; } @@ -784,10 +786,10 @@ public final class TextClassifierImpl implements TextClassifier { } @NonNull - private static LabeledIntent createCalendarViewIntent(Context context, Calendar eventTime) { + private static LabeledIntent createCalendarViewIntent(Context context, Instant parsedTime) { Uri.Builder builder = CalendarContract.CONTENT_URI.buildUpon(); builder.appendPath("time"); - ContentUris.appendId(builder, eventTime.getTimeInMillis()); + ContentUris.appendId(builder, parsedTime.toEpochMilli()); return new LabeledIntent( context.getString(com.android.internal.R.string.view_calendar), context.getString(com.android.internal.R.string.view_calendar_desc), @@ -796,7 +798,7 @@ public final class TextClassifierImpl implements TextClassifier { @NonNull private static LabeledIntent createCalendarCreateEventIntent( - Context context, Calendar eventTime, @EntityType String type) { + Context context, Instant parsedTime, @EntityType String type) { final boolean isAllDay = TextClassifier.TYPE_DATE.equals(type); return new LabeledIntent( context.getString(com.android.internal.R.string.add_calendar_event), @@ -805,9 +807,9 @@ public final class TextClassifierImpl implements TextClassifier { .setData(CalendarContract.Events.CONTENT_URI) .putExtra(CalendarContract.EXTRA_EVENT_ALL_DAY, isAllDay) .putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, - eventTime.getTimeInMillis()) + parsedTime.toEpochMilli()) .putExtra(CalendarContract.EXTRA_EVENT_END_TIME, - eventTime.getTimeInMillis() + DEFAULT_EVENT_DURATION)); + parsedTime.toEpochMilli() + DEFAULT_EVENT_DURATION)); } } } diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java index afc4bd5aa783..5d58f550b3f5 100644 --- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java +++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java @@ -37,9 +37,10 @@ import android.view.View; import org.junit.Test; import org.junit.runner.RunWith; -import java.util.Calendar; +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZonedDateTime; import java.util.Locale; -import java.util.TimeZone; @SmallTest @RunWith(AndroidJUnit4.class) @@ -163,8 +164,9 @@ public class TextClassificationTest { @Test public void testParcelOptions() { - Calendar referenceTime = Calendar.getInstance(TimeZone.getTimeZone("UTC"), Locale.US); - referenceTime.setTimeInMillis(946771200000L); // 2000-01-02 + ZonedDateTime referenceTime = ZonedDateTime.ofInstant( + Instant.ofEpochMilli(946771200000L), // 2000-01-02 + ZoneId.of("UTC")); TextClassification.Options reference = new TextClassification.Options(); reference.setDefaultLocales(new LocaleList(Locale.US, Locale.GERMANY)); -- GitLab From 540f7adf289585f63509107f629ec7b2de7866a3 Mon Sep 17 00:00:00 2001 From: Jaekyun Seok Date: Fri, 30 Mar 2018 00:31:57 +0900 Subject: [PATCH 066/179] Clean up codes holding mInstallLock in PackageParserCallback Bug: 77232370 Test: succeeded building and tested with taimen Change-Id: Id588cffdcd63684abcb115532bed597d8ca10924 --- .../server/pm/PackageManagerService.java | 39 ++++++++----------- 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index e08ec556c68f..b0b313b80ed8 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -808,7 +808,7 @@ public class PackageManagerService extends IPackageManager.Stub } final String[] getStaticOverlayPaths(List overlayPackages, - String targetPath, Object installLock) { + String targetPath) { if (overlayPackages == null || overlayPackages.isEmpty()) { return null; } @@ -828,20 +828,9 @@ public class PackageManagerService extends IPackageManager.Stub // // OverlayManagerService will update each of them with a correct gid from its // target package app id. - if (installLock != null) { - synchronized (installLock) { - mInstaller.idmap(targetPath, overlayPackage.baseCodePath, - UserHandle.getSharedAppGid( - UserHandle.getUserGid(UserHandle.USER_SYSTEM))); - } - } else { - // We can call mInstaller without holding mInstallLock because mInstallLock - // is held before running parallel parsing. - // Moreover holding mInstallLock on each parsing thread causes dead-lock. - mInstaller.idmap(targetPath, overlayPackage.baseCodePath, - UserHandle.getSharedAppGid( - UserHandle.getUserGid(UserHandle.USER_SYSTEM))); - } + mInstaller.idmap(targetPath, overlayPackage.baseCodePath, + UserHandle.getSharedAppGid( + UserHandle.getUserGid(UserHandle.USER_SYSTEM))); if (overlayPathList == null) { overlayPathList = new ArrayList(); } @@ -856,13 +845,15 @@ public class PackageManagerService extends IPackageManager.Stub String[] getStaticOverlayPaths(String targetPackageName, String targetPath) { List overlayPackages; - synchronized (mPackages) { - overlayPackages = getStaticOverlayPackages( - mPackages.values(), targetPackageName); + synchronized (mInstallLock) { + synchronized (mPackages) { + overlayPackages = getStaticOverlayPackages( + mPackages.values(), targetPackageName); + } + // It is safe to keep overlayPackages without holding mPackages because static overlay + // packages can't be uninstalled or disabled. + return getStaticOverlayPaths(overlayPackages, targetPath); } - // It is safe to keep overlayPackages without holding mPackages because static overlay - // packages can't be uninstalled or disabled. - return getStaticOverlayPaths(overlayPackages, targetPath, mInstallLock); } @Override public final String[] getOverlayApks(String targetPackageName) { @@ -895,11 +886,13 @@ public class PackageManagerService extends IPackageManager.Stub synchronized String[] getStaticOverlayPaths(String targetPackageName, String targetPath) { // We can trust mOverlayPackages without holding mPackages because package uninstall // can't happen while running parallel parsing. - // Moreover holding mPackages on each parsing thread causes dead-lock. + // And we can call mInstaller inside getStaticOverlayPaths without holding mInstallLock + // because mInstallLock is held before running parallel parsing. + // Moreover holding mPackages or mInstallLock on each parsing thread causes dead-lock. return mOverlayPackages == null ? null : getStaticOverlayPaths( getStaticOverlayPackages(mOverlayPackages, targetPackageName), - targetPath, null); + targetPath); } } -- GitLab From 9272dab49efa9c70ab92879c3e79a76fc8364d34 Mon Sep 17 00:00:00 2001 From: Brian Young Date: Fri, 23 Feb 2018 18:04:20 +0000 Subject: [PATCH 067/179] Restore "Add "Unlocked device required" parameter to keys" Add a keymaster parameter for keys that should be inaccessible when the device screen is locked. "Locked" here is a state where the device can be used or accessed without any further trust factor such as a PIN, password, fingerprint, or trusted face or voice. This parameter is added to the Java keystore interface for key creation and import, as well as enums specified by and for the native keystore process. This reverts commit da82e2cb7193032867f86b996467bcd117545616. Test: CTS tests in I8a5affd1eaed176756175158e3057e44934fffed Bug: 67752510 Merged-In: Ia162f1db81d050f64995d0360f714e79033ea8a5 Change-Id: Ia162f1db81d050f64995d0360f714e79033ea8a5 (cherry picked from d7c961ee914192e09ec10727da6d31a6b597bf51) --- keystore/java/android/security/KeyStore.java | 5 ++++- .../android/security/keystore/KeymasterUtils.java | 9 ++++++--- .../android/security/keystore/UserAuthArgs.java | 1 + .../policy/keyguard/KeyguardStateMonitor.java | 13 +++++++++++++ 4 files changed, 24 insertions(+), 4 deletions(-) diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java index 33ce582eda96..6837a630fa9a 100644 --- a/keystore/java/android/security/KeyStore.java +++ b/keystore/java/android/security/KeyStore.java @@ -16,6 +16,7 @@ package android.security; +import android.app.ActivityManager; import android.app.ActivityThread; import android.app.Application; import android.app.KeyguardManager; @@ -545,7 +546,9 @@ public class KeyStore { try { args = args != null ? args : new KeymasterArguments(); entropy = entropy != null ? entropy : new byte[0]; - // TODO(67752510): Apply USER_ID tag + if (!args.containsTag(KeymasterDefs.KM_TAG_USER_ID)) { + args.addUnsignedInt(KeymasterDefs.KM_TAG_USER_ID, ActivityManager.getCurrentUser()); + } return mBinder.begin(getToken(), alias, purpose, pruneable, args, entropy, uid); } catch (RemoteException e) { Log.w(TAG, "Cannot connect to keystore", e); diff --git a/keystore/java/android/security/keystore/KeymasterUtils.java b/keystore/java/android/security/keystore/KeymasterUtils.java index d194f0b9e4e9..6e5012160d6e 100644 --- a/keystore/java/android/security/keystore/KeymasterUtils.java +++ b/keystore/java/android/security/keystore/KeymasterUtils.java @@ -16,9 +16,8 @@ package android.security.keystore; -import android.util.Log; +import android.app.ActivityManager; import android.hardware.fingerprint.FingerprintManager; -import android.os.UserHandle; import android.security.GateKeeper; import android.security.KeyStore; import android.security.keymaster.KeymasterArguments; @@ -102,7 +101,7 @@ public abstract class KeymasterUtils { * require user authentication. */ public static void addUserAuthArgs(KeymasterArguments args, UserAuthArgs spec) { - // TODO (67752510): Implement "unlocked device required" + args.addUnsignedInt(KeymasterDefs.KM_TAG_USER_ID, ActivityManager.getCurrentUser()); if (spec.isUserConfirmationRequired()) { args.addBoolean(KeymasterDefs.KM_TAG_TRUSTED_CONFIRMATION_REQUIRED); @@ -112,6 +111,10 @@ public abstract class KeymasterUtils { args.addBoolean(KeymasterDefs.KM_TAG_TRUSTED_USER_PRESENCE_REQUIRED); } + if (spec.isUnlockedDeviceRequired()) { + args.addBoolean(KeymasterDefs.KM_TAG_UNLOCKED_DEVICE_REQUIRED); + } + if (!spec.isUserAuthenticationRequired()) { args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED); return; diff --git a/keystore/java/android/security/keystore/UserAuthArgs.java b/keystore/java/android/security/keystore/UserAuthArgs.java index 1949592e7240..ad18ff8aef76 100644 --- a/keystore/java/android/security/keystore/UserAuthArgs.java +++ b/keystore/java/android/security/keystore/UserAuthArgs.java @@ -33,5 +33,6 @@ public interface UserAuthArgs { boolean isUserConfirmationRequired(); long getBoundToSpecificSecureUserId(); boolean isTrustedUserPresenceRequired(); + boolean isUnlockedDeviceRequired(); } diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java index 37e79e70d70a..e56caf849aac 100644 --- a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java +++ b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java @@ -19,6 +19,8 @@ package com.android.server.policy.keyguard; import android.app.ActivityManager; import android.content.Context; import android.os.RemoteException; +import android.os.ServiceManager; +import android.security.IKeystoreService; import android.util.Slog; import com.android.internal.policy.IKeyguardService; @@ -51,11 +53,16 @@ public class KeyguardStateMonitor extends IKeyguardStateCallback.Stub { private final LockPatternUtils mLockPatternUtils; private final StateCallback mCallback; + IKeystoreService mKeystoreService; + public KeyguardStateMonitor(Context context, IKeyguardService service, StateCallback callback) { mLockPatternUtils = new LockPatternUtils(context); mCurrentUserId = ActivityManager.getCurrentUser(); mCallback = callback; + mKeystoreService = IKeystoreService.Stub.asInterface(ServiceManager + .getService("android.security.keystore")); + try { service.addStateMonitorCallback(this); } catch (RemoteException e) { @@ -86,6 +93,12 @@ public class KeyguardStateMonitor extends IKeyguardStateCallback.Stub { @Override // Binder interface public void onShowingStateChanged(boolean showing) { mIsShowing = showing; + + try { + mKeystoreService.onKeyguardVisibilityChanged(showing, mCurrentUserId); + } catch (RemoteException e) { + Slog.e(TAG, "Error informing keystore of screen lock", e); + } } @Override // Binder interface -- GitLab From 9e8749058039b92fbed6ecf5a78eb9bf0c45c0e8 Mon Sep 17 00:00:00 2001 From: "Brian C. Young" Date: Mon, 26 Mar 2018 11:40:13 -0700 Subject: [PATCH 068/179] Enable "Unlocked device required" API Remove the @hide annotations so the SDP asymmetric-write functionality is included in the public API. Test: CtsKeystoreTestCases Bug: 63928827 Change-Id: I8f462b0ebe4d9a7b96b48fa1672dd2ab9140c505 --- api/current.txt | 4 ++++ .../java/android/security/keystore/KeyGenParameterSpec.java | 4 ++-- keystore/java/android/security/keystore/KeyProtection.java | 4 ++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/api/current.txt b/api/current.txt index dda00ba8e94d..826795a4b978 100644 --- a/api/current.txt +++ b/api/current.txt @@ -38505,6 +38505,7 @@ package android.security.keystore { method public boolean isRandomizedEncryptionRequired(); method public boolean isStrongBoxBacked(); method public boolean isTrustedUserPresenceRequired(); + method public boolean isUnlockedDeviceRequired(); method public boolean isUserAuthenticationRequired(); method public boolean isUserAuthenticationValidWhileOnBody(); method public boolean isUserConfirmationRequired(); @@ -38532,6 +38533,7 @@ package android.security.keystore { method public android.security.keystore.KeyGenParameterSpec.Builder setRandomizedEncryptionRequired(boolean); method public android.security.keystore.KeyGenParameterSpec.Builder setSignaturePaddings(java.lang.String...); method public android.security.keystore.KeyGenParameterSpec.Builder setTrustedUserPresenceRequired(boolean); + method public android.security.keystore.KeyGenParameterSpec.Builder setUnlockedDeviceRequired(boolean); method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationRequired(boolean); method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationValidWhileOnBody(boolean); method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationValidityDurationSeconds(int); @@ -38624,6 +38626,7 @@ package android.security.keystore { method public boolean isInvalidatedByBiometricEnrollment(); method public boolean isRandomizedEncryptionRequired(); method public boolean isTrustedUserPresenceRequired(); + method public boolean isUnlockedDeviceRequired(); method public boolean isUserAuthenticationRequired(); method public boolean isUserAuthenticationValidWhileOnBody(); method public boolean isUserConfirmationRequired(); @@ -38643,6 +38646,7 @@ package android.security.keystore { method public android.security.keystore.KeyProtection.Builder setRandomizedEncryptionRequired(boolean); method public android.security.keystore.KeyProtection.Builder setSignaturePaddings(java.lang.String...); method public android.security.keystore.KeyProtection.Builder setTrustedUserPresenceRequired(boolean); + method public android.security.keystore.KeyProtection.Builder setUnlockedDeviceRequired(boolean); method public android.security.keystore.KeyProtection.Builder setUserAuthenticationRequired(boolean); method public android.security.keystore.KeyProtection.Builder setUserAuthenticationValidWhileOnBody(boolean); method public android.security.keystore.KeyProtection.Builder setUserAuthenticationValidityDurationSeconds(int); diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java index 5d596cbbbc44..c342acdf101e 100644 --- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java +++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java @@ -673,7 +673,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu } /** - * @hide Returns {@code true} if the key cannot be used unless the device screen is unlocked. + * Returns {@code true} if the key cannot be used unless the device screen is unlocked. * * @see Builder#setUnlockedDeviceRequired(boolean) */ @@ -1288,7 +1288,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu } /** - * @hide Sets whether the keystore requires the screen to be unlocked before allowing decryption + * Sets whether the keystore requires the screen to be unlocked before allowing decryption * using this key. If this is set to {@code true}, any attempt to decrypt using this key * while the screen is locked will fail. A locked device requires a PIN, password, * fingerprint, or other trusted factor to access. diff --git a/keystore/java/android/security/keystore/KeyProtection.java b/keystore/java/android/security/keystore/KeyProtection.java index cc7870ce1889..22568ce7a596 100644 --- a/keystore/java/android/security/keystore/KeyProtection.java +++ b/keystore/java/android/security/keystore/KeyProtection.java @@ -508,7 +508,7 @@ public final class KeyProtection implements ProtectionParameter, UserAuthArgs { } /** - * @hide Returns {@code true} if the key cannot be used unless the device screen is unlocked. + * Returns {@code true} if the key cannot be used unless the device screen is unlocked. * * @see Builder#setUnlockedDeviceRequired(boolean) */ @@ -928,7 +928,7 @@ public final class KeyProtection implements ProtectionParameter, UserAuthArgs { } /** - * @hide Sets whether the keystore requires the screen to be unlocked before allowing decryption + * Sets whether the keystore requires the screen to be unlocked before allowing decryption * using this key. If this is set to {@code true}, any attempt to decrypt using this key * while the screen is locked will fail. A locked device requires a PIN, password, * fingerprint, or other trusted factor to access. -- GitLab From 462e29da9ba854eb3651dd9664b09a2852a05141 Mon Sep 17 00:00:00 2001 From: Bryan Mawhinney Date: Thu, 22 Mar 2018 15:52:41 +0000 Subject: [PATCH 069/179] Add a SystemApi to control display saturation. Allows an app with the appropriate permission to reduce (make more gray) the saturation of colors on the display. Test: manual Bug: 77189882 Change-Id: I2b7b065d07bd2ca24730b2e8c52d161c22b307ab --- api/system-current.txt | 2 ++ .../hardware/display/DisplayManager.java | 13 +++++++ .../display/DisplayManagerGlobal.java | 11 ++++++ .../hardware/display/IDisplayManager.aidl | 3 ++ core/res/AndroidManifest.xml | 6 ++++ .../server/display/DisplayManagerService.java | 34 +++++++++++++++++++ .../display/DisplayTransformManager.java | 6 ++-- 7 files changed, 73 insertions(+), 2 deletions(-) diff --git a/api/system-current.txt b/api/system-current.txt index a81afed5ecdb..ed763babb7ef 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -57,6 +57,7 @@ package android { field public static final java.lang.String CONFIGURE_DISPLAY_BRIGHTNESS = "android.permission.CONFIGURE_DISPLAY_BRIGHTNESS"; field public static final java.lang.String CONNECTIVITY_INTERNAL = "android.permission.CONNECTIVITY_INTERNAL"; field public static final java.lang.String CONNECTIVITY_USE_RESTRICTED_NETWORKS = "android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS"; + field public static final java.lang.String CONTROL_DISPLAY_SATURATION = "android.permission.CONTROL_DISPLAY_SATURATION"; field public static final java.lang.String CONTROL_INCALL_EXPERIENCE = "android.permission.CONTROL_INCALL_EXPERIENCE"; field public static final java.lang.String CONTROL_LOCATION_UPDATES = "android.permission.CONTROL_LOCATION_UPDATES"; field public static final java.lang.String CONTROL_VPN = "android.permission.CONTROL_VPN"; @@ -1252,6 +1253,7 @@ package android.hardware.display { method public android.hardware.display.BrightnessConfiguration getDefaultBrightnessConfiguration(); method public android.graphics.Point getStableDisplaySize(); method public void setBrightnessConfiguration(android.hardware.display.BrightnessConfiguration); + method public void setSaturationLevel(float); } } diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java index a3b2d22deccb..efb9517adc00 100644 --- a/core/java/android/hardware/display/DisplayManager.java +++ b/core/java/android/hardware/display/DisplayManager.java @@ -534,6 +534,19 @@ public final class DisplayManager { return mGlobal.getWifiDisplayStatus(); } + /** + * Set the level of color saturation to apply to the display. + * @param level The amount of saturation to apply, between 0 and 1 inclusive. + * 0 produces a grayscale image, 1 is normal. + * + * @hide + */ + @SystemApi + @RequiresPermission(Manifest.permission.CONTROL_DISPLAY_SATURATION) + public void setSaturationLevel(float level) { + mGlobal.setSaturationLevel(level); + } + /** * Creates a virtual display. * diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java index 1f67a6bf71a7..2d0ef2f23432 100644 --- a/core/java/android/hardware/display/DisplayManagerGlobal.java +++ b/core/java/android/hardware/display/DisplayManagerGlobal.java @@ -384,6 +384,17 @@ public final class DisplayManagerGlobal { } } + /** + * Set the level of color saturation to apply to the display. + */ + public void setSaturationLevel(float level) { + try { + mDm.setSaturationLevel(level); + } catch (RemoteException ex) { + throw ex.rethrowFromSystemServer(); + } + } + public VirtualDisplay createVirtualDisplay(Context context, MediaProjection projection, String name, int width, int height, int densityDpi, Surface surface, int flags, VirtualDisplay.Callback callback, Handler handler, String uniqueId) { diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl index 9fcb9d3fc265..b77de748a987 100644 --- a/core/java/android/hardware/display/IDisplayManager.aidl +++ b/core/java/android/hardware/display/IDisplayManager.aidl @@ -65,6 +65,9 @@ interface IDisplayManager { // Requires CONFIGURE_DISPLAY_COLOR_MODE void requestColorMode(int displayId, int colorMode); + // Requires CONTROL_DISPLAY_SATURATION + void setSaturationLevel(float level); + // Requires CAPTURE_VIDEO_OUTPUT, CAPTURE_SECURE_VIDEO_OUTPUT, or an appropriate // MediaProjection token for certain combinations of flags. int createVirtualDisplay(in IVirtualDisplayCallback callback, diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index cb375d5394fa..f4715fc7645d 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -3121,6 +3121,12 @@ + + + @dimen/status_bar_height_landscape - - @dimen/status_bar_height_landscape - - 152dp + 40dip diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 354880cad6d2..cb8d629abaaf 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1670,7 +1670,6 @@ - diff --git a/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml b/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml index 388b6333c719..f38129f0dffa 100644 --- a/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml +++ b/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml @@ -31,23 +31,25 @@ + android:gravity="center_vertical|start" + systemui:showDark="false" + /> + android:gravity="center_vertical|center_horizontal" + /> - + android:gravity="center_vertical|end" + /> diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java index 0683514f6f2a..1ae06d751255 100644 --- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java +++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java @@ -81,14 +81,6 @@ public class BatteryMeterView extends LinearLayout implements private float mDarkIntensity; private int mUser; - /** - * Whether we should use colors that adapt based on wallpaper/the scrim behind quick settings. - */ - private boolean mUseWallpaperTextColors; - - private int mNonAdaptedForegroundColor; - private int mNonAdaptedBackgroundColor; - public BatteryMeterView(Context context) { this(context, null, 0); } @@ -148,29 +140,6 @@ public class BatteryMeterView extends LinearLayout implements updateShowPercent(); } - /** - * Sets whether the battery meter view uses the wallpaperTextColor. If we're not using it, we'll - * revert back to dark-mode-based/tinted colors. - * - * @param shouldUseWallpaperTextColor whether we should use wallpaperTextColor for all - * components - */ - public void useWallpaperTextColor(boolean shouldUseWallpaperTextColor) { - if (shouldUseWallpaperTextColor == mUseWallpaperTextColors) { - return; - } - - mUseWallpaperTextColors = shouldUseWallpaperTextColor; - - if (mUseWallpaperTextColors) { - updateColors( - Utils.getColorAttr(mContext, R.attr.wallpaperTextColor), - Utils.getColorAttr(mContext, R.attr.wallpaperTextColorSecondary)); - } else { - updateColors(mNonAdaptedForegroundColor, mNonAdaptedBackgroundColor); - } - } - public void setColorsFromContext(Context context) { if (context == null) { return; @@ -210,8 +179,7 @@ public class BatteryMeterView extends LinearLayout implements getContext().getContentResolver().registerContentObserver( Settings.System.getUriFor(SHOW_BATTERY_PERCENT), false, mSettingObserver, mUser); updateShowPercent(); - Dependency.get(TunerService.class) - .addTunable(this, StatusBarIconController.ICON_BLACKLIST); + Dependency.get(TunerService.class).addTunable(this, StatusBarIconController.ICON_BLACKLIST); Dependency.get(ConfigurationController.class).addCallback(this); mUserTracker.startTracking(); } @@ -305,23 +273,19 @@ public class BatteryMeterView extends LinearLayout implements @Override public void onDarkChanged(Rect area, float darkIntensity, int tint) { mDarkIntensity = darkIntensity; - float intensity = DarkIconDispatcher.isInArea(area, this) ? darkIntensity : 0; - mNonAdaptedForegroundColor = getColorForDarkIntensity( - intensity, mLightModeFillColor, mDarkModeFillColor); - mNonAdaptedBackgroundColor = getColorForDarkIntensity( - intensity, mLightModeBackgroundColor,mDarkModeBackgroundColor); - - if (!mUseWallpaperTextColors) { - updateColors(mNonAdaptedForegroundColor, mNonAdaptedBackgroundColor); - } + int foreground = getColorForDarkIntensity(intensity, mLightModeFillColor, + mDarkModeFillColor); + int background = getColorForDarkIntensity(intensity, mLightModeBackgroundColor, + mDarkModeBackgroundColor); + mDrawable.setColors(foreground, background); + setTextColor(foreground); } - private void updateColors(int foregroundColor, int backgroundColor) { - mDrawable.setColors(foregroundColor, backgroundColor); - mTextColor = foregroundColor; + public void setTextColor(int color) { + mTextColor = color; if (mBatteryPercentView != null) { - mBatteryPercentView.setTextColor(foregroundColor); + mBatteryPercentView.setTextColor(color); } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java index 71614634cd00..bfbfbf6fe813 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java @@ -18,15 +18,17 @@ package com.android.systemui.qs; import android.content.Context; import android.content.res.Configuration; +import android.graphics.Canvas; +import android.graphics.Path; import android.graphics.Point; import android.util.AttributeSet; -import android.util.Log; import android.view.View; import android.widget.FrameLayout; import com.android.settingslib.Utils; import com.android.systemui.R; import com.android.systemui.qs.customize.QSCustomizer; +import com.android.systemui.statusbar.ExpandableOutlineView; /** * Wrapper view with background which contains {@link QSPanel} and {@link BaseStatusBarHeader} @@ -42,11 +44,7 @@ public class QSContainerImpl extends FrameLayout { protected float mQsExpansion; private QSCustomizer mQSCustomizer; private View mQSFooter; - private View mBackground; - private View mBackgroundGradient; - private View mStatusBarBackground; - private int mSideMargins; public QSContainerImpl(Context context, AttributeSet attrs) { @@ -62,8 +60,6 @@ public class QSContainerImpl extends FrameLayout { mQSCustomizer = findViewById(R.id.qs_customize); mQSFooter = findViewById(R.id.qs_footer); mBackground = findViewById(R.id.quick_settings_background); - mStatusBarBackground = findViewById(R.id.quick_settings_status_bar_background); - mBackgroundGradient = findViewById(R.id.quick_settings_gradient_view); mSideMargins = getResources().getDimensionPixelSize(R.dimen.notification_side_paddings); setClickable(true); @@ -71,22 +67,6 @@ public class QSContainerImpl extends FrameLayout { setMargins(); } - @Override - protected void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - - // Hide the backgrounds when in landscape mode. - if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) { - mBackgroundGradient.setVisibility(View.INVISIBLE); - mStatusBarBackground.setVisibility(View.INVISIBLE); - } else { - mBackgroundGradient.setVisibility(View.VISIBLE); - mStatusBarBackground.setVisibility(View.VISIBLE); - } - - updateResources(); - } - @Override public boolean performClick() { // Want to receive clicks so missing QQS tiles doesn't cause collapse, but @@ -121,14 +101,6 @@ public class QSContainerImpl extends FrameLayout { updateExpansion(); } - private void updateResources() { - LayoutParams layoutParams = (LayoutParams) mQSPanel.getLayoutParams(); - layoutParams.topMargin = mContext.getResources().getDimensionPixelSize( - com.android.internal.R.dimen.quick_qs_offset_height); - - mQSPanel.setLayoutParams(layoutParams); - } - /** * Overrides the height of this view (post-layout), so that the content is clipped to that * height and the background is set to that height. diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java index ca88d704fd87..0ac8b9ccef7e 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java @@ -26,7 +26,6 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.res.Configuration; -import android.content.res.Resources; import android.graphics.Color; import android.graphics.Rect; import android.media.AudioManager; @@ -56,10 +55,8 @@ import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.phone.PhoneStatusBarView; import com.android.systemui.statusbar.phone.StatusBarIconController; import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager; -import com.android.systemui.statusbar.policy.Clock; import com.android.systemui.statusbar.policy.DarkIconDispatcher; import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver; -import com.android.systemui.statusbar.policy.DateView; import com.android.systemui.statusbar.policy.NextAlarmController; import java.util.Locale; @@ -94,7 +91,6 @@ public class QuickStatusBarHeader extends RelativeLayout implements CommandQueue private TouchAnimator mStatusIconsAlphaAnimator; private TouchAnimator mHeaderTextContainerAlphaAnimator; - private View mSystemIconsView; private View mQuickQsStatusIcons; private View mDate; private View mHeaderTextContainerView; @@ -112,9 +108,6 @@ public class QuickStatusBarHeader extends RelativeLayout implements CommandQueue private View mStatusSeparator; private ImageView mRingerModeIcon; private TextView mRingerModeTextView; - private BatteryMeterView mBatteryMeterView; - private Clock mClockView; - private DateView mDateView; private NextAlarmController mAlarmController; /** Counts how many times the long press tooltip has been shown to the user. */ @@ -146,7 +139,6 @@ public class QuickStatusBarHeader extends RelativeLayout implements CommandQueue mHeaderQsPanel = findViewById(R.id.quick_qs_panel); mDate = findViewById(R.id.date); mDate.setOnClickListener(this); - mSystemIconsView = findViewById(R.id.quick_status_bar_system_icons); mQuickQsStatusIcons = findViewById(R.id.quick_qs_status_icons); mIconManager = new TintedIconManager(findViewById(R.id.statusIcons)); @@ -174,10 +166,8 @@ public class QuickStatusBarHeader extends RelativeLayout implements CommandQueue // Set the correct tint for the status icons so they contrast mIconManager.setTint(fillColor); - mBatteryMeterView = findViewById(R.id.battery); - mBatteryMeterView.setForceShowPercent(true); - mClockView = findViewById(R.id.clock); - mDateView = findViewById(R.id.date); + BatteryMeterView battery = findViewById(R.id.battery); + battery.setForceShowPercent(true); } private void updateStatusText() { @@ -224,13 +214,6 @@ public class QuickStatusBarHeader extends RelativeLayout implements CommandQueue protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); updateResources(); - - // Update color schemes in landscape to use wallpaperTextColor - boolean shouldUseWallpaperTextColor = - newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE; - mBatteryMeterView.useWallpaperTextColor(shouldUseWallpaperTextColor); - mClockView.useWallpaperTextColor(shouldUseWallpaperTextColor); - mDateView.useWallpaperTextColor(shouldUseWallpaperTextColor); } @Override @@ -240,21 +223,11 @@ public class QuickStatusBarHeader extends RelativeLayout implements CommandQueue } private void updateResources() { - Resources resources = mContext.getResources(); - - // Update height for a few views, especially due to landscape mode restricting space. + // Update height, especially due to landscape mode restricting space. mHeaderTextContainerView.getLayoutParams().height = - resources.getDimensionPixelSize(R.dimen.qs_header_tooltip_height); + mContext.getResources().getDimensionPixelSize(R.dimen.qs_header_tooltip_height); mHeaderTextContainerView.setLayoutParams(mHeaderTextContainerView.getLayoutParams()); - mSystemIconsView.getLayoutParams().height = resources.getDimensionPixelSize( - com.android.internal.R.dimen.quick_qs_offset_height); - mSystemIconsView.setLayoutParams(mSystemIconsView.getLayoutParams()); - - getLayoutParams().height = - resources.getDimensionPixelSize(com.android.internal.R.dimen.quick_qs_total_height); - setLayoutParams(getLayoutParams()); - updateStatusIconAlphaAnimator(); updateHeaderTextContainerAlphaAnimator(); } @@ -526,8 +499,9 @@ public class QuickStatusBarHeader extends RelativeLayout implements CommandQueue mHeaderQsPanel.setHost(host, null /* No customization in header */); // Use SystemUI context to get battery meter colors, and let it use the default tint (white) - mBatteryMeterView.setColorsFromContext(mHost.getContext()); - mBatteryMeterView.onDarkChanged(new Rect(), 0, DarkIconDispatcher.DEFAULT_ICON_TINT); + BatteryMeterView battery = findViewById(R.id.battery); + battery.setColorsFromContext(mHost.getContext()); + battery.onDarkChanged(new Rect(), 0, DarkIconDispatcher.DEFAULT_ICON_TINT); } public void setCallback(Callback qsPanelCallback) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java index 4e12936ff47a..2c025b5e2392 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java @@ -85,7 +85,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo /** * Default alpha value for most scrims. */ - public static final float GRADIENT_SCRIM_ALPHA = 0.70f; + public static final float GRADIENT_SCRIM_ALPHA = 0.45f; /** * A scrim varies its opacity based on a busyness factor, for example * how many notifications are currently visible. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java index baeaaadf419f..4c92d01eae4c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java @@ -40,7 +40,6 @@ import android.view.Display; import android.view.View; import android.widget.TextView; -import com.android.settingslib.Utils; import com.android.systemui.DemoMode; import com.android.systemui.Dependency; import com.android.systemui.FontSizeUtils; @@ -85,17 +84,6 @@ public class Clock extends TextView implements DemoMode, Tunable, CommandQueue.C private boolean mShowSeconds; private Handler mSecondsHandler; - /** - * Whether we should use colors that adapt based on wallpaper/the scrim behind quick settings - * for text. - */ - private boolean mUseWallpaperTextColor; - - /** - * Color to be set on this {@link TextView}, when wallpaperTextColor is not utilized. - */ - private int mNonAdaptedColor; - public Clock(Context context) { this(context, null); } @@ -113,7 +101,6 @@ public class Clock extends TextView implements DemoMode, Tunable, CommandQueue.C try { mAmPmStyle = a.getInt(R.styleable.Clock_amPmStyle, AM_PM_STYLE_GONE); mShowDark = a.getBoolean(R.styleable.Clock_showDark, true); - mNonAdaptedColor = getCurrentTextColor(); } finally { a.recycle(); } @@ -240,10 +227,7 @@ public class Clock extends TextView implements DemoMode, Tunable, CommandQueue.C @Override public void onDarkChanged(Rect area, float darkIntensity, int tint) { - mNonAdaptedColor = DarkIconDispatcher.getTint(area, this, tint); - if (!mUseWallpaperTextColor) { - setTextColor(mNonAdaptedColor); - } + setTextColor(DarkIconDispatcher.getTint(area, this, tint)); } @Override @@ -258,25 +242,6 @@ public class Clock extends TextView implements DemoMode, Tunable, CommandQueue.C 0); } - /** - * Sets whether the clock uses the wallpaperTextColor. If we're not using it, we'll revert back - * to dark-mode-based/tinted colors. - * - * @param shouldUseWallpaperTextColor whether we should use wallpaperTextColor for text color - */ - public void useWallpaperTextColor(boolean shouldUseWallpaperTextColor) { - if (shouldUseWallpaperTextColor == mUseWallpaperTextColor) { - return; - } - mUseWallpaperTextColor = shouldUseWallpaperTextColor; - - if (mUseWallpaperTextColor) { - setTextColor(Utils.getColorAttr(mContext, R.attr.wallpaperTextColor)); - } else { - setTextColor(mNonAdaptedColor); - } - } - private void updateShowSeconds() { if (mShowSeconds) { // Wait until we have a display to start trying to show seconds. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java index ef630c7205e1..74a30fa8094f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java @@ -27,7 +27,6 @@ import android.text.TextUtils; import android.util.AttributeSet; import android.widget.TextView; -import com.android.settingslib.Utils; import com.android.systemui.Dependency; import com.android.systemui.R; @@ -43,17 +42,6 @@ public class DateView extends TextView { private String mLastText; private String mDatePattern; - /** - * Whether we should use colors that adapt based on wallpaper/the scrim behind quick settings - * for text. - */ - private boolean mUseWallpaperTextColor; - - /** - * Color to be set on this {@link TextView}, when wallpaperTextColor is not utilized. - */ - private int mNonAdaptedTextColor; - private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -74,7 +62,6 @@ public class DateView extends TextView { public DateView(Context context, AttributeSet attrs) { super(context, attrs); - mNonAdaptedTextColor = getCurrentTextColor(); TypedArray a = context.getTheme().obtainStyledAttributes( attrs, R.styleable.DateView, @@ -130,25 +117,6 @@ public class DateView extends TextView { } } - /** - * Sets whether the date view uses the wallpaperTextColor. If we're not using it, we'll revert - * back to dark-mode-based/tinted colors. - * - * @param shouldUseWallpaperTextColor whether we should use wallpaperTextColor for text color - */ - public void useWallpaperTextColor(boolean shouldUseWallpaperTextColor) { - if (shouldUseWallpaperTextColor == mUseWallpaperTextColor) { - return; - } - mUseWallpaperTextColor = shouldUseWallpaperTextColor; - - if (mUseWallpaperTextColor) { - setTextColor(Utils.getColorAttr(mContext, R.attr.wallpaperTextColor)); - } else { - setTextColor(mNonAdaptedTextColor); - } - } - public void setDatePattern(String pattern) { if (TextUtils.equals(pattern, mDatePattern)) { return; diff --git a/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values-land/config.xml b/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values-land/config.xml deleted file mode 100644 index 1aa1af3b76fc..000000000000 --- a/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values-land/config.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - @dimen/status_bar_height_landscape - - 156dp - \ No newline at end of file diff --git a/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values-land/config.xml b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values-land/config.xml deleted file mode 100644 index 1aa1af3b76fc..000000000000 --- a/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values-land/config.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - @dimen/status_bar_height_landscape - - 156dp - \ No newline at end of file diff --git a/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values-land/config.xml b/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values-land/config.xml deleted file mode 100644 index 1aa1af3b76fc..000000000000 --- a/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values-land/config.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - @dimen/status_bar_height_landscape - - 156dp - \ No newline at end of file diff --git a/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values-land/config.xml b/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values-land/config.xml deleted file mode 100644 index 1aa1af3b76fc..000000000000 --- a/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values-land/config.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - @dimen/status_bar_height_landscape - - 156dp - \ No newline at end of file diff --git a/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values-land/config.xml b/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values-land/config.xml deleted file mode 100644 index 1aa1af3b76fc..000000000000 --- a/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values-land/config.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - @dimen/status_bar_height_landscape - - 156dp - \ No newline at end of file -- GitLab From 37121d467c3e2fe56dc30cc2a6f6a37231791d7a Mon Sep 17 00:00:00 2001 From: Brad Ebinger Date: Thu, 29 Mar 2018 11:12:24 -0700 Subject: [PATCH 075/179] Unhide @SystemApi Constructor There are a few small classes that never got properly exposed as @SystemApi. These classes were not caught because vendors currently build against the source directly and have access to hidden APIs. We can not change the vendor code at this point (different vendor code for each year for all supported devices), but we can start pulling back the API for new devices. 1) Keep all public mutable fields @hide and put todo (and file bug b/74402619) to make fields private or final. 2) Add public constructor that populates all fields so that @hide public mutable fields can be set to private/final in the future. 3) Provide getters for fields that will not be public in the future. In this way, we can make minimal API changes for P, support new vendor/3rd party ImsServices, and phase out old ImsService implementations that still build against the source instead of using the correct @SystemApi. Bug: 77278031 Bug: 74402619 Test: Manual Change-Id: Ifa3b6d0cbdb12e92efc699b760ca874768a89a7c --- api/system-current.txt | 5 +- .../telephony/ims/ImsCallForwardInfo.java | 20 ++ .../java/android/telephony/ims/ImsSsData.java | 309 +++++++++++++++--- .../java/android/telephony/ims/ImsSsInfo.java | 24 ++ 4 files changed, 318 insertions(+), 40 deletions(-) diff --git a/api/system-current.txt b/api/system-current.txt index 1e2fe3df0d2c..b7a976f726c9 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -5535,6 +5535,7 @@ package android.telephony.euicc { package android.telephony.ims { public final class ImsCallForwardInfo implements android.os.Parcelable { + ctor public ImsCallForwardInfo(int, int, int, int, java.lang.String, int); method public int describeContents(); method public int getCondition(); method public java.lang.String getNumber(); @@ -5848,7 +5849,7 @@ package android.telephony.ims { } public final class ImsSsData implements android.os.Parcelable { - ctor public ImsSsData(); + ctor public ImsSsData(int, int, int, int, int); method public int describeContents(); method public boolean isTypeBarring(); method public boolean isTypeCf(); @@ -5899,7 +5900,7 @@ package android.telephony.ims { } public final class ImsSsInfo implements android.os.Parcelable { - ctor public ImsSsInfo(); + ctor public ImsSsInfo(int, java.lang.String); method public int describeContents(); method public java.lang.String getIcbNum(); method public int getStatus(); diff --git a/telephony/java/android/telephony/ims/ImsCallForwardInfo.java b/telephony/java/android/telephony/ims/ImsCallForwardInfo.java index 6d7218179067..283112793d87 100644 --- a/telephony/java/android/telephony/ims/ImsCallForwardInfo.java +++ b/telephony/java/android/telephony/ims/ImsCallForwardInfo.java @@ -29,27 +29,47 @@ import android.os.Parcelable; public final class ImsCallForwardInfo implements Parcelable { // Refer to ImsUtInterface#CDIV_CF_XXX /** @hide */ + // TODO: Make private, do not modify this field directly, use getter. public int mCondition; // 0: disabled, 1: enabled /** @hide */ + // TODO: Make private, do not modify this field directly, use getter. public int mStatus; // 0x91: International, 0x81: Unknown /** @hide */ + // TODO: Make private, do not modify this field directly, use getter. public int mToA; // Service class /** @hide */ + // TODO: Make private, do not modify this field directly, use getter. public int mServiceClass; // Number (it will not include the "sip" or "tel" URI scheme) /** @hide */ + // TODO: Make private, do not modify this field directly, use getter. public String mNumber; // No reply timer for CF /** @hide */ + // TODO: Make private, do not modify this field directly, use getter. public int mTimeSeconds; /** @hide */ + // TODO: Will be removed in the future, use public constructor instead. public ImsCallForwardInfo() { } + /** + * IMS Call Forward Information. + */ + public ImsCallForwardInfo(int condition, int status, int toA, int serviceClass, String number, + int replyTimerSec) { + mCondition = condition; + mStatus = status; + mToA = toA; + mServiceClass = serviceClass; + mNumber = number; + mTimeSeconds = replyTimerSec; + } + /** @hide */ public ImsCallForwardInfo(Parcel in) { readFromParcel(in); diff --git a/telephony/java/android/telephony/ims/ImsSsData.java b/telephony/java/android/telephony/ims/ImsSsData.java index 1ddf1994f26b..49ead770b42a 100644 --- a/telephony/java/android/telephony/ims/ImsSsData.java +++ b/telephony/java/android/telephony/ims/ImsSsData.java @@ -15,19 +15,24 @@ */ package android.telephony.ims; +import android.annotation.IntDef; import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + /** - * Provided STK Call Control Suplementary Service information + * Provides STK Call Control Supplementary Service information. * * {@hide} */ @SystemApi public final class ImsSsData implements Parcelable { - //ServiceType + // Supplementary Service Type + // Call Forwarding public static final int SS_CFU = 0; public static final int SS_CF_BUSY = 1; public static final int SS_CF_NO_REPLY = 2; @@ -35,12 +40,16 @@ public final class ImsSsData implements Parcelable { public static final int SS_CF_ALL = 4; public static final int SS_CF_ALL_CONDITIONAL = 5; public static final int SS_CFUT = 6; + // Called Line Presentation public static final int SS_CLIP = 7; public static final int SS_CLIR = 8; public static final int SS_COLP = 9; public static final int SS_COLR = 10; + // Calling Name Presentation public static final int SS_CNAP = 11; + // Call Waiting public static final int SS_WAIT = 12; + // Call Barring public static final int SS_BAOC = 13; public static final int SS_BAOIC = 14; public static final int SS_BAOIC_EXC_HOME = 15; @@ -52,14 +61,14 @@ public final class ImsSsData implements Parcelable { public static final int SS_INCOMING_BARRING_DN = 21; public static final int SS_INCOMING_BARRING_ANONYMOUS = 22; - //SSRequestType + //Supplementary Service Request Types public static final int SS_ACTIVATION = 0; public static final int SS_DEACTIVATION = 1; public static final int SS_INTERROGATION = 2; public static final int SS_REGISTRATION = 3; public static final int SS_ERASURE = 4; - //TeleserviceType + // Supplementary Service Teleservice Type public static final int SS_ALL_TELE_AND_BEARER_SERVICES = 0; public static final int SS_ALL_TELESEVICES = 1; public static final int SS_TELEPHONY = 2; @@ -67,40 +76,226 @@ public final class ImsSsData implements Parcelable { public static final int SS_SMS_SERVICES = 4; public static final int SS_ALL_TELESERVICES_EXCEPT_SMS = 5; - // Refer to ServiceType + // Service Class of Supplementary Service + // See 27.007 +CCFC or +CLCK /** @hide */ - public int serviceType; - // Refere to SSRequestType + public static final int SERVICE_CLASS_NONE = 0; // no user input /** @hide */ - public int requestType; - // Refer to TeleserviceType + public static final int SERVICE_CLASS_VOICE = 1; /** @hide */ - public int teleserviceType; - // Service Class + public static final int SERVICE_CLASS_DATA = (1 << 1); /** @hide */ - public int serviceClass; - // Error information + public static final int SERVICE_CLASS_FAX = (1 << 2); /** @hide */ - public int result; - + public static final int SERVICE_CLASS_SMS = (1 << 3); + /** @hide */ + public static final int SERVICE_CLASS_DATA_SYNC = (1 << 4); + /** @hide */ + public static final int SERVICE_CLASS_DATA_ASYNC = (1 << 5); /** @hide */ - public int[] ssInfo; /* Valid for all supplementary services. - This field will be empty for RequestType SS_INTERROGATION - and ServiceType SS_CF_*, SS_INCOMING_BARRING_DN, - SS_INCOMING_BARRING_ANONYMOUS.*/ + public static final int SERVICE_CLASS_PACKET = (1 << 6); + /** @hide */ + public static final int SERVICE_CLASS_PAD = (1 << 7); + + /** + * Result code used if the operation was successful. See {@link #result}. + * @hide + */ + public static final int RESULT_SUCCESS = 0; /** @hide */ - public ImsCallForwardInfo[] cfInfo; /* Valid only for supplementary services - ServiceType SS_CF_* and RequestType SS_INTERROGATION */ + @IntDef(flag = true, prefix = { "SS_" }, value = { + SS_CFU, + SS_CF_BUSY, + SS_CF_NO_REPLY, + SS_CF_NOT_REACHABLE, + SS_CF_ALL, + SS_CF_ALL_CONDITIONAL, + SS_CFUT, + SS_CLIP, + SS_CLIR, + SS_COLP, + SS_COLR, + SS_CNAP, + SS_WAIT, + SS_BAOC, + SS_BAOIC, + SS_BAOIC_EXC_HOME, + SS_BAIC, + SS_BAIC_ROAMING, + SS_ALL_BARRING, + SS_OUTGOING_BARRING, + SS_INCOMING_BARRING, + SS_INCOMING_BARRING_DN, + SS_INCOMING_BARRING_ANONYMOUS + }) + @Retention(RetentionPolicy.SOURCE) + public @interface ServiceType{} /** @hide */ - public ImsSsInfo[] imsSsInfo; /* Valid only for ServiceType SS_INCOMING_BARRING_DN and - ServiceType SS_INCOMING_BARRING_ANONYMOUS */ + @IntDef(flag = true, prefix = { "SERVICE_CLASS" }, value = { + SERVICE_CLASS_NONE, + SERVICE_CLASS_VOICE, + SERVICE_CLASS_DATA, + SERVICE_CLASS_FAX, + SERVICE_CLASS_SMS, + SERVICE_CLASS_DATA_SYNC, + SERVICE_CLASS_DATA_ASYNC, + SERVICE_CLASS_PACKET, + SERVICE_CLASS_PAD + }) + @Retention(RetentionPolicy.SOURCE) + public @interface ServiceClass{} + + /** + * The Service type of this Supplementary service. Valid values include: + * SS_CFU, + * SS_CF_BUSY, + * SS_CF_NO_REPLY, + * SS_CF_NOT_REACHABLE, + * SS_CF_ALL, + * SS_CF_ALL_CONDITIONAL, + * SS_CFUT, + * SS_CLIP, + * SS_CLIR, + * SS_COLP, + * SS_COLR, + * SS_CNAP, + * SS_WAIT, + * SS_BAOC, + * SS_BAOIC, + * SS_BAOIC_EXC_HOME, + * SS_BAIC, + * SS_BAIC_ROAMING, + * SS_ALL_BARRING, + * SS_OUTGOING_BARRING, + * SS_INCOMING_BARRING, + * SS_INCOMING_BARRING_DN, + * SS_INCOMING_BARRING_ANONYMOUS + * + * @hide + */ + // TODO: Make final, do not modify this field directly! + public int serviceType; + + /** + * Supplementary Service request Type. Valid values are: + * SS_ACTIVATION, + * SS_DEACTIVATION, + * SS_INTERROGATION, + * SS_REGISTRATION, + * SS_ERASURE + * + * @hide + */ + // TODO: Make final, do not modify this field directly! + public int requestType; + + /** + * Supplementary Service teleservice type: + * SS_TELESERVICE_ALL_TELE_AND_BEARER, + * SS_TELESERVICE_ALL_TELESEVICES, + * SS_TELESERVICE_TELEPHONY, + * SS_TELESERVICE_ALL_DATA, + * SS_TELESERVICE_SMS, + * SS_TELESERVICE_ALL_TELESERVICES_EXCEPT_SMS + * + * @hide + */ + // TODO: Make this param final! Do not try to modify this param directly. + public int teleserviceType; + + /** + * Supplementary Service service class. Valid values are: + * SERVICE_CLASS_NONE, + * SERVICE_CLASS_VOICE, + * SERVICE_CLASS_DATA, + * SERVICE_CLASS_FAX, + * SERVICE_CLASS_SMS, + * SERVICE_CLASS_DATA_SYNC, + * SERVICE_CLASS_DATA_ASYNC, + * SERVICE_CLASS_PACKET, + * SERVICE_CLASS_PAD + * + * @hide + */ + // TODO: Make this param final! Do not try to modify this param directly. + public int serviceClass; + + /** + * Result of Supplementary Service operation. Valid values are: + * RESULT_SUCCESS if the result is success, or + * ImsReasonInfo code if the result is a failure. + * + * @hide + */ + // TODO: Make this param final! Do not try to modify this param directly. + public final int result; + + private int[] mSsInfo; + private ImsCallForwardInfo[] mCfInfo; + private ImsSsInfo[] mImsSsInfo; - public ImsSsData() {} + /** + * Generate IMS Supplementary Service information. + * @param serviceType The Supplementary Service type. Valid entries: + * SS_CFU, + * SS_CF_BUSY, + * SS_CF_NO_REPLY, + * SS_CF_NOT_REACHABLE, + * SS_CF_ALL, + * SS_CF_ALL_CONDITIONAL, + * SS_CFUT, + * SS_CLIP, + * SS_CLIR, + * SS_COLP, + * SS_COLR, + * SS_CNAP, + * SS_WAIT, + * SS_BAOC, + * SS_BAOIC, + * SS_BAOIC_EXC_HOME, + * SS_BAIC, + * SS_BAIC_ROAMING, + * SS_ALL_BARRING, + * SS_OUTGOING_BARRING, + * SS_INCOMING_BARRING, + * SS_INCOMING_BARRING_DN, + * SS_INCOMING_BARRING_ANONYMOUS + * @param requestType Supplementary Service request Type. Valid values are: + * SS_ACTIVATION, + * SS_DEACTIVATION, + * SS_INTERROGATION, + * SS_REGISTRATION, + * SS_ERASURE + * @param teleserviceType Supplementary Service teleservice type: + * SS_TELESERVICE_ALL_TELE_AND_BEARER, + * SS_TELESERVICE_ALL_TELESEVICES, + * SS_TELESERVICE_TELEPHONY, + * SS_TELESERVICE_ALL_DATA, + * SS_TELESERVICE_SMS, + * SS_TELESERVICE_ALL_TELESERVICES_EXCEPT_SMS + * @param serviceClass Supplementary Service service class. See See 27.007 +CCFC or +CLCK. + * @param result Result of Supplementary Service operation. Valid values are 0 if the result is + * success, or ImsReasonInfo code if the result is a failure. + */ + public ImsSsData(@ServiceType int serviceType, int requestType, int teleserviceType, + @ServiceClass int serviceClass, int result) { + this.serviceType = serviceType; + this.requestType = requestType; + this.teleserviceType = teleserviceType; + this.serviceClass = serviceClass; + this.result = result; + } private ImsSsData(Parcel in) { - readFromParcel(in); + serviceType = in.readInt(); + requestType = in.readInt(); + teleserviceType = in.readInt(); + serviceClass = in.readInt(); + result = in.readInt(); + mSsInfo = in.createIntArray(); + mCfInfo = (ImsCallForwardInfo[])in.readParcelableArray(this.getClass().getClassLoader()); } public static final Creator CREATOR = new Creator() { @@ -122,18 +317,8 @@ public final class ImsSsData implements Parcelable { out.writeInt(teleserviceType); out.writeInt(serviceClass); out.writeInt(result); - out.writeIntArray(ssInfo); - out.writeParcelableArray(cfInfo, 0); - } - - private void readFromParcel(Parcel in) { - serviceType = in.readInt(); - requestType = in.readInt(); - teleserviceType = in.readInt(); - serviceClass = in.readInt(); - result = in.readInt(); - ssInfo = in.createIntArray(); - cfInfo = (ImsCallForwardInfo[])in.readParcelableArray(this.getClass().getClassLoader()); + out.writeIntArray(mSsInfo); + out.writeParcelableArray(mCfInfo, 0); } @Override @@ -200,7 +385,55 @@ public final class ImsSsData implements Parcelable { } public boolean isTypeInterrogation() { - return (requestType == SS_INTERROGATION); + return (serviceType == SS_INTERROGATION); + } + + /** @hide */ + public void setSuppServiceInfo(int[] ssInfo) { + mSsInfo = ssInfo; + } + + /** @hide */ + public void setImsSpecificSuppServiceInfo(ImsSsInfo[] imsSsInfo) { + mImsSsInfo = imsSsInfo; + } + + /** @hide */ + public void setCallForwardingInfo(ImsCallForwardInfo[] cfInfo) { + mCfInfo = cfInfo; + } + + /** + * This field will be null for RequestType SS_INTERROGATION + * and ServiceType SS_CF_*, SS_INCOMING_BARRING_DN, + * SS_INCOMING_BARRING_ANONYMOUS. + * + * @hide + */ + public int[] getSuppServiceInfo() { + return mSsInfo; + } + + /** + * Valid only for ServiceTypes + * - SS_INCOMING_BARRING_DN and + * - ServiceType SS_INCOMING_BARRING_ANONYMOUS. + * Will be null otherwise. + * @hide + */ + public ImsSsInfo[] getImsSpecificSuppServiceInfo() { + return mImsSsInfo; + } + + /** + * Valid only for supplementary services + * - ServiceType SS_CF_* and + * - RequestType SS_INTERROGATION. + * Will be null otherwise. + * @hide + **/ + public ImsCallForwardInfo[] getCallForwardInfo() { + return mCfInfo; } public String toString() { diff --git a/telephony/java/android/telephony/ims/ImsSsInfo.java b/telephony/java/android/telephony/ims/ImsSsInfo.java index 1d1292fb9f72..c6f8622f3fd9 100644 --- a/telephony/java/android/telephony/ims/ImsSsInfo.java +++ b/telephony/java/android/telephony/ims/ImsSsInfo.java @@ -36,13 +36,31 @@ public final class ImsSsInfo implements Parcelable { // 0: disabled, 1: enabled /** @hide */ + // TODO: Make private, do not modify this field directly, use getter! public int mStatus; /** @hide */ + // TODO: Make private, do not modify this field directly, use getter! public String mIcbNum; + /**@hide*/ + // TODO: Remove! Do not use this constructor, instead use public version. public ImsSsInfo() { } + /** + * + * @param status The status of the service registration of activation/deactiviation. Valid + * entries include: + * {@link #NOT_REGISTERED}, + * {@link #DISABLED}, + * {@link #ENABLED} + * @param icbNum The Incoming barring number. + */ + public ImsSsInfo(int status, String icbNum) { + mStatus = status; + mIcbNum = icbNum; + } + private ImsSsInfo(Parcel in) { readFromParcel(in); } @@ -81,6 +99,12 @@ public final class ImsSsInfo implements Parcelable { } }; + /** + * @return Supplementary Service Configuration status. Valid Values are: + * {@link #NOT_REGISTERED}, + * {@link #DISABLED}, + * {@link #ENABLED} + */ public int getStatus() { return mStatus; } -- GitLab From d0c78f9f28599ac97dbca06c1634238f9b25be40 Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Wed, 28 Mar 2018 17:50:08 -0700 Subject: [PATCH 076/179] Fix empty program list filter handling. Also, fix some minor issues about program list fetching. Test: manual Bug: 74353024 Change-Id: I77546b806f2d9de9505e64335af47e99079cea3e --- core/java/android/hardware/radio/ProgramList.java | 11 +++++++++++ core/java/android/hardware/radio/TunerAdapter.java | 2 ++ .../android/hardware/radio/TunerCallbackAdapter.java | 6 ++++++ .../server/broadcastradio/hal1/TunerCallback.java | 6 ++++-- .../android/server/broadcastradio/hal2/Convert.java | 4 +++- 5 files changed, 26 insertions(+), 3 deletions(-) diff --git a/core/java/android/hardware/radio/ProgramList.java b/core/java/android/hardware/radio/ProgramList.java index b2aa9ba532a9..e6f523c07e70 100644 --- a/core/java/android/hardware/radio/ProgramList.java +++ b/core/java/android/hardware/radio/ProgramList.java @@ -260,6 +260,17 @@ public final class ProgramList implements AutoCloseable { mVendorFilter = null; } + /** + * @hide for framework use only + */ + public Filter() { + mIdentifierTypes = Collections.emptySet(); + mIdentifiers = Collections.emptySet(); + mIncludeCategories = false; + mExcludeModifications = false; + mVendorFilter = null; + } + /** * @hide for framework use only */ diff --git a/core/java/android/hardware/radio/TunerAdapter.java b/core/java/android/hardware/radio/TunerAdapter.java index 85f3115689cd..be2846f87079 100644 --- a/core/java/android/hardware/radio/TunerAdapter.java +++ b/core/java/android/hardware/radio/TunerAdapter.java @@ -60,6 +60,7 @@ class TunerAdapter extends RadioTuner { mLegacyListProxy.close(); mLegacyListProxy = null; } + mCallback.close(); } try { mTuner.close(); @@ -278,6 +279,7 @@ class TunerAdapter extends RadioTuner { try { mTuner.startProgramListUpdates(filter); } catch (UnsupportedOperationException ex) { + Log.i(TAG, "Program list is not supported with this hardware"); return null; } catch (RemoteException ex) { mCallback.setProgramListObserver(null, () -> { }); diff --git a/core/java/android/hardware/radio/TunerCallbackAdapter.java b/core/java/android/hardware/radio/TunerCallbackAdapter.java index 7437c40351db..0fb93e532cd3 100644 --- a/core/java/android/hardware/radio/TunerCallbackAdapter.java +++ b/core/java/android/hardware/radio/TunerCallbackAdapter.java @@ -53,6 +53,12 @@ class TunerCallbackAdapter extends ITunerCallback.Stub { } } + void close() { + synchronized (mLock) { + if (mProgramList != null) mProgramList.close(); + } + } + void setProgramListObserver(@Nullable ProgramList programList, @NonNull ProgramList.OnCloseListener closeListener) { Objects.requireNonNull(closeListener); diff --git a/services/core/java/com/android/server/broadcastradio/hal1/TunerCallback.java b/services/core/java/com/android/server/broadcastradio/hal1/TunerCallback.java index 32b1d1adfe3a..7a6d9647bf43 100644 --- a/services/core/java/com/android/server/broadcastradio/hal1/TunerCallback.java +++ b/services/core/java/com/android/server/broadcastradio/hal1/TunerCallback.java @@ -17,6 +17,7 @@ package com.android.server.broadcastradio.hal1; import android.annotation.NonNull; +import android.annotation.Nullable; import android.hardware.radio.ITuner; import android.hardware.radio.ITunerCallback; import android.hardware.radio.ProgramList; @@ -87,8 +88,9 @@ class TunerCallback implements ITunerCallback { mTuner.close(); } - void startProgramListUpdates(@NonNull ProgramList.Filter filter) { - mProgramListFilter.set(Objects.requireNonNull(filter)); + void startProgramListUpdates(@Nullable ProgramList.Filter filter) { + if (filter == null) filter = new ProgramList.Filter(); + mProgramListFilter.set(filter); sendProgramListUpdate(); } diff --git a/services/core/java/com/android/server/broadcastradio/hal2/Convert.java b/services/core/java/com/android/server/broadcastradio/hal2/Convert.java index 248151ca2bd3..9730c9a1a380 100644 --- a/services/core/java/com/android/server/broadcastradio/hal2/Convert.java +++ b/services/core/java/com/android/server/broadcastradio/hal2/Convert.java @@ -375,7 +375,9 @@ class Convert { ); } - static @NonNull ProgramFilter programFilterToHal(@NonNull ProgramList.Filter filter) { + static @NonNull ProgramFilter programFilterToHal(@Nullable ProgramList.Filter filter) { + if (filter == null) filter = new ProgramList.Filter(); + ProgramFilter hwFilter = new ProgramFilter(); filter.getIdentifierTypes().stream().forEachOrdered(hwFilter.identifierTypes::add); -- GitLab From ff815c299733d7dec75b0f8747fe670b25d15727 Mon Sep 17 00:00:00 2001 From: Amin Shaikh Date: Thu, 29 Mar 2018 14:38:59 -0400 Subject: [PATCH 077/179] Show ripples in QQS. Bug: 74581934 Test: visual Change-Id: I59d9835b6ccb26fbef01c5687dbd5ab88f7e60a7 --- .../SystemUI/res/layout/quick_status_bar_expanded_header.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml index ca8fcba017b1..ed18dc728402 100644 --- a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml +++ b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml @@ -22,6 +22,7 @@ android:layout_width="match_parent" android:layout_height="@*android:dimen/quick_qs_total_height" android:layout_gravity="@integer/notification_panel_layout_gravity" + android:background="@android:color/transparent" android:baselineAligned="false" android:clickable="false" android:clipChildren="false" -- GitLab From 3e0970566276039dbceed737bbc55e9094b53645 Mon Sep 17 00:00:00 2001 From: jdesprez Date: Thu, 29 Mar 2018 12:17:50 -0700 Subject: [PATCH 078/179] Add the CorePerfTests and MultiUserPerfTests to APCT metrics Add them to the suite version of APCT metric instrumentation. Test: atest CorePerfTests Bug: 77280599 Change-Id: Ia8f0c44fcb9fd21869ed64e54483aa87556a469d --- apct-tests/perftests/core/AndroidTest.xml | 27 +++++++++++++++++++ apct-tests/perftests/multiuser/Android.mk | 2 ++ .../perftests/multiuser/AndroidTest.xml | 27 +++++++++++++++++++ 3 files changed, 56 insertions(+) create mode 100644 apct-tests/perftests/core/AndroidTest.xml create mode 100644 apct-tests/perftests/multiuser/AndroidTest.xml diff --git a/apct-tests/perftests/core/AndroidTest.xml b/apct-tests/perftests/core/AndroidTest.xml new file mode 100644 index 000000000000..6aa34a627940 --- /dev/null +++ b/apct-tests/perftests/core/AndroidTest.xml @@ -0,0 +1,27 @@ + + + + diff --git a/apct-tests/perftests/multiuser/Android.mk b/apct-tests/perftests/multiuser/Android.mk index a803369d1e03..9bc7d051121a 100644 --- a/apct-tests/perftests/multiuser/Android.mk +++ b/apct-tests/perftests/multiuser/Android.mk @@ -26,6 +26,8 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ LOCAL_PACKAGE_NAME := MultiUserPerfTests LOCAL_PRIVATE_PLATFORM_APIS := true +LOCAL_COMPATIBILITY_SUITE += device-tests + LOCAL_CERTIFICATE := platform include $(BUILD_PACKAGE) diff --git a/apct-tests/perftests/multiuser/AndroidTest.xml b/apct-tests/perftests/multiuser/AndroidTest.xml new file mode 100644 index 000000000000..6ede8275afcb --- /dev/null +++ b/apct-tests/perftests/multiuser/AndroidTest.xml @@ -0,0 +1,27 @@ + + + + -- GitLab From 58298fdba91ae541715bd7765e0b8425ed4cbfb3 Mon Sep 17 00:00:00 2001 From: jdesprez Date: Thu, 29 Mar 2018 12:27:57 -0700 Subject: [PATCH 079/179] Add MtpDocumentsProviderPerfTests to APCT metric Add it to the suite version of APCT metric instrumentation Test: build device-tests.zip Bug: 77280599 Change-Id: I3a00af2382f4905d84b500b6f5523456d211689f --- .../perf_tests/Android.mk | 1 + .../perf_tests/AndroidTest.xml | 27 +++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 packages/MtpDocumentsProvider/perf_tests/AndroidTest.xml diff --git a/packages/MtpDocumentsProvider/perf_tests/Android.mk b/packages/MtpDocumentsProvider/perf_tests/Android.mk index 6504af12db23..e873157dcf34 100644 --- a/packages/MtpDocumentsProvider/perf_tests/Android.mk +++ b/packages/MtpDocumentsProvider/perf_tests/Android.mk @@ -8,5 +8,6 @@ LOCAL_PACKAGE_NAME := MtpDocumentsProviderPerfTests LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_INSTRUMENTATION_FOR := MtpDocumentsProvider LOCAL_CERTIFICATE := media +LOCAL_COMPATIBILITY_SUITE += device-tests include $(BUILD_PACKAGE) diff --git a/packages/MtpDocumentsProvider/perf_tests/AndroidTest.xml b/packages/MtpDocumentsProvider/perf_tests/AndroidTest.xml new file mode 100644 index 000000000000..8b7292b625e1 --- /dev/null +++ b/packages/MtpDocumentsProvider/perf_tests/AndroidTest.xml @@ -0,0 +1,27 @@ + + + + -- GitLab From 1a12ab26d419bad8e5c3c121d98114199e05f47c Mon Sep 17 00:00:00 2001 From: Leon Scroggins III Date: Mon, 26 Mar 2018 15:00:49 -0400 Subject: [PATCH 080/179] Fix Skia's impl for TextureView.getBitmap Bug: 73392905 Test: New test added with I2d4ef440f943a50b9367976ba1444f4350071bfd When providing a width and height, getBitmap should scale to the destination. Add a parameter to LayerDrawable::DrawLayer for a destination rectangle to scale to. Pass the size of the bitmap in SkiaOpenGLPipeline::copyLayerInto down to DrawLayer. The only other caller of DrawLayer is unaffected. Change-Id: I7aa192181c2d15bc8fd4de2fb15c4d276b05d2ac --- libs/hwui/pipeline/skia/LayerDrawable.cpp | 40 +++++++++++++------ libs/hwui/pipeline/skia/LayerDrawable.h | 3 +- .../hwui/pipeline/skia/SkiaOpenGLPipeline.cpp | 4 +- 3 files changed, 32 insertions(+), 15 deletions(-) diff --git a/libs/hwui/pipeline/skia/LayerDrawable.cpp b/libs/hwui/pipeline/skia/LayerDrawable.cpp index d9584db2df9d..293e45f2273f 100644 --- a/libs/hwui/pipeline/skia/LayerDrawable.cpp +++ b/libs/hwui/pipeline/skia/LayerDrawable.cpp @@ -34,7 +34,8 @@ void LayerDrawable::onDraw(SkCanvas* canvas) { } } -bool LayerDrawable::DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer) { +bool LayerDrawable::DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer, + const SkRect* dstRect) { if (context == nullptr) { SkDEBUGF(("Attempting to draw LayerDrawable into an unsupported surface")); return false; @@ -43,8 +44,8 @@ bool LayerDrawable::DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer SkMatrix layerTransform; layer->getTransform().copyTo(layerTransform); sk_sp layerImage; - int layerWidth = layer->getWidth(); - int layerHeight = layer->getHeight(); + const int layerWidth = layer->getWidth(); + const int layerHeight = layer->getHeight(); if (layer->getApi() == Layer::Api::OpenGL) { GlLayer* glLayer = static_cast(layer); GrGLTextureInfo externalTexture; @@ -62,21 +63,21 @@ bool LayerDrawable::DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer } if (layerImage) { - SkMatrix textureMatrix; - layer->getTexTransform().copyTo(textureMatrix); + SkMatrix textureMatrixInv; + layer->getTexTransform().copyTo(textureMatrixInv); // TODO: after skia bug https://bugs.chromium.org/p/skia/issues/detail?id=7075 is fixed // use bottom left origin and remove flipV and invert transformations. SkMatrix flipV; flipV.setAll(1, 0, 0, 0, -1, 1, 0, 0, 1); - textureMatrix.preConcat(flipV); - textureMatrix.preScale(1.0f / layerWidth, 1.0f / layerHeight); - textureMatrix.postScale(layerWidth, layerHeight); - SkMatrix textureMatrixInv; - if (!textureMatrix.invert(&textureMatrixInv)) { - textureMatrixInv = textureMatrix; + textureMatrixInv.preConcat(flipV); + textureMatrixInv.preScale(1.0f / layerWidth, 1.0f / layerHeight); + textureMatrixInv.postScale(layerWidth, layerHeight); + SkMatrix textureMatrix; + if (!textureMatrixInv.invert(&textureMatrix)) { + textureMatrix = textureMatrixInv; } - SkMatrix matrix = SkMatrix::Concat(layerTransform, textureMatrixInv); + SkMatrix matrix = SkMatrix::Concat(layerTransform, textureMatrix); SkPaint paint; paint.setAlpha(layer->getAlpha()); @@ -88,7 +89,20 @@ bool LayerDrawable::DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer canvas->save(); canvas->concat(matrix); } - canvas->drawImage(layerImage.get(), 0, 0, &paint); + if (dstRect) { + SkMatrix matrixInv; + if (!matrix.invert(&matrixInv)) { + matrixInv = matrix; + } + SkRect srcRect = SkRect::MakeIWH(layerWidth, layerHeight); + matrixInv.mapRect(&srcRect); + SkRect skiaDestRect = *dstRect; + matrixInv.mapRect(&skiaDestRect); + canvas->drawImageRect(layerImage.get(), srcRect, skiaDestRect, &paint, + SkCanvas::kFast_SrcRectConstraint); + } else { + canvas->drawImage(layerImage.get(), 0, 0, &paint); + } // restore the original matrix if (nonIdentityMatrix) { canvas->restore(); diff --git a/libs/hwui/pipeline/skia/LayerDrawable.h b/libs/hwui/pipeline/skia/LayerDrawable.h index 345038769306..18d118405a39 100644 --- a/libs/hwui/pipeline/skia/LayerDrawable.h +++ b/libs/hwui/pipeline/skia/LayerDrawable.h @@ -32,7 +32,8 @@ class LayerDrawable : public SkDrawable { public: explicit LayerDrawable(DeferredLayerUpdater* layerUpdater) : mLayerUpdater(layerUpdater) {} - static bool DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer); + static bool DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer, + const SkRect* dstRect = nullptr); protected: virtual SkRect onGetBounds() override { diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp index 365d7403e046..74cfb2854e62 100644 --- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp @@ -138,7 +138,9 @@ bool SkiaOpenGLPipeline::copyLayerInto(DeferredLayerUpdater* deferredLayer, SkBi SkBudgeted::kYes, bitmap->info()); Layer* layer = deferredLayer->backingLayer(); - if (LayerDrawable::DrawLayer(mRenderThread.getGrContext(), tmpSurface->getCanvas(), layer)) { + const SkRect dstRect = SkRect::MakeIWH(bitmap->width(), bitmap->height()); + if (LayerDrawable::DrawLayer(mRenderThread.getGrContext(), tmpSurface->getCanvas(), layer, + &dstRect)) { sk_sp tmpImage = tmpSurface->makeImageSnapshot(); if (tmpImage->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), 0, 0)) { bitmap->notifyPixelsChanged(); -- GitLab From 7cdba9fcf0089075d6f932fee50d647a440621ba Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Thu, 29 Mar 2018 11:56:58 -0700 Subject: [PATCH 081/179] Fixed annotation typo. Bug: 73648631 Test: not really Change-Id: I4a10642f05e28e5e324ca5b40e50a29138f49b8b --- core/java/android/service/autofill/FillEventHistory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/java/android/service/autofill/FillEventHistory.java b/core/java/android/service/autofill/FillEventHistory.java index df62446427d3..6e5bacf1aad1 100644 --- a/core/java/android/service/autofill/FillEventHistory.java +++ b/core/java/android/service/autofill/FillEventHistory.java @@ -424,7 +424,7 @@ public final class FillEventHistory implements Parcelable { * @return map map whose key is the id of the manually-entered field, and value is the * ids of the datasets that have that value but were not selected by the user. */ - @Nullable public Map> getManuallyEnteredField() { + @NonNull public Map> getManuallyEnteredField() { if (mManuallyFilledFieldIds == null || mManuallyFilledDatasetIds == null) { return Collections.emptyMap(); } -- GitLab From 7276e63f4c62e37cae1540c928d5f07d7da52a7d Mon Sep 17 00:00:00 2001 From: Julia Reynolds Date: Thu, 29 Mar 2018 15:22:59 -0400 Subject: [PATCH 082/179] Wait before computing contact affinity Instead of assuming we'll have an answer as soon as the handler gets around to handling the rankingreconsideration. Change-Id: Id8f2147f59abf6435d869b9ffcc5cf2c2b52f0f7 Fixes: 73010730 Test: cts-verifier --- .../server/notification/ValidateNotificationPeople.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/notification/ValidateNotificationPeople.java b/services/core/java/com/android/server/notification/ValidateNotificationPeople.java index c0c66b248ea5..6cf8f86aed83 100644 --- a/services/core/java/com/android/server/notification/ValidateNotificationPeople.java +++ b/services/core/java/com/android/server/notification/ValidateNotificationPeople.java @@ -468,12 +468,14 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor { private final LinkedList mPendingLookups; private final Context mContext; + // Amount of time to wait for a result from the contacts db before rechecking affinity. + private static final long LOOKUP_TIME = 1000; private float mContactAffinity = NONE; private NotificationRecord mRecord; private PeopleRankingReconsideration(Context context, String key, LinkedList pendingLookups) { - super(key); + super(key, LOOKUP_TIME); mContext = context; mPendingLookups = pendingLookups; } -- GitLab From d62f27250ab99d67242f1de293a31c12c397beb2 Mon Sep 17 00:00:00 2001 From: Leon Scroggins III Date: Thu, 29 Mar 2018 14:52:29 -0400 Subject: [PATCH 083/179] Rename getters and setters on ImageDecoder Bug: 76448408 Test: Ib8782ff10072c81a5ed2a1031a70475fffee7ccf - Use "is" prefix for booleans instead of "get" - Reverse "require" and "unpremultiplied" for a more natural sound - Add "Required" to "Mutable" methods - Add "Enabled" to "DecodeAsAlphaMask" methods Change-Id: I644ddccd37898d89609e4534ece4ea70f74587c4 --- api/current.txt | 12 +-- api/removed.txt | 6 ++ .../java/android/graphics/ImageDecoder.java | 93 ++++++++++++++----- 3 files changed, 83 insertions(+), 28 deletions(-) diff --git a/api/current.txt b/api/current.txt index 2837091a400b..cc6ef71818c9 100644 --- a/api/current.txt +++ b/api/current.txt @@ -13630,22 +13630,22 @@ package android.graphics { method public int getAllocator(); method public boolean getConserveMemory(); method public android.graphics.Rect getCrop(); - method public boolean getDecodeAsAlphaMask(); - method public boolean getMutable(); method public android.graphics.ImageDecoder.OnPartialImageListener getOnPartialImageListener(); method public android.graphics.PostProcessor getPostProcessor(); - method public boolean getRequireUnpremultiplied(); + method public boolean isDecodeAsAlphaMaskEnabled(); + method public boolean isMutableRequired(); + method public boolean isUnpremultipliedRequired(); method public android.graphics.ImageDecoder setAllocator(int); method public android.graphics.ImageDecoder setConserveMemory(boolean); method public android.graphics.ImageDecoder setCrop(android.graphics.Rect); - method public android.graphics.ImageDecoder setDecodeAsAlphaMask(boolean); - method public android.graphics.ImageDecoder setMutable(boolean); + method public android.graphics.ImageDecoder setDecodeAsAlphaMaskEnabled(boolean); + method public android.graphics.ImageDecoder setMutableRequired(boolean); method public android.graphics.ImageDecoder setOnPartialImageListener(android.graphics.ImageDecoder.OnPartialImageListener); method public android.graphics.ImageDecoder setPostProcessor(android.graphics.PostProcessor); - method public android.graphics.ImageDecoder setRequireUnpremultiplied(boolean); method public android.graphics.ImageDecoder setTargetColorSpace(android.graphics.ColorSpace); method public android.graphics.ImageDecoder setTargetSampleSize(int); method public android.graphics.ImageDecoder setTargetSize(int, int); + method public android.graphics.ImageDecoder setUnpremultipliedRequired(boolean); field public static final int ALLOCATOR_DEFAULT = 0; // 0x0 field public static final int ALLOCATOR_HARDWARE = 3; // 0x3 field public static final int ALLOCATOR_SHARED_MEMORY = 2; // 0x2 diff --git a/api/removed.txt b/api/removed.txt index 5863e777bb14..2d76c5a575a0 100644 --- a/api/removed.txt +++ b/api/removed.txt @@ -183,7 +183,13 @@ package android.graphics { public final class ImageDecoder implements java.lang.AutoCloseable { method public deprecated boolean getAsAlphaMask(); + method public deprecated boolean getDecodeAsAlphaMask(); + method public deprecated boolean getMutable(); + method public deprecated boolean getRequireUnpremultiplied(); method public deprecated android.graphics.ImageDecoder setAsAlphaMask(boolean); + method public deprecated android.graphics.ImageDecoder setDecodeAsAlphaMask(boolean); + method public deprecated android.graphics.ImageDecoder setMutable(boolean); + method public deprecated android.graphics.ImageDecoder setRequireUnpremultiplied(boolean); method public deprecated android.graphics.ImageDecoder setResize(int, int); method public deprecated android.graphics.ImageDecoder setResize(int); field public static final deprecated int ERROR_SOURCE_ERROR = 3; // 0x3 diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java index 6051f88733bf..1ed6bfbebf38 100644 --- a/graphics/java/android/graphics/ImageDecoder.java +++ b/graphics/java/android/graphics/ImageDecoder.java @@ -597,7 +597,7 @@ public final class ImageDecoder implements AutoCloseable { private int mDesiredWidth; private int mDesiredHeight; private int mAllocator = ALLOCATOR_DEFAULT; - private boolean mRequireUnpremultiplied = false; + private boolean mUnpremultipliedRequired = false; private boolean mMutable = false; private boolean mConserveMemory = false; private boolean mDecodeAsAlphaMask = false; @@ -782,7 +782,7 @@ public final class ImageDecoder implements AutoCloseable { * height that can be achieved by sampling the encoded image. Other widths * and heights may be supported, but will require an additional (internal) * scaling step. Such internal scaling is *not* supported with - * {@link #setRequireUnpremultiplied} set to {@code true}.

    + * {@link #setUnpremultipliedRequired} set to {@code true}.

    * * @param sampleSize Sampling rate of the encoded image. * @return {@link android.util.Size} of the width and height after @@ -909,7 +909,7 @@ public final class ImageDecoder implements AutoCloseable { * Will typically result in a {@link Bitmap.Config#HARDWARE} * allocation, but may be software for small images. In addition, this will * switch to software when HARDWARE is incompatible, e.g. - * {@link #setMutable}, {@link #setDecodeAsAlphaMask}. + * {@link #setMutableRequired}, {@link #setDecodeAsAlphaMaskEnabled}. */ public static final int ALLOCATOR_DEFAULT = 0; @@ -932,8 +932,8 @@ public final class ImageDecoder implements AutoCloseable { * Require a {@link Bitmap.Config#HARDWARE} {@link Bitmap}. * * When this is combined with incompatible options, like - * {@link #setMutable} or {@link #setDecodeAsAlphaMask}, {@link #decodeDrawable} - * / {@link #decodeBitmap} will throw an + * {@link #setMutableRequired} or {@link #setDecodeAsAlphaMaskEnabled}, + * {@link #decodeDrawable} / {@link #decodeBitmap} will throw an * {@link java.lang.IllegalStateException}. */ public static final int ALLOCATOR_HARDWARE = 3; @@ -984,16 +984,32 @@ public final class ImageDecoder implements AutoCloseable { * * @return this object for chaining. */ - public ImageDecoder setRequireUnpremultiplied(boolean requireUnpremultiplied) { - mRequireUnpremultiplied = requireUnpremultiplied; + public ImageDecoder setUnpremultipliedRequired(boolean unpremultipliedRequired) { + mUnpremultipliedRequired = unpremultipliedRequired; return this; } + /** @removed + * @deprecated Renamed to {@link #setUnpremultipliedRequired}. + */ + @java.lang.Deprecated + public ImageDecoder setRequireUnpremultiplied(boolean unpremultipliedRequired) { + return this.setUnpremultipliedRequired(unpremultipliedRequired); + } + /** * Return whether the {@link Bitmap} will have unpremultiplied pixels. */ + public boolean isUnpremultipliedRequired() { + return mUnpremultipliedRequired; + } + + /** @removed + * @deprecated Renamed to {@link #isUnpremultipliedRequired}. + */ + @java.lang.Deprecated public boolean getRequireUnpremultiplied() { - return mRequireUnpremultiplied; + return this.isUnpremultipliedRequired(); } /** @@ -1105,18 +1121,34 @@ public final class ImageDecoder implements AutoCloseable { * * @return this object for chaining. */ - public ImageDecoder setMutable(boolean mutable) { + public ImageDecoder setMutableRequired(boolean mutable) { mMutable = mutable; return this; } + /** @removed + * @deprecated Renamed to {@link #setMutableRequired}. + */ + @java.lang.Deprecated + public ImageDecoder setMutable(boolean mutable) { + return this.setMutableRequired(mutable); + } + /** * Return whether the {@link Bitmap} will be mutable. */ - public boolean getMutable() { + public boolean isMutableRequired() { return mMutable; } + /** @removed + * @deprecated Renamed to {@link #isMutableRequired}. + */ + @java.lang.Deprecated + public boolean getMutable() { + return this.isMutableRequired(); + } + /** * Specify whether to potentially save RAM at the expense of quality. * @@ -1154,20 +1186,28 @@ public final class ImageDecoder implements AutoCloseable { * with only one channel, treat that channel as alpha. Otherwise this call has * no effect.

    * - *

    setDecodeAsAlphaMask is incompatible with {@link #ALLOCATOR_HARDWARE}. Trying to + *

    This is incompatible with {@link #ALLOCATOR_HARDWARE}. Trying to * combine them will result in {@link #decodeDrawable}/ * {@link #decodeBitmap} throwing an * {@link java.lang.IllegalStateException}.

    * * @return this object for chaining. */ - public ImageDecoder setDecodeAsAlphaMask(boolean decodeAsAlphaMask) { - mDecodeAsAlphaMask = decodeAsAlphaMask; + public ImageDecoder setDecodeAsAlphaMaskEnabled(boolean enabled) { + mDecodeAsAlphaMask = enabled; return this; } /** @removed - * @deprecated Call {@link #setDecodeAsAlphaMask} instead. + * @deprecated Renamed to {@link #setDecodeAsAlphaMaskEnabled}. + */ + @java.lang.Deprecated + public ImageDecoder setDecodeAsAlphaMask(boolean enabled) { + return this.setDecodeAsAlphaMaskEnabled(enabled); + } + + /** @removed + * @deprecated Renamed to {@link #setDecodeAsAlphaMaskEnabled}. */ @java.lang.Deprecated public ImageDecoder setAsAlphaMask(boolean asAlphaMask) { @@ -1177,16 +1217,25 @@ public final class ImageDecoder implements AutoCloseable { /** * Return whether to treat single channel input as alpha. * - *

    This returns whether {@link #setDecodeAsAlphaMask} was set to {@code true}. - * It may still return {@code true} even if the image has more than one - * channel and therefore will not be treated as an alpha mask.

    + *

    This returns whether {@link #setDecodeAsAlphaMaskEnabled} was set to + * {@code true}. It may still return {@code true} even if the image has + * more than one channel and therefore will not be treated as an alpha + * mask.

    + */ + public boolean isDecodeAsAlphaMaskEnabled() { + return mDecodeAsAlphaMask; + } + + /** @removed + * @deprecated Renamed to {@link #isDecodeAsAlphaMaskEnabled}. */ + @java.lang.Deprecated public boolean getDecodeAsAlphaMask() { return mDecodeAsAlphaMask; } /** @removed - * @deprecated Call {@link #getDecodeAsAlphaMask} instead. + * @deprecated Renamed to {@link #isDecodeAsAlphaMaskEnabled}. */ @java.lang.Deprecated public boolean getAsAlphaMask() { @@ -1259,7 +1308,7 @@ public final class ImageDecoder implements AutoCloseable { } } - if (mPostProcessor != null && mRequireUnpremultiplied) { + if (mPostProcessor != null && mUnpremultipliedRequired) { throw new IllegalStateException("Cannot draw to unpremultiplied pixels!"); } @@ -1290,7 +1339,7 @@ public final class ImageDecoder implements AutoCloseable { checkState(); return nDecodeBitmap(mNativePtr, this, mPostProcessor != null, mDesiredWidth, mDesiredHeight, mCropRect, - mMutable, mAllocator, mRequireUnpremultiplied, + mMutable, mAllocator, mUnpremultipliedRequired, mConserveMemory, mDecodeAsAlphaMask, mDesiredColorSpace); } @@ -1334,7 +1383,7 @@ public final class ImageDecoder implements AutoCloseable { decoder.mSource = src; decoder.callHeaderDecoded(listener, src); - if (decoder.mRequireUnpremultiplied) { + if (decoder.mUnpremultipliedRequired) { // Though this could be supported (ignored) for opaque images, // it seems better to always report this error. throw new IllegalStateException("Cannot decode a Drawable " + @@ -1534,7 +1583,7 @@ public final class ImageDecoder implements AutoCloseable { boolean doPostProcess, int width, int height, @Nullable Rect cropRect, boolean mutable, - int allocator, boolean requireUnpremul, + int allocator, boolean unpremulRequired, boolean conserveMemory, boolean decodeAsAlphaMask, @Nullable ColorSpace desiredColorSpace) throws IOException; -- GitLab From 3a021b3762a7ddeb365a0a660a88f4187497ffb6 Mon Sep 17 00:00:00 2001 From: Rubin Xu Date: Thu, 29 Mar 2018 12:04:34 +0100 Subject: [PATCH 084/179] Remove password blacklist API Bug: 73750934 Test: compiles Change-Id: I4a73ea47285b7d0be06f84d45a5166a6642c29cf --- api/current.txt | 2 - .../app/admin/DevicePolicyManager.java | 104 ----------- .../app/admin/IDevicePolicyManager.aidl | 4 - .../BaseIDevicePolicyManager.java | 17 -- .../DevicePolicyManagerService.java | 152 ---------------- .../devicepolicy/PasswordBlacklist.java | 165 ------------------ .../DevicePolicyManagerServiceTestable.java | 11 -- .../devicepolicy/DevicePolicyManagerTest.java | 30 ---- .../devicepolicy/MockSystemServices.java | 2 - .../devicepolicy/PasswordBlacklistTest.java | 110 ------------ 10 files changed, 597 deletions(-) delete mode 100644 services/devicepolicy/java/com/android/server/devicepolicy/PasswordBlacklist.java delete mode 100644 services/tests/servicestests/src/com/android/server/devicepolicy/PasswordBlacklistTest.java diff --git a/api/current.txt b/api/current.txt index 406ebac6c5eb..95d3c2412fc5 100644 --- a/api/current.txt +++ b/api/current.txt @@ -6464,7 +6464,6 @@ package android.app.admin { method public java.lang.CharSequence getOrganizationName(android.content.ComponentName); method public java.util.List getOverrideApns(android.content.ComponentName); method public android.app.admin.DevicePolicyManager getParentProfileInstance(android.content.ComponentName); - method public java.lang.String getPasswordBlacklistName(android.content.ComponentName); method public long getPasswordExpiration(android.content.ComponentName); method public long getPasswordExpirationTimeout(android.content.ComponentName); method public int getPasswordHistoryLength(android.content.ComponentName); @@ -6573,7 +6572,6 @@ package android.app.admin { method public void setOrganizationName(android.content.ComponentName, java.lang.CharSequence); method public void setOverrideApnsEnabled(android.content.ComponentName, boolean); method public java.lang.String[] setPackagesSuspended(android.content.ComponentName, java.lang.String[], boolean); - method public boolean setPasswordBlacklist(android.content.ComponentName, java.lang.String, java.util.List); method public void setPasswordExpirationTimeout(android.content.ComponentName, long); method public void setPasswordHistoryLength(android.content.ComponentName, int); method public void setPasswordMinimumLength(android.content.ComponentName, int); diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 106b42fba40d..36829235e60b 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -2726,110 +2726,6 @@ public class DevicePolicyManager { return 16; } - /** - * The maximum number of characters allowed in the password blacklist. - */ - private static final int PASSWORD_BLACKLIST_CHARACTER_LIMIT = 128 * 1000; - - /** - * Throws an exception if the password blacklist is too large. - * - * @hide - */ - public static void enforcePasswordBlacklistSize(List blacklist) { - if (blacklist == null) { - return; - } - long characterCount = 0; - for (final String item : blacklist) { - characterCount += item.length(); - } - if (characterCount > PASSWORD_BLACKLIST_CHARACTER_LIMIT) { - throw new IllegalArgumentException("128 thousand blacklist character limit exceeded by " - + (characterCount - PASSWORD_BLACKLIST_CHARACTER_LIMIT) + " characters"); - } - } - - /** - * Called by an application that is administering the device to blacklist passwords. - *

    - * Any blacklisted password or PIN is prevented from being enrolled by the user or the admin. - * Note that the match against the blacklist is case insensitive. The blacklist applies for all - * password qualities requested by {@link #setPasswordQuality} however it is not taken into - * consideration by {@link #isActivePasswordSufficient}. - *

    - * The blacklist can be cleared by passing {@code null} or an empty list. The blacklist is - * given a name that is used to track which blacklist is currently set by calling {@link - * #getPasswordBlacklistName}. If the blacklist is being cleared, the name is ignored and {@link - * #getPasswordBlacklistName} will return {@code null}. The name can only be {@code null} when - * the blacklist is being cleared. - *

    - * The blacklist is limited to a total of 128 thousand characters rather than limiting to a - * number of entries. - *

    - * This method can be called on the {@link DevicePolicyManager} instance returned by - * {@link #getParentProfileInstance(ComponentName)} in order to set restrictions on the parent - * profile. - * - * @param admin the {@link DeviceAdminReceiver} this request is associated with - * @param name name to associate with the blacklist - * @param blacklist list of passwords to blacklist or {@code null} to clear the blacklist - * @return whether the new blacklist was successfully installed - * @throws SecurityException if {@code admin} is not a device or profile owner - * @throws IllegalArgumentException if the blacklist surpasses the character limit - * @throws NullPointerException if {@code name} is {@code null} when setting a non-empty list - * - * @see #getPasswordBlacklistName - * @see #isActivePasswordSufficient - * @see #resetPasswordWithToken - */ - public boolean setPasswordBlacklist(@NonNull ComponentName admin, @Nullable String name, - @Nullable List blacklist) { - enforcePasswordBlacklistSize(blacklist); - - try { - return mService.setPasswordBlacklist(admin, name, blacklist, mParentInstance); - } catch (RemoteException re) { - throw re.rethrowFromSystemServer(); - } - } - - /** - * Get the name of the password blacklist set by the given admin. - * - * @param admin the {@link DeviceAdminReceiver} this request is associated with - * @return the name of the blacklist or {@code null} if no blacklist is set - * - * @see #setPasswordBlacklist - */ - public @Nullable String getPasswordBlacklistName(@NonNull ComponentName admin) { - try { - return mService.getPasswordBlacklistName(admin, myUserId(), mParentInstance); - } catch (RemoteException re) { - throw re.rethrowFromSystemServer(); - } - } - - /** - * Test if a given password is blacklisted. - * - * @param userId the user to valiate for - * @param password the password to check against the blacklist - * @return whether the password is blacklisted - * - * @see #setPasswordBlacklist - * - * @hide - */ - @RequiresPermission(android.Manifest.permission.TEST_BLACKLISTED_PASSWORD) - public boolean isPasswordBlacklisted(@UserIdInt int userId, @NonNull String password) { - try { - return mService.isPasswordBlacklisted(userId, password); - } catch (RemoteException re) { - throw re.rethrowFromSystemServer(); - } - } - /** * Determine whether the current password the user has set is sufficient to meet the policy * requirements (e.g. quality, minimum length) that have been requested by the admins of this diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index 4b39a9a53252..37508cdc1119 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -79,10 +79,6 @@ interface IDevicePolicyManager { long getPasswordExpiration(in ComponentName who, int userHandle, boolean parent); - boolean setPasswordBlacklist(in ComponentName who, String name, in List blacklist, boolean parent); - String getPasswordBlacklistName(in ComponentName who, int userId, boolean parent); - boolean isPasswordBlacklisted(int userId, String password); - boolean isActivePasswordSufficient(int userHandle, boolean parent); boolean isProfileActivePasswordSufficientForParent(int userHandle); boolean isUsingUnifiedPassword(in ComponentName admin); diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java index 71c2ea18eb1b..1c9782fa5565 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java @@ -78,23 +78,6 @@ abstract class BaseIDevicePolicyManager extends IDevicePolicyManager.Stub { return false; } - @Override - public boolean setPasswordBlacklist(ComponentName who, String name, List blacklist, - boolean parent) { - return false; - } - - @Override - public String getPasswordBlacklistName(ComponentName who, @UserIdInt int userId, - boolean parent) { - return null; - } - - @Override - public boolean isPasswordBlacklisted(@UserIdInt int userId, String password) { - return false; - } - public boolean isUsingUnifiedPassword(ComponentName who) { return true; } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 5cfba22d2c66..d52fd212b7b8 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -820,7 +820,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { private static final String TAG_PASSWORD_HISTORY_LENGTH = "password-history-length"; private static final String TAG_MIN_PASSWORD_LENGTH = "min-password-length"; private static final String ATTR_VALUE = "value"; - private static final String TAG_PASSWORD_BLACKLIST = "password-blacklist"; private static final String TAG_PASSWORD_QUALITY = "password-quality"; private static final String TAG_POLICIES = "policies"; private static final String TAG_CROSS_PROFILE_WIDGET_PROVIDERS = @@ -961,9 +960,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { // Default title of confirm credentials screen String organizationName = null; - // The blacklist data is stored in a file whose name is stored in the XML - String passwordBlacklistFile = null; - // The component name of the backup transport which has to be used if backups are mandatory // or null if backups are not mandatory. ComponentName mandatoryBackupTransport = null; @@ -1053,11 +1049,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { out.endTag(null, TAG_MIN_PASSWORD_NONLETTER); } } - if (passwordBlacklistFile != null) { - out.startTag(null, TAG_PASSWORD_BLACKLIST); - out.attribute(null, ATTR_VALUE, passwordBlacklistFile); - out.endTag(null, TAG_PASSWORD_BLACKLIST); - } if (maximumTimeToUnlock != DEF_MAXIMUM_TIME_TO_UNLOCK) { out.startTag(null, TAG_MAX_TIME_TO_UNLOCK); out.attribute(null, ATTR_VALUE, Long.toString(maximumTimeToUnlock)); @@ -1313,8 +1304,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } else if (TAG_MIN_PASSWORD_NONLETTER.equals(tag)) { minimumPasswordMetrics.nonLetter = Integer.parseInt( parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_PASSWORD_BLACKLIST.equals(tag)) { - passwordBlacklistFile = parser.getAttributeValue(null, ATTR_VALUE); }else if (TAG_MAX_TIME_TO_UNLOCK.equals(tag)) { maximumTimeToUnlock = Long.parseLong( parser.getAttributeValue(null, ATTR_VALUE)); @@ -1589,8 +1578,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { pw.println(minimumPasswordMetrics.symbols); pw.print(prefix); pw.print("minimumPasswordNonLetter="); pw.println(minimumPasswordMetrics.nonLetter); - pw.print(prefix); pw.print("passwordBlacklist="); - pw.println(passwordBlacklistFile != null); pw.print(prefix); pw.print("maximumTimeToUnlock="); pw.println(maximumTimeToUnlock); pw.print(prefix); pw.print("strongAuthUnlockTimeout="); @@ -1857,10 +1844,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return new LockPatternUtils(mContext); } - PasswordBlacklist newPasswordBlacklist(File file) { - return new PasswordBlacklist(file); - } - boolean storageManagerIsFileBasedEncryptionEnabled() { return StorageManager.isFileEncryptedNativeOnly(); } @@ -4412,136 +4395,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } - /* @return the password blacklist set by the admin or {@code null} if none. */ - PasswordBlacklist getAdminPasswordBlacklistLocked(@NonNull ActiveAdmin admin) { - final int userId = UserHandle.getUserId(admin.getUid()); - return admin.passwordBlacklistFile == null ? null : new PasswordBlacklist( - new File(getPolicyFileDirectory(userId), admin.passwordBlacklistFile)); - } - - private static final String PASSWORD_BLACKLIST_FILE_PREFIX = "password-blacklist-"; - private static final String PASSWORD_BLACKLIST_FILE_SUFFIX = ""; - - @Override - public boolean setPasswordBlacklist(ComponentName who, String name, List blacklist, - boolean parent) { - if (!mHasFeature) { - return false; - } - Preconditions.checkNotNull(who, "who is null"); - - synchronized (this) { - final ActiveAdmin admin = getActiveAdminForCallerLocked( - who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, parent); - final int userId = mInjector.userHandleGetCallingUserId(); - PasswordBlacklist adminBlacklist = getAdminPasswordBlacklistLocked(admin); - - if (blacklist == null || blacklist.isEmpty()) { - // Remove the adminBlacklist - admin.passwordBlacklistFile = null; - saveSettingsLocked(userId); - if (adminBlacklist != null) { - adminBlacklist.delete(); - } - return true; - } - - // Validate server side - Preconditions.checkNotNull(name, "name is null"); - DevicePolicyManager.enforcePasswordBlacklistSize(blacklist); - - // Blacklist is case insensitive so normalize to lower case - final int blacklistSize = blacklist.size(); - for (int i = 0; i < blacklistSize; ++i) { - blacklist.set(i, blacklist.get(i).toLowerCase()); - } - - final boolean isNewBlacklist = adminBlacklist == null; - if (isNewBlacklist) { - // Create a new file for the blacklist. There could be multiple admins, each setting - // different blacklists, to restrict a user's credential, for example a managed - // profile can impose restrictions on its parent while the parent is already - // restricted by its own admin. A deterministic naming scheme would be fragile if - // new types of admin are introduced so we generate and save the file name instead. - // This isn't a temporary file but it reuses the name generation logic - final File file; - try { - file = File.createTempFile(PASSWORD_BLACKLIST_FILE_PREFIX, - PASSWORD_BLACKLIST_FILE_SUFFIX, getPolicyFileDirectory(userId)); - } catch (IOException e) { - Slog.e(LOG_TAG, "Failed to make a file for the blacklist", e); - return false; - } - adminBlacklist = mInjector.newPasswordBlacklist(file); - } - - if (adminBlacklist.savePasswordBlacklist(name, blacklist)) { - if (isNewBlacklist) { - // The blacklist was saved so point the admin to the file - admin.passwordBlacklistFile = adminBlacklist.getFile().getName(); - saveSettingsLocked(userId); - } - return true; - } - } - - return false; - } - - @Override - public String getPasswordBlacklistName(ComponentName who, @UserIdInt int userId, - boolean parent) { - if (!mHasFeature) { - return null; - } - Preconditions.checkNotNull(who, "who is null"); - enforceFullCrossUsersPermission(userId); - synchronized (this) { - final ActiveAdmin admin = getActiveAdminForCallerLocked( - who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, parent); - final PasswordBlacklist blacklist = getAdminPasswordBlacklistLocked(admin); - if (blacklist == null) { - return null; - } - return blacklist.getName(); - } - } - - @Override - public boolean isPasswordBlacklisted(@UserIdInt int userId, String password) { - if (!mHasFeature) { - return false; - } - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.TEST_BLACKLISTED_PASSWORD, null); - return isPasswordBlacklistedInternal(userId, password); - } - - private boolean isPasswordBlacklistedInternal(@UserIdInt int userId, String password) { - Preconditions.checkNotNull(password, "Password is null"); - enforceFullCrossUsersPermission(userId); - - // Normalize to lower case for case insensitive blacklist match - final String lowerCasePassword = password.toLowerCase(); - - synchronized (this) { - final List admins = - getActiveAdminsForLockscreenPoliciesLocked(userId, /* parent */ false); - final int N = admins.size(); - for (int i = 0; i < N; i++) { - final PasswordBlacklist blacklist - = getAdminPasswordBlacklistLocked(admins.get(i)); - if (blacklist != null) { - if (blacklist.isPasswordBlacklisted(lowerCasePassword)) { - return true; - } - } - } - } - - return false; - } - @Override public boolean isActivePasswordSufficient(int userHandle, boolean parent) { if (!mHasFeature) { @@ -4937,11 +4790,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return false; } } - - if (isPasswordBlacklistedInternal(userHandle, password)) { - Slog.w(LOG_TAG, "resetPassword: the password is blacklisted"); - return false; - } } DevicePolicyData policy = getUserData(userHandle); diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PasswordBlacklist.java b/services/devicepolicy/java/com/android/server/devicepolicy/PasswordBlacklist.java deleted file mode 100644 index a17a1075f100..000000000000 --- a/services/devicepolicy/java/com/android/server/devicepolicy/PasswordBlacklist.java +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.devicepolicy; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.util.AtomicFile; -import android.util.Slog; - -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.util.List; - -/** - * Manages the blacklisted passwords. - * - * This caller must ensure synchronized access. - */ -public class PasswordBlacklist { - private static final String TAG = "PasswordBlacklist"; - - private final AtomicFile mFile; - - /** - * Create an object to manage the password blacklist. - * - * This is a lightweight operation to prepare variables but not perform any IO. - */ - public PasswordBlacklist(File file) { - mFile = new AtomicFile(file, "device-policy"); - } - - /** - * Atomically replace the blacklist. - * - * Pass {@code null} for an empty list. - */ - public boolean savePasswordBlacklist(@NonNull String name, @NonNull List blacklist) { - FileOutputStream fos = null; - try { - fos = mFile.startWrite(); - final DataOutputStream out = buildStreamForWriting(fos); - final Header header = new Header(Header.VERSION_1, name, blacklist.size()); - header.write(out); - final int blacklistSize = blacklist.size(); - for (int i = 0; i < blacklistSize; ++i) { - out.writeUTF(blacklist.get(i)); - } - out.flush(); - mFile.finishWrite(fos); - return true; - } catch (IOException e) { - mFile.failWrite(fos); - return false; - } - } - - /** @return the name of the blacklist or {@code null} if none set. */ - public String getName() { - try (DataInputStream in = openForReading()) { - return Header.read(in).mName; - } catch (IOException e) { - Slog.wtf(TAG, "Failed to read blacklist file", e); - } - return null; - } - - /** @return the number of blacklisted passwords. */ - public int getSize() { - final int blacklistSize; - try (DataInputStream in = openForReading()) { - return Header.read(in).mSize; - } catch (IOException e) { - Slog.wtf(TAG, "Failed to read blacklist file", e); - } - return 0; - } - - /** @return whether the password matches an blacklisted item. */ - public boolean isPasswordBlacklisted(@NonNull String password) { - final int blacklistSize; - try (DataInputStream in = openForReading()) { - final Header header = Header.read(in); - for (int i = 0; i < header.mSize; ++i) { - if (in.readUTF().equals(password)) { - return true; - } - } - } catch (IOException e) { - Slog.wtf(TAG, "Failed to read blacklist file", e); - // Fail safe and block all passwords. Setting a new blacklist should resolve this - // problem which can be identified by examining the log. - return true; - } - return false; - } - - /** Delete the blacklist completely from disk. */ - public void delete() { - mFile.delete(); - } - - /** Get the file the blacklist is stored in. */ - public File getFile() { - return mFile.getBaseFile(); - } - - private DataOutputStream buildStreamForWriting(FileOutputStream fos) { - return new DataOutputStream(new BufferedOutputStream(fos)); - } - - private DataInputStream openForReading() throws IOException { - return new DataInputStream(new BufferedInputStream(mFile.openRead())); - } - - /** - * Helper to read and write the header of the blacklist file. - */ - private static class Header { - static final int VERSION_1 = 1; - - final int mVersion; // File format version - final String mName; - final int mSize; - - Header(int version, String name, int size) { - mVersion = version; - mName = name; - mSize = size; - } - - void write(DataOutputStream out) throws IOException { - out.writeInt(mVersion); - out.writeUTF(mName); - out.writeInt(mSize); - } - - static Header read(DataInputStream in) throws IOException { - final int version = in.readInt(); - final String name = in.readUTF(); - final int size = in.readInt(); - return new Header(version, name, size); - } - } -} diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java index ab0bfefbbd4d..8537bc176467 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java @@ -98,12 +98,6 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi this.context = injector.context; } - @Override - public boolean isPasswordBlacklisted(int userId, String password) { - return false; - } - - public void notifyChangeToContentObserver(Uri uri, int userHandle) { ContentObserver co = mMockInjector.mContentObservers.get(new Pair<>(uri, userHandle)); if (co != null) { @@ -219,11 +213,6 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi return services.lockPatternUtils; } - @Override - PasswordBlacklist newPasswordBlacklist(File file) { - return services.passwordBlacklist; - } - @Override boolean storageManagerIsFileBasedEncryptionEnabled() { return services.storageManager.isFileBasedEncryptionEnabled(); diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java index fe47de602cda..43ddbe30e0dd 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -4191,36 +4191,6 @@ public class DevicePolicyManagerTest extends DpmTestBase { assertTrue(dpm.clearResetPasswordToken(admin1)); } - public void testSetPasswordBlacklistCannotBeCalledByNonAdmin() throws Exception { - assertExpectException(SecurityException.class, /* messageRegex= */ null, - () -> dpm.setPasswordBlacklist(admin1, null, null)); - verifyZeroInteractions(getServices().passwordBlacklist); - } - - public void testClearingPasswordBlacklistDoesNotCreateNewBlacklist() throws Exception { - setupProfileOwner(); - dpm.setPasswordBlacklist(admin1, null, null); - verifyZeroInteractions(getServices().passwordBlacklist); - } - - public void testSetPasswordBlacklistCreatesNewBlacklist() throws Exception { - final String name = "myblacklist"; - final List explicit = Arrays.asList("password", "letmein"); - setupProfileOwner(); - dpm.setPasswordBlacklist(admin1, name, explicit); - verify(getServices().passwordBlacklist).savePasswordBlacklist(name, explicit); - } - - public void testSetPasswordBlacklistOnlyConvertsExplicitToLowerCase() throws Exception { - final List mixedCase = Arrays.asList("password", "LETMEIN", "FooTBAll"); - final List lowerCase = Arrays.asList("password", "letmein", "football"); - mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; - setupDeviceOwner(); - final String name = "Name of the Blacklist"; - dpm.setPasswordBlacklist(admin1, name, mixedCase); - verify(getServices().passwordBlacklist).savePasswordBlacklist(name, lowerCase); - } - public void testIsActivePasswordSufficient() throws Exception { mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; mContext.packageName = admin1.getPackageName(); diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java index 34c69f5b0c5b..95ab59776a43 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java @@ -96,7 +96,6 @@ public class MockSystemServices { public final IBackupManager ibackupManager; public final IAudioService iaudioService; public final LockPatternUtils lockPatternUtils; - public final PasswordBlacklist passwordBlacklist; public final StorageManagerForMock storageManager; public final WifiManager wifiManager; public final SettingsForMock settings; @@ -135,7 +134,6 @@ public class MockSystemServices { ibackupManager = mock(IBackupManager.class); iaudioService = mock(IAudioService.class); lockPatternUtils = mock(LockPatternUtils.class); - passwordBlacklist = mock(PasswordBlacklist.class); storageManager = mock(StorageManagerForMock.class); wifiManager = mock(WifiManager.class); settings = mock(SettingsForMock.class); diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/PasswordBlacklistTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/PasswordBlacklistTest.java deleted file mode 100644 index 1b3fc2c1f207..000000000000 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/PasswordBlacklistTest.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.server.devicepolicy; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import android.content.Context; -import android.support.test.InstrumentationRegistry; -import android.support.test.runner.AndroidJUnit4; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.Arrays; -import java.util.ArrayList; -import java.util.List; - -/** - * Unit tests for {@link PasswordBlacklist}. - * - * bit FrameworksServicesTests:com.android.server.devicepolicy.PasswordBlacklistTest - * runtest -x frameworks/base/services/tests/servicestests/src/com/android/server/devicepolicy/PasswordBlacklistTest.java - */ -@RunWith(AndroidJUnit4.class) -public final class PasswordBlacklistTest { - private File mBlacklistFile; - private PasswordBlacklist mBlacklist; - - @Before - public void setUp() throws IOException { - mBlacklistFile = File.createTempFile("pwdbl", null); - mBlacklist = new PasswordBlacklist(mBlacklistFile); - } - - @After - public void tearDown() { - mBlacklist.delete(); - } - - @Test - public void matchIsExact() { - // Note: Case sensitivity is handled by the user of PasswordBlacklist by normalizing the - // values stored in and tested against it. - mBlacklist.savePasswordBlacklist("matchIsExact", Arrays.asList("password", "qWERty")); - assertTrue(mBlacklist.isPasswordBlacklisted("password")); - assertTrue(mBlacklist.isPasswordBlacklisted("qWERty")); - assertFalse(mBlacklist.isPasswordBlacklisted("Password")); - assertFalse(mBlacklist.isPasswordBlacklisted("qwert")); - assertFalse(mBlacklist.isPasswordBlacklisted("letmein")); - } - - @Test - public void matchIsNotRegex() { - mBlacklist.savePasswordBlacklist("matchIsNotRegex", Arrays.asList("a+b*")); - assertTrue(mBlacklist.isPasswordBlacklisted("a+b*")); - assertFalse(mBlacklist.isPasswordBlacklisted("aaaa")); - assertFalse(mBlacklist.isPasswordBlacklisted("abbbb")); - assertFalse(mBlacklist.isPasswordBlacklisted("aaaa")); - } - - @Test - public void matchFailsSafe() throws IOException { - try (FileOutputStream fos = new FileOutputStream(mBlacklistFile)) { - // Write a malformed blacklist file - fos.write(17); - } - assertTrue(mBlacklist.isPasswordBlacklisted("anything")); - assertTrue(mBlacklist.isPasswordBlacklisted("at")); - assertTrue(mBlacklist.isPasswordBlacklisted("ALL")); - } - - @Test - public void blacklistCanBeNamed() { - final String name = "identifier"; - mBlacklist.savePasswordBlacklist(name, Arrays.asList("one", "two", "three")); - assertEquals(mBlacklist.getName(), name); - } - - @Test - public void reportsTheCorrectNumberOfEntries() { - mBlacklist.savePasswordBlacklist("Count Entries", Arrays.asList("1", "2", "3", "4")); - assertEquals(mBlacklist.getSize(), 4); - } - - @Test - public void reportsBlacklistFile() { - assertEquals(mBlacklistFile, mBlacklist.getFile()); - } -} -- GitLab From b03dd4f4a3c5e2a1e2378005ee5e93ca2614dc92 Mon Sep 17 00:00:00 2001 From: Vishwath Mohan Date: Thu, 29 Mar 2018 17:56:33 +0000 Subject: [PATCH 085/179] Revert "Clear pattern on completion (if fade is enabled)." This reverts commit b8e9782f70d6aa28368798cdb969607831c826ce. Bug: 77257848 Test: Can change from pattern to pin/password Change-Id: I17f9625e506c8e0839fffa95a62c904890cac603 --- core/java/com/android/internal/widget/LockPatternView.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java index 957c784087af..51dd92961f54 100644 --- a/core/java/com/android/internal/widget/LockPatternView.java +++ b/core/java/com/android/internal/widget/LockPatternView.java @@ -1008,9 +1008,6 @@ public class LockPatternView extends View { mDrawingProfilingStarted = false; } } - if (mFadePattern) { - clearPattern(); - } } private void cancelLineAnimations() { -- GitLab From 8ce43a5e701de4ddb2f1e281b946d5ea96711d06 Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Thu, 29 Mar 2018 13:01:49 -0700 Subject: [PATCH 086/179] Minor javadoc fixes. Test: echo 'In TH we trust!' Bug: 74830976 Change-Id: Ib88fc0b0275e87ea31d22759507b4c29c7849c05 --- .../AutofillFieldClassificationService.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/core/java/android/service/autofill/AutofillFieldClassificationService.java b/core/java/android/service/autofill/AutofillFieldClassificationService.java index 99d45f40c26a..1cd76d2e9ec9 100644 --- a/core/java/android/service/autofill/AutofillFieldClassificationService.java +++ b/core/java/android/service/autofill/AutofillFieldClassificationService.java @@ -41,11 +41,11 @@ import java.util.List; * *

    A field classification score is a {@code float} representing how well an * {@link AutofillValue} filled matches a expected value predicted by an autofill service - * —a full-match is {@code 1.0} (representing 100%), while a full mismatch is {@code 0.0}. + * —a full match is {@code 1.0} (representing 100%), while a full mismatch is {@code 0.0}. * - *

    The exact score depends on the algorithm used to calculate it— the service must provide + *

    The exact score depends on the algorithm used to calculate it—the service must provide * at least one default algorithm (which is used when the algorithm is not specified or is invalid), - * but it could provide more (in which case the algorithm name should be specifiied by the caller + * but it could provide more (in which case the algorithm name should be specified by the caller * when calculating the scores). * * {@hide} @@ -115,15 +115,15 @@ public abstract class AutofillFieldClassificationService extends Service { * *

    A field classification score is a {@code float} representing how well an * {@link AutofillValue} filled matches a expected value predicted by an autofill service - * —a full-match is {@code 1.0} (representing 100%), while a full mismatch is {@code 0.0}. + * —a full match is {@code 1.0} (representing 100%), while a full mismatch is {@code 0.0}. * - *

    The exact score depends on the algorithm used to calculate it— the service must + *

    The exact score depends on the algorithm used to calculate it—the service must * provide at least one default algorithm (which is used when the algorithm is not specified * or is invalid), but it could provide more (in which case the algorithm name should be - * specifiied by the caller when calculating the scores). + * specified by the caller when calculating the scores). * *

    For example, if the service provides an algorithm named {@code EXACT_MATCH} that - * returns {@code 1.0} if all characters in match or {@code 0.0} otherwise, a call to: + * returns {@code 1.0} if all characters match or {@code 0.0} otherwise, a call to: * *

          * service.onGetScores("EXACT_MATCH", null,
    -- 
    GitLab
    
    
    From b1b423a46f187c978ba7d7b7572890ea8e75ba56 Mon Sep 17 00:00:00 2001
    From: Mihai Popa 
    Date: Tue, 27 Mar 2018 19:03:09 +0100
    Subject: [PATCH 087/179] [Magnifier-37] Hide handle when overlaps magnifier
    
    In most cases, the magnifier will be displayed above the current line,
    so it will not overlap with the handle being dragged. However, when
    there is not enough space in the current surface for the magnifier to be
    displayed above the current line, the handle can overlap with the
    magnifier. Since the handle is implemented as a different window, we
    cannot really control the z ordering between them, and we noticed that
    the handle will be rendered over the magnifier, which looks bad. This CL
    better handles this situation, by hiding the handle when it would
    overlap with the magnifier.
    
    Bug: 76459199
    Test: manual testing
    Test: atest FrameworksCoreTests:android.widget.TextViewActivityTest
    Test: atest FrameworksCoreTests:android.widget.TextViewTest
    Change-Id: Id5a17fd964360df6094f9e2680e5bcca886c4d2d
    ---
     core/java/android/widget/Editor.java | 40 +++++++++++++++++++++-------
     1 file changed, 30 insertions(+), 10 deletions(-)
    
    diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
    index 92f496a87c3f..99467265b5c5 100644
    --- a/core/java/android/widget/Editor.java
    +++ b/core/java/android/widget/Editor.java
    @@ -4585,8 +4585,8 @@ public class Editor {
                 return mContainer.isShowing();
             }
     
    -        private boolean isVisible() {
    -            // Always show a dragging handle.
    +        private boolean shouldShow() {
    +            // A dragging handle should always be shown.
                 if (mIsDragging) {
                     return true;
                 }
    @@ -4599,6 +4599,10 @@ public class Editor {
                         mPositionX + mHotspotX + getHorizontalOffset(), mPositionY);
             }
     
    +        private void setVisible(final boolean visible) {
    +            mContainer.getContentView().setVisibility(visible ? VISIBLE : INVISIBLE);
    +        }
    +
             public abstract int getCurrentCursorOffset();
     
             protected abstract void updateSelection(int offset);
    @@ -4692,7 +4696,7 @@ public class Editor {
                         onHandleMoved();
                     }
     
    -                if (isVisible()) {
    +                if (shouldShow()) {
                         // Transform to the window coordinates to follow the view tranformation.
                         final int[] pts = { mPositionX + mHotspotX + getHorizontalOffset(), mPositionY};
                         mTextView.transformFromViewToWindowSpace(pts);
    @@ -4745,6 +4749,15 @@ public class Editor {
                 return 0;
             }
     
    +        private boolean tooLargeTextForMagnifier() {
    +            final float magnifierContentHeight = Math.round(
    +                    mMagnifierAnimator.mMagnifier.getHeight()
    +                            / mMagnifierAnimator.mMagnifier.getZoom());
    +            final Paint.FontMetrics fontMetrics = mTextView.getPaint().getFontMetrics();
    +            final float glyphHeight = fontMetrics.descent - fontMetrics.ascent;
    +            return glyphHeight > magnifierContentHeight;
    +        }
    +
             /**
              * Computes the position where the magnifier should be shown, relative to
              * {@code mTextView}, and writes them to {@code showPosInView}. Also decides
    @@ -4824,13 +4837,12 @@ public class Editor {
                 return true;
             }
     
    -        private boolean tooLargeTextForMagnifier() {
    -            final float magnifierContentHeight = Math.round(
    -                    mMagnifierAnimator.mMagnifier.getHeight()
    -                            / mMagnifierAnimator.mMagnifier.getZoom());
    -            final Paint.FontMetrics fontMetrics = mTextView.getPaint().getFontMetrics();
    -            final float glyphHeight = fontMetrics.descent - fontMetrics.ascent;
    -            return glyphHeight > magnifierContentHeight;
    +        private boolean handleOverlapsMagnifier() {
    +            final int handleY = mContainer.getDecorViewLayoutParams().y;
    +            final int magnifierBottomWhenAtWindowTop =
    +                    mTextView.getRootWindowInsets().getSystemWindowInsetTop()
    +                        + mMagnifierAnimator.mMagnifier.getHeight();
    +            return handleY <= magnifierBottomWhenAtWindowTop;
             }
     
             protected final void updateMagnifier(@NonNull final MotionEvent event) {
    @@ -4846,6 +4858,13 @@ public class Editor {
                     mRenderCursorRegardlessTiming = true;
                     mTextView.invalidateCursorPath();
                     suspendBlink();
    +                // Hide handle if it overlaps the magnifier.
    +                if (handleOverlapsMagnifier()) {
    +                    setVisible(false);
    +                } else {
    +                    setVisible(true);
    +                }
    +
                     mMagnifierAnimator.show(showPosInView.x, showPosInView.y);
                 } else {
                     dismissMagnifier();
    @@ -4857,6 +4876,7 @@ public class Editor {
                     mMagnifierAnimator.dismiss();
                     mRenderCursorRegardlessTiming = false;
                     resumeBlink();
    +                setVisible(true);
                 }
             }
     
    -- 
    GitLab
    
    
    From 18bbed586595cd6bb4c77d5edac03316bb3a5645 Mon Sep 17 00:00:00 2001
    From: Jeff Sharkey 
    Date: Thu, 29 Mar 2018 14:20:48 -0600
    Subject: [PATCH 088/179] Only return internal path when not visible.
    
    When a volume is visible (wrapped in sdcardfs), we need all file
    operations to go through that sdcardfs layer to keep it in sync.
    
    Test: manual
    Bug: 73922090
    Change-Id: I14f1f4743f470a6cbc78030e1ea8411f9910a5b9
    ---
     core/java/android/os/storage/VolumeInfo.java | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/core/java/android/os/storage/VolumeInfo.java b/core/java/android/os/storage/VolumeInfo.java
    index 5c99f6c87d7c..9e3e386eedb2 100644
    --- a/core/java/android/os/storage/VolumeInfo.java
    +++ b/core/java/android/os/storage/VolumeInfo.java
    @@ -312,7 +312,7 @@ public class VolumeInfo implements Parcelable {
          * {@link android.Manifest.permission#WRITE_MEDIA_STORAGE}.
          */
         public File getInternalPathForUser(int userId) {
    -        if (type == TYPE_PUBLIC) {
    +        if (type == TYPE_PUBLIC && !isVisible()) {
                 // TODO: plumb through cleaner path from vold
                 return new File(path.replace("/storage/", "/mnt/media_rw/"));
             } else {
    -- 
    GitLab
    
    
    From c0281f10f5e79243abd087bb664054ac6ad6370b Mon Sep 17 00:00:00 2001
    From: yuemingw 
    Date: Wed, 28 Mar 2018 15:58:49 +0100
    Subject: [PATCH 089/179] Allow PO to call setSystemSetting.
    
    As system setting is per user, we should allow PO to call it.
    
    Bug: 77204777
    Test: runtest -x services/tests/servicestests/src/
    com/android/server/devicepolicy/DevicePolicyManagerTest.java
    
    Change-Id: I84152fa04adb441955b48b676be6e792134b52c2
    ---
     .../app/admin/DevicePolicyManager.java        | 11 ++++++-----
     .../DevicePolicyManagerService.java           | 13 ++++++++-----
     .../DevicePolicyManagerServiceTestable.java   |  4 ++--
     .../devicepolicy/DevicePolicyManagerTest.java | 19 ++++++++++---------
     .../devicepolicy/MockSystemServices.java      |  2 +-
     5 files changed, 27 insertions(+), 22 deletions(-)
    
    diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
    index 1534a15ab889..3c6f13570d3e 100644
    --- a/core/java/android/app/admin/DevicePolicyManager.java
    +++ b/core/java/android/app/admin/DevicePolicyManager.java
    @@ -7326,11 +7326,12 @@ public class DevicePolicyManager {
         public @interface SystemSettingsWhitelist {}
     
         /**
    -     * Called by device owner to update {@link android.provider.Settings.System} settings.
    -     * Validation that the value of the setting is in the correct form for the setting type should
    -     * be performed by the caller.
    +     * Called by a device or profile owner to update {@link android.provider.Settings.System}
    +     * settings. Validation that the value of the setting is in the correct form for the setting
    +     * type should be performed by the caller.
          * 

    - * The settings that can be updated with this method are: + * The settings that can be updated by a device owner or profile owner of secondary user with + * this method are: *

      *
    • {@link android.provider.Settings.System#SCREEN_BRIGHTNESS}
    • *
    • {@link android.provider.Settings.System#SCREEN_BRIGHTNESS_MODE}
    • @@ -7342,7 +7343,7 @@ public class DevicePolicyManager { * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @param setting The name of the setting to update. * @param value The value to update the setting to. - * @throws SecurityException if {@code admin} is not a device owner. + * @throws SecurityException if {@code admin} is not a device or profile owner. */ public void setSystemSetting(@NonNull ComponentName admin, @NonNull @SystemSettingsWhitelist String setting, String value) { diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 02cd3b6572ef..ffa7311f607d 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -2028,8 +2028,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { Settings.Global.putString(mContext.getContentResolver(), name, value); } - void settingsSystemPutString(String name, String value) { - Settings.System.putString(mContext.getContentResolver(), name, value); + void settingsSystemPutStringForUser(String name, String value, int userId) { + Settings.System.putStringForUser( + mContext.getContentResolver(), name, value, userId); } void securityLogSetLoggingEnabledProperty(boolean enabled) { @@ -10049,15 +10050,17 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { Preconditions.checkStringNotEmpty(setting, "String setting is null or empty"); synchronized (this) { - getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); + getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); if (!SYSTEM_SETTINGS_WHITELIST.contains(setting)) { throw new SecurityException(String.format( "Permission denial: device owners cannot update %1$s", setting)); } - mInjector.binderWithCleanCallingIdentity(() -> mInjector.settingsSystemPutString( - setting, value)); + final int callingUserId = mInjector.userHandleGetCallingUserId(); + + mInjector.binderWithCleanCallingIdentity(() -> + mInjector.settingsSystemPutStringForUser(setting, value, callingUserId)); } } diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java index ab0bfefbbd4d..520f31879e35 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java @@ -393,8 +393,8 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi } @Override - void settingsSystemPutString(String name, String value) { - services.settings.settingsSystemPutString(name, value); + void settingsSystemPutStringForUser(String name, String value, int userId) { + services.settings.settingsSystemPutStringForUser(name, value, userId); } @Override diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java index fe47de602cda..ccf4a8293d67 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -3454,18 +3454,19 @@ public class DevicePolicyManagerTest extends DpmTestBase { dpm.setSystemSetting(admin1, Settings.System.SCREEN_BRIGHTNESS_FOR_VR, "0")); } - public void testSetSystemSettingFailWithPO() throws Exception { - setupProfileOwner(); - assertExpectException(SecurityException.class, null, () -> - dpm.setSystemSetting(admin1, Settings.System.SCREEN_BRIGHTNESS, "0")); - } - - public void testSetSystemSetting() throws Exception { + public void testSetSystemSettingWithDO() throws Exception { mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; setupDeviceOwner(); dpm.setSystemSetting(admin1, Settings.System.SCREEN_BRIGHTNESS, "0"); - verify(getServices().settings).settingsSystemPutString( - Settings.System.SCREEN_BRIGHTNESS, "0"); + verify(getServices().settings).settingsSystemPutStringForUser( + Settings.System.SCREEN_BRIGHTNESS, "0", UserHandle.USER_SYSTEM); + } + + public void testSetSystemSettingWithPO() throws Exception { + setupProfileOwner(); + dpm.setSystemSetting(admin1, Settings.System.SCREEN_BRIGHTNESS, "0"); + verify(getServices().settings).settingsSystemPutStringForUser( + Settings.System.SCREEN_BRIGHTNESS, "0", DpmMockContext.CALLER_USER_HANDLE); } public void testSetTime() throws Exception { diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java index 34c69f5b0c5b..81ed6e2588fd 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java @@ -419,7 +419,7 @@ public class MockSystemServices { public void settingsGlobalPutString(String name, String value) { } - public void settingsSystemPutString(String name, String value) { + public void settingsSystemPutStringForUser(String name, String value, int callingUserId) { } public int settingsGlobalGetInt(String name, int value) { -- GitLab From 18f325012d1c807f2b0a9c577868722cc5fe4252 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Thu, 29 Mar 2018 14:29:27 -0600 Subject: [PATCH 090/179] Handle public volumes and otherwise invalid UUIDs. Public volumes have short UUIDs (which aren't valid 128-bit UUIDs), so we can't pass them around. Even if they were valid UUIDs, we don't handle clearing cached data on them, and they most likely don't support fallocate(), so don't match them. Test: manual Bug: 74132243 Change-Id: Ib855eb869a86392e96ced94a9926c0b32b87e57e --- core/java/android/os/storage/StorageManager.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java index bf20e6a82962..8905ad1e6abc 100644 --- a/core/java/android/os/storage/StorageManager.java +++ b/core/java/android/os/storage/StorageManager.java @@ -756,10 +756,15 @@ public class StorageManager { } try { for (VolumeInfo vol : mStorageManager.getVolumes(0)) { - if (vol.path != null && FileUtils.contains(vol.path, pathString)) { + if (vol.path != null && FileUtils.contains(vol.path, pathString) + && vol.type != VolumeInfo.TYPE_PUBLIC) { // TODO: verify that emulated adopted devices have UUID of // underlying volume - return convert(vol.fsUuid); + try { + return convert(vol.fsUuid); + } catch (IllegalArgumentException e) { + continue; + } } } } catch (RemoteException e) { -- GitLab From e5e2a75e8e470d0664d34f9c566b1a6529cfa762 Mon Sep 17 00:00:00 2001 From: Yi Jin Date: Wed, 28 Mar 2018 18:31:07 -0700 Subject: [PATCH 091/179] Add more privacy tags. Bug: 74837756 Test: manual Change-Id: I8993ae736df171f379aa6e24e865a6fbace9d091 --- core/proto/android/os/system_properties.proto | 2 ++ core/proto/android/server/jobscheduler.proto | 4 +--- core/proto/android/service/usb.proto | 5 ++++- core/proto/android/view/displayinfo.proto | 2 +- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/core/proto/android/os/system_properties.proto b/core/proto/android/os/system_properties.proto index 694b94b6fd2e..8bf3772a6a5d 100644 --- a/core/proto/android/os/system_properties.proto +++ b/core/proto/android/os/system_properties.proto @@ -192,6 +192,8 @@ message SystemPropertiesProto { optional string libc_debug_malloc_program = 15; message Log { + option (android.msg_privacy).dest = DEST_AUTOMATIC; + optional string tag_WifiHAL = 1; optional string tag_stats_log = 2; diff --git a/core/proto/android/server/jobscheduler.proto b/core/proto/android/server/jobscheduler.proto index bb8ce813b2f9..4df3b63a3eab 100644 --- a/core/proto/android/server/jobscheduler.proto +++ b/core/proto/android/server/jobscheduler.proto @@ -527,9 +527,7 @@ message JobStatusShortInfoProto { optional int32 calling_uid = 1; // Job IDs can technically be negative. optional int32 job_id = 2; - optional string battery_name = 3 [ - (.android.privacy).dest = DEST_EXPLICIT - ]; + optional string battery_name = 3; } // Dump from a com.android.server.job.controllers.JobStatus object. diff --git a/core/proto/android/service/usb.proto b/core/proto/android/service/usb.proto index b60c56995223..8240d8aff153 100644 --- a/core/proto/android/service/usb.proto +++ b/core/proto/android/service/usb.proto @@ -80,7 +80,7 @@ message UsbAccessoryProto { optional string model = 2; optional string description = 3; optional string version = 4; - optional string uri = 5; + optional string uri = 5 [ (android.privacy).dest = DEST_EXPLICIT ]; optional string serial = 6 [ (android.privacy).dest = DEST_EXPLICIT ]; } @@ -155,6 +155,7 @@ message UsbEndPointProto { message UsbConnectionRecordProto { option (android.msg_privacy).dest = DEST_AUTOMATIC; + // usb device's address, e.g. 001/002, nothing about the phone optional string device_address = 1; optional android.service.UsbConnectionRecordMode mode = 2; optional int64 timestamp = 3; @@ -251,6 +252,7 @@ message UsbAlsaDeviceProto { optional string name = 3; optional bool has_playback = 4; optional bool has_capture = 5; + // usb device's address, e.g. 001/002, nothing about the phone optional string address = 6; } @@ -259,6 +261,7 @@ message UsbMidiDeviceProto { optional int32 card = 1; optional int32 device = 2; + // usb device's address, e.g. 001/002, nothing about the phone optional string device_address = 3; } diff --git a/core/proto/android/view/displayinfo.proto b/core/proto/android/view/displayinfo.proto index cbd06fdb8c04..2a030509e617 100644 --- a/core/proto/android/view/displayinfo.proto +++ b/core/proto/android/view/displayinfo.proto @@ -29,5 +29,5 @@ message DisplayInfoProto { optional int32 logical_height = 2; optional int32 app_width = 3; optional int32 app_height = 4; - optional string name = 5; + optional string name = 5 [ (.android.privacy).dest = DEST_EXPLICIT ]; } -- GitLab From 8d2b053611fe4a52602c125bf1f577c12083848a Mon Sep 17 00:00:00 2001 From: Julia Reynolds Date: Thu, 29 Mar 2018 15:44:13 -0400 Subject: [PATCH 092/179] Update notification blocking documentation. Change-Id: I3e5425321d127fbf11adfa1c4ac5bed53fc73e03 Fixes: 73750866 Test: make --- core/java/android/app/NotificationChannel.java | 6 +++++- core/java/android/app/NotificationChannelGroup.java | 4 +++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java index 30f2697c1b1f..4a7cf62356e3 100644 --- a/core/java/android/app/NotificationChannel.java +++ b/core/java/android/app/NotificationChannel.java @@ -463,7 +463,11 @@ public final class NotificationChannel implements Parcelable { /** * Returns the user specified importance e.g. {@link NotificationManager#IMPORTANCE_LOW} for - * notifications posted to this channel. + * notifications posted to this channel. Note: This value might be > + * {@link NotificationManager#IMPORTANCE_NONE}, but notifications posted to this channel will + * not be shown to the user if the parent {@link NotificationChannelGroup} or app is blocked. + * See {@link NotificationChannelGroup#isBlocked()} and + * {@link NotificationManager#areNotificationsEnabled()}. */ public int getImportance() { return mImportance; diff --git a/core/java/android/app/NotificationChannelGroup.java b/core/java/android/app/NotificationChannelGroup.java index 16166f7cf1cf..0fa3c7fa6492 100644 --- a/core/java/android/app/NotificationChannelGroup.java +++ b/core/java/android/app/NotificationChannelGroup.java @@ -145,7 +145,9 @@ public final class NotificationChannelGroup implements Parcelable { /** * Returns whether or not notifications posted to {@link NotificationChannel channels} belonging - * to this group are blocked. + * to this group are blocked. This value is independent of + * {@link NotificationManager#areNotificationsEnabled()} and + * {@link NotificationChannel#getImportance()}. */ public boolean isBlocked() { return mBlocked; -- GitLab From 634fb404d3e4a92c2ef669a3b14b234c7968cdfd Mon Sep 17 00:00:00 2001 From: Victor Hsieh Date: Tue, 27 Mar 2018 15:02:38 -0700 Subject: [PATCH 093/179] Fix seccomp filter set up in zygote This needs to land with extra syscalls whitelisted, including capset and setresuid. These privileged syscalls are used in the setup after the filter is initialized. Test: system starts, different apps run Bug: 63944145 Bug: 76461821 Change-Id: I49e6b292805f35baffb3530461c8741e75aceb32 Merged-In: I49e6b292805f35baffb3530461c8741e75aceb32 --- core/jni/com_android_internal_os_Zygote.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index b5fd7929eeae..b2853c9f1c61 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -260,7 +260,7 @@ static void SetUpSeccompFilter(uid_t uid) { } // Apply system or app filter based on uid. - if (getuid() >= AID_APP_START) { + if (uid >= AID_APP_START) { set_app_seccomp_filter(); } else { set_system_seccomp_filter(); @@ -619,11 +619,6 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra fail_fn(CREATE_ERROR("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno))); } - // Must be called when the new process still has CAP_SYS_ADMIN. The other alternative is to - // call prctl(PR_SET_NO_NEW_PRIVS, 1) afterward, but that breaks SELinux domain transition (see - // b/71859146). - SetUpSeccompFilter(uid); - // Keep capabilities across UID change, unless we're staying root. if (uid != 0) { if (!EnableKeepCapabilities(&error_msg)) { @@ -699,6 +694,13 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra fail_fn(CREATE_ERROR("setresgid(%d) failed: %s", gid, strerror(errno))); } + // Must be called when the new process still has CAP_SYS_ADMIN, in this case, before changing + // uid from 0, which clears capabilities. The other alternative is to call + // prctl(PR_SET_NO_NEW_PRIVS, 1) afterward, but that breaks SELinux domain transition (see + // b/71859146). As the result, privileged syscalls used below still need to be accessible in + // app process. + SetUpSeccompFilter(uid); + rc = setresuid(uid, uid, uid); if (rc == -1) { fail_fn(CREATE_ERROR("setresuid(%d) failed: %s", uid, strerror(errno))); -- GitLab From ac55e01e1c8b67603134846c9b63002cc28aef48 Mon Sep 17 00:00:00 2001 From: Julia Reynolds Date: Tue, 27 Mar 2018 11:17:30 -0400 Subject: [PATCH 094/179] Volume UI updates - Reorder streams - constrain ripples - Show an introductory ripple on the ringer toggle - Add sound/vibration feedback for the ringer toggle - resize some elements Test: manual Bug: 76438403 Fixes: 73892482 Change-Id: I92dd6f5681f1822ae493a5a2b218b15970293e80 --- .../plugins/VolumeDialogController.java | 4 +- .../res/drawable/rounded_full_bg_bottom.xml | 14 +++ .../SystemUI/res/drawable/rounded_ripple.xml | 30 +++++ .../SystemUI/res/layout/car_volume_dialog.xml | 2 +- .../SystemUI/res/layout/volume_dialog.xml | 23 ++-- .../SystemUI/res/layout/volume_dialog_row.xml | 2 +- packages/SystemUI/res/values/dimens.xml | 10 +- packages/SystemUI/res/values/strings.xml | 2 +- .../src/com/android/systemui/Prefs.java | 4 +- .../volume/VolumeDialogControllerImpl.java | 39 ++++++- .../systemui/volume/VolumeDialogImpl.java | 108 +++++++++++++++--- .../android/systemui/volume/VolumePrefs.java | 2 +- 12 files changed, 198 insertions(+), 42 deletions(-) create mode 100644 packages/SystemUI/res/drawable/rounded_ripple.xml diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialogController.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialogController.java index c8bcdaac1d4a..5f4cf033a45a 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialogController.java +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialogController.java @@ -19,6 +19,7 @@ import android.content.ComponentName; import android.media.AudioManager; import android.media.AudioSystem; import android.os.Handler; +import android.os.VibrationEffect; import android.util.SparseArray; import com.android.systemui.plugins.VolumeDialogController.Callbacks; @@ -44,7 +45,8 @@ public interface VolumeDialogController { void setRingerMode(int ringerModeNormal, boolean external); boolean hasVibrator(); - void vibrate(); + void vibrate(VibrationEffect effect); + void scheduleTouchFeedback(); AudioManager getAudioManager(); diff --git a/packages/SystemUI/res/drawable/rounded_full_bg_bottom.xml b/packages/SystemUI/res/drawable/rounded_full_bg_bottom.xml index c3e36f211845..a4b3c99f7ec6 100644 --- a/packages/SystemUI/res/drawable/rounded_full_bg_bottom.xml +++ b/packages/SystemUI/res/drawable/rounded_full_bg_bottom.xml @@ -1,4 +1,18 @@ + diff --git a/packages/SystemUI/res/drawable/rounded_ripple.xml b/packages/SystemUI/res/drawable/rounded_ripple.xml new file mode 100644 index 000000000000..5588eb21ad8e --- /dev/null +++ b/packages/SystemUI/res/drawable/rounded_ripple.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/SystemUI/res/layout/car_volume_dialog.xml b/packages/SystemUI/res/layout/car_volume_dialog.xml index e45c0f9f5e4e..94cc001ca01a 100644 --- a/packages/SystemUI/res/layout/car_volume_dialog.xml +++ b/packages/SystemUI/res/layout/car_volume_dialog.xml @@ -38,7 +38,7 @@ android:orientation="vertical" android:clipChildren="false" android:clipToPadding="false" - android:elevation="@dimen/volume_panel_elevation" > + android:elevation="@dimen/volume_dialog_elevation" > + android:clipChildren="false" + android:clipToPadding="false"> + android:clipChildren="false" + android:clipToPadding="false" > @@ -59,10 +64,10 @@ android:minWidth="@dimen/volume_dialog_panel_width" android:layout_height="wrap_content" android:orientation="vertical" + android:translationZ="@dimen/volume_dialog_elevation" android:clipChildren="false" android:clipToPadding="false" - android:background="@drawable/rounded_bg_full" - android:elevation="@dimen/volume_panel_elevation" > + android:background="@drawable/rounded_bg_full" > diff --git a/packages/SystemUI/res/layout/volume_dialog_row.xml b/packages/SystemUI/res/layout/volume_dialog_row.xml index bcc369252c29..6128da8627a9 100644 --- a/packages/SystemUI/res/layout/volume_dialog_row.xml +++ b/packages/SystemUI/res/layout/volume_dialog_row.xml @@ -60,7 +60,7 @@ style="@style/VolumeButtons" android:layout_width="@dimen/volume_dialog_tap_target_size" android:layout_height="@dimen/volume_dialog_tap_target_size" - android:background="?android:selectableItemBackgroundBorderless" + android:background="@drawable/ripple_drawable_20dp" android:layout_marginBottom="@dimen/volume_dialog_row_margin_bottom" android:tint="@color/accent_tint_color_selector" android:soundEffectsEnabled="false" /> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 91c872495c9d..0f07ca45bc7f 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -270,13 +270,15 @@ @dimen/notification_panel_width + 8dp + 8dp 64dp - 108dp + 116dp 252dp @@ -286,7 +288,7 @@ 4dp - 22dp + 14dp -2dp @@ -294,6 +296,8 @@ 16dp + 9dp + 0x31 @@ -734,8 +738,6 @@ 2dp 6dp - 8dp - 4dp diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 419e9d28fa4e..e9b2be9b5b3e 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -1350,7 +1350,7 @@ %s volume controls - Calls and notifications will ring + Calls and notifications will ring (%1$s) Media output Phone call output diff --git a/packages/SystemUI/src/com/android/systemui/Prefs.java b/packages/SystemUI/src/com/android/systemui/Prefs.java index 1a9655ef62cd..2a2714735951 100644 --- a/packages/SystemUI/src/com/android/systemui/Prefs.java +++ b/packages/SystemUI/src/com/android/systemui/Prefs.java @@ -53,7 +53,8 @@ public final class Prefs { Key.NUM_APPS_LAUNCHED, Key.HAS_SEEN_RECENTS_ONBOARDING, Key.SEEN_RINGER_GUIDANCE_COUNT, - Key.QS_HAS_TURNED_OFF_MOBILE_DATA + Key.QS_HAS_TURNED_OFF_MOBILE_DATA, + Key.TOUCHED_RINGER_TOGGLE }) public @interface Key { @Deprecated @@ -91,6 +92,7 @@ public final class Prefs { String SEEN_RINGER_GUIDANCE_COUNT = "RingerGuidanceCount"; String QS_TILE_SPECS_REVEALED = "QsTileSpecsRevealed"; String QS_HAS_TURNED_OFF_MOBILE_DATA = "QsHasTurnedOffMobileData"; + String TOUCHED_RINGER_TOGGLE = "TouchedRingerToggle"; } public static boolean getBoolean(Context context, @Key String key, boolean defaultValue) { diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java index ee6748eee2f8..a97effd3a023 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java @@ -16,6 +16,8 @@ package com.android.systemui.volume; +import static android.media.AudioManager.RINGER_MODE_NORMAL; + import android.app.NotificationManager; import android.content.BroadcastReceiver; import android.content.ComponentName; @@ -29,6 +31,7 @@ import android.database.ContentObserver; import android.media.AudioAttributes; import android.media.AudioManager; import android.media.AudioSystem; +import android.media.IAudioService; import android.media.IVolumeController; import android.media.VolumePolicy; import android.media.session.MediaController.PlaybackInfo; @@ -39,6 +42,7 @@ import android.os.HandlerThread; import android.os.Looper; import android.os.Message; import android.os.RemoteException; +import android.os.ServiceManager; import android.os.VibrationEffect; import android.os.Vibrator; import android.provider.Settings; @@ -73,9 +77,11 @@ import java.util.Objects; public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpable { private static final String TAG = Util.logTag(VolumeDialogControllerImpl.class); + + private static final int TOUCH_FEEDBACK_TIMEOUT_MS = 1000; private static final int DYNAMIC_STREAM_START_INDEX = 100; private static final int VIBRATE_HINT_DURATION = 50; - private static final AudioAttributes SONFICIATION_VIBRATION_ATTRIBUTES = + private static final AudioAttributes SONIFICIATION_VIBRATION_ATTRIBUTES = new AudioAttributes.Builder() .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION) @@ -100,6 +106,7 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa private final W mWorker; private final Context mContext; private AudioManager mAudio; + private IAudioService mAudioService; protected StatusBar mStatusBar; private final NotificationManager mNoMan; private final SettingObserver mObserver; @@ -113,6 +120,7 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa private boolean mShowA11yStream; private boolean mShowVolumeDialog; private boolean mShowSafetyWarning; + private long mLastToggledRingerOn; private final NotificationManager mNotificationManager; private boolean mDestroyed; @@ -140,6 +148,8 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa mReceiver.init(); mVibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE); mHasVibrator = mVibrator != null && mVibrator.hasVibrator(); + mAudioService = IAudioService.Stub.asInterface( + ServiceManager.getService(Context.AUDIO_SERVICE)); updateStatusBar(); boolean accessibilityVolumeStreamActive = context.getSystemService( @@ -300,10 +310,24 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa mShowSafetyWarning = safetyWarning; } - public void vibrate() { + @Override + public void scheduleTouchFeedback() { + mLastToggledRingerOn = System.currentTimeMillis(); + } + + private void playTouchFeedback() { + if (System.currentTimeMillis() - mLastToggledRingerOn < TOUCH_FEEDBACK_TIMEOUT_MS) { + try { + mAudioService.playSoundEffect(AudioManager.FX_KEYPRESS_STANDARD); + } catch (RemoteException e) { + // ignore + } + } + } + + public void vibrate(VibrationEffect effect) { if (mHasVibrator) { - mVibrator.vibrate(VibrationEffect.createOneShot(VIBRATE_HINT_DURATION, - VibrationEffect.DEFAULT_AMPLITUDE), SONFICIATION_VIBRATION_ATTRIBUTES); + mVibrator.vibrate(effect, SONIFICIATION_VIBRATION_ATTRIBUTES); } } @@ -425,7 +449,7 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa for (int stream : STREAMS.keySet()) { updateStreamLevelW(stream, getAudioManagerStreamVolume(stream)); streamStateW(stream).levelMin = getAudioManagerStreamMinVolume(stream); - streamStateW(stream).levelMax = getAudioManagerStreamMaxVolume(stream); + streamStateW(stream).levelMax = Math.max(1, getAudioManagerStreamMaxVolume(stream)); updateStreamMuteW(stream, mAudio.isStreamMute(stream)); final StreamState ss = streamStateW(stream); ss.muteSupported = mAudio.isStreamAffectedByMute(stream); @@ -556,6 +580,11 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa if (rm == mState.ringerModeInternal) return false; mState.ringerModeInternal = rm; Events.writeEvent(mContext, Events.EVENT_INTERNAL_RINGER_MODE_CHANGED, rm); + + if (mState.ringerModeInternal == RINGER_MODE_NORMAL) { + playTouchFeedback(); + } + return true; } diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java index 71c7f80ef659..acdd0c71b491 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java @@ -22,6 +22,10 @@ import static android.media.AudioManager.RINGER_MODE_NORMAL; import static android.media.AudioManager.RINGER_MODE_SILENT; import static android.media.AudioManager.RINGER_MODE_VIBRATE; import static android.media.AudioManager.STREAM_ACCESSIBILITY; +import static android.media.AudioManager.STREAM_ALARM; +import static android.media.AudioManager.STREAM_MUSIC; +import static android.media.AudioManager.STREAM_RING; +import static android.media.AudioManager.STREAM_VOICE_CALL; import static android.view.View.GONE; import static android.view.View.VISIBLE; @@ -41,13 +45,17 @@ import android.content.res.Resources; import android.graphics.Color; import android.graphics.PixelFormat; import android.graphics.drawable.ColorDrawable; +import android.media.AudioAttributes; import android.media.AudioManager; import android.media.AudioSystem; +import android.media.MediaPlayer; import android.os.Debug; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.SystemClock; +import android.os.VibrationEffect; +import android.os.Vibrator; import android.provider.Settings; import android.provider.Settings.Global; import android.text.InputFilter; @@ -126,6 +134,7 @@ public class VolumeDialogImpl implements VolumeDialog { private final Accessibility mAccessibility = new Accessibility(); private final ColorStateList mActiveSliderTint; private final ColorStateList mInactiveSliderTint; + private final Vibrator mVibrator; private boolean mShowing; private boolean mShowA11yStream; @@ -146,6 +155,7 @@ public class VolumeDialogImpl implements VolumeDialog { mActiveSliderTint = ColorStateList.valueOf(Utils.getColorAccent(mContext)); mInactiveSliderTint = loadColorStateList(R.color.volume_slider_inactive); mDeviceProvisionedController = Dependency.get(DeviceProvisionedController.class); + mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); } public void init(int windowType, Callback callback) { @@ -203,6 +213,9 @@ public class VolumeDialogImpl implements VolumeDialog { .setInterpolator(new SystemUIInterpolators.LogDecelerateInterpolator()) .withEndAction(() -> { mWindow.getDecorView().requestAccessibilityFocus(); + if (!Prefs.getBoolean(mContext, Prefs.Key.TOUCHED_RINGER_TOGGLE, true)) { + mRingerIcon.postOnAnimationDelayed(mSinglePress, 1500); + } }) .start(); }); @@ -223,12 +236,16 @@ public class VolumeDialogImpl implements VolumeDialog { mSettingsIcon = mDialog.findViewById(R.id.settings); if (mRows.isEmpty()) { + if (!AudioSystem.isSingleVolume(mContext)) { + addRow(STREAM_ACCESSIBILITY, R.drawable.ic_volume_accessibility, + R.drawable.ic_volume_accessibility, true, false); + } addRow(AudioManager.STREAM_MUSIC, R.drawable.ic_volume_media, R.drawable.ic_volume_media_mute, true, true); if (!AudioSystem.isSingleVolume(mContext)) { addRow(AudioManager.STREAM_RING, R.drawable.ic_volume_ringer, R.drawable.ic_volume_ringer_mute, true, false); - addRow(AudioManager.STREAM_ALARM, + addRow(STREAM_ALARM, R.drawable.ic_volume_alarm, R.drawable.ic_volume_alarm_mute, true, false); addRow(AudioManager.STREAM_VOICE_CALL, R.drawable.ic_volume_voice, R.drawable.ic_volume_voice, false, false); @@ -236,8 +253,6 @@ public class VolumeDialogImpl implements VolumeDialog { R.drawable.ic_volume_bt_sco, R.drawable.ic_volume_bt_sco, false, false); addRow(AudioManager.STREAM_SYSTEM, R.drawable.ic_volume_system, R.drawable.ic_volume_system_mute, false, false); - addRow(STREAM_ACCESSIBILITY, R.drawable.ic_volume_accessibility, - R.drawable.ic_volume_accessibility, true, false); } } else { addExistingRows(); @@ -287,11 +302,11 @@ public class VolumeDialogImpl implements VolumeDialog { if (D.BUG) Slog.d(TAG, "Adding row for stream " + stream); VolumeRow row = new VolumeRow(); initRow(row, stream, iconRes, iconMuteRes, important, defaultStream); - int rowSize; - if (mShowA11yStream && dynamic && (rowSize = mRows.size()) > 1) { - // A11y Stream should be the first in the list, so it's shown to start of other rows - mDialogRowsView.addView(row.view, 0); - mRows.add(rowSize - 2, row); + if (dynamic && mRows.size() > 2) { + // Dynamic Streams should be the first in the list, so they're shown to start of + // everything except a11y + mDialogRowsView.addView(row.view, 1); + mRows.add(1, row); } else { mDialogRowsView.addView(row.view); mRows.add(row); @@ -315,6 +330,11 @@ public class VolumeDialogImpl implements VolumeDialog { return row; } } + for (VolumeRow row : mRows) { + if (row.stream == STREAM_MUSIC) { + return row; + } + } return mRows.get(0); } @@ -414,6 +434,7 @@ public class VolumeDialogImpl implements VolumeDialog { mRingerIcon.setOnClickListener(v -> { Events.writeEvent(mContext, Events.EVENT_ICON_CLICK, AudioManager.STREAM_RING, mRingerIcon.getTag()); + Prefs.putBoolean(mContext, Prefs.Key.TOUCHED_RINGER_TOGGLE, true); final StreamState ss = mState.states.get(AudioManager.STREAM_RING); if (ss == null) { return; @@ -424,7 +445,6 @@ public class VolumeDialogImpl implements VolumeDialog { final boolean hasVibrator = mController.hasVibrator(); if (mState.ringerModeInternal == AudioManager.RINGER_MODE_NORMAL) { if (hasVibrator) { - mController.vibrate(); newRingerMode = AudioManager.RINGER_MODE_VIBRATE; } else { newRingerMode = AudioManager.RINGER_MODE_SILENT; @@ -438,30 +458,56 @@ public class VolumeDialogImpl implements VolumeDialog { } } updateRingerH(); - + provideTouchFeedbackH(newRingerMode); mController.setRingerMode(newRingerMode, false); maybeShowToastH(newRingerMode); }); updateRingerH(); } + + private void provideTouchFeedbackH(int newRingerMode) { + VibrationEffect effect = null; + switch (newRingerMode) { + case RINGER_MODE_NORMAL: + mController.scheduleTouchFeedback(); + break; + case RINGER_MODE_SILENT: + effect = VibrationEffect.get(VibrationEffect.EFFECT_CLICK); + break; + case RINGER_MODE_VIBRATE: + default: + effect = VibrationEffect.get(VibrationEffect.EFFECT_DOUBLE_CLICK); + } + if (effect != null) { + mController.vibrate(effect); + } + } + private void maybeShowToastH(int newRingerMode) { int seenToastCount = Prefs.getInt(mContext, Prefs.Key.SEEN_RINGER_GUIDANCE_COUNT, 0); if (seenToastCount > VolumePrefs.SHOW_RINGER_TOAST_COUNT) { return; } - int toastText; + CharSequence toastText = null; switch (newRingerMode) { case RINGER_MODE_NORMAL: - toastText = R.string.volume_dialog_ringer_guidance_ring; + final StreamState ss = mState.states.get(AudioManager.STREAM_RING); + if (ss != null) { + toastText = mContext.getString( + R.string.volume_dialog_ringer_guidance_ring, + Utils.formatPercentage(ss.level, ss.levelMax)); + } break; case RINGER_MODE_SILENT: - toastText = com.android.internal.R.string.volume_dialog_ringer_guidance_silent; + toastText = mContext.getString( + com.android.internal.R.string.volume_dialog_ringer_guidance_silent); break; case RINGER_MODE_VIBRATE: default: - toastText = com.android.internal.R.string.volume_dialog_ringer_guidance_vibrate; + toastText = mContext.getString( + com.android.internal.R.string.volume_dialog_ringer_guidance_vibrate); } Toast.makeText(mContext, toastText, Toast.LENGTH_SHORT).show(); @@ -538,7 +584,7 @@ public class VolumeDialogImpl implements VolumeDialog { } private boolean shouldBeVisibleH(VolumeRow row, VolumeRow activeRow) { - boolean isActive = row == activeRow; + boolean isActive = row.stream == activeRow.stream; if (row.stream == AudioSystem.STREAM_ACCESSIBILITY) { return mShowA11yStream; } @@ -550,7 +596,17 @@ public class VolumeDialogImpl implements VolumeDialog { return true; } - return row.defaultStream || isActive; + if (isActive) { + return true; + } + + if (row.defaultStream) { + return activeRow.stream == STREAM_RING + || activeRow.stream == STREAM_ALARM + || activeRow.stream == STREAM_VOICE_CALL; + } + + return false; } private void updateRowsH(final VolumeRow activeRow) { @@ -670,7 +726,8 @@ public class VolumeDialogImpl implements VolumeDialog { if (mActiveStream != state.activeStream) { mPrevActiveStream = mActiveStream; mActiveStream = state.activeStream; - updateRowsH(getActiveRow()); + VolumeRow activeRow = getActiveRow(); + updateRowsH(activeRow); rescheduleTimeoutH(); } for (VolumeRow row : mRows) { @@ -696,7 +753,7 @@ public class VolumeDialogImpl implements VolumeDialog { final boolean isA11yStream = row.stream == STREAM_ACCESSIBILITY; final boolean isRingStream = row.stream == AudioManager.STREAM_RING; final boolean isSystemStream = row.stream == AudioManager.STREAM_SYSTEM; - final boolean isAlarmStream = row.stream == AudioManager.STREAM_ALARM; + final boolean isAlarmStream = row.stream == STREAM_ALARM; final boolean isMusicStream = row.stream == AudioManager.STREAM_MUSIC; final boolean isRingVibrate = isRingStream && mState.ringerModeInternal == AudioManager.RINGER_MODE_VIBRATE; @@ -921,6 +978,21 @@ public class VolumeDialogImpl implements VolumeDialog { } } + private Runnable mSinglePress = new Runnable() { + @Override + public void run() { + mRingerIcon.setPressed(true); + mRingerIcon.postOnAnimationDelayed(mSingleUnpress, 200); + } + }; + + private Runnable mSingleUnpress = new Runnable() { + @Override + public void run() { + mRingerIcon.setPressed(false); + } + }; + private final VolumeDialogController.Callbacks mControllerCallbackH = new VolumeDialogController.Callbacks() { @Override diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumePrefs.java b/packages/SystemUI/src/com/android/systemui/volume/VolumePrefs.java index 173400f5e31a..434327cd491c 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumePrefs.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumePrefs.java @@ -43,7 +43,7 @@ public class VolumePrefs { public static final String PREF_ADJUST_ALARMS = "pref_adjust_alarms"; public static final String PREF_ADJUST_NOTIFICATION = "pref_adjust_notification"; - public static final int SHOW_RINGER_TOAST_COUNT = 9; + public static final int SHOW_RINGER_TOAST_COUNT = 12; public static final boolean DEFAULT_SHOW_HEADERS = true; public static final boolean DEFAULT_ENABLE_AUTOMUTE = true; -- GitLab From 70dcd00d4a8dd3fa52983121a8052c99e66368bf Mon Sep 17 00:00:00 2001 From: Beverly Date: Thu, 29 Mar 2018 17:09:16 -0400 Subject: [PATCH 095/179] System notif channels updated on locale change - both System and SystemUi notification channels' names change on locale update Change-Id: I0d23fe9b008c608c54ac178a97c2f682aa46d954 Fixes: 64887866 Test: manual --- .../android/systemui/SystemUIApplication.java | 30 +++++++++---------- .../systemui/util/NotificationChannels.java | 3 +- .../NotificationManagerService.java | 3 ++ 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java index 2c0e95b5af26..a61ce8c291fd 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java @@ -29,30 +29,16 @@ import android.os.SystemProperties; import android.os.Trace; import android.os.UserHandle; import android.util.ArraySet; -import android.util.TimingsTraceLog; import android.util.Log; +import android.util.TimingsTraceLog; -import com.android.systemui.globalactions.GlobalActionsComponent; -import com.android.systemui.keyboard.KeyboardUI; -import com.android.systemui.keyguard.KeyguardViewMediator; -import com.android.systemui.media.RingtonePlayer; -import com.android.systemui.pip.PipUI; import com.android.systemui.plugins.OverlayPlugin; import com.android.systemui.plugins.PluginListener; import com.android.systemui.plugins.PluginManager; -import com.android.systemui.power.PowerUI; -import com.android.systemui.recents.Recents; -import com.android.systemui.shortcut.ShortcutKeyDispatcher; -import com.android.systemui.stackdivider.Divider; -import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.phone.StatusBarWindowManager; -import com.android.systemui.usb.StorageNotification; import com.android.systemui.util.NotificationChannels; -import com.android.systemui.util.leak.GarbageMonitor; -import com.android.systemui.volume.VolumeUI; -import java.util.ArrayList; import java.util.HashMap; import java.util.Map; @@ -99,6 +85,10 @@ public class SystemUIApplication extends Application implements SysUiServiceProv mServices[i].onBootCompleted(); } } + + IntentFilter localeChangedFilter = new IntentFilter( + Intent.ACTION_LOCALE_CHANGED); + registerReceiver(mLocaleChangeReceiver, localeChangedFilter); } }, filter); } else { @@ -249,4 +239,14 @@ public class SystemUIApplication extends Application implements SysUiServiceProv public SystemUI[] getServices() { return mServices; } + + private final BroadcastReceiver mLocaleChangeReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) { + // Update names of SystemUi notification channels + NotificationChannels.createAll(context); + } + } + }; } diff --git a/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java b/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java index 1cbdfe81869d..7a9cdfd85645 100644 --- a/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java +++ b/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java @@ -39,8 +39,7 @@ public class NotificationChannels extends SystemUI { public static String BATTERY = "BAT"; public static String HINTS = "HNT"; - @VisibleForTesting - static void createAll(Context context) { + public static void createAll(Context context) { final NotificationManager nm = context.getSystemService(NotificationManager.class); final NotificationChannel batteryChannel = new NotificationChannel(BATTERY, context.getString(R.string.notification_channel_battery), diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 210857e1b097..8e0058940e30 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -182,6 +182,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.internal.notification.SystemNotificationChannels; import com.android.internal.os.BackgroundThread; import com.android.internal.statusbar.NotificationVisibility; import com.android.internal.util.ArrayUtils; @@ -898,6 +899,8 @@ public class NotificationManagerService extends SystemService { @Override public void onReceive(Context context, Intent intent) { if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) { + // update system notification channels + SystemNotificationChannels.createAll(context); mZenModeHelper.updateDefaultZenRules(); mRankingHelper.onLocaleChanged(context, ActivityManager.getCurrentUser()); } -- GitLab From fd38aa5114daf9656e38f1a64faff7cb435e3049 Mon Sep 17 00:00:00 2001 From: Salvador Martinez Date: Wed, 28 Mar 2018 23:56:59 -0700 Subject: [PATCH 096/179] Update triggering logic for hybrid notification Currently in the worst case a user can receive 4 battery notifications if the time estimates and percentages line up right. This CL makes it so a user can at MOST receive one "low" battery warning and one "critical" battery warning per charge cycle. A charge cycle is restarted when a user charges to at least 45% battery AND has 6 hours remaining. This does not affect the behavior of the non-hybrid notification. Test: robotests Bug: 76203825 Change-Id: Ib3c7fe589f1ce4c0cdb821e1f21d1139a56fad62 --- .../com/android/systemui/power/PowerUI.java | 76 +++++++++++-------- .../android/systemui/power/PowerUITest.java | 11 ++- 2 files changed, 55 insertions(+), 32 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java index f08219a8f742..c409f738ec2a 100644 --- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java +++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java @@ -52,6 +52,7 @@ import com.android.systemui.statusbar.phone.StatusBar; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.time.Duration; import java.util.Arrays; public class PowerUI extends SystemUI { @@ -61,6 +62,8 @@ public class PowerUI extends SystemUI { private static final long TEMPERATURE_LOGGING_INTERVAL = DateUtils.HOUR_IN_MILLIS; private static final int MAX_RECENT_TEMPS = 125; // TEMPERATURE_LOGGING_INTERVAL plus a buffer static final long THREE_HOURS_IN_MILLIS = DateUtils.HOUR_IN_MILLIS * 3; + private static final int CHARGE_CYCLE_PERCENT_RESET = 45; + private static final long SIX_HOURS_MILLIS = Duration.ofHours(6).toMillis(); private final Handler mHandler = new Handler(); private final Receiver mReceiver = new Receiver(); @@ -69,7 +72,6 @@ public class PowerUI extends SystemUI { private HardwarePropertiesManager mHardwarePropertiesManager; private WarningsUI mWarnings; private final Configuration mLastConfiguration = new Configuration(); - private int mBatteryLevel = 100; private long mTimeRemaining = Long.MAX_VALUE; private int mPlugType = 0; private int mInvalidCharger = 0; @@ -88,6 +90,7 @@ public class PowerUI extends SystemUI { private long mNextLogTime; private IThermalService mThermalService; + @VisibleForTesting int mBatteryLevel = 100; @VisibleForTesting int mBatteryStatus = BatteryManager.BATTERY_STATUS_UNKNOWN; // by using the same instance (method references are not guaranteed to be the same object @@ -205,12 +208,6 @@ public class PowerUI extends SystemUI { final boolean plugged = mPlugType != 0; final boolean oldPlugged = oldPlugType != 0; - // if we are now unplugged but we were previously plugged in we should allow the - // time based trigger again. - if (!plugged && plugged != oldPlugged) { - mLowWarningShownThisChargeCycle = false; - mSevereWarningShownThisChargeCycle = false; - } int oldBucket = findBatteryLevelBucket(oldBatteryLevel); int bucket = findBatteryLevelBucket(mBatteryLevel); @@ -261,7 +258,8 @@ public class PowerUI extends SystemUI { boolean isPowerSaver = mPowerManager.isPowerSaveMode(); // only play SFX when the dialog comes up or the bucket changes final boolean playSound = bucket != oldBucket || oldPlugged; - if (mEnhancedEstimates.isHybridNotificationEnabled()) { + final boolean hybridEnabled = mEnhancedEstimates.isHybridNotificationEnabled(); + if (hybridEnabled) { final Estimate estimate = mEnhancedEstimates.getEstimate(); // Turbo is not always booted once SysUI is running so we have ot make sure we actually // get data back @@ -270,6 +268,14 @@ public class PowerUI extends SystemUI { mWarnings.updateEstimate(estimate); mWarnings.updateThresholds(mEnhancedEstimates.getLowWarningThreshold(), mEnhancedEstimates.getSevereWarningThreshold()); + + // if we are now over 45% battery & 6 hours remaining we can trigger hybrid + // notification again + if (mBatteryLevel >= CHARGE_CYCLE_PERCENT_RESET + && mTimeRemaining > SIX_HOURS_MILLIS) { + mLowWarningShownThisChargeCycle = false; + mSevereWarningShownThisChargeCycle = false; + } } } @@ -277,13 +283,15 @@ public class PowerUI extends SystemUI { mTimeRemaining, isPowerSaver, mBatteryStatus)) { mWarnings.showLowBatteryWarning(playSound); - // mark if we've already shown a warning this cycle. This will prevent the time based - // trigger from spamming users since the time remaining can vary based on current - // device usage. - if (mTimeRemaining < mEnhancedEstimates.getSevereWarningThreshold()) { - mSevereWarningShownThisChargeCycle = true; - } else { - mLowWarningShownThisChargeCycle = true; + // mark if we've already shown a warning this cycle. This will prevent the notification + // trigger from spamming users by only showing low/critical warnings once per cycle + if (hybridEnabled) { + if (mTimeRemaining < mEnhancedEstimates.getSevereWarningThreshold() + || mBatteryLevel < mLowBatteryReminderLevels[1]) { + mSevereWarningShownThisChargeCycle = true; + } else { + mLowWarningShownThisChargeCycle = true; + } } } else if (shouldDismissLowBatteryWarning(plugged, oldBucket, bucket, mTimeRemaining, isPowerSaver)) { @@ -295,12 +303,16 @@ public class PowerUI extends SystemUI { @VisibleForTesting boolean shouldShowLowBatteryWarning(boolean plugged, boolean oldPlugged, int oldBucket, - int bucket, long timeRemaining, boolean isPowerSaver, int mBatteryStatus) { + int bucket, long timeRemaining, boolean isPowerSaver, int batteryStatus) { + if (mEnhancedEstimates.isHybridNotificationEnabled()) { + // triggering logic when enhanced estimate is available + return isEnhancedTrigger(plugged, timeRemaining, isPowerSaver, batteryStatus); + } + // legacy triggering logic return !plugged && !isPowerSaver - && (((bucket < oldBucket || oldPlugged) && bucket < 0) - || isTimeBasedTrigger(timeRemaining)) - && mBatteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN; + && (((bucket < oldBucket || oldPlugged) && bucket < 0)) + && batteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN; } @VisibleForTesting @@ -315,19 +327,23 @@ public class PowerUI extends SystemUI { || hybridWouldDismiss)); } - private boolean isTimeBasedTrigger(long timeRemaining) { - if (!mEnhancedEstimates.isHybridNotificationEnabled()) { + private boolean isEnhancedTrigger(boolean plugged, long timeRemaining, boolean isPowerSaver, + int batteryStatus) { + if (plugged || isPowerSaver || batteryStatus == BatteryManager.BATTERY_STATUS_UNKNOWN) { return false; } - - // Only show the time based warning once per charge cycle - final boolean canShowWarning = timeRemaining < mEnhancedEstimates.getLowWarningThreshold() - && !mLowWarningShownThisChargeCycle; - - // Only show the severe time based warning once per charge cycle - final boolean canShowSevereWarning = - timeRemaining < mEnhancedEstimates.getSevereWarningThreshold() - && !mSevereWarningShownThisChargeCycle; + int warnLevel = mLowBatteryReminderLevels[0]; + int critLevel = mLowBatteryReminderLevels[1]; + + // Only show the low warning once per charge cycle + final boolean canShowWarning = !mLowWarningShownThisChargeCycle + && (timeRemaining < mEnhancedEstimates.getLowWarningThreshold() + || mBatteryLevel <= warnLevel); + + // Only show the severe warning once per charge cycle + final boolean canShowSevereWarning = !mSevereWarningShownThisChargeCycle + && (timeRemaining < mEnhancedEstimates.getSevereWarningThreshold() + || mBatteryLevel <= critLevel); return canShowWarning || canShowSevereWarning; } diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java index 4b455baee56b..149f2de06be4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java @@ -58,6 +58,7 @@ public class PowerUITest extends SysuiTestCase { public static final int BELOW_WARNING_BUCKET = -1; public static final long BELOW_HYBRID_THRESHOLD = TimeUnit.HOURS.toMillis(2); public static final long ABOVE_HYBRID_THRESHOLD = TimeUnit.HOURS.toMillis(4); + private static final long ABOVE_CHARGE_CYCLE_THRESHOLD = Duration.ofHours(8).toMillis(); private HardwarePropertiesManager mHardProps; private WarningsUI mMockWarnings; private PowerUI mPowerUI; @@ -198,6 +199,7 @@ public class PowerUITest extends SysuiTestCase { when(mEnhancedEstimates.isHybridNotificationEnabled()).thenReturn(true); when(mEnhancedEstimates.getLowWarningThreshold()).thenReturn(PowerUI.THREE_HOURS_IN_MILLIS); when(mEnhancedEstimates.getSevereWarningThreshold()).thenReturn(ONE_HOUR_MILLIS); + mPowerUI.mBatteryLevel = 10; mPowerUI.start(); // unplugged device that would show the non-hybrid notification and the hybrid @@ -213,6 +215,7 @@ public class PowerUITest extends SysuiTestCase { when(mEnhancedEstimates.isHybridNotificationEnabled()).thenReturn(true); when(mEnhancedEstimates.getLowWarningThreshold()).thenReturn(PowerUI.THREE_HOURS_IN_MILLIS); when(mEnhancedEstimates.getSevereWarningThreshold()).thenReturn(ONE_HOUR_MILLIS); + mPowerUI.mBatteryLevel = 10; mPowerUI.start(); // unplugged device that would show the non-hybrid but not the hybrid @@ -254,13 +257,14 @@ public class PowerUITest extends SysuiTestCase { } @Test - public void testShouldShowLowBatteryWarning_deviceBatteryStatusUnkown_returnsNoShow() { + public void testShouldShowLowBatteryWarning_deviceBatteryStatusUnknown_returnsNoShow() { when(mEnhancedEstimates.isHybridNotificationEnabled()).thenReturn(true); when(mEnhancedEstimates.getLowWarningThreshold()).thenReturn(PowerUI.THREE_HOURS_IN_MILLIS); when(mEnhancedEstimates.getSevereWarningThreshold()).thenReturn(ONE_HOUR_MILLIS); mPowerUI.start(); - // Unknown battery status device that would show the neither due + // Unknown battery status device that would show the neither due to the battery status being + // unknown boolean shouldShow = mPowerUI.shouldShowLowBatteryWarning(UNPLUGGED, UNPLUGGED, ABOVE_WARNING_BUCKET, BELOW_WARNING_BUCKET, BELOW_HYBRID_THRESHOLD, @@ -295,6 +299,9 @@ public class PowerUITest extends SysuiTestCase { mPowerUI.maybeShowBatteryWarning(UNPLUGGED, UNPLUGGED, ABOVE_WARNING_BUCKET, ABOVE_WARNING_BUCKET); + + // reduce battery level to handle time based trigger -> level trigger interactions + mPowerUI.mBatteryLevel = 10; boolean shouldShow = mPowerUI.shouldShowLowBatteryWarning(UNPLUGGED, UNPLUGGED, ABOVE_WARNING_BUCKET, ABOVE_WARNING_BUCKET, BELOW_HYBRID_THRESHOLD, -- GitLab From 57ca3da24f26164104aecbcebf345cfcfac17a66 Mon Sep 17 00:00:00 2001 From: Dmitry Dementyev Date: Wed, 28 Mar 2018 12:36:45 -0700 Subject: [PATCH 097/179] Add support for testing mode root certificate. 1) Add Certificate 2) Helper class for end-to-end tests 3) Only create snapshot for passwords with special prefix in test mode 4) Sync only keys with insecure prefix in test mode. Bug: 76433465 Test: adb shell am instrument -w -e package com.android.server.locksettings.recoverablekeystore com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner Change-Id: I6edc8c4716c3a034b6b79c7aa6f4b8478e9a3c9e --- .../recovery/TrustedRootCertificates.java | 70 +++++++++- .../recoverablekeystore/KeySyncTask.java | 44 +++--- .../RecoverableKeyStoreManager.java | 48 +++---- .../TestOnlyInsecureCertificateHelper.java | 103 ++++++++++++++ .../recoverablekeystore/KeySyncTaskTest.java | 118 +++++++++++++++- .../RecoverableKeyStoreManagerTest.java | 108 ++++++++++++++- .../recoverablekeystore/TestData.java | 10 ++ ...TestOnlyInsecureCertificateHelperTest.java | 128 ++++++++++++++++++ 8 files changed, 567 insertions(+), 62 deletions(-) create mode 100644 services/core/java/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelper.java create mode 100644 services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelperTest.java diff --git a/core/java/android/security/keystore/recovery/TrustedRootCertificates.java b/core/java/android/security/keystore/recovery/TrustedRootCertificates.java index 383af424989c..63faac3d525d 100644 --- a/core/java/android/security/keystore/recovery/TrustedRootCertificates.java +++ b/core/java/android/security/keystore/recovery/TrustedRootCertificates.java @@ -37,6 +37,40 @@ public final class TrustedRootCertificates { public static final String GOOGLE_CLOUD_KEY_VAULT_SERVICE_V1_ALIAS = "GoogleCloudKeyVaultServiceV1"; + /** + * Certificate used for client-side end-to-end encryption tests. + * When recovery controller is initialized with the certificate, recovery snapshots will only + * contain application keys started with {@link INSECURE_KEY_ALIAS}. + * Recovery snapshot will only be created if device is unlocked with password started with + * {@link #INSECURE_PASSWORD_PREFIX}. + * + * @hide + */ + public static final String TEST_ONLY_INSECURE_CERTIFICATE_ALIAS = + "TEST_ONLY_INSECURE_CERTIFICATE_ALIAS"; + + /** + * TODO: Add insecure certificate to TestApi. + * @hide + */ + public static @NonNull X509Certificate getTestOnlyInsecureCertificate() { + return parseBase64Certificate(TEST_ONLY_INSECURE_CERTIFICATE_BASE64); + } + /** + * Keys, which alias starts with the prefix are not protected if + * recovery agent uses {@link #TEST_ONLY_INSECURE_CERTIFICATE_ALIAS} root certificate. + * @hide + */ + public static final String INSECURE_KEY_ALIAS_PREFIX = + "INSECURE_KEY_ALIAS_KEY_MATERIAL_IS_NOT_PROTECTED_"; + /** + * Prefix for insecure passwords with length 14. + * Passwords started with the prefix are not protected if recovery agent uses + * {@link #TEST_ONLY_INSECURE_CERTIFICATE_ALIAS} root certificate. + * @hide + */ + public static final String INSECURE_PASSWORD_PREFIX = + "INSECURE_PSWD_"; private static final String GOOGLE_CLOUD_KEY_VAULT_SERVICE_V1_BASE64 = "" + "MIIFJjCCAw6gAwIBAgIJAIobXsJlzhNdMA0GCSqGSIb3DQEBDQUAMCAxHjAcBgNV" @@ -68,13 +102,43 @@ public final class TrustedRootCertificates { + "/oM58v0orUWINtIc2hBlka36PhATYQiLf+AiWKnwhCaaHExoYKfQlMtXBodNvOK8" + "xqx69x05q/qbHKEcTHrsss630vxrp1niXvA="; + private static final String TEST_ONLY_INSECURE_CERTIFICATE_BASE64 = "" + + "MIIFMDCCAxigAwIBAgIJAIZ9/G8KQie9MA0GCSqGSIb3DQEBDQUAMCUxIzAhBgNV" + + "BAMMGlRlc3QgT25seSBVbnNlY3VyZSBSb290IENBMB4XDTE4MDMyODAwMzIyM1oX" + + "DTM4MDMyMzAwMzIyM1owJTEjMCEGA1UEAwwaVGVzdCBPbmx5IFVuc2VjdXJlIFJv" + + "b3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDGxFNzAEyzSPmw" + + "E5gfuBXdXq++bl9Ep62V7Xn1UiejvmS+pRHT39pf/M7sl4Zr9ezanJTrFvf9+B85" + + "VGehdsD32TgfEjThcqaoQCI6pKkHYsUo7FZ5n+G3eE8oabWRZJMVo3QDjnnFYp7z" + + "20vnpjDofI2oQyxHcb/1yep+ca1+4lIvbUp/ybhNFqhRXAMcDXo7pyH38eUQ1JdK" + + "Q/QlBbShpFEqx1Y6KilKfTDf7Wenqr67LkaEim//yLZjlHzn/BpuRTrpo+XmJZx1" + + "P9CX9LGOXTtmsaCcYgD4yijOvV8aEsIJaf1kCIO558oH0oQc+0JG5aXeLN7BDlyZ" + + "vH0RdSx5nQLS9kj2I6nthOw/q00/L+S6A0m5jyNZOAl1SY78p+wO0d9eHbqQzJwf" + + "EsSq3qGAqlgQyyjp6oxHBqT9hZtN4rxw+iq0K1S4kmTLNF1FvmIB1BE+lNvvoGdY" + + "5G0b6Pe4R5JFn9LV3C3PEmSYnae7iG0IQlKmRADIuvfJ7apWAVanJPJAAWh2Akfp" + + "8Uxr02cHoY6o7vsEhJJOeMkipaBHThESm/XeFVubQzNfZ9gjQnB9ZX2v+lyj+WYZ" + + "SAz3RuXx6TlLrmWccMpQDR1ibcgyyjLUtX3kwZl2OxmJXitjuD7xlxvAXYob15N+" + + "K4xKHgxUDrbt2zU/tY0vgepAUg/xbwIDAQABo2MwYTAdBgNVHQ4EFgQUwyeNpYgs" + + "XXYvh9z0/lFrja7sV+swHwYDVR0jBBgwFoAUwyeNpYgsXXYvh9z0/lFrja7sV+sw" + + "DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQENBQAD" + + "ggIBAGuOsvMN5SD3RIQnMJtBpcHNrxun+QFjPZFlYCLfIPrUkHpn5O1iIIq8tVLd" + + "2V+12VKnToUEANsYBD3MP8XjP+6GZ7ZQ2rwLGvUABKSX4YXvmjEEXZUZp0y3tIV4" + + "kUDlbACzguPneZDp5Qo7YWH4orgqzHkn0sD/ikO5XrAqmzc245ewJlrf+V11mjcu" + + "ELfDrEejpPhi7Hk/ZNR0ftP737Hs/dNoCLCIaVNgYzBZhgo4kd220TeJu2ttW0XZ" + + "ldyShtpcOmyWKBgVseixR6L/3sspPHyAPXkSuRo0Eh1xvzDKCg9ttb0qoacTlXMF" + + "GkBpNzmVq67NWFGGa9UElift1mv6RfktPCAGZ+Ai8xUiKAUB0Eookpt/8gX9Senq" + + "yP/jMxkxXmHWxUu8+KnLvj6WLrfftuuD7u3cfc7j5kkrheDz3O4h4477GnqL5wdo" + + "9DuEsNc4FxJVz8Iy8RS6cJuW4pihYpM1Tyn7uopLnImpYzEY+R5aQqqr+q/A1diq" + + "ogbEKPH6oUiqJUwq3nD70gPBUKJmIzS4vLwLouqUHEm1k/MgHV/BkEU0uVHszPFa" + + "XUMMCHb0iT9P8LuZ7Ajer3SR/0TRVApCrk/6OV68e+6k/OFpM5kcZnNMD5ANyBri" + + "Tsz3NrDwSw4i4+Dsfh6A9dB/cEghw4skLaBxnQLQIgVeqCzK"; + /** * The X509 certificate of the trusted root CA cert for the recoverable key store service. * * TODO: Change it to the production certificate root CA before the final launch. */ private static final X509Certificate GOOGLE_CLOUD_KEY_VAULT_SERVICE_V1_CERTIFICATE = - parseGoogleCloudKeyVaultServiceV1Certificate(); + parseBase64Certificate(GOOGLE_CLOUD_KEY_VAULT_SERVICE_V1_BASE64); private static final int NUMBER_OF_ROOT_CERTIFICATES = 1; @@ -107,9 +171,9 @@ public final class TrustedRootCertificates { return certificates; } - private static X509Certificate parseGoogleCloudKeyVaultServiceV1Certificate() { + private static X509Certificate parseBase64Certificate(String base64Certificate) { try { - return decodeBase64Cert(GOOGLE_CLOUD_KEY_VAULT_SERVICE_V1_BASE64); + return decodeBase64Cert(base64Certificate); } catch (CertificateException e) { // Should not happen throw new RuntimeException(e); diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java index 050c1f4a6141..b0afac2c62dd 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java @@ -79,6 +79,7 @@ public class KeySyncTask implements Runnable { private final PlatformKeyManager mPlatformKeyManager; private final RecoverySnapshotStorage mRecoverySnapshotStorage; private final RecoverySnapshotListenersStorage mSnapshotListenersStorage; + private final TestOnlyInsecureCertificateHelper mTestOnlyInsecureCertificateHelper; public static KeySyncTask newInstance( Context context, @@ -98,7 +99,8 @@ public class KeySyncTask implements Runnable { credentialType, credential, credentialUpdated, - PlatformKeyManager.getInstance(context, recoverableKeyStoreDb)); + PlatformKeyManager.getInstance(context, recoverableKeyStoreDb), + new TestOnlyInsecureCertificateHelper()); } /** @@ -110,6 +112,7 @@ public class KeySyncTask implements Runnable { * @param credential The credential, encoded as a {@link String}. * @param credentialUpdated signals weather credentials were updated. * @param platformKeyManager platform key manager + * @param TestOnlyInsecureCertificateHelper utility class used for end-to-end tests */ @VisibleForTesting KeySyncTask( @@ -120,7 +123,8 @@ public class KeySyncTask implements Runnable { int credentialType, String credential, boolean credentialUpdated, - PlatformKeyManager platformKeyManager) { + PlatformKeyManager platformKeyManager, + TestOnlyInsecureCertificateHelper TestOnlyInsecureCertificateHelper) { mSnapshotListenersStorage = recoverySnapshotListenersStorage; mRecoverableKeyStoreDb = recoverableKeyStoreDb; mUserId = userId; @@ -129,6 +133,7 @@ public class KeySyncTask implements Runnable { mCredentialUpdated = credentialUpdated; mPlatformKeyManager = platformKeyManager; mRecoverySnapshotStorage = snapshotStorage; + mTestOnlyInsecureCertificateHelper = TestOnlyInsecureCertificateHelper; } @Override @@ -189,8 +194,9 @@ public class KeySyncTask implements Runnable { PublicKey publicKey; String rootCertAlias = mRecoverableKeyStoreDb.getActiveRootOfTrust(mUserId, recoveryAgentUid); + rootCertAlias = mTestOnlyInsecureCertificateHelper + .getDefaultCertificateAliasIfEmpty(rootCertAlias); - rootCertAlias = replaceEmptyValueWithSecureDefault(rootCertAlias); CertPath certPath = mRecoverableKeyStoreDb.getRecoveryServiceCertPath(mUserId, recoveryAgentUid, rootCertAlias); if (certPath != null) { @@ -212,12 +218,18 @@ public class KeySyncTask implements Runnable { return; } - // The only place in this class which uses credential value - if (!TrustedRootCertificates.GOOGLE_CLOUD_KEY_VAULT_SERVICE_V1_ALIAS.equals( - rootCertAlias)) { - // TODO: allow only whitelisted LSKF usage - Log.w(TAG, "Untrusted root certificate is used by recovery agent " + if (mTestOnlyInsecureCertificateHelper.isTestOnlyCertificate(rootCertAlias)) { + Log.w(TAG, "Insecure root certificate is used by recovery agent " + recoveryAgentUid); + if (mTestOnlyInsecureCertificateHelper.doesCredentailSupportInsecureMode( + mCredentialType, mCredential)) { + Log.w(TAG, "Whitelisted credential is used to generate snapshot by " + + "recovery agent "+ recoveryAgentUid); + } else { + Log.w(TAG, "Non whitelisted credential is used to generate recovery snapshot by " + + recoveryAgentUid + " - ignore attempt."); + return; // User secret will not be used. + } } byte[] salt = generateSalt(); @@ -239,8 +251,10 @@ public class KeySyncTask implements Runnable { return; } - // TODO: filter raw keys based on the root of trust. - // It is the only place in the class where raw key material is used. + // Only include insecure key material for test + if (mTestOnlyInsecureCertificateHelper.isTestOnlyCertificate(rootCertAlias)) { + rawKeys = mTestOnlyInsecureCertificateHelper.keepOnlyWhitelistedInsecureKeys(rawKeys); + } SecretKey recoveryKey; try { recoveryKey = generateRecoveryKey(); @@ -467,14 +481,4 @@ public class KeySyncTask implements Runnable { } return keyEntries; } - - private @NonNull String replaceEmptyValueWithSecureDefault( - @Nullable String rootCertificateAlias) { - if (rootCertificateAlias == null || rootCertificateAlias.isEmpty()) { - Log.e(TAG, "rootCertificateAlias is null or empty"); - // Use the default Google Key Vault Service CA certificate if the alias is not provided - rootCertificateAlias = TrustedRootCertificates.GOOGLE_CLOUD_KEY_VAULT_SERVICE_V1_ALIAS; - } - return rootCertificateAlias; - } } diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java index 77d7c3cfdbf2..1dab5920288b 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java @@ -38,7 +38,6 @@ import android.security.keystore.recovery.KeyChainProtectionParams; import android.security.keystore.recovery.KeyChainSnapshot; import android.security.keystore.recovery.RecoveryCertPath; import android.security.keystore.recovery.RecoveryController; -import android.security.keystore.recovery.TrustedRootCertificates; import android.security.keystore.recovery.WrappedApplicationKey; import android.security.KeyStore; import android.util.ArrayMap; @@ -100,6 +99,7 @@ public class RecoverableKeyStoreManager { private final RecoverySnapshotStorage mSnapshotStorage; private final PlatformKeyManager mPlatformKeyManager; private final ApplicationKeyStorage mApplicationKeyStorage; + private final TestOnlyInsecureCertificateHelper mTestCertHelper; /** * Returns a new or existing instance. @@ -130,7 +130,8 @@ public class RecoverableKeyStoreManager { RecoverySnapshotStorage.newInstance(), new RecoverySnapshotListenersStorage(), platformKeyManager, - applicationKeyStorage); + applicationKeyStorage, + new TestOnlyInsecureCertificateHelper()); } return mInstance; } @@ -144,7 +145,8 @@ public class RecoverableKeyStoreManager { RecoverySnapshotStorage snapshotStorage, RecoverySnapshotListenersStorage listenersStorage, PlatformKeyManager platformKeyManager, - ApplicationKeyStorage applicationKeyStorage) { + ApplicationKeyStorage applicationKeyStorage, + TestOnlyInsecureCertificateHelper TestOnlyInsecureCertificateHelper) { mContext = context; mDatabase = recoverableKeyStoreDb; mRecoverySessionStorage = recoverySessionStorage; @@ -153,6 +155,7 @@ public class RecoverableKeyStoreManager { mSnapshotStorage = snapshotStorage; mPlatformKeyManager = platformKeyManager; mApplicationKeyStorage = applicationKeyStorage; + mTestCertHelper = TestOnlyInsecureCertificateHelper; try { mRecoverableKeyGenerator = RecoverableKeyGenerator.newInstance(mDatabase); @@ -171,7 +174,8 @@ public class RecoverableKeyStoreManager { checkRecoverKeyStorePermission(); int userId = UserHandle.getCallingUserId(); int uid = Binder.getCallingUid(); - rootCertificateAlias = replaceEmptyValueWithSecureDefault(rootCertificateAlias); + rootCertificateAlias + = mTestCertHelper.getDefaultCertificateAliasIfEmpty(rootCertificateAlias); // Always set active alias to the argument of the last call to initRecoveryService method, // even if cert file is incorrect. @@ -216,7 +220,8 @@ public class RecoverableKeyStoreManager { // Randomly choose and validate an endpoint certificate from the list CertPath certPath; - X509Certificate rootCert = getRootCertificate(rootCertificateAlias); + X509Certificate rootCert = + mTestCertHelper.getRootCertificate(rootCertificateAlias); try { Log.d(TAG, "Getting and validating a random endpoint certificate"); certPath = certXml.getRandomEndpointCert(rootCert); @@ -265,7 +270,8 @@ public class RecoverableKeyStoreManager { @NonNull byte[] recoveryServiceSigFile) throws RemoteException { checkRecoverKeyStorePermission(); - rootCertificateAlias = replaceEmptyValueWithSecureDefault(rootCertificateAlias); + rootCertificateAlias = + mTestCertHelper.getDefaultCertificateAliasIfEmpty(rootCertificateAlias); Preconditions.checkNotNull(recoveryServiceCertFile, "recoveryServiceCertFile is null"); Preconditions.checkNotNull(recoveryServiceSigFile, "recoveryServiceSigFile is null"); @@ -279,7 +285,8 @@ public class RecoverableKeyStoreManager { ERROR_BAD_CERTIFICATE_FORMAT, "Failed to parse the sig file."); } - X509Certificate rootCert = getRootCertificate(rootCertificateAlias); + X509Certificate rootCert = + mTestCertHelper.getRootCertificate(rootCertificateAlias); try { sigXml.verifyFileSignature(rootCert, recoveryServiceCertFile); } catch (CertValidationException e) { @@ -519,7 +526,8 @@ public class RecoverableKeyStoreManager { @NonNull List secrets) throws RemoteException { checkRecoverKeyStorePermission(); - rootCertificateAlias = replaceEmptyValueWithSecureDefault(rootCertificateAlias); + rootCertificateAlias = + mTestCertHelper.getDefaultCertificateAliasIfEmpty(rootCertificateAlias); Preconditions.checkNotNull(sessionId, "invalid session"); Preconditions.checkNotNull(verifierCertPath, "verifierCertPath is null"); Preconditions.checkNotNull(vaultParams, "vaultParams is null"); @@ -534,7 +542,8 @@ public class RecoverableKeyStoreManager { } try { - CertUtils.validateCertPath(getRootCertificate(rootCertificateAlias), certPath); + CertUtils.validateCertPath( + mTestCertHelper.getRootCertificate(rootCertificateAlias), certPath); } catch (CertValidationException e) { Log.e(TAG, "Failed to validate the given cert path", e); throw new ServiceSpecificException(ERROR_INVALID_CERTIFICATE, e.getMessage()); @@ -960,27 +969,6 @@ public class RecoverableKeyStoreManager { } } - private X509Certificate getRootCertificate(String rootCertificateAlias) throws RemoteException { - rootCertificateAlias = replaceEmptyValueWithSecureDefault(rootCertificateAlias); - X509Certificate rootCertificate = - TrustedRootCertificates.getRootCertificate(rootCertificateAlias); - if (rootCertificate == null) { - throw new ServiceSpecificException( - ERROR_INVALID_CERTIFICATE, "The provided root certificate alias is invalid"); - } - return rootCertificate; - } - - private @NonNull String replaceEmptyValueWithSecureDefault( - @Nullable String rootCertificateAlias) { - if (rootCertificateAlias == null || rootCertificateAlias.isEmpty()) { - Log.e(TAG, "rootCertificateAlias is null or empty"); - // Use the default Google Key Vault Service CA certificate if the alias is not provided - rootCertificateAlias = TrustedRootCertificates.GOOGLE_CLOUD_KEY_VAULT_SERVICE_V1_ALIAS; - } - return rootCertificateAlias; - } - private void checkRecoverKeyStorePermission() { mContext.enforceCallingOrSelfPermission( Manifest.permission.RECOVER_KEYSTORE, diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelper.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelper.java new file mode 100644 index 000000000000..490f733f149f --- /dev/null +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelper.java @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.locksettings.recoverablekeystore; + +import static android.security.keystore.recovery.RecoveryController.ERROR_INVALID_CERTIFICATE; + +import com.android.internal.widget.LockPatternUtils; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.os.RemoteException; +import android.os.ServiceSpecificException; +import android.security.keystore.recovery.TrustedRootCertificates; +import android.util.Log; + +import java.util.HashMap; +import java.security.cert.X509Certificate; +import java.util.Map; +import javax.crypto.SecretKey; + +/** + * The class provides helper methods to support end-to-end test with insecure certificate. + */ +public class TestOnlyInsecureCertificateHelper { + private static final String TAG = "TestCertHelper"; + + /** + * Constructor for the helper class. + */ + public TestOnlyInsecureCertificateHelper() { + } + + /** + * Returns a root certificate installed in the system for given alias. + * Returns default secure certificate if alias is empty or null. + * Can return insecure certificate for its alias. + */ + public @NonNull X509Certificate + getRootCertificate(String rootCertificateAlias) throws RemoteException { + rootCertificateAlias = getDefaultCertificateAliasIfEmpty(rootCertificateAlias); + if (isTestOnlyCertificate(rootCertificateAlias)) { + return TrustedRootCertificates.getTestOnlyInsecureCertificate(); + } + + X509Certificate rootCertificate = + TrustedRootCertificates.getRootCertificate(rootCertificateAlias); + if (rootCertificate == null) { + throw new ServiceSpecificException( + ERROR_INVALID_CERTIFICATE, "The provided root certificate alias is invalid"); + } + return rootCertificate; + } + + public @NonNull String getDefaultCertificateAliasIfEmpty( + @Nullable String rootCertificateAlias) { + if (rootCertificateAlias == null || rootCertificateAlias.isEmpty()) { + Log.e(TAG, "rootCertificateAlias is null or empty - use secure default value"); + // Use the default Google Key Vault Service CA certificate if the alias is not provided + rootCertificateAlias = TrustedRootCertificates.GOOGLE_CLOUD_KEY_VAULT_SERVICE_V1_ALIAS; + } + return rootCertificateAlias; + } + + public boolean isTestOnlyCertificate(String rootCertificateAlias) { + return TrustedRootCertificates.TEST_ONLY_INSECURE_CERTIFICATE_ALIAS + .equals(rootCertificateAlias); + } + + public boolean doesCredentailSupportInsecureMode(int credentialType, String credential) { + return (credentialType == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD) + && (credential != null) + && credential.startsWith(TrustedRootCertificates.INSECURE_PASSWORD_PREFIX); + } + + public Map keepOnlyWhitelistedInsecureKeys(Map rawKeys) { + if (rawKeys == null) { + return null; + } + Map filteredKeys = new HashMap<>(); + for (Map.Entry entry : rawKeys.entrySet()) { + String alias = entry.getKey(); + if (alias != null + && alias.startsWith(TrustedRootCertificates.INSECURE_KEY_ALIAS_PREFIX)) { + filteredKeys.put(entry.getKey(), entry.getValue()); + Log.d(TAG, "adding key with insecure alias " + alias + " to the recovery snapshot"); + } + } + return filteredKeys; + } +} diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java index 81a73efd94ad..b8d2c3e3d5b0 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java @@ -33,6 +33,11 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -42,8 +47,8 @@ import android.os.FileUtils; import android.security.keystore.AndroidKeyStoreSecretKey; import android.security.keystore.KeyGenParameterSpec; import android.security.keystore.KeyProperties; -import android.security.keystore.recovery.KeyDerivationParams; import android.security.keystore.recovery.KeyChainSnapshot; +import android.security.keystore.recovery.KeyDerivationParams; import android.security.keystore.recovery.RecoveryController; import android.security.keystore.recovery.WrappedApplicationKey; import android.support.test.InstrumentationRegistry; @@ -59,6 +64,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.mockito.Spy; import java.io.File; import java.nio.charset.StandardCharsets; @@ -94,6 +100,7 @@ public class KeySyncTaskTest { @Mock private PlatformKeyManager mPlatformKeyManager; @Mock private RecoverySnapshotListenersStorage mSnapshotListenersStorage; + @Spy private TestOnlyInsecureCertificateHelper mTestOnlyInsecureCertificateHelper; private RecoverySnapshotStorage mRecoverySnapshotStorage; private RecoverableKeyStoreDb mRecoverableKeyStoreDb; @@ -130,7 +137,8 @@ public class KeySyncTaskTest { TEST_CREDENTIAL_TYPE, TEST_CREDENTIAL, /*credentialUpdated=*/ false, - mPlatformKeyManager); + mPlatformKeyManager, + mTestOnlyInsecureCertificateHelper); mWrappingKey = generateAndroidKeyStoreKey(); mEncryptKey = new PlatformEncryptionKey(TEST_GENERATION_ID, mWrappingKey); @@ -283,6 +291,100 @@ public class KeySyncTaskTest { assertNotNull(mRecoverySnapshotStorage.get(TEST_RECOVERY_AGENT_UID)); } + @Test + public void run_InTestModeWithWhitelistedCredentials() throws Exception { + mRecoverableKeyStoreDb.setServerParams( + TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_VAULT_HANDLE); + mRecoverableKeyStoreDb.setPlatformKeyGenerationId(TEST_USER_ID, TEST_GENERATION_ID); + addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_APP_KEY_ALIAS); + mRecoverableKeyStoreDb.setRecoveryServiceCertPath( + TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_ROOT_CERT_ALIAS, TestData.CERT_PATH_1); + + // Enter test mode with whitelisted credentials + when(mTestOnlyInsecureCertificateHelper.isTestOnlyCertificate(any())).thenReturn(true); + when(mTestOnlyInsecureCertificateHelper.doesCredentailSupportInsecureMode(anyInt(), any())) + .thenReturn(true); + mKeySyncTask.run(); + + verify(mTestOnlyInsecureCertificateHelper) + .getDefaultCertificateAliasIfEmpty(eq(TEST_ROOT_CERT_ALIAS)); + + // run whitelist checks + verify(mTestOnlyInsecureCertificateHelper) + .doesCredentailSupportInsecureMode(anyInt(), any()); + verify(mTestOnlyInsecureCertificateHelper) + .keepOnlyWhitelistedInsecureKeys(any()); + + KeyChainSnapshot keyChainSnapshot = mRecoverySnapshotStorage.get(TEST_RECOVERY_AGENT_UID); + assertNotNull(keyChainSnapshot); // created snapshot + List applicationKeys = keyChainSnapshot.getWrappedApplicationKeys(); + assertThat(applicationKeys).hasSize(0); // non whitelisted key is not included + } + + @Test + public void run_InTestModeWithNonWhitelistedCredentials() throws Exception { + mRecoverableKeyStoreDb.setServerParams( + TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_VAULT_HANDLE); + mRecoverableKeyStoreDb.setPlatformKeyGenerationId(TEST_USER_ID, TEST_GENERATION_ID); + addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_APP_KEY_ALIAS); + mRecoverableKeyStoreDb.setRecoveryServiceCertPath( + TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_ROOT_CERT_ALIAS, TestData.CERT_PATH_1); + + // Enter test mode with non whitelisted credentials + when(mTestOnlyInsecureCertificateHelper.isTestOnlyCertificate(any())).thenReturn(true); + when(mTestOnlyInsecureCertificateHelper.doesCredentailSupportInsecureMode(anyInt(), any())) + .thenReturn(false); + mKeySyncTask.run(); + + assertNull(mRecoverySnapshotStorage.get(TEST_RECOVERY_AGENT_UID)); // not created + verify(mTestOnlyInsecureCertificateHelper) + .getDefaultCertificateAliasIfEmpty(eq(TEST_ROOT_CERT_ALIAS)); + verify(mTestOnlyInsecureCertificateHelper) + .doesCredentailSupportInsecureMode(anyInt(), any()); + } + + @Test + public void run_doesNotFilterCredentialsAndAliasesInProd() throws Exception { + mRecoverableKeyStoreDb.setServerParams( + TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_VAULT_HANDLE); + mRecoverableKeyStoreDb.setPlatformKeyGenerationId(TEST_USER_ID, TEST_GENERATION_ID); + addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_APP_KEY_ALIAS); + mRecoverableKeyStoreDb.setRecoveryServiceCertPath( + TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_ROOT_CERT_ALIAS, TestData.CERT_PATH_1); + + mKeySyncTask.run(); + assertNotNull(mRecoverySnapshotStorage.get(TEST_RECOVERY_AGENT_UID)); + + verify(mTestOnlyInsecureCertificateHelper) + .getDefaultCertificateAliasIfEmpty(eq(TEST_ROOT_CERT_ALIAS)); + verify(mTestOnlyInsecureCertificateHelper, atLeast(1)) + .isTestOnlyCertificate(eq(TEST_ROOT_CERT_ALIAS)); + + // no whitelists check + verify(mTestOnlyInsecureCertificateHelper, never()) + .doesCredentailSupportInsecureMode(anyInt(), any()); + verify(mTestOnlyInsecureCertificateHelper, never()) + .keepOnlyWhitelistedInsecureKeys(any()); + } + + @Test + public void run_replacesNullActiveRootAliasWithDefaultValue() throws Exception { + mRecoverableKeyStoreDb.setServerParams( + TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_VAULT_HANDLE); + mRecoverableKeyStoreDb.setPlatformKeyGenerationId(TEST_USER_ID, TEST_GENERATION_ID); + addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_APP_KEY_ALIAS); + mRecoverableKeyStoreDb.setRecoveryServiceCertPath( + TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_ROOT_CERT_ALIAS, TestData.CERT_PATH_1); + mRecoverableKeyStoreDb.setActiveRootOfTrust(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, + /*alias=*/ null); + + when(mTestOnlyInsecureCertificateHelper.getDefaultCertificateAliasIfEmpty(null)) + .thenReturn(TEST_ROOT_CERT_ALIAS); // override default. + mKeySyncTask.run(); + + verify(mTestOnlyInsecureCertificateHelper).getDefaultCertificateAliasIfEmpty(null); + } + @Test public void run_sendsEncryptedKeysIfAvailableToSync_withRawPublicKey() throws Exception { mRecoverableKeyStoreDb.setRecoveryServiceCertPath( @@ -398,7 +500,8 @@ public class KeySyncTaskTest { CREDENTIAL_TYPE_PASSWORD, "password", /*credentialUpdated=*/ false, - mPlatformKeyManager); + mPlatformKeyManager, + mTestOnlyInsecureCertificateHelper); mRecoverableKeyStoreDb.setRecoveryServiceCertPath( TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_ROOT_CERT_ALIAS, TestData.CERT_PATH_1); @@ -424,7 +527,8 @@ public class KeySyncTaskTest { CREDENTIAL_TYPE_PASSWORD, /*credential=*/ "1234", /*credentialUpdated=*/ false, - mPlatformKeyManager); + mPlatformKeyManager, + mTestOnlyInsecureCertificateHelper); mRecoverableKeyStoreDb.setRecoveryServiceCertPath( TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_ROOT_CERT_ALIAS, TestData.CERT_PATH_1); @@ -451,7 +555,8 @@ public class KeySyncTaskTest { CREDENTIAL_TYPE_PATTERN, "12345", /*credentialUpdated=*/ false, - mPlatformKeyManager); + mPlatformKeyManager, + mTestOnlyInsecureCertificateHelper); mRecoverableKeyStoreDb.setRecoveryServiceCertPath( TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_ROOT_CERT_ALIAS, TestData.CERT_PATH_1); @@ -532,7 +637,8 @@ public class KeySyncTaskTest { /*credentialType=*/ 3, "12345", /*credentialUpdated=*/ false, - mPlatformKeyManager); + mPlatformKeyManager, + mTestOnlyInsecureCertificateHelper); addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_APP_KEY_ALIAS); diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java index 18a3885aea6a..a98e29137fb6 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java @@ -27,6 +27,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -67,6 +68,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.mockito.Spy; import java.io.File; import java.nio.charset.StandardCharsets; @@ -93,6 +95,8 @@ public class RecoverableKeyStoreManagerTest { private static final String ROOT_CERTIFICATE_ALIAS = ""; private static final String DEFAULT_ROOT_CERT_ALIAS = TrustedRootCertificates.GOOGLE_CLOUD_KEY_VAULT_SERVICE_V1_ALIAS; + private static final String INSECURE_CERTIFICATE_ALIAS = + TrustedRootCertificates.TEST_ONLY_INSECURE_CERTIFICATE_ALIAS; private static final String TEST_SESSION_ID = "karlin"; private static final byte[] TEST_PUBLIC_KEY = new byte[] { (byte) 0x30, (byte) 0x59, (byte) 0x30, (byte) 0x13, (byte) 0x06, (byte) 0x07, (byte) 0x2a, @@ -160,6 +164,7 @@ public class RecoverableKeyStoreManagerTest { @Mock private KeyguardManager mKeyguardManager; @Mock private PlatformKeyManager mPlatformKeyManager; @Mock private ApplicationKeyStorage mApplicationKeyStorage; + @Spy private TestOnlyInsecureCertificateHelper mTestOnlyInsecureCertificateHelper; private RecoverableKeyStoreDb mRecoverableKeyStoreDb; private File mDatabaseFile; @@ -195,7 +200,8 @@ public class RecoverableKeyStoreManagerTest { mRecoverySnapshotStorage, mMockListenersStorage, mPlatformKeyManager, - mApplicationKeyStorage); + mApplicationKeyStorage, + mTestOnlyInsecureCertificateHelper); } @After @@ -300,6 +306,9 @@ public class RecoverableKeyStoreManagerTest { mRecoverableKeyStoreManager.initRecoveryService(ROOT_CERTIFICATE_ALIAS, TestData.getCertXmlWithSerial(certSerial)); + verify(mTestOnlyInsecureCertificateHelper, atLeast(1)) + .getDefaultCertificateAliasIfEmpty(ROOT_CERTIFICATE_ALIAS); + assertThat(mRecoverableKeyStoreDb.getShouldCreateSnapshot(userId, uid)).isFalse(); assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertPath(userId, uid, DEFAULT_ROOT_CERT_ALIAS)).isEqualTo(TestData.CERT_PATH_1); @@ -308,6 +317,67 @@ public class RecoverableKeyStoreManagerTest { assertThat(mRecoverableKeyStoreDb.getRecoveryServicePublicKey(userId, uid)).isNull(); } + @Test + public void initRecoveryService_triesToFilterRootAlias() throws Exception { + int uid = Binder.getCallingUid(); + int userId = UserHandle.getCallingUserId(); + long certSerial = 1000L; + mRecoverableKeyStoreDb.setShouldCreateSnapshot(userId, uid, false); + + mRecoverableKeyStoreManager.initRecoveryService(ROOT_CERTIFICATE_ALIAS, + TestData.getCertXmlWithSerial(certSerial)); + + verify(mTestOnlyInsecureCertificateHelper, atLeast(1)) + .getDefaultCertificateAliasIfEmpty(eq(ROOT_CERTIFICATE_ALIAS)); + + verify(mTestOnlyInsecureCertificateHelper, atLeast(1)) + .getRootCertificate(eq(DEFAULT_ROOT_CERT_ALIAS)); + + String activeRootAlias = mRecoverableKeyStoreDb.getActiveRootOfTrust(userId, uid); + assertThat(activeRootAlias).isEqualTo(DEFAULT_ROOT_CERT_ALIAS); + + } + + @Test + public void initRecoveryService_usesProdCertificateForEmptyRootAlias() throws Exception { + int uid = Binder.getCallingUid(); + int userId = UserHandle.getCallingUserId(); + long certSerial = 1000L; + mRecoverableKeyStoreDb.setShouldCreateSnapshot(userId, uid, false); + + mRecoverableKeyStoreManager.initRecoveryService(/*rootCertificateAlias=*/ "", + TestData.getCertXmlWithSerial(certSerial)); + + verify(mTestOnlyInsecureCertificateHelper, atLeast(1)) + .getDefaultCertificateAliasIfEmpty(eq("")); + + verify(mTestOnlyInsecureCertificateHelper, atLeast(1)) + .getRootCertificate(eq(DEFAULT_ROOT_CERT_ALIAS)); + + String activeRootAlias = mRecoverableKeyStoreDb.getActiveRootOfTrust(userId, uid); + assertThat(activeRootAlias).isEqualTo(DEFAULT_ROOT_CERT_ALIAS); + } + + @Test + public void initRecoveryService_usesProdCertificateForNullRootAlias() throws Exception { + int uid = Binder.getCallingUid(); + int userId = UserHandle.getCallingUserId(); + long certSerial = 1000L; + mRecoverableKeyStoreDb.setShouldCreateSnapshot(userId, uid, false); + + mRecoverableKeyStoreManager.initRecoveryService(/*rootCertificateAlias=*/ null, + TestData.getCertXmlWithSerial(certSerial)); + + verify(mTestOnlyInsecureCertificateHelper, atLeast(1)) + .getDefaultCertificateAliasIfEmpty(null); + + verify(mTestOnlyInsecureCertificateHelper, atLeast(1)) + .getRootCertificate(eq(DEFAULT_ROOT_CERT_ALIAS)); + + String activeRootAlias = mRecoverableKeyStoreDb.getActiveRootOfTrust(userId, uid); + assertThat(activeRootAlias).isEqualTo(DEFAULT_ROOT_CERT_ALIAS); + } + @Test public void initRecoveryService_regeneratesCounterId() throws Exception { int uid = Binder.getCallingUid(); @@ -416,6 +486,24 @@ public class RecoverableKeyStoreManagerTest { assertThat(mRecoverableKeyStoreDb.getRecoveryServicePublicKey(userId, uid)).isNull(); } + @Test + public void initRecoveryServiceWithSigFile_usesProdCertificateForNullRootAlias() + throws Exception { + int uid = Binder.getCallingUid(); + int userId = UserHandle.getCallingUserId(); + long certSerial = 1000L; + mRecoverableKeyStoreDb.setShouldCreateSnapshot(userId, uid, false); + + mRecoverableKeyStoreManager.initRecoveryServiceWithSigFile( + /*rootCertificateAlias=*/null, TestData.getCertXml(), TestData.getSigXml()); + + verify(mTestOnlyInsecureCertificateHelper, atLeast(1)) + .getDefaultCertificateAliasIfEmpty(null); + + verify(mTestOnlyInsecureCertificateHelper, atLeast(1)) + .getRootCertificate(eq(DEFAULT_ROOT_CERT_ALIAS)); + } + @Test public void initRecoveryServiceWithSigFile_throwsIfNullCertFile() throws Exception { try { @@ -452,6 +540,18 @@ public class RecoverableKeyStoreManagerTest { } } + @Test + public void initRecoveryServiceWithSigFile_throwsIfTestAliasUsedWithProdCert() + throws Exception { + try { + mRecoverableKeyStoreManager.initRecoveryServiceWithSigFile( + INSECURE_CERTIFICATE_ALIAS, TestData.getCertXml(), TestData.getSigXml()); + fail("should have thrown"); + } catch (ServiceSpecificException e) { + assertThat(e.getMessage()).contains("signature over the cert file is invalid"); + } + } + @Test public void initRecoveryServiceWithSigFile_throwsIfInvalidFileSignature() throws Exception { byte[] modifiedCertXml = TestData.getCertXml(); @@ -712,7 +812,8 @@ public class RecoverableKeyStoreManagerTest { } @Test - public void recoverKeyChainSnapshot_throwsIfFailedToDecryptAllApplicationKeys() throws Exception { + public void recoverKeyChainSnapshot_throwsIfFailedToDecryptAllApplicationKeys() + throws Exception { mRecoverableKeyStoreManager.startRecoverySession( TEST_SESSION_ID, TEST_PUBLIC_KEY, @@ -792,7 +893,8 @@ public class RecoverableKeyStoreManagerTest { } @Test - public void recoverKeyChainSnapshot_worksOnOtherApplicationKeysIfOneDecryptionFails() throws Exception { + public void recoverKeyChainSnapshot_worksOnOtherApplicationKeysIfOneDecryptionFails() + throws Exception { mRecoverableKeyStoreManager.startRecoverySession( TEST_SESSION_ID, TEST_PUBLIC_KEY, diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestData.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestData.java index 4b059c665b54..9b2c853d6b6f 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestData.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestData.java @@ -14,8 +14,12 @@ import java.security.cert.CertificateFactory; import java.security.cert.CertPath; import java.security.spec.ECPrivateKeySpec; +import javax.crypto.KeyGenerator; +import javax.crypto.SecretKey; + public final class TestData { + private static final String KEY_ALGORITHM = "AES"; private static final long DEFAULT_SERIAL = 1000; private static final String CERT_PATH_ENCODING = "PkiPath"; @@ -308,4 +312,10 @@ public final class TestData { KeyFactory keyFactory = KeyFactory.getInstance("EC"); return keyFactory.generatePrivate(new ECPrivateKeySpec(priv, SecureBox.EC_PARAM_SPEC)); } + + public static SecretKey generateKey() throws Exception { + KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_ALGORITHM); + keyGenerator.init(/*keySize=*/ 256); + return keyGenerator.generateKey(); + } } diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelperTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelperTest.java new file mode 100644 index 000000000000..bc50c9e487e8 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelperTest.java @@ -0,0 +1,128 @@ +package com.android.server.locksettings.recoverablekeystore; + +import static com.google.common.truth.Truth.assertThat; + +import android.os.RemoteException; +import android.os.ServiceSpecificException; +import android.security.keystore.recovery.TrustedRootCertificates; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; +import android.util.Log; + +import com.android.internal.widget.LockPatternUtils; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.HashMap; +import java.security.cert.X509Certificate; +import java.util.Map; +import javax.crypto.SecretKey; + +@SmallTest +@RunWith(AndroidJUnit4.class) +public class TestOnlyInsecureCertificateHelperTest { + private final TestOnlyInsecureCertificateHelper mHelper + = new TestOnlyInsecureCertificateHelper(); + + @Test + public void testDoesCredentailSupportInsecureMode_forNonWhitelistedPassword() throws Exception { + assertThat(mHelper.doesCredentailSupportInsecureMode( + LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, "secret12345")).isFalse(); + assertThat(mHelper.doesCredentailSupportInsecureMode( + LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, "1234")).isFalse(); + } + + @Test + public void testDoesCredentailSupportInsecureMode_forWhitelistedPassword() throws Exception { + assertThat(mHelper.doesCredentailSupportInsecureMode( + LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, + TrustedRootCertificates.INSECURE_PASSWORD_PREFIX)).isTrue(); + + assertThat(mHelper.doesCredentailSupportInsecureMode( + LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, + TrustedRootCertificates.INSECURE_PASSWORD_PREFIX + "12")).isTrue(); + } + + @Test + public void testDoesCredentailSupportInsecureMode_Pattern() throws Exception { + assertThat(mHelper.doesCredentailSupportInsecureMode( + LockPatternUtils.CREDENTIAL_TYPE_PATTERN, + TrustedRootCertificates.INSECURE_PASSWORD_PREFIX)).isFalse(); + assertThat(mHelper.doesCredentailSupportInsecureMode( + LockPatternUtils.CREDENTIAL_TYPE_NONE, + TrustedRootCertificates.INSECURE_PASSWORD_PREFIX)).isFalse(); + } + + @Test + public void testIsTestOnlyCertificate() throws Exception { + assertThat(mHelper.isTestOnlyCertificate( + TrustedRootCertificates.GOOGLE_CLOUD_KEY_VAULT_SERVICE_V1_ALIAS)).isFalse(); + assertThat(mHelper.isTestOnlyCertificate( + TrustedRootCertificates.TEST_ONLY_INSECURE_CERTIFICATE_ALIAS)).isTrue(); + assertThat(mHelper.isTestOnlyCertificate( + "UNKNOWN_ALIAS")).isFalse(); + } + + @Test + public void testKeepOnlyWhitelistedInsecureKeys_emptyKeysList() throws Exception { + Map rawKeys = new HashMap<>(); + Map expectedResult = new HashMap<>(); + + Map filteredKeys = + mHelper.keepOnlyWhitelistedInsecureKeys(rawKeys); + assertThat(filteredKeys.entrySet()).containsExactlyElementsIn(expectedResult.entrySet()); + assertThat(filteredKeys.entrySet()).containsAllIn(rawKeys.entrySet()); + } + + @Test + public void testKeepOnlyWhitelistedInsecureKeys_singleNonWhitelistedKey() throws Exception { + Map rawKeys = new HashMap<>(); + Map expectedResult = new HashMap<>(); + + String alias = "secureAlias"; + rawKeys.put(alias, TestData.generateKey()); + + Map filteredKeys = + mHelper.keepOnlyWhitelistedInsecureKeys(rawKeys); + assertThat(filteredKeys.entrySet()).containsExactlyElementsIn(expectedResult.entrySet()); + assertThat(rawKeys.entrySet()).containsAllIn(filteredKeys.entrySet()); + } + + @Test + public void testKeepOnlyWhitelistedInsecureKeys_singleWhitelistedKey() throws Exception { + Map rawKeys = new HashMap<>(); + Map expectedResult = new HashMap<>(); + + String alias = TrustedRootCertificates.INSECURE_KEY_ALIAS_PREFIX; + rawKeys.put(alias, TestData.generateKey()); + expectedResult.put(alias, rawKeys.get(alias)); + + Map filteredKeys = + mHelper.keepOnlyWhitelistedInsecureKeys(rawKeys); + assertThat(filteredKeys.entrySet()).containsExactlyElementsIn(expectedResult.entrySet()); + assertThat(rawKeys.entrySet()).containsAllIn(filteredKeys.entrySet()); + } + + @Test + public void testKeepOnlyWhitelistedInsecureKeys() throws Exception { + Map rawKeys = new HashMap<>(); + Map expectedResult = new HashMap<>(); + + String alias = "SECURE_ALIAS" + TrustedRootCertificates.INSECURE_KEY_ALIAS_PREFIX; + rawKeys.put(alias, TestData.generateKey()); + + alias = TrustedRootCertificates.INSECURE_KEY_ALIAS_PREFIX + "1"; + rawKeys.put(alias, TestData.generateKey()); + expectedResult.put(alias, rawKeys.get(alias)); + + alias = TrustedRootCertificates.INSECURE_KEY_ALIAS_PREFIX + "2"; + rawKeys.put(alias, TestData.generateKey()); + expectedResult.put(alias, rawKeys.get(alias)); + + Map filteredKeys = + mHelper.keepOnlyWhitelistedInsecureKeys(rawKeys); + assertThat(filteredKeys.entrySet()).containsExactlyElementsIn(expectedResult.entrySet()); + assertThat(rawKeys.entrySet()).containsAllIn(filteredKeys.entrySet()); + } +} -- GitLab From 15caf835ec5761e35db698f1f270c25b3a9e639d Mon Sep 17 00:00:00 2001 From: Kweku Adams Date: Thu, 29 Mar 2018 14:26:23 -0700 Subject: [PATCH 098/179] Creating java package for Privacy proto. Also setting fields in the GlobalSettingsProto.Private message to LOCAL. Bug: 72814439 Bug: 74975371 Test: flash device and check incident.proto output Change-Id: Ia580144b8b0d0cb9bd9a3297a37213ed5f60a514 --- core/proto/android/providers/settings/global.proto | 6 ++++-- libs/incident/proto/android/privacy.proto | 6 +++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto index c7de947cdca9..b5303c8a4eec 100644 --- a/core/proto/android/providers/settings/global.proto +++ b/core/proto/android/providers/settings/global.proto @@ -672,8 +672,10 @@ message GlobalSettingsProto { option (android.msg_privacy).dest = DEST_LOCAL; // The requested Private DNS mode and an accompanying specifier. - optional SettingProto dns_mode = 1; - optional SettingProto dns_specifier = 2; + // msg_privacy settings don't apply to sub messages, only to primitive + // fields, so these must also be explicitly set to LOCAL. + optional SettingProto dns_mode = 1 [ (android.privacy).dest = DEST_LOCAL ]; + optional SettingProto dns_specifier = 2 [ (android.privacy).dest = DEST_LOCAL ]; } optional Private private = 96; diff --git a/libs/incident/proto/android/privacy.proto b/libs/incident/proto/android/privacy.proto index f29f57f1c197..1ef36df8121f 100644 --- a/libs/incident/proto/android/privacy.proto +++ b/libs/incident/proto/android/privacy.proto @@ -16,13 +16,13 @@ syntax = "proto2"; -option java_package = "android"; +package android; + +option java_package = "com.android.incident"; option java_multiple_files = true; import "google/protobuf/descriptor.proto"; -package android; - enum Destination { // Fields or messages annotated with DEST_LOCAL must never be // extracted from the device automatically. They can be accessed -- GitLab From 5b8606023341b24846c7ab84d83978145eb7ff06 Mon Sep 17 00:00:00 2001 From: Derek Sollenberger Date: Thu, 29 Mar 2018 17:29:29 -0400 Subject: [PATCH 099/179] Fix drawing sequence from using deprecated Canvas APIs. Bug: 77286317 Test: marlin-userdebug reboots successfully Change-Id: I72688931f29ff9db6bb1e39af9d313be7df33a03 --- .../com/android/server/wm/StrictModeFlash.java | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/wm/StrictModeFlash.java b/services/core/java/com/android/server/wm/StrictModeFlash.java index f51a6a921984..e97b36683362 100644 --- a/services/core/java/com/android/server/wm/StrictModeFlash.java +++ b/services/core/java/com/android/server/wm/StrictModeFlash.java @@ -79,17 +79,25 @@ class StrictModeFlash { } // Top - c.clipRect(new Rect(0, 0, dw, mThickness), Region.Op.REPLACE); + c.save(); + c.clipRect(new Rect(0, 0, dw, mThickness)); c.drawColor(Color.RED); + c.restore(); // Left - c.clipRect(new Rect(0, 0, mThickness, dh), Region.Op.REPLACE); + c.save(); + c.clipRect(new Rect(0, 0, mThickness, dh)); c.drawColor(Color.RED); + c.restore(); // Right - c.clipRect(new Rect(dw - mThickness, 0, dw, dh), Region.Op.REPLACE); + c.save(); + c.clipRect(new Rect(dw - mThickness, 0, dw, dh)); c.drawColor(Color.RED); + c.restore(); // Bottom - c.clipRect(new Rect(0, dh - mThickness, dw, dh), Region.Op.REPLACE); + c.save(); + c.clipRect(new Rect(0, dh - mThickness, dw, dh)); c.drawColor(Color.RED); + c.restore(); mSurface.unlockCanvasAndPost(c); } -- GitLab From 89a55cb83d8d9f9a187e9319936273042e91f8f9 Mon Sep 17 00:00:00 2001 From: Kevin Chyn Date: Thu, 29 Mar 2018 14:52:59 -0700 Subject: [PATCH 100/179] Clear fingerprint stats after dump --proto Fixes: 77165025 Test: adb shell dumpsys fingerprint --proto adb shell dumpsys fingerprint counts are cleared after dumping proto Change-Id: I115f435b50307112f7a052ef42f91999468e40dd --- .../java/com/android/server/fingerprint/FingerprintService.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java index 262a2f8ea817..92d3772e0607 100644 --- a/services/core/java/com/android/server/fingerprint/FingerprintService.java +++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java @@ -1470,6 +1470,8 @@ public class FingerprintService extends SystemService implements IHwBinder.Death proto.end(userToken); } proto.flush(); + mPerformanceMap.clear(); + mCryptoPerformanceMap.clear(); } @Override -- GitLab From 75ad2496ebd8162771687510dfe40b5316cb38bc Mon Sep 17 00:00:00 2001 From: Makoto Onuki Date: Wed, 28 Mar 2018 14:42:42 -0700 Subject: [PATCH 101/179] AppStandby exemption: sync requested by FG apps Bug: 72443754 Fix: 72443754 Test: atest ${ANDROID_BUILD_TOP}/frameworks/base/services/tests/servicestests/src/com/android/server/content/SyncOperationTest.java Test: Manual test with contacts sync: Precondition: Put the contacts sync in RARE bucket. adb shell dumpsys deviceidle tempwhitelist -r com.google.android.syncadapters.contacts adb shell am make-uid-idle com.google.android.syncadapters.contacts adb shell am set-standby-bucket com.google.android.syncadapters.contacts 40 Test 1: Toggle contacts sync from the Settings -> Account - Make sure a sync happens. Test 2: Mutate a contact on the WEB - Sync is scheduled, but won't run because it has no network access. - am set-standby-bucket com.google.android.syncadapters.contacts 30 - Sync run runs. Test 3. adb shell requestsync -n ACCOUNT -t com.google -a com.android.contacts - Sync is scheduled but won't run. Test 4. adb shell requestsync -n ACCOUNT -t com.google -a com.android.contacts -f - Sync is scheduled but it still won't run. Test 5. adb shell requestsync -n ACCOUNT -t com.google -a com.android.contacts -F - Sync now runs Change-Id: I1eb972ed321d2a1a782ae23ccb806671926d3e6b --- .../commands/requestsync/RequestSync.java | 23 +- .../android/app/usage/UsageStatsManager.java | 6 + .../app/usage/UsageStatsManagerInternal.java | 8 + .../java/android/content/ContentResolver.java | 47 ++- core/java/android/os/UserHandle.java | 2 +- .../server/content/ContentService.java | 77 ++-- .../content/SyncAdapterStateFetcher.java | 68 ++++ .../android/server/content/SyncManager.java | 111 +++--- .../server/content/SyncManagerConstants.java | 21 ++ .../android/server/content/SyncOperation.java | 72 ++-- .../server/content/SyncStorageEngine.java | 25 +- .../server/content/SyncOperationTest.java | 15 +- .../server/content/SyncStorageEngineTest.java | 349 ------------------ .../server/usage/AppStandbyController.java | 34 ++ .../server/usage/UsageStatsService.java | 5 + 15 files changed, 369 insertions(+), 494 deletions(-) create mode 100644 services/core/java/com/android/server/content/SyncAdapterStateFetcher.java delete mode 100644 services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java diff --git a/cmds/requestsync/src/com/android/commands/requestsync/RequestSync.java b/cmds/requestsync/src/com/android/commands/requestsync/RequestSync.java index b76d6694ca2d..37b7acfaf5e6 100644 --- a/cmds/requestsync/src/com/android/commands/requestsync/RequestSync.java +++ b/cmds/requestsync/src/com/android/commands/requestsync/RequestSync.java @@ -29,23 +29,21 @@ public class RequestSync { private String[] mArgs; private int mNextArg; private String mCurArgData; - private boolean mIsForegroundRequest; + + private int mExemptionFlag = ContentResolver.SYNC_EXEMPTION_NONE; enum Operation { REQUEST_SYNC { @Override void invoke(RequestSync caller) { - if (caller.mIsForegroundRequest) { - caller.mExtras.putBoolean( - ContentResolver.SYNC_VIRTUAL_EXTRAS_FORCE_FG_SYNC, true); - } else { - caller.mExtras.putBoolean( - ContentResolver.SYNC_VIRTUAL_EXTRAS_FORCE_BG_SYNC, true); + final int flag = caller.mExemptionFlag; + caller.mExtras.putInt(ContentResolver.SYNC_VIRTUAL_EXTRAS_EXEMPTION_FLAG, flag); + if (flag == ContentResolver.SYNC_EXEMPTION_NONE) { System.out.println( "Making a sync request as a background app.\n" + "Note: request may be throttled by App Standby.\n" + "To override this behavior and run a sync immediately," - + " pass a -f option.\n"); + + " pass a -f or -F option (use -h for help).\n"); } final SyncRequest request = new SyncRequest.Builder() @@ -213,7 +211,10 @@ public class RequestSync { mExtras.putBoolean(key, Boolean.valueOf(value)); } else if (opt.equals("-f") || opt.equals("--foreground")) { - mIsForegroundRequest = true; + mExemptionFlag = ContentResolver.SYNC_EXEMPTION_ACTIVE; + + } else if (opt.equals("-F") || opt.equals("--top")) { + mExemptionFlag = ContentResolver.SYNC_EXEMPTION_ACTIVE_WITH_TEMP; } else { System.err.println("Error: Unknown option: " + opt); @@ -293,7 +294,9 @@ public class RequestSync { " -a|--authority \n" + " App-standby related options\n" + "\n" + - " -f|--foreground (Exempt a sync from app standby)\n" + + " -f|--foreground (cause WORKING_SET, FREQUENT sync adapters" + + " to run immediately)\n" + + " -F|--top (cause even RARE sync adapters to run immediately)\n" + " ContentResolver extra options:\n" + " --is|--ignore-settings: Add SYNC_EXTRAS_IGNORE_SETTINGS\n" + " --ib|--ignore-backoff: Add SYNC_EXTRAS_IGNORE_BACKOFF\n" + diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java index d27265259daf..eafe91a3450a 100644 --- a/core/java/android/app/usage/UsageStatsManager.java +++ b/core/java/android/app/usage/UsageStatsManager.java @@ -183,10 +183,13 @@ public final class UsageStatsManager { public static final int REASON_SUB_USAGE_SLICE_PINNED = 0x0009; /** @hide */ public static final int REASON_SUB_USAGE_SLICE_PINNED_PRIV = 0x000A; + /** @hide */ + public static final int REASON_SUB_USAGE_EXEMPTED_SYNC_START = 0x000B; /** @hide */ public static final int REASON_SUB_PREDICTED_RESTORED = 0x0001; + /** @hide */ @IntDef(flag = false, prefix = { "STANDBY_BUCKET_" }, value = { STANDBY_BUCKET_EXEMPTED, @@ -665,6 +668,9 @@ public final class UsageStatsManager { case REASON_SUB_USAGE_SLICE_PINNED_PRIV: sb.append("slpp"); break; + case REASON_SUB_USAGE_EXEMPTED_SYNC_START: + sb.append("es"); + break; } break; } diff --git a/core/java/android/app/usage/UsageStatsManagerInternal.java b/core/java/android/app/usage/UsageStatsManagerInternal.java index 09ced2648de1..b8628a4d446b 100644 --- a/core/java/android/app/usage/UsageStatsManagerInternal.java +++ b/core/java/android/app/usage/UsageStatsManagerInternal.java @@ -243,4 +243,12 @@ public abstract class UsageStatsManagerInternal { */ public abstract void reportAppJobState(String packageName, @UserIdInt int userId, int numDeferredJobs, long timeSinceLastJobRun); + + /** + * Report a sync that was scheduled by an active app is about to be executed. + * + * @param packageName name of the package that owns the sync adapter. + * @param userId which user the app is associated with + */ + public abstract void reportExemptedSyncStart(String packageName, @UserIdInt int userId); } diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java index 440103a6d8a4..9f3df377c4e2 100644 --- a/core/java/android/content/ContentResolver.java +++ b/core/java/android/content/ContentResolver.java @@ -166,24 +166,13 @@ public abstract class ContentResolver { public static final String SYNC_EXTRAS_DISALLOW_METERED = "allow_metered"; /** - * {@hide} Flag only used by the requestsync command to treat a request as if it was made by - * a foreground app. + * {@hide} Integer extra containing a SyncExemption flag. * * Only the system and the shell user can set it. * * This extra is "virtual". Once passed to the system server, it'll be removed from the bundle. */ - public static final String SYNC_VIRTUAL_EXTRAS_FORCE_FG_SYNC = "force_fg_sync"; - - /** - * {@hide} Flag only used by the requestsync command to treat a request as if it was made by - * a background app. - * - * Only the system and the shell user can set it. - * - * This extra is "virtual". Once passed to the system server, it'll be removed from the bundle. - */ - public static final String SYNC_VIRTUAL_EXTRAS_FORCE_BG_SYNC = "force_bg_sync"; + public static final String SYNC_VIRTUAL_EXTRAS_EXEMPTION_FLAG = "v_exemption"; /** * Set by the SyncManager to request that the SyncAdapter initialize itself for @@ -525,6 +514,38 @@ public abstract class ContentResolver { */ public static final int NOTIFY_SKIP_NOTIFY_FOR_DESCENDANTS = 1<<1; + /** + * No exception, throttled by app standby normally. + * @hide + */ + public static final int SYNC_EXEMPTION_NONE = 0; + + /** + * When executing a sync with this exemption, we'll put the target app in the ACTIVE bucket + * for 10 minutes. This will allow the sync adapter to schedule/run further syncs and jobs. + * + * Note this will still *not* let RARE apps to run syncs, because they still won't get network + * connection. + * @hide + */ + public static final int SYNC_EXEMPTION_ACTIVE = 1; + + /** + * In addition to {@link #SYNC_EXEMPTION_ACTIVE}, we put the sync adapter app in the + * temp whitelist for 10 minutes, so that even RARE apps can run syncs right away. + * @hide + */ + public static final int SYNC_EXEMPTION_ACTIVE_WITH_TEMP = 2; + + /** @hide */ + @IntDef(flag = false, prefix = { "SYNC_EXEMPTION_" }, value = { + SYNC_EXEMPTION_NONE, + SYNC_EXEMPTION_ACTIVE, + SYNC_EXEMPTION_ACTIVE_WITH_TEMP, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface SyncExemption {} + // Always log queries which take 500ms+; shorter queries are // sampled accordingly. private static final boolean ENABLE_CONTENT_SAMPLE = false; diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java index 5be72bc5c54b..094f0046649b 100644 --- a/core/java/android/os/UserHandle.java +++ b/core/java/android/os/UserHandle.java @@ -158,7 +158,7 @@ public final class UserHandle implements Parcelable { * @hide */ public static boolean isCore(int uid) { - if (uid > 0) { + if (uid >= 0) { final int appId = getAppId(uid); return appId < Process.FIRST_APPLICATION_UID; } else { diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java index 63308f894d09..ec404feeceb7 100644 --- a/services/core/java/com/android/server/content/ContentService.java +++ b/services/core/java/com/android/server/content/ContentService.java @@ -26,6 +26,7 @@ import android.app.job.JobInfo; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ContentResolver; +import android.content.ContentResolver.SyncExemption; import android.content.Context; import android.content.IContentService; import android.content.ISyncStatusObserver; @@ -78,7 +79,7 @@ import java.util.List; */ public final class ContentService extends IContentService.Stub { static final String TAG = "ContentService"; - static final boolean DEBUG = false; + static final boolean DEBUG = true; public static class Lifecycle extends SystemService { private ContentService mService; @@ -451,7 +452,7 @@ public final class ContentService extends IContentService.Stub { SyncManager syncManager = getSyncManager(); if (syncManager != null) { syncManager.scheduleLocalSync(null /* all accounts */, callingUserHandle, uid, - uri.getAuthority(), /*isAppStandbyExempted=*/ isUidInForeground(uid)); + uri.getAuthority(), getSyncExemptionForCaller(uid)); } } @@ -508,7 +509,7 @@ public final class ContentService extends IContentService.Stub { int uId = Binder.getCallingUid(); validateExtras(uId, extras); - final boolean isForegroundSyncRequest = isForegroundSyncRequest(uId, extras); + final int syncExemption = getSyncExemptionAndCleanUpExtrasForCaller(uId, extras); // This makes it so that future permission checks will be in the context of this // process rather than the caller's process. We will restore this before returning. @@ -518,7 +519,7 @@ public final class ContentService extends IContentService.Stub { if (syncManager != null) { syncManager.scheduleSync(account, userId, uId, authority, extras, SyncStorageEngine.AuthorityInfo.UNDEFINED, - /*isAppStandbyExempted=*/ isForegroundSyncRequest); + syncExemption); } } finally { restoreCallingIdentity(identityToken); @@ -561,7 +562,7 @@ public final class ContentService extends IContentService.Stub { final Bundle extras = request.getBundle(); validateExtras(callerUid, extras); - final boolean isForegroundSyncRequest = isForegroundSyncRequest(callerUid, extras); + final int syncExemption = getSyncExemptionAndCleanUpExtrasForCaller(callerUid, extras); // This makes it so that future permission checks will be in the context of this // process rather than the caller's process. We will restore this before returning. @@ -589,7 +590,7 @@ public final class ContentService extends IContentService.Stub { syncManager.scheduleSync( request.getAccount(), userId, callerUid, request.getProvider(), extras, SyncStorageEngine.AuthorityInfo.UNDEFINED, - /*isAppStandbyExempted=*/ isForegroundSyncRequest); + syncExemption); } } finally { restoreCallingIdentity(identityToken); @@ -777,13 +778,15 @@ public final class ContentService extends IContentService.Stub { "no permission to write the sync settings"); enforceCrossUserPermission(userId, "no permission to modify the sync settings for user " + userId); + final int callingUid = Binder.getCallingUid(); + final int syncExemptionFlag = getSyncExemptionForCaller(callingUid); long identityToken = clearCallingIdentity(); try { SyncManager syncManager = getSyncManager(); if (syncManager != null) { syncManager.getSyncStorageEngine().setSyncAutomatically(account, userId, - providerName, sync); + providerName, sync, syncExemptionFlag); } } finally { restoreCallingIdentity(identityToken); @@ -964,11 +967,14 @@ public final class ContentService extends IContentService.Stub { mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS, "no permission to write the sync settings"); + final int callingUid = Binder.getCallingUid(); + long identityToken = clearCallingIdentity(); try { SyncManager syncManager = getSyncManager(); if (syncManager != null) { - syncManager.getSyncStorageEngine().setMasterSyncAutomatically(flag, userId); + syncManager.getSyncStorageEngine().setMasterSyncAutomatically(flag, userId, + getSyncExemptionForCaller(callingUid)); } } finally { restoreCallingIdentity(identityToken); @@ -1263,9 +1269,7 @@ public final class ContentService extends IContentService.Stub { } private void validateExtras(int callingUid, Bundle extras) { - if (extras.containsKey(ContentResolver.SYNC_VIRTUAL_EXTRAS_FORCE_FG_SYNC) - || extras.containsKey(ContentResolver.SYNC_VIRTUAL_EXTRAS_FORCE_FG_SYNC) - ) { + if (extras.containsKey(ContentResolver.SYNC_VIRTUAL_EXTRAS_EXEMPTION_FLAG)) { switch (callingUid) { case Process.ROOT_UID: case Process.SHELL_UID: @@ -1277,39 +1281,36 @@ public final class ContentService extends IContentService.Stub { } } - private boolean isForegroundSyncRequest(int callingUid, Bundle extras) { - final boolean isForegroundRequest; - if (extras.getBoolean(ContentResolver.SYNC_VIRTUAL_EXTRAS_FORCE_FG_SYNC)) { - isForegroundRequest = true; - } else if (extras.getBoolean(ContentResolver.SYNC_VIRTUAL_EXTRAS_FORCE_BG_SYNC)) { - isForegroundRequest = false; - } else { - isForegroundRequest = isUidInForeground(callingUid); - } - extras.remove(ContentResolver.SYNC_VIRTUAL_EXTRAS_FORCE_FG_SYNC); - extras.remove(ContentResolver.SYNC_VIRTUAL_EXTRAS_FORCE_BG_SYNC); - - return isForegroundRequest; + @SyncExemption + private int getSyncExemptionForCaller(int callingUid) { + return getSyncExemptionAndCleanUpExtrasForCaller(callingUid, null); } - private boolean isUidInForeground(int uid) { - // If the caller is ADB, we assume it's a background request by default, because - // that's also the default of requests from the requestsync command. - // The requestsync command will always set either SYNC_VIRTUAL_EXTRAS_FORCE_FG_SYNC or - // SYNC_VIRTUAL_EXTRAS_FORCE_BG_SYNC (for non-periodic sync requests), - // so it shouldn't matter in practice. - switch (uid) { - case Process.SHELL_UID: - case Process.ROOT_UID: - return false; + @SyncExemption + private int getSyncExemptionAndCleanUpExtrasForCaller(int callingUid, Bundle extras) { + if (extras != null) { + final int exemption = + extras.getInt(ContentResolver.SYNC_VIRTUAL_EXTRAS_EXEMPTION_FLAG, -1); + + // Need to remove the virtual extra. + extras.remove(ContentResolver.SYNC_VIRTUAL_EXTRAS_EXEMPTION_FLAG); + if (exemption != -1) { + return exemption; + } } final ActivityManagerInternal ami = LocalServices.getService(ActivityManagerInternal.class); - if (ami != null) { - return ami.getUidProcessState(uid) - <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND; + final int procState = (ami != null) + ? ami.getUidProcessState(callingUid) + : ActivityManager.PROCESS_STATE_NONEXISTENT; + + if (procState <= ActivityManager.PROCESS_STATE_TOP) { + return ContentResolver.SYNC_EXEMPTION_ACTIVE_WITH_TEMP; } - return false; + if (procState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) { + return ContentResolver.SYNC_EXEMPTION_ACTIVE; + } + return ContentResolver.SYNC_EXEMPTION_NONE; } /** diff --git a/services/core/java/com/android/server/content/SyncAdapterStateFetcher.java b/services/core/java/com/android/server/content/SyncAdapterStateFetcher.java new file mode 100644 index 000000000000..62fb75107755 --- /dev/null +++ b/services/core/java/com/android/server/content/SyncAdapterStateFetcher.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.server.content; + +import android.app.usage.UsageStatsManagerInternal; +import android.os.SystemClock; +import android.util.Pair; + +import com.android.server.AppStateTracker; +import com.android.server.LocalServices; + +import java.util.HashMap; + +class SyncAdapterStateFetcher { + + private final HashMap, Integer> mBucketCache = + new HashMap<>(); + + public SyncAdapterStateFetcher() { + } + + /** + * Return sync adapter state with a cache. + */ + public int getStandbyBucket(int userId, String packageName) { + final Pair key = Pair.create(userId, packageName); + final Integer cached = mBucketCache.get(key); + if (cached != null) { + return cached; + } + final UsageStatsManagerInternal usmi = + LocalServices.getService(UsageStatsManagerInternal.class); + if (usmi == null) { + return -1; // Unknown. + } + + final int value = usmi.getAppStandbyBucket(packageName, userId, + SystemClock.elapsedRealtime()); + mBucketCache.put(key, value); + return value; + } + + /** + * Return UID active state. + */ + public boolean isAppActive(int uid) { + final AppStateTracker ast = + LocalServices.getService(AppStateTracker.class); + if (ast == null) { + return false; + } + + return ast.isUidActive(uid); + } +} diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java index 70892685d8b4..d1f50b733894 100644 --- a/services/core/java/com/android/server/content/SyncManager.java +++ b/services/core/java/com/android/server/content/SyncManager.java @@ -29,9 +29,11 @@ import android.app.NotificationManager; import android.app.PendingIntent; import android.app.job.JobInfo; import android.app.job.JobScheduler; +import android.app.usage.UsageStatsManagerInternal; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ContentResolver; +import android.content.ContentResolver.SyncExemption; import android.content.Context; import android.content.ISyncAdapter; import android.content.ISyncAdapterUnsyncableAccountCallback; @@ -70,6 +72,7 @@ import android.os.Looper; import android.os.Message; import android.os.Messenger; import android.os.PowerManager; +import android.os.Process; import android.os.RemoteCallback; import android.os.RemoteException; import android.os.ServiceManager; @@ -88,6 +91,8 @@ import android.util.Slog; import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; import com.android.internal.notification.SystemNotificationChannels; import com.android.internal.util.ArrayUtils; +import com.android.server.DeviceIdleController; +import com.android.server.DeviceIdleController.LocalService; import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.job.JobSchedulerInternal; @@ -550,10 +555,6 @@ public class SyncManager { return mJobScheduler; } - /** - * Should only be created after {@link ContentService#systemReady()} so that - * {@link PackageManager} is ready to query. - */ public SyncManager(Context context, boolean factoryTest) { // Initialize the SyncStorageEngine first, before registering observers // and creating threads and so on; it may fail if the disk is full. @@ -566,9 +567,9 @@ public class SyncManager { mSyncStorageEngine.setOnSyncRequestListener(new OnSyncRequestListener() { @Override public void onSyncRequest(SyncStorageEngine.EndPoint info, int reason, Bundle extras, - boolean isAppStandbyExempted) { + @SyncExemption int syncExemptionFlag) { scheduleSync(info.account, info.userId, reason, info.provider, extras, - AuthorityInfo.UNDEFINED, isAppStandbyExempted); + AuthorityInfo.UNDEFINED, syncExemptionFlag); } }); @@ -599,7 +600,7 @@ public class SyncManager { scheduleSync(null, UserHandle.USER_ALL, SyncOperation.REASON_SERVICE_CHANGED, type.authority, null, AuthorityInfo.UNDEFINED, - /*isAppStandbyExempted=*/ false); + ContentResolver.SYNC_EXEMPTION_NONE); } } }, mSyncHandler); @@ -649,7 +650,7 @@ public class SyncManager { scheduleSync(account, UserHandle.getUserId(uid), SyncOperation.REASON_ACCOUNTS_UPDATED, null, null, AuthorityInfo.SYNCABLE_NO_ACCOUNT_ACCESS, - /*isAppStandbyExempted=*/ false); + ContentResolver.SYNC_EXEMPTION_NONE); } }); @@ -883,9 +884,9 @@ public class SyncManager { */ public void scheduleSync(Account requestedAccount, int userId, int reason, String requestedAuthority, Bundle extras, int targetSyncState, - boolean isAppStandbyExempted) { + @SyncExemption int syncExemptionFlag) { scheduleSync(requestedAccount, userId, reason, requestedAuthority, extras, targetSyncState, - 0 /* min delay */, true /* checkIfAccountReady */, isAppStandbyExempted); + 0 /* min delay */, true /* checkIfAccountReady */, syncExemptionFlag); } /** @@ -894,7 +895,7 @@ public class SyncManager { private void scheduleSync(Account requestedAccount, int userId, int reason, String requestedAuthority, Bundle extras, int targetSyncState, final long minDelayMillis, boolean checkIfAccountReady, - boolean isAppStandbyExempted) { + @SyncExemption int syncExemptionFlag) { final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE); if (extras == null) { extras = new Bundle(); @@ -904,7 +905,7 @@ public class SyncManager { + requestedAuthority + " reason=" + reason + " checkIfAccountReady=" + checkIfAccountReady - + " isAppStandbyExempted=" + isAppStandbyExempted); + + " syncExemptionFlag=" + syncExemptionFlag); } AccountAndUser[] accounts = null; @@ -1016,7 +1017,7 @@ public class SyncManager { scheduleSync(account.account, userId, reason, authority, finalExtras, targetSyncState, minDelayMillis, true /* checkIfAccountReady */, - isAppStandbyExempted); + syncExemptionFlag); } } )); @@ -1067,7 +1068,7 @@ public class SyncManager { sendOnUnsyncableAccount(mContext, syncAdapterInfo, account.userId, () -> scheduleSync(account.account, account.userId, reason, authority, finalExtras, targetSyncState, minDelayMillis, - false, isAppStandbyExempted)); + false, syncExemptionFlag)); } else { // Initialisation sync. Bundle newExtras = new Bundle(); @@ -1086,7 +1087,7 @@ public class SyncManager { new SyncOperation(account.account, account.userId, owningUid, owningPackage, reason, source, authority, newExtras, allowParallelSyncs, - isAppStandbyExempted), + syncExemptionFlag), minDelayMillis ); } @@ -1103,7 +1104,7 @@ public class SyncManager { postScheduleSyncMessage( new SyncOperation(account.account, account.userId, owningUid, owningPackage, reason, source, - authority, extras, allowParallelSyncs, isAppStandbyExempted), + authority, extras, allowParallelSyncs, syncExemptionFlag), minDelayMillis ); } @@ -1217,12 +1218,12 @@ public class SyncManager { * ms to batch syncs. */ public void scheduleLocalSync(Account account, int userId, int reason, String authority, - boolean isAppStandbyExempted) { + @SyncExemption int syncExemptionFlag) { final Bundle extras = new Bundle(); extras.putBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, true); scheduleSync(account, userId, reason, authority, extras, AuthorityInfo.UNDEFINED, LOCAL_SYNC_DELAY, true /* checkIfAccountReady */, - isAppStandbyExempted); + syncExemptionFlag); } public SyncAdapterType[] getSyncAdapterTypes(int userId) { @@ -1493,7 +1494,7 @@ public class SyncManager { // If any of the duplicate ones has exemption, then we inherit it. if (!syncOperation.isPeriodic) { - boolean inheritAppStandbyExemption = false; + int inheritedSyncExemptionFlag = ContentResolver.SYNC_EXEMPTION_NONE; // Check currently running syncs for (ActiveSyncContext asc: mActiveSyncContexts) { @@ -1534,10 +1535,11 @@ public class SyncManager { // This means the duplicate one has a negative expected run time, but it hasn't // been executed possibly because of app-standby. - if (syncOperation.isAppStandbyExempted - && (minDelay == 0) - && !syncToRun.isAppStandbyExempted) { + if ((minDelay == 0) + && (syncToRun.syncExemptionFlag < syncOperation.syncExemptionFlag)) { syncToRun = syncOperation; + inheritedSyncExemptionFlag = + Math.max(inheritedSyncExemptionFlag, syncToRun.syncExemptionFlag); } } @@ -1551,9 +1553,8 @@ public class SyncManager { if (isLoggable) { Slog.v(TAG, "Cancelling duplicate sync " + op); } - if (op.isAppStandbyExempted) { - inheritAppStandbyExemption = true; - } + inheritedSyncExemptionFlag = + Math.max(inheritedSyncExemptionFlag, op.syncExemptionFlag); cancelJob(op, "scheduleSyncOperationH-duplicate"); } } @@ -1570,8 +1571,9 @@ public class SyncManager { } // If any of the duplicates had exemption, we exempt the current one. - if (inheritAppStandbyExemption) { - syncOperation.isAppStandbyExempted = true; + // + if (inheritedSyncExemptionFlag > ContentResolver.SYNC_EXEMPTION_NONE) { + syncOperation.syncExemptionFlag = inheritedSyncExemptionFlag; } } @@ -1591,7 +1593,7 @@ public class SyncManager { // Note this logic means when an exempted sync fails, // the back-off one will inherit it too, and will be exempted from app-standby. - final int jobFlags = syncOperation.isAppStandbyExempted + final int jobFlags = syncOperation.isAppStandbyExempted() ? JobInfo.FLAG_EXEMPT_FROM_APP_STANDBY : 0; JobInfo.Builder b = new JobInfo.Builder(syncOperation.jobId, @@ -1615,6 +1617,19 @@ public class SyncManager { b.setRequiresCharging(true); } + if (syncOperation.syncExemptionFlag + == ContentResolver.SYNC_EXEMPTION_ACTIVE_WITH_TEMP) { + DeviceIdleController.LocalService dic = + LocalServices.getService(DeviceIdleController.LocalService.class); + if (dic != null) { + dic.addPowerSaveTempWhitelistApp(Process.SYSTEM_UID, + syncOperation.owningPackage, + mConstants.getKeyExemptionTempWhitelistDurationInSeconds() * 1000, + UserHandle.getUserId(syncOperation.owningUid), + /* sync=*/ false, "sync by top app"); + } + } + getJobScheduler().scheduleAsPackage(b.build(), syncOperation.owningPackage, syncOperation.target.userId, syncOperation.wakeLockName()); } @@ -1736,7 +1751,7 @@ public class SyncManager { mContext.getOpPackageName()); for (Account account : accounts) { scheduleSync(account, userId, SyncOperation.REASON_USER_START, null, null, - AuthorityInfo.NOT_INITIALIZED, /*isAppStandbyExempted=*/ false); + AuthorityInfo.NOT_INITIALIZED, ContentResolver.SYNC_EXEMPTION_NONE); } } @@ -1930,7 +1945,10 @@ public class SyncManager { protected void dump(FileDescriptor fd, PrintWriter pw, boolean dumpAll) { final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); - dumpSyncState(ipw); + + final SyncAdapterStateFetcher buckets = new SyncAdapterStateFetcher(); + + dumpSyncState(ipw, buckets); mConstants.dump(pw, ""); dumpSyncAdapters(ipw); @@ -1991,7 +2009,7 @@ public class SyncManager { return ret; } - protected void dumpPendingSyncs(PrintWriter pw) { + protected void dumpPendingSyncs(PrintWriter pw, SyncAdapterStateFetcher buckets) { List pendingSyncs = getAllPendingSyncs(); pw.print("Pending Syncs: "); @@ -2001,14 +2019,14 @@ public class SyncManager { int count = 0; for (SyncOperation op: pendingSyncs) { if (!op.isPeriodic) { - pw.println(op.dump(null, false)); + pw.println(op.dump(null, false, buckets)); count++; } } pw.println(); } - protected void dumpPeriodicSyncs(PrintWriter pw) { + protected void dumpPeriodicSyncs(PrintWriter pw, SyncAdapterStateFetcher buckets) { List pendingSyncs = getAllPendingSyncs(); pw.print("Periodic Syncs: "); @@ -2018,7 +2036,7 @@ public class SyncManager { int count = 0; for (SyncOperation op: pendingSyncs) { if (op.isPeriodic) { - pw.println(op.dump(null, false)); + pw.println(op.dump(null, false, buckets)); count++; } } @@ -2075,7 +2093,7 @@ public class SyncManager { return true; } - protected void dumpSyncState(PrintWriter pw) { + protected void dumpSyncState(PrintWriter pw, SyncAdapterStateFetcher buckets) { final StringBuilder sb = new StringBuilder(); pw.print("Data connected: "); pw.println(mDataConnectionIsConnected); @@ -2150,13 +2168,13 @@ public class SyncManager { sb.setLength(0); pw.print(formatDurationHMS(sb, durationInSeconds)); pw.print(" - "); - pw.print(activeSyncContext.mSyncOperation.dump(pm, false)); + pw.print(activeSyncContext.mSyncOperation.dump(pm, false, buckets)); pw.println(); } pw.println(); - dumpPendingSyncs(pw); - dumpPeriodicSyncs(pw); + dumpPendingSyncs(pw, buckets); + dumpPeriodicSyncs(pw, buckets); // Join the installed sync adapter with the accounts list and emit for everything. pw.println("Sync Status"); @@ -3219,7 +3237,7 @@ public class SyncManager { scheduleSync(syncTargets.account, syncTargets.userId, SyncOperation.REASON_ACCOUNTS_UPDATED, syncTargets.provider, null, AuthorityInfo.NOT_INITIALIZED, - /*isAppStandbyExempted=*/ false); + ContentResolver.SYNC_EXEMPTION_NONE); } } @@ -3286,7 +3304,7 @@ public class SyncManager { syncAdapterInfo.componentName.getPackageName(), SyncOperation.REASON_PERIODIC, SyncStorageEngine.SOURCE_PERIODIC, extras, syncAdapterInfo.type.allowParallelSyncs(), true, SyncOperation.NO_JOB_ID, - pollFrequencyMillis, flexMillis, /*isAppStandbyExempted=*/ false); + pollFrequencyMillis, flexMillis, ContentResolver.SYNC_EXEMPTION_NONE); final int syncOpState = computeSyncOpState(op); switch (syncOpState) { @@ -3431,6 +3449,15 @@ public class SyncManager { Slog.v(TAG, syncContext.toString()); } } + if (op.isAppStandbyExempted()) { + final UsageStatsManagerInternal usmi = LocalServices.getService( + UsageStatsManagerInternal.class); + if (usmi != null) { + usmi.reportExemptedSyncStart(op.owningPackage, + UserHandle.getUserId(op.owningUid)); + } + } + // Connect to the sync adapter. int targetUid; ComponentName targetComponent; @@ -3604,7 +3631,7 @@ public class SyncManager { syncOperation.retries++; if (syncOperation.retries > mConstants.getMaxRetriesWithAppStandbyExemption()) { - syncOperation.isAppStandbyExempted = false; + syncOperation.syncExemptionFlag = ContentResolver.SYNC_EXEMPTION_NONE; } // the operation failed so increase the backoff time @@ -3672,7 +3699,7 @@ public class SyncManager { syncOperation.reason, syncOperation.syncSource, info.provider, new Bundle(), syncOperation.allowParallelSyncs, - syncOperation.isAppStandbyExempted)); + syncOperation.syncExemptionFlag)); } } diff --git a/services/core/java/com/android/server/content/SyncManagerConstants.java b/services/core/java/com/android/server/content/SyncManagerConstants.java index 061e4ca02d2d..2a5858c3e182 100644 --- a/services/core/java/com/android/server/content/SyncManagerConstants.java +++ b/services/core/java/com/android/server/content/SyncManagerConstants.java @@ -52,6 +52,12 @@ public class SyncManagerConstants extends ContentObserver { private static final int DEF_MAX_RETRIES_WITH_APP_STANDBY_EXEMPTION = 5; private int mMaxRetriesWithAppStandbyExemption = DEF_MAX_RETRIES_WITH_APP_STANDBY_EXEMPTION; + private static final String KEY_EXEMPTION_TEMP_WHITELIST_DURATION_IN_SECONDS = + "exemption_temp_whitelist_duration_in_seconds"; + private static final int DEF_EXEMPTION_TEMP_WHITELIST_DURATION_IN_SECONDS = 10 * 60; + private int mKeyExemptionTempWhitelistDurationInSeconds + = DEF_EXEMPTION_TEMP_WHITELIST_DURATION_IN_SECONDS; + protected SyncManagerConstants(Context context) { super(null); mContext = context; @@ -97,6 +103,11 @@ public class SyncManagerConstants extends ContentObserver { mMaxRetriesWithAppStandbyExemption = parser.getInt( KEY_MAX_RETRIES_WITH_APP_STANDBY_EXEMPTION, DEF_MAX_RETRIES_WITH_APP_STANDBY_EXEMPTION); + + mKeyExemptionTempWhitelistDurationInSeconds = parser.getInt( + KEY_EXEMPTION_TEMP_WHITELIST_DURATION_IN_SECONDS, + DEF_EXEMPTION_TEMP_WHITELIST_DURATION_IN_SECONDS); + } } @@ -124,6 +135,12 @@ public class SyncManagerConstants extends ContentObserver { } } + public int getKeyExemptionTempWhitelistDurationInSeconds() { + synchronized (mLock) { + return mKeyExemptionTempWhitelistDurationInSeconds; + } + } + public void dump(PrintWriter pw, String prefix) { synchronized (mLock) { pw.print(prefix); @@ -144,6 +161,10 @@ public class SyncManagerConstants extends ContentObserver { pw.print(prefix); pw.print(" mMaxRetriesWithAppStandbyExemption="); pw.println(mMaxRetriesWithAppStandbyExemption); + + pw.print(prefix); + pw.print(" mKeyExemptionTempWhitelistDurationInSeconds="); + pw.println(mKeyExemptionTempWhitelistDurationInSeconds); } } } diff --git a/services/core/java/com/android/server/content/SyncOperation.java b/services/core/java/com/android/server/content/SyncOperation.java index 96bdaeabf17c..d0975637e686 100644 --- a/services/core/java/com/android/server/content/SyncOperation.java +++ b/services/core/java/com/android/server/content/SyncOperation.java @@ -19,6 +19,7 @@ package com.android.server.content; import android.accounts.Account; import android.app.job.JobInfo; import android.content.ContentResolver; +import android.content.ContentResolver.SyncExemption; import android.content.pm.PackageManager; import android.os.Bundle; import android.os.PersistableBundle; @@ -98,33 +99,33 @@ public class SyncOperation { /** jobId of the JobScheduler job corresponding to this sync */ public int jobId; - /** Whether this operation should be exempted from the app-standby throttling. */ - public boolean isAppStandbyExempted; + @SyncExemption + public int syncExemptionFlag; public SyncOperation(Account account, int userId, int owningUid, String owningPackage, int reason, int source, String provider, Bundle extras, - boolean allowParallelSyncs, boolean isAppStandbyExempted) { + boolean allowParallelSyncs, @SyncExemption int syncExemptionFlag) { this(new SyncStorageEngine.EndPoint(account, provider, userId), owningUid, owningPackage, - reason, source, extras, allowParallelSyncs, isAppStandbyExempted); + reason, source, extras, allowParallelSyncs, syncExemptionFlag); } private SyncOperation(SyncStorageEngine.EndPoint info, int owningUid, String owningPackage, int reason, int source, Bundle extras, boolean allowParallelSyncs, - boolean isAppStandbyExempted) { + @SyncExemption int syncExemptionFlag) { this(info, owningUid, owningPackage, reason, source, extras, allowParallelSyncs, false, - NO_JOB_ID, 0, 0, isAppStandbyExempted); + NO_JOB_ID, 0, 0, syncExemptionFlag); } public SyncOperation(SyncOperation op, long periodMillis, long flexMillis) { this(op.target, op.owningUid, op.owningPackage, op.reason, op.syncSource, new Bundle(op.extras), op.allowParallelSyncs, op.isPeriodic, op.sourcePeriodicId, - periodMillis, flexMillis, /*isAppStandbyExempted=*/ false); + periodMillis, flexMillis, ContentResolver.SYNC_EXEMPTION_NONE); } public SyncOperation(SyncStorageEngine.EndPoint info, int owningUid, String owningPackage, int reason, int source, Bundle extras, boolean allowParallelSyncs, boolean isPeriodic, int sourcePeriodicId, long periodMillis, - long flexMillis, boolean isAppStandbyExempted) { + long flexMillis, @SyncExemption int syncExemptionFlag) { this.target = info; this.owningUid = owningUid; this.owningPackage = owningPackage; @@ -138,7 +139,7 @@ public class SyncOperation { this.flexMillis = flexMillis; this.jobId = NO_JOB_ID; this.key = toKey(); - this.isAppStandbyExempted = isAppStandbyExempted; + this.syncExemptionFlag = syncExemptionFlag; } /* Get a one off sync operation instance from a periodic sync. */ @@ -148,7 +149,7 @@ public class SyncOperation { } SyncOperation op = new SyncOperation(target, owningUid, owningPackage, reason, syncSource, new Bundle(extras), allowParallelSyncs, false, jobId /* sourcePeriodicId */, - periodMillis, flexMillis, /*isAppStandbyExempted=*/ false); + periodMillis, flexMillis, ContentResolver.SYNC_EXEMPTION_NONE); return op; } @@ -166,7 +167,7 @@ public class SyncOperation { periodMillis = other.periodMillis; flexMillis = other.flexMillis; this.key = other.key; - isAppStandbyExempted = other.isAppStandbyExempted; + syncExemptionFlag = other.syncExemptionFlag; } /** @@ -235,7 +236,7 @@ public class SyncOperation { jobInfoExtras.putLong("flexMillis", flexMillis); jobInfoExtras.putLong("expectedRuntime", expectedRuntime); jobInfoExtras.putInt("retries", retries); - jobInfoExtras.putBoolean("isAppStandbyExempted", isAppStandbyExempted); + jobInfoExtras.putInt("syncExemptionFlag", syncExemptionFlag); return jobInfoExtras; } @@ -256,7 +257,7 @@ public class SyncOperation { Bundle extras; boolean allowParallelSyncs, isPeriodic; long periodMillis, flexMillis; - boolean isAppStandbyExempted; + int syncExemptionFlag; if (!jobExtras.getBoolean("SyncManagerJob", false)) { return null; @@ -275,7 +276,8 @@ public class SyncOperation { initiatedBy = jobExtras.getInt("sourcePeriodicId", NO_JOB_ID); periodMillis = jobExtras.getLong("periodMillis"); flexMillis = jobExtras.getLong("flexMillis"); - isAppStandbyExempted = jobExtras.getBoolean("isAppStandbyExempted", false); + syncExemptionFlag = jobExtras.getInt("syncExemptionFlag", + ContentResolver.SYNC_EXEMPTION_NONE); extras = new Bundle(); PersistableBundle syncExtras = jobExtras.getPersistableBundle("syncExtras"); @@ -298,7 +300,7 @@ public class SyncOperation { new SyncStorageEngine.EndPoint(account, provider, userId); SyncOperation op = new SyncOperation(target, owningUid, owningPackage, reason, source, extras, allowParallelSyncs, isPeriodic, initiatedBy, periodMillis, flexMillis, - isAppStandbyExempted); + syncExemptionFlag); op.jobId = jobExtras.getInt("jobId"); op.expectedRuntime = jobExtras.getLong("expectedRuntime"); op.retries = jobExtras.getInt("retries"); @@ -361,10 +363,10 @@ public class SyncOperation { @Override public String toString() { - return dump(null, true); + return dump(null, true, null); } - String dump(PackageManager pm, boolean shorter) { + String dump(PackageManager pm, boolean shorter, SyncAdapterStateFetcher appStates) { StringBuilder sb = new StringBuilder(); sb.append("JobId=").append(jobId) .append(" ") @@ -385,8 +387,18 @@ public class SyncOperation { if (extras.getBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, false)) { sb.append(" EXPEDITED"); } - if (isAppStandbyExempted) { - sb.append(" STANDBY-EXEMPTED"); + switch (syncExemptionFlag) { + case ContentResolver.SYNC_EXEMPTION_NONE: + break; + case ContentResolver.SYNC_EXEMPTION_ACTIVE: + sb.append(" STANDBY-EXEMPTED"); + break; + case ContentResolver.SYNC_EXEMPTION_ACTIVE_WITH_TEMP: + sb.append(" STANDBY-EXEMPTED(TOP)"); + break; + default: + sb.append(" ExemptionFlag=" + syncExemptionFlag); + break; } sb.append(" Reason="); sb.append(reasonToString(pm, reason)); @@ -397,21 +409,31 @@ public class SyncOperation { SyncManager.formatDurationHMS(sb, flexMillis); sb.append(")"); } + if (retries > 0) { + sb.append(" Retries="); + sb.append(retries); + } if (!shorter) { sb.append(" Owner={"); UserHandle.formatUid(sb, owningUid); sb.append(" "); sb.append(owningPackage); + if (appStates != null) { + sb.append(" ["); + sb.append(appStates.getStandbyBucket( + UserHandle.getUserId(owningUid), owningPackage)); + sb.append("]"); + + if (appStates.isAppActive(owningUid)) { + sb.append(" [ACTIVE]"); + } + } sb.append("}"); if (!extras.keySet().isEmpty()) { sb.append(" "); extrasToStringBuilder(extras, sb); } } - if (retries > 0) { - sb.append(" Retries="); - sb.append(retries); - } return sb.toString(); } @@ -464,6 +486,10 @@ public class SyncOperation { return extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, false); } + boolean isAppStandbyExempted() { + return syncExemptionFlag != ContentResolver.SYNC_EXEMPTION_NONE; + } + static void extrasToStringBuilder(Bundle bundle, StringBuilder sb) { if (bundle == null) { sb.append("null"); diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java index 8b67b7a27e7e..6081af8d6a55 100644 --- a/services/core/java/com/android/server/content/SyncStorageEngine.java +++ b/services/core/java/com/android/server/content/SyncStorageEngine.java @@ -22,6 +22,7 @@ import android.accounts.AccountManager; import android.app.backup.BackupManager; import android.content.ComponentName; import android.content.ContentResolver; +import android.content.ContentResolver.SyncExemption; import android.content.Context; import android.content.ISyncStatusObserver; import android.content.PeriodicSync; @@ -341,7 +342,7 @@ public class SyncStorageEngine { /** Called when a sync is needed on an account(s) due to some change in state. */ public void onSyncRequest(EndPoint info, int reason, Bundle extras, - boolean exemptFromAppStandby); + @SyncExemption int syncExemptionFlag); } interface PeriodicSyncAddedListener { @@ -647,7 +648,7 @@ public class SyncStorageEngine { } public void setSyncAutomatically(Account account, int userId, String providerName, - boolean sync) { + boolean sync, @SyncExemption int syncExemptionFlag) { if (Log.isLoggable(TAG, Log.VERBOSE)) { Slog.d(TAG, "setSyncAutomatically: " + /* account + */" provider " + providerName + ", user " + userId + " -> " + sync); @@ -677,7 +678,7 @@ public class SyncStorageEngine { if (sync) { requestSync(account, userId, SyncOperation.REASON_SYNC_AUTO, providerName, new Bundle(), - /* exemptFromAppStandby=*/ false); + syncExemptionFlag); } reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS); queueBackup(); @@ -739,7 +740,7 @@ public class SyncStorageEngine { } if (syncable == AuthorityInfo.SYNCABLE) { requestSync(aInfo, SyncOperation.REASON_IS_SYNCABLE, new Bundle(), - /*exemptFromAppStandby=*/ false); // Or the caller FG state? + ContentResolver.SYNC_EXEMPTION_NONE); } reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS); } @@ -900,7 +901,8 @@ public class SyncStorageEngine { return true; } - public void setMasterSyncAutomatically(boolean flag, int userId) { + public void setMasterSyncAutomatically(boolean flag, int userId, + @SyncExemption int syncExemptionFlag) { synchronized (mAuthorities) { Boolean auto = mMasterSyncAutomatically.get(userId); if (auto != null && auto.equals(flag)) { @@ -912,7 +914,7 @@ public class SyncStorageEngine { if (flag) { requestSync(null, userId, SyncOperation.REASON_MASTER_SYNC_AUTO, null, new Bundle(), - /*exemptFromAppStandby=*/ false); // Or the caller FG state? + syncExemptionFlag); } reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS); mContext.sendBroadcast(ContentResolver.ACTION_SYNC_CONN_STATUS_CHANGED); @@ -2046,7 +2048,8 @@ public class SyncStorageEngine { String value = c.getString(c.getColumnIndex("value")); if (name == null) continue; if (name.equals("listen_for_tickles")) { - setMasterSyncAutomatically(value == null || Boolean.parseBoolean(value), 0); + setMasterSyncAutomatically(value == null || Boolean.parseBoolean(value), 0, + ContentResolver.SYNC_EXEMPTION_NONE); } else if (name.startsWith("sync_provider_")) { String provider = name.substring("sync_provider_".length(), name.length()); @@ -2143,11 +2146,11 @@ public class SyncStorageEngine { } private void requestSync(AuthorityInfo authorityInfo, int reason, Bundle extras, - boolean exemptFromAppStandby) { + @SyncExemption int syncExemptionFlag) { if (android.os.Process.myUid() == android.os.Process.SYSTEM_UID && mSyncRequestListener != null) { mSyncRequestListener.onSyncRequest(authorityInfo.target, reason, extras, - exemptFromAppStandby); + syncExemptionFlag); } else { SyncRequest.Builder req = new SyncRequest.Builder() @@ -2159,7 +2162,7 @@ public class SyncStorageEngine { } private void requestSync(Account account, int userId, int reason, String authority, - Bundle extras, boolean exemptFromAppStandby) { + Bundle extras, @SyncExemption int syncExemptionFlag) { // If this is happening in the system process, then call the syncrequest listener // to make a request back to the SyncManager directly. // If this is probably a test instance, then call back through the ContentResolver @@ -2168,7 +2171,7 @@ public class SyncStorageEngine { && mSyncRequestListener != null) { mSyncRequestListener.onSyncRequest( new EndPoint(account, authority, userId), - reason, extras, exemptFromAppStandby); + reason, extras, syncExemptionFlag); } else { ContentResolver.requestSync(account, authority, extras); } diff --git a/services/tests/servicestests/src/com/android/server/content/SyncOperationTest.java b/services/tests/servicestests/src/com/android/server/content/SyncOperationTest.java index 7c3ea4ffe86a..e37ed7976a86 100644 --- a/services/tests/servicestests/src/com/android/server/content/SyncOperationTest.java +++ b/services/tests/servicestests/src/com/android/server/content/SyncOperationTest.java @@ -17,6 +17,7 @@ package com.android.server.content; import android.accounts.Account; +import android.content.ContentResolver; import android.os.Bundle; import android.os.PersistableBundle; import android.test.AndroidTestCase; @@ -60,7 +61,7 @@ public class SyncOperationTest extends AndroidTestCase { "authority1", b1, false, - /*isAppStandbyExempted=*/ false); + ContentResolver.SYNC_EXEMPTION_NONE); // Same as op1 but different time infos SyncOperation op2 = new SyncOperation(account1, 0, @@ -69,7 +70,7 @@ public class SyncOperationTest extends AndroidTestCase { "authority1", b1, false, - /*isAppStandbyExempted=*/ false); + ContentResolver.SYNC_EXEMPTION_NONE); // Same as op1 but different authority SyncOperation op3 = new SyncOperation(account1, 0, @@ -78,7 +79,7 @@ public class SyncOperationTest extends AndroidTestCase { "authority2", b1, false, - /*isAppStandbyExempted=*/ false); + ContentResolver.SYNC_EXEMPTION_NONE); // Same as op1 but different account SyncOperation op4 = new SyncOperation(account2, 0, @@ -87,7 +88,7 @@ public class SyncOperationTest extends AndroidTestCase { "authority1", b1, false, - /*isAppStandbyExempted=*/ false); + ContentResolver.SYNC_EXEMPTION_NONE); // Same as op1 but different bundle SyncOperation op5 = new SyncOperation(account1, 0, @@ -96,7 +97,7 @@ public class SyncOperationTest extends AndroidTestCase { "authority1", b2, false, - /*isAppStandbyExempted=*/ false); + ContentResolver.SYNC_EXEMPTION_NONE); assertEquals(op1.key, op2.key); assertNotSame(op1.key, op3.key); @@ -117,7 +118,7 @@ public class SyncOperationTest extends AndroidTestCase { "authority1", b1, false, - /*isAppStandbyExempted=*/ false); + ContentResolver.SYNC_EXEMPTION_NONE); PersistableBundle pb = op1.toJobInfoExtras(); SyncOperation op2 = SyncOperation.maybeCreateFromJobExtras(pb); @@ -145,7 +146,7 @@ public class SyncOperationTest extends AndroidTestCase { Bundle extras = new Bundle(); SyncOperation periodic = new SyncOperation(ep, 0, "package", 0, 0, extras, false, true, SyncOperation.NO_JOB_ID, 60000, 10000, - /*isAppStandbyExempted=*/ false); + ContentResolver.SYNC_EXEMPTION_NONE); SyncOperation oneoff = periodic.createOneTimeSyncOperation(); assertFalse("Conversion to oneoff sync failed.", oneoff.isPeriodic); assertEquals("Period not restored", periodic.periodMillis, oneoff.periodMillis); diff --git a/services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java b/services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java deleted file mode 100644 index 7209c7971145..000000000000 --- a/services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java +++ /dev/null @@ -1,349 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.content; - -import android.accounts.Account; -import android.content.ComponentName; -import android.content.ContentResolver; -import android.content.Context; -import android.content.ContextWrapper; -import android.content.Intent; -import android.content.res.Resources; -import android.os.Bundle; -import android.test.AndroidTestCase; -import android.test.RenamingDelegatingContext; -import android.test.mock.MockContentResolver; -import android.test.mock.MockContext; -import android.test.suitebuilder.annotation.LargeTest; -import android.test.suitebuilder.annotation.MediumTest; -import android.test.suitebuilder.annotation.SmallTest; -import android.test.suitebuilder.annotation.Suppress; - -import com.android.internal.os.AtomicFile; - -import java.io.File; -import java.io.FileOutputStream; - -/** - * Test for SyncStorageEngine. - * - * bit FrameworksServicesTests:com.android.server.content.SyncStorageEngineTest - * - * TODO Broken. Fix it. b/62485315 - */ -@Suppress -public class SyncStorageEngineTest extends AndroidTestCase { - - protected Account account1; - protected Account account2; - protected ComponentName syncService1; - protected String authority1 = "testprovider"; - protected Bundle defaultBundle; - protected final int DEFAULT_USER = 0; - - /* Some default poll frequencies. */ - final long dayPoll = (60 * 60 * 24); - final long dayFuzz = 60; - final long thousandSecs = 1000; - final long thousandSecsFuzz = 100; - - MockContentResolver mockResolver; - SyncStorageEngine engine; - - private File getSyncDir() { - return new File(new File(getContext().getFilesDir(), "system"), "sync"); - } - - @Override - public void setUp() { - account1 = new Account("a@example.com", "example.type"); - account2 = new Account("b@example.com", "example.type"); - syncService1 = new ComponentName("com.example", "SyncService"); - // Default bundle. - defaultBundle = new Bundle(); - defaultBundle.putInt("int_key", 0); - defaultBundle.putString("string_key", "hello"); - // Set up storage engine. - mockResolver = new MockContentResolver(); - engine = SyncStorageEngine.newTestInstance( - new TestContext(mockResolver, getContext())); - } - - /** - * Test that we handle the case of a history row being old enough to purge before the - * corresponding sync is finished. This can happen if the clock changes while we are syncing. - * - */ - // TODO: this test causes AidlTest to fail. Omit for now - // @SmallTest - public void testPurgeActiveSync() throws Exception { - final Account account = new Account("a@example.com", "example.type"); - final String authority = "testprovider"; - - MockContentResolver mockResolver = new MockContentResolver(); - - SyncStorageEngine engine = SyncStorageEngine.newTestInstance( - new TestContext(mockResolver, getContext())); - long time0 = 1000; - SyncOperation op = new SyncOperation(account, 0, 0, "foo", - SyncOperation.REASON_PERIODIC, - SyncStorageEngine.SOURCE_LOCAL, - authority, - Bundle.EMPTY, true, - /*isAppStandbyExempted=*/ false); - long historyId = engine.insertStartSyncEvent(op, time0); - long time1 = time0 + SyncStorageEngine.MILLIS_IN_4WEEKS * 2; - engine.stopSyncEvent(historyId, time1 - time0, "yay", 0, 0); - } - - @LargeTest - public void testAuthorityPersistence() throws Exception { - final Account account1 = new Account("a@example.com", "example.type"); - final Account account2 = new Account("b@example.com", "example.type.2"); - final String authority1 = "testprovider1"; - final String authority2 = "testprovider2"; - - engine.setMasterSyncAutomatically(false, 0); - - engine.setIsSyncable(account1, 0, authority1, 1); - engine.setSyncAutomatically(account1, 0, authority1, true); - - engine.setIsSyncable(account2, 0, authority1, 1); - engine.setSyncAutomatically(account2, 0, authority1, true); - - engine.setIsSyncable(account1, 0, authority2, 1); - engine.setSyncAutomatically(account1, 0, authority2, false); - - engine.setIsSyncable(account2, 0, authority2, 0); - engine.setSyncAutomatically(account2, 0, authority2, true); - - engine.writeAllState(); - engine.clearAndReadState(); - - assertEquals(true, engine.getSyncAutomatically(account1, 0, authority1)); - assertEquals(true, engine.getSyncAutomatically(account2, 0, authority1)); - assertEquals(false, engine.getSyncAutomatically(account1, 0, authority2)); - assertEquals(true, engine.getSyncAutomatically(account2, 0, authority2)); - - assertEquals(1, engine.getIsSyncable(account1, 0, authority1)); - assertEquals(1, engine.getIsSyncable(account2, 0, authority1)); - assertEquals(1, engine.getIsSyncable(account1, 0, authority2)); - assertEquals(0, engine.getIsSyncable(account2, 0, authority2)); - } - - @MediumTest - public void testListenForTicklesParsing() throws Exception { - byte[] accountsFileData = ("\n" - + "\n" - + "" - + "" - + "\n" - + "\n" - + "\n").getBytes(); - - MockContentResolver mockResolver = new MockContentResolver(); - final TestContext testContext = new TestContext(mockResolver, getContext()); - - File syncDir = getSyncDir(); - syncDir.mkdirs(); - AtomicFile accountInfoFile = new AtomicFile(new File(syncDir, "accounts.xml")); - FileOutputStream fos = accountInfoFile.startWrite(); - fos.write(accountsFileData); - accountInfoFile.finishWrite(fos); - - SyncStorageEngine engine = SyncStorageEngine.newTestInstance(testContext); - - assertEquals(false, engine.getMasterSyncAutomatically(0)); - assertEquals(true, engine.getMasterSyncAutomatically(1)); - assertEquals(true, engine.getMasterSyncAutomatically(2)); - - } - - @MediumTest - public void testAuthorityRenaming() throws Exception { - final Account account1 = new Account("acc1", "type1"); - final Account account2 = new Account("acc2", "type2"); - final String authorityContacts = "contacts"; - final String authorityCalendar = "calendar"; - final String authorityOther = "other"; - final String authorityContactsNew = "com.android.contacts"; - final String authorityCalendarNew = "com.android.calendar"; - - MockContentResolver mockResolver = new MockContentResolver(); - - final TestContext testContext = new TestContext(mockResolver, getContext()); - - byte[] accountsFileData = ("\n" - + "\n" - + "\n" - + "\n" - + "\n" - + "\n" - + "\n" - + "\n" - + "\n" - + "\n" - + "\n").getBytes(); - - File syncDir = new File(new File(testContext.getFilesDir(), "system"), "sync"); - syncDir.mkdirs(); - AtomicFile accountInfoFile = new AtomicFile(new File(syncDir, "accounts.xml")); - FileOutputStream fos = accountInfoFile.startWrite(); - fos.write(accountsFileData); - accountInfoFile.finishWrite(fos); - - SyncStorageEngine engine = SyncStorageEngine.newTestInstance(testContext); - - assertEquals(false, engine.getSyncAutomatically(account1, 0, authorityContacts)); - assertEquals(false, engine.getSyncAutomatically(account1, 0, authorityCalendar)); - assertEquals(true, engine.getSyncAutomatically(account1, 0, authorityOther)); - assertEquals(true, engine.getSyncAutomatically(account1, 0, authorityContactsNew)); - assertEquals(true, engine.getSyncAutomatically(account1, 0, authorityCalendarNew)); - - assertEquals(false, engine.getSyncAutomatically(account2, 0, authorityContacts)); - assertEquals(false, engine.getSyncAutomatically(account2, 0, authorityCalendar)); - assertEquals(true, engine.getSyncAutomatically(account2, 0, authorityOther)); - assertEquals(false, engine.getSyncAutomatically(account2, 0, authorityContactsNew)); - assertEquals(false, engine.getSyncAutomatically(account2, 0, authorityCalendarNew)); - } - - @SmallTest - public void testSyncableMigration() throws Exception { - final Account account = new Account("acc", "type"); - - MockContentResolver mockResolver = new MockContentResolver(); - - final TestContext testContext = new TestContext(mockResolver, getContext()); - - byte[] accountsFileData = ("\n" - + "\n" - + "\n" - + "\n" - + "\n" - + "\n" - + "\n").getBytes(); - - File syncDir = new File(new File(testContext.getFilesDir(), "system"), "sync"); - syncDir.mkdirs(); - AtomicFile accountInfoFile = new AtomicFile(new File(syncDir, "accounts.xml")); - FileOutputStream fos = accountInfoFile.startWrite(); - fos.write(accountsFileData); - accountInfoFile.finishWrite(fos); - - SyncStorageEngine engine = SyncStorageEngine.newTestInstance(testContext); - - assertEquals(-1, engine.getIsSyncable(account, 0, "other1")); - assertEquals(1, engine.getIsSyncable(account, 0, "other2")); - assertEquals(0, engine.getIsSyncable(account, 0, "other3")); - assertEquals(1, engine.getIsSyncable(account, 0, "other4")); - } - - /** - * Verify that the API cannot cause a run-time reboot by passing in the empty string as an - * authority. The problem here is that - * {@link SyncStorageEngine#getOrCreateAuthorityLocked(account, provider)} would register - * an empty authority which causes a RTE in {@link SyncManager#scheduleReadyPeriodicSyncs()}. - * This is not strictly a SSE test, but it does depend on the SSE data structures. - */ - @SmallTest - public void testExpectedIllegalArguments() throws Exception { - try { - ContentResolver.setSyncAutomatically(account1, "", true); - fail("empty provider string should throw IllegalArgumentException"); - } catch (IllegalArgumentException expected) {} - - try { - ContentResolver.addPeriodicSync(account1, "", Bundle.EMPTY, 84000L); - fail("empty provider string should throw IllegalArgumentException"); - } catch (IllegalArgumentException expected) {} - - try { - ContentResolver.removePeriodicSync(account1, "", Bundle.EMPTY); - fail("empty provider string should throw IllegalArgumentException"); - } catch (IllegalArgumentException expected) {} - - try { - ContentResolver.cancelSync(account1, ""); - fail("empty provider string should throw IllegalArgumentException"); - } catch (IllegalArgumentException expected) {} - - try { - ContentResolver.setIsSyncable(account1, "", 0); - fail("empty provider string should throw IllegalArgumentException"); - } catch (IllegalArgumentException expected) {} - - try { - ContentResolver.cancelSync(account1, ""); - fail("empty provider string should throw IllegalArgumentException"); - } catch (IllegalArgumentException expected) {} - - try { - ContentResolver.requestSync(account1, "", Bundle.EMPTY); - fail("empty provider string should throw IllegalArgumentException"); - } catch (IllegalArgumentException expected) {} - - try { - ContentResolver.getSyncStatus(account1, ""); - fail("empty provider string should throw IllegalArgumentException"); - } catch (IllegalArgumentException expected) {} - - // Make sure we aren't blocking null account/provider for those functions that use it - // to specify ALL accounts/providers. - ContentResolver.requestSync(null, null, Bundle.EMPTY); - ContentResolver.cancelSync(null, null); - } -} - -class TestContext extends ContextWrapper { - - ContentResolver mResolver; - - private final Context mRealContext; - - public TestContext(ContentResolver resolver, Context realContext) { - super(new RenamingDelegatingContext(new MockContext(), realContext, "test.")); - mRealContext = realContext; - mResolver = resolver; - } - - @Override - public Resources getResources() { - return mRealContext.getResources(); - } - - @Override - public File getFilesDir() { - return mRealContext.getFilesDir(); - } - - @Override - public void enforceCallingOrSelfPermission(String permission, String message) { - } - - @Override - public void sendBroadcast(Intent intent) { - } - - @Override - public ContentResolver getContentResolver() { - return mResolver; - } -} diff --git a/services/usage/java/com/android/server/usage/AppStandbyController.java b/services/usage/java/com/android/server/usage/AppStandbyController.java index 571ed00a2884..5f01518b7449 100644 --- a/services/usage/java/com/android/server/usage/AppStandbyController.java +++ b/services/usage/java/com/android/server/usage/AppStandbyController.java @@ -24,6 +24,7 @@ import static android.app.usage.UsageStatsManager.REASON_MAIN_TIMEOUT; import static android.app.usage.UsageStatsManager.REASON_MAIN_USAGE; import static android.app.usage.UsageStatsManager.REASON_SUB_PREDICTED_RESTORED; import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_ACTIVE_TIMEOUT; +import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_EXEMPTED_SYNC_START; import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_MOVE_TO_BACKGROUND; import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_MOVE_TO_FOREGROUND; import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_NOTIFICATION_SEEN; @@ -186,6 +187,7 @@ public class AppStandbyController { static final int MSG_ONE_TIME_CHECK_IDLE_STATES = 10; /** Check the state of one app: arg1 = userId, arg2 = uid, obj = (String) packageName */ static final int MSG_CHECK_PACKAGE_IDLE_STATE = 11; + static final int MSG_REPORT_EXEMPTED_SYNC_START = 12; long mCheckIdleIntervalMillis; long mAppIdleParoleIntervalMillis; @@ -202,6 +204,8 @@ public class AppStandbyController { long mPredictionTimeoutMillis; /** Maximum time a sync adapter associated with a CP should keep the buckets elevated. */ long mSyncAdapterTimeoutMillis; + /** Maximum time an exempted sync should keep the buckets elevated. */ + long mExemptedSyncAdapterTimeoutMillis; /** Maximum time a system interaction should keep the buckets elevated. */ long mSystemInteractionTimeoutMillis; @@ -375,6 +379,21 @@ public class AppStandbyController { } } + void reportExemptedSyncStart(String packageName, int userId) { + if (!mAppIdleEnabled) return; + + final long elapsedRealtime = mInjector.elapsedRealtime(); + + synchronized (mAppIdleLock) { + AppUsageHistory appUsage = mAppIdleHistory.reportUsage(packageName, userId, + STANDBY_BUCKET_ACTIVE, REASON_SUB_USAGE_EXEMPTED_SYNC_START, + 0, + elapsedRealtime + mExemptedSyncAdapterTimeoutMillis); + maybeInformListeners(packageName, userId, elapsedRealtime, + appUsage.currentBucket, appUsage.bucketingReason, false); + } + } + void setChargingState(boolean charging) { synchronized (mAppIdleLock) { if (mCharging != charging) { @@ -1274,6 +1293,11 @@ public class AppStandbyController { .sendToTarget(); } + void postReportExemptedSyncStart(String packageName, int userId) { + mHandler.obtainMessage(MSG_REPORT_EXEMPTED_SYNC_START, userId, 0, packageName) + .sendToTarget(); + } + void dumpUser(IndentingPrintWriter idpw, int userId, String pkg) { synchronized (mAppIdleLock) { mAppIdleHistory.dump(idpw, userId, pkg); @@ -1488,6 +1512,11 @@ public class AppStandbyController { checkAndUpdateStandbyState((String) msg.obj, msg.arg1, msg.arg2, mInjector.elapsedRealtime()); break; + + case MSG_REPORT_EXEMPTED_SYNC_START: + reportExemptedSyncStart((String) msg.obj, msg.arg1); + break; + default: super.handleMessage(msg); break; @@ -1550,6 +1579,7 @@ public class AppStandbyController { "system_update_usage_duration"; private static final String KEY_PREDICTION_TIMEOUT = "prediction_timeout"; private static final String KEY_SYNC_ADAPTER_HOLD_DURATION = "sync_adapter_duration"; + private static final String KEY_EXEMPTED_SYNC_HOLD_DURATION = "exempted_sync_duration"; private static final String KEY_SYSTEM_INTERACTION_HOLD_DURATION = "system_interaction_duration"; public static final long DEFAULT_STRONG_USAGE_TIMEOUT = 1 * ONE_HOUR; @@ -1557,6 +1587,7 @@ public class AppStandbyController { public static final long DEFAULT_SYSTEM_UPDATE_TIMEOUT = 2 * ONE_HOUR; public static final long DEFAULT_SYSTEM_INTERACTION_TIMEOUT = 10 * ONE_MINUTE; public static final long DEFAULT_SYNC_ADAPTER_TIMEOUT = 10 * ONE_MINUTE; + public static final long DEFAULT_EXEMPTED_SYNC_TIMEOUT = 10 * ONE_MINUTE; private final KeyValueListParser mParser = new KeyValueListParser(','); @@ -1632,6 +1663,9 @@ public class AppStandbyController { mSyncAdapterTimeoutMillis = mParser.getDurationMillis (KEY_SYNC_ADAPTER_HOLD_DURATION, COMPRESS_TIME ? ONE_MINUTE : DEFAULT_SYNC_ADAPTER_TIMEOUT); + mExemptedSyncAdapterTimeoutMillis = mParser.getDurationMillis + (KEY_EXEMPTED_SYNC_HOLD_DURATION, + COMPRESS_TIME ? ONE_MINUTE : DEFAULT_EXEMPTED_SYNC_TIMEOUT); mSystemInteractionTimeoutMillis = mParser.getDurationMillis (KEY_SYSTEM_INTERACTION_HOLD_DURATION, COMPRESS_TIME ? ONE_MINUTE : DEFAULT_SYSTEM_INTERACTION_TIMEOUT); diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java index 2258b243cc3a..1fbc27b58854 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UsageStatsService.java @@ -1279,5 +1279,10 @@ public class UsageStatsService extends SystemService implements public void onAdminDataAvailable() { mAppStandby.onAdminDataAvailable(); } + + @Override + public void reportExemptedSyncStart(String packageName, int userId) { + mAppStandby.postReportExemptedSyncStart(packageName, userId); + } } } -- GitLab From 369dd4257ca7928ca525ff1e1391fe985bee113b Mon Sep 17 00:00:00 2001 From: Beverly Date: Thu, 29 Mar 2018 18:14:04 -0400 Subject: [PATCH 102/179] Don't exit dnd rule for old alarms Bug: 77209521 Test: atest ScheduleCalendarTest Change-Id: I394a6a74872f76f90b75238593197bb6c50531ef --- .../notification/ScheduleCalendar.java | 3 ++- .../notification/ScheduleCalendarTest.java | 25 +++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/core/java/android/service/notification/ScheduleCalendar.java b/core/java/android/service/notification/ScheduleCalendar.java index 8a7ff4da26e3..01287104f9b2 100644 --- a/core/java/android/service/notification/ScheduleCalendar.java +++ b/core/java/android/service/notification/ScheduleCalendar.java @@ -144,7 +144,8 @@ public class ScheduleCalendar { } return mSchedule.exitAtAlarm && mSchedule.nextAlarm != 0 - && time >= mSchedule.nextAlarm; + && time >= mSchedule.nextAlarm + && isInSchedule(mSchedule.nextAlarm); } private boolean isInSchedule(int daysOffset, long time, long start, long end) { diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ScheduleCalendarTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ScheduleCalendarTest.java index 36136a8932c9..ce7445788489 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ScheduleCalendarTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ScheduleCalendarTest.java @@ -205,6 +205,31 @@ public class ScheduleCalendarTest extends UiServiceTestCase { assertTrue(mScheduleCalendar.shouldExitForAlarm(1000)); } + @Test + public void testShouldExitForAlarm_oldAlarm() { + // Cal: today 2:15pm + Calendar cal = new GregorianCalendar(); + cal.set(Calendar.HOUR_OF_DAY, 14); + cal.set(Calendar.MINUTE, 15); + cal.set(Calendar.SECOND, 0); + cal.set(Calendar.MILLISECOND, 0); + + // ScheduleInfo: today 12:16pm - today 3:15pm + mScheduleInfo.days = new int[] {getTodayDay()}; + mScheduleInfo.startHour = 12; + mScheduleInfo.endHour = 3; + mScheduleInfo.startMinute = 16; + mScheduleInfo.endMinute = 15; + mScheduleInfo.exitAtAlarm = true; + mScheduleInfo.nextAlarm = 1000; // very old alarm + + mScheduleCalendar.setSchedule(mScheduleInfo); + assertTrue(mScheduleCalendar.isInSchedule(cal.getTimeInMillis())); + + // don't exit for an alarm if it's an old alarm + assertFalse(mScheduleCalendar.shouldExitForAlarm(1000)); + } + @Test public void testMaybeSetNextAlarm_settingOff() { mScheduleInfo.exitAtAlarm = false; -- GitLab From 2492c00ae347de412a7772343156f051c08f8979 Mon Sep 17 00:00:00 2001 From: Dongwon Kang Date: Thu, 29 Mar 2018 15:00:43 -0700 Subject: [PATCH 103/179] Unhide MediaPlayer#MEDIA_INFO_STARTED_AS_NEXT Expose a listener constant which is used with OnInfoListener() in order to notify that the player instance started the playback since previous player just completed the playback. Bug: 76121592 Test: make offline-sdk-docs Change-Id: I69ade8e9f6916bc653ea2831e3721dc7d171dc0e --- api/current.txt | 1 + media/java/android/media/MediaPlayer.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/api/current.txt b/api/current.txt index 8c6207fc5286..89a43e13443b 100644 --- a/api/current.txt +++ b/api/current.txt @@ -24001,6 +24001,7 @@ package android.media { field public static final int MEDIA_INFO_BUFFERING_START = 701; // 0x2bd field public static final int MEDIA_INFO_METADATA_UPDATE = 802; // 0x322 field public static final int MEDIA_INFO_NOT_SEEKABLE = 801; // 0x321 + field public static final int MEDIA_INFO_STARTED_AS_NEXT = 2; // 0x2 field public static final int MEDIA_INFO_SUBTITLE_TIMED_OUT = 902; // 0x386 field public static final int MEDIA_INFO_UNKNOWN = 1; // 0x1 field public static final int MEDIA_INFO_UNSUPPORTED_SUBTITLE = 901; // 0x385 diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java index befbade0c701..aef31b116dd6 100644 --- a/media/java/android/media/MediaPlayer.java +++ b/media/java/android/media/MediaPlayer.java @@ -4099,8 +4099,8 @@ public class MediaPlayer extends PlayerBase /** The player was started because it was used as the next player for another * player, which just completed playback. + * @see android.media.MediaPlayer#setNextMediaPlayer(MediaPlayer) * @see android.media.MediaPlayer.OnInfoListener - * @hide */ public static final int MEDIA_INFO_STARTED_AS_NEXT = 2; -- GitLab From 7cdd9599937aeaba3f0e0b9436efc8a03784d3bc Mon Sep 17 00:00:00 2001 From: David Brazdil Date: Thu, 29 Mar 2018 23:16:38 +0100 Subject: [PATCH 104/179] Add more hidden API on light greylist Bug: 64382372 Bug: 74763801 Test: make Change-Id: I9cac934983addb32127f7571a3d290b4d57fb55d --- config/hiddenapi-light-greylist.txt | 271 +++++++++++++++++++++++++++- 1 file changed, 266 insertions(+), 5 deletions(-) diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt index 70e3fade244f..015c4b664bc3 100644 --- a/config/hiddenapi-light-greylist.txt +++ b/config/hiddenapi-light-greylist.txt @@ -7,6 +7,7 @@ Landroid/animation/ValueAnimator;->animateValue(F)V Landroid/animation/ValueAnimator;->sDurationScale:F Landroid/app/Activity;->getActivityOptions()Landroid/app/ActivityOptions; Landroid/app/Activity;->getActivityToken()Landroid/os/IBinder; +Landroid/app/ActivityGroup;->mLocalActivityManager:Landroid/app/LocalActivityManager; Landroid/app/Activity;->mActivityInfo:Landroid/content/pm/ActivityInfo; Landroid/app/ActivityManager;->clearApplicationUserData(Ljava/lang/String;Landroid/content/pm/IPackageDataObserver;)Z Landroid/app/ActivityManager;->getMaxRecentTasksStatic()I @@ -63,8 +64,10 @@ Landroid/app/ActivityThread$ActivityClientRecord;->token:Landroid/os/IBinder; Landroid/app/ActivityThread$AppBindData;->appInfo:Landroid/content/pm/ApplicationInfo; Landroid/app/ActivityThread$AppBindData;->info:Landroid/app/LoadedApk; Landroid/app/ActivityThread$AppBindData;->instrumentationArgs:Landroid/os/Bundle; +Landroid/app/ActivityThread$AppBindData;->persistent:Z Landroid/app/ActivityThread$AppBindData;->processName:Ljava/lang/String; Landroid/app/ActivityThread$AppBindData;->providers:Ljava/util/List; +Landroid/app/ActivityThread$AppBindData;->restrictedBackupMode:Z Landroid/app/ActivityThread$BindServiceData;->intent:Landroid/content/Intent; Landroid/app/ActivityThread$BindServiceData;->token:Landroid/os/IBinder; Landroid/app/ActivityThread$CreateServiceData;->compatInfo:Landroid/content/res/CompatibilityInfo; @@ -89,11 +92,13 @@ Landroid/app/ActivityThread;->handleBindApplication(Landroid/app/ActivityThread$ Landroid/app/ActivityThread$H;->BIND_SERVICE:I Landroid/app/ActivityThread$H;->CREATE_SERVICE:I Landroid/app/ActivityThread$H;->DUMP_PROVIDER:I +Landroid/app/ActivityThread$H;->ENTER_ANIMATION_COMPLETE:I Landroid/app/ActivityThread$H;->EXIT_APPLICATION:I Landroid/app/ActivityThread$H;->GC_WHEN_IDLE:I Landroid/app/ActivityThread$H;->INSTALL_PROVIDER:I Landroid/app/ActivityThread$H;->RECEIVER:I Landroid/app/ActivityThread$H;->REMOVE_PROVIDER:I +Landroid/app/ActivityThread$H;->SCHEDULE_CRASH:I Landroid/app/ActivityThread$H;->SERVICE_ARGS:I Landroid/app/ActivityThread$H;->STOP_SERVICE:I Landroid/app/ActivityThread$H;->UNBIND_SERVICE:I @@ -102,6 +107,7 @@ Landroid/app/ActivityThread;->installProvider(Landroid/content/Context;Landroid/ Landroid/app/ActivityThread;->mActivities:Landroid/util/ArrayMap; Landroid/app/ActivityThread;->mAllApplications:Ljava/util/ArrayList; Landroid/app/ActivityThread;->mBoundApplication:Landroid/app/ActivityThread$AppBindData; +Landroid/app/ActivityThread;->mConfiguration:Landroid/content/res/Configuration; Landroid/app/ActivityThread;->mDensityCompatMode:Z Landroid/app/ActivityThread;->mH:Landroid/app/ActivityThread$H; Landroid/app/ActivityThread;->mInitialApplication:Landroid/app/Application; @@ -110,8 +116,10 @@ Landroid/app/ActivityThread;->mLocalProvidersByName:Landroid/util/ArrayMap; Landroid/app/ActivityThread;->mLocalProviders:Landroid/util/ArrayMap; Landroid/app/ActivityThread;->mNumVisibleActivities:I Landroid/app/ActivityThread;->mPackages:Landroid/util/ArrayMap; +Landroid/app/ActivityThread;->mPendingConfiguration:Landroid/content/res/Configuration; Landroid/app/ActivityThread;->mProviderMap:Landroid/util/ArrayMap; Landroid/app/ActivityThread;->mResourcePackages:Landroid/util/ArrayMap; +Landroid/app/ActivityThread;->mResourcesManager:Landroid/app/ResourcesManager; Landroid/app/ActivityThread;->mServices:Landroid/util/ArrayMap; Landroid/app/ActivityThread;->performNewIntents(Landroid/os/IBinder;Ljava/util/List;Z)V Landroid/app/ActivityThread;->performStopActivity(Landroid/os/IBinder;ZLjava/lang/String;)V @@ -146,6 +154,7 @@ Landroid/app/AlarmManager;->WINDOW_HEURISTIC:J Landroid/app/AlertDialog$Builder;->P:Lcom/android/internal/app/AlertController$AlertParams; Landroid/app/AlertDialog;->mAlert:Lcom/android/internal/app/AlertController; Landroid/app/AppGlobals;->getInitialApplication()Landroid/app/Application; +Landroid/app/AppGlobals;->getInitialPackage()Ljava/lang/String; Landroid/app/AppGlobals;->getPackageManager()Landroid/content/pm/IPackageManager; Landroid/app/Application;->attach(Landroid/content/Context;)V Landroid/app/Application;->collectActivityLifecycleCallbacks()[Ljava/lang/Object; @@ -166,21 +175,26 @@ Landroid/app/ApplicationPackageManager;->getPackageCurrentVolume(Landroid/conten Landroid/app/ApplicationPackageManager;->getPackageSizeInfoAsUser(Ljava/lang/String;ILandroid/content/pm/IPackageStatsObserver;)V Landroid/app/ApplicationPackageManager;->(Landroid/app/ContextImpl;Landroid/content/pm/IPackageManager;)V Landroid/app/ApplicationPackageManager;->mPM:Landroid/content/pm/IPackageManager; +Landroid/app/ApplicationPackageManager;->shouldShowRequestPermissionRationale(Ljava/lang/String;)Z Landroid/app/AppOpsManager;->checkOp(IILjava/lang/String;)I Landroid/app/AppOpsManager;->checkOpNoThrow(IILjava/lang/String;)I Landroid/app/AppOpsManager;->getOpsForPackage(ILjava/lang/String;[I)Ljava/util/List; Landroid/app/AppOpsManager;->mService:Lcom/android/internal/app/IAppOpsService; Landroid/app/AppOpsManager;->noteOp(I)I Landroid/app/AppOpsManager;->noteOp(IILjava/lang/String;)I +Landroid/app/AppOpsManager;->OP_AUDIO_NOTIFICATION_VOLUME:I Landroid/app/AppOpsManager;->OP_COARSE_LOCATION:I Landroid/app/AppOpsManager$OpEntry;->getDuration()I Landroid/app/AppOpsManager$OpEntry;->getRejectTime()J Landroid/app/AppOpsManager;->OP_FINE_LOCATION:I Landroid/app/AppOpsManager;->OP_GET_USAGE_STATS:I Landroid/app/AppOpsManager;->OP_POST_NOTIFICATION:I +Landroid/app/AppOpsManager;->OP_READ_CONTACTS:I Landroid/app/AppOpsManager;->OP_READ_PHONE_STATE:I Landroid/app/AppOpsManager;->OP_READ_SMS:I +Landroid/app/AppOpsManager;->OP_VIBRATE:I Landroid/app/AppOpsManager;->OP_WIFI_SCAN:I +Landroid/app/AppOpsManager;->OP_WRITE_CONTACTS:I Landroid/app/AppOpsManager;->OP_WRITE_SMS:I Landroid/app/AppOpsManager;->permissionToOpCode(Ljava/lang/String;)I Landroid/app/AppOpsManager;->strOpToOp(Ljava/lang/String;)I @@ -204,6 +218,7 @@ Landroid/app/ContextImpl;->getDisplay()Landroid/view/Display; Landroid/app/ContextImpl;->getPreferencesDir()Ljava/io/File; Landroid/app/ContextImpl;->getReceiverRestrictedContext()Landroid/content/Context; Landroid/app/ContextImpl;->mBasePackageName:Ljava/lang/String; +Landroid/app/ContextImpl;->mClassLoader:Ljava/lang/ClassLoader; Landroid/app/ContextImpl;->mContentResolver:Landroid/app/ContextImpl$ApplicationContentResolver; Landroid/app/ContextImpl;->mMainThread:Landroid/app/ActivityThread; Landroid/app/ContextImpl;->mOpPackageName:Ljava/lang/String; @@ -213,6 +228,7 @@ Landroid/app/ContextImpl;->mPackageManager:Landroid/content/pm/PackageManager; Landroid/app/ContextImpl;->mResources:Landroid/content/res/Resources; Landroid/app/ContextImpl;->mServiceCache:[Ljava/lang/Object; Landroid/app/ContextImpl;->mTheme:Landroid/content/res/Resources$Theme; +Landroid/app/ContextImpl;->mThemeResource:I Landroid/app/ContextImpl;->scheduleFinalCleanup(Ljava/lang/String;Ljava/lang/String;)V Landroid/app/ContextImpl;->setOuterContext(Landroid/content/Context;)V Landroid/app/ContextImpl;->sSharedPrefsCache:Landroid/util/ArrayMap; @@ -230,10 +246,13 @@ Landroid/app/FragmentManagerImpl;->noteStateNotSaved()V Landroid/app/Fragment;->mChildFragmentManager:Landroid/app/FragmentManagerImpl; Landroid/app/Fragment;->mWho:Ljava/lang/String; Landroid/app/IActivityManager;->bindService(Landroid/app/IApplicationThread;Landroid/os/IBinder;Landroid/content/Intent;Ljava/lang/String;Landroid/app/IServiceConnection;ILjava/lang/String;I)I +Landroid/app/IActivityManager;->broadcastIntent(Landroid/app/IApplicationThread;Landroid/content/Intent;Ljava/lang/String;Landroid/content/IIntentReceiver;ILjava/lang/String;Landroid/os/Bundle;[Ljava/lang/String;ILandroid/os/Bundle;ZZI)I Landroid/app/IActivityManager;->finishActivity(Landroid/os/IBinder;ILandroid/content/Intent;I)Z Landroid/app/IActivityManager;->finishReceiver(Landroid/os/IBinder;ILjava/lang/String;Landroid/os/Bundle;ZI)V Landroid/app/IActivityManager;->forceStopPackage(Ljava/lang/String;I)V +Landroid/app/IActivityManager;->getIntentSender(ILjava/lang/String;Landroid/os/IBinder;Ljava/lang/String;I[Landroid/content/Intent;[Ljava/lang/String;ILandroid/os/Bundle;I)Landroid/content/IIntentSender; Landroid/app/IActivityManager;->getLaunchedFromPackage(Landroid/os/IBinder;)Ljava/lang/String; +Landroid/app/IActivityManager;->getProviderMimeType(Landroid/net/Uri;I)Ljava/lang/String; Landroid/app/IActivityManager;->getTaskForActivity(Landroid/os/IBinder;Z)I Landroid/app/IActivityManager;->moveTaskToFront(IILandroid/os/Bundle;)V Landroid/app/IActivityManager;->publishContentProviders(Landroid/app/IApplicationThread;Ljava/util/List;)V @@ -241,16 +260,23 @@ Landroid/app/IActivityManager;->requestBugReport(I)V Landroid/app/IActivityManager;->resumeAppSwitches()V Landroid/app/IActivityManager;->setRequestedOrientation(Landroid/os/IBinder;I)V Landroid/app/IActivityManager;->setTaskResizeable(II)V +Landroid/app/IActivityManager;->stopService(Landroid/app/IApplicationThread;Landroid/content/Intent;Ljava/lang/String;I)I Landroid/app/IActivityManager$Stub$Proxy;->getConfiguration()Landroid/content/res/Configuration; Landroid/app/IActivityManager$Stub$Proxy;->getLaunchedFromUid(Landroid/os/IBinder;)I +Landroid/app/IActivityManager$Stub$Proxy;->getProcessLimit()I Landroid/app/IActivityManager$Stub$Proxy;->getProcessPss([I)[J Landroid/app/IActivityManager$Stub$Proxy;->isAppForeground(I)Z Landroid/app/IActivityManager$Stub$Proxy;->mRemote:Landroid/os/IBinder; Landroid/app/IActivityManager;->unbindService(Landroid/app/IServiceConnection;)Z +Landroid/app/IActivityManager;->unstableProviderDied(Landroid/os/IBinder;)V Landroid/app/IAlarmManager$Stub$Proxy;->(Landroid/os/IBinder;)V Landroid/app/IAlarmManager$Stub;->TRANSACTION_remove:I Landroid/app/IAlarmManager$Stub;->TRANSACTION_set:I Landroid/app/IApplicationThread;->scheduleTrimMemory(I)V +Landroid/app/INotificationManager;->cancelAllNotifications(Ljava/lang/String;I)V +Landroid/app/INotificationManager;->cancelNotificationWithTag(Ljava/lang/String;Ljava/lang/String;II)V +Landroid/app/INotificationManager;->cancelToast(Ljava/lang/String;Landroid/app/ITransientNotification;)V +Landroid/app/INotificationManager;->enqueueToast(Ljava/lang/String;Landroid/app/ITransientNotification;I)V Landroid/app/INotificationManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/app/INotificationManager; Landroid/app/INotificationManager$Stub$Proxy;->(Landroid/os/IBinder;)V Landroid/app/Instrumentation;->execStartActivities(Landroid/content/Context;Landroid/os/IBinder;Landroid/os/IBinder;Landroid/app/Activity;[Landroid/content/Intent;Landroid/os/Bundle;)V @@ -258,9 +284,12 @@ Landroid/app/Instrumentation;->execStartActivity(Landroid/content/Context;Landro Landroid/app/Instrumentation;->execStartActivity(Landroid/content/Context;Landroid/os/IBinder;Landroid/os/IBinder;Ljava/lang/String;Landroid/content/Intent;ILandroid/os/Bundle;)Landroid/app/Instrumentation$ActivityResult; Landroid/app/Instrumentation;->execStartActivity(Landroid/content/Context;Landroid/os/IBinder;Landroid/os/IBinder;Ljava/lang/String;Landroid/content/Intent;ILandroid/os/Bundle;Landroid/os/UserHandle;)Landroid/app/Instrumentation$ActivityResult; Landroid/app/IntentService;->mServiceHandler:Landroid/app/IntentService$ServiceHandler; +Landroid/app/IProcessObserver$Stub;->()V Landroid/app/ISearchManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/app/ISearchManager; Landroid/app/ISearchManager$Stub$Proxy;->getGlobalSearchActivity()Landroid/content/ComponentName; Landroid/app/ISearchManager$Stub$Proxy;->getWebSearchActivity()Landroid/content/ComponentName; +Landroid/app/IServiceConnection$Stub;->asInterface(Landroid/os/IBinder;)Landroid/app/IServiceConnection; +Landroid/app/IStopUserCallback;->userStopped(I)V Landroid/app/IUiModeManager$Stub$Proxy;->(Landroid/os/IBinder;)V Landroid/app/IWallpaperManager;->getWallpaper(Ljava/lang/String;Landroid/app/IWallpaperManagerCallback;ILandroid/os/Bundle;I)Landroid/os/ParcelFileDescriptor; Landroid/app/job/IJobScheduler$Stub;->asInterface(Landroid/os/IBinder;)Landroid/app/job/IJobScheduler; @@ -287,16 +316,21 @@ Landroid/app/LoadedApk;->mSplitResDirs:[Ljava/lang/String; Landroid/app/LoadedApk;->rewriteRValues(Ljava/lang/ClassLoader;Ljava/lang/String;I)V Landroid/app/LocalActivityManager;->mActivities:Ljava/util/Map; Landroid/app/LocalActivityManager;->mActivityArray:Ljava/util/ArrayList; +Landroid/app/LocalActivityManager;->mParent:Landroid/app/Activity; +Landroid/app/LocalActivityManager;->mResumed:Landroid/app/LocalActivityManager$LocalActivityRecord; +Landroid/app/LocalActivityManager;->mSingleMode:Z Landroid/app/NativeActivity;->hideIme(I)V Landroid/app/NativeActivity;->setWindowFlags(II)V Landroid/app/NativeActivity;->setWindowFormat(I)V Landroid/app/NativeActivity;->showIme(I)V Landroid/app/Notification$Builder;->mActions:Ljava/util/ArrayList; +Landroid/app/Notification$Builder;->makePublicContentView()Landroid/widget/RemoteViews; Landroid/app/Notification$Builder;->setChannel(Ljava/lang/String;)Landroid/app/Notification$Builder; Landroid/app/Notification;->isGroupSummary()Z Landroid/app/NotificationManager;->getService()Landroid/app/INotificationManager; Landroid/app/NotificationManager;->notifyAsUser(Ljava/lang/String;ILandroid/app/Notification;Landroid/os/UserHandle;)V Landroid/app/NotificationManager;->sService:Landroid/app/INotificationManager; +Landroid/app/Notification;->mChannelId:Ljava/lang/String; Landroid/app/Notification;->mGroupKey:Ljava/lang/String; Landroid/app/Notification;->mLargeIcon:Landroid/graphics/drawable/Icon; Landroid/app/Notification;->mSmallIcon:Landroid/graphics/drawable/Icon; @@ -309,6 +343,7 @@ Landroid/app/Presentation;->createPresentationContext(Landroid/content/Context;L Landroid/app/ProgressDialog;->mProgressNumber:Landroid/widget/TextView; Landroid/app/QueuedWork;->addFinisher(Ljava/lang/Runnable;)V Landroid/app/QueuedWork;->removeFinisher(Ljava/lang/Runnable;)V +Landroid/app/QueuedWork;->sFinishers:Ljava/util/LinkedList; Landroid/app/ResourcesManager;->appendLibAssetForMainAssetPath(Ljava/lang/String;Ljava/lang/String;)V Landroid/app/ResourcesManager;->getInstance()Landroid/app/ResourcesManager; Landroid/app/ResourcesManager;->mActivityResourceReferences:Ljava/util/WeakHashMap; @@ -322,7 +357,9 @@ Landroid/app/Service;->mStartCompatibility:Z Landroid/app/Service;->mThread:Landroid/app/ActivityThread; Landroid/app/Service;->mToken:Landroid/os/IBinder; Landroid/app/Service;->setForeground(Z)V +Landroid/app/SharedPreferencesImpl;->(Ljava/io/File;I)V Landroid/app/SharedPreferencesImpl;->mFile:Ljava/io/File; +Landroid/app/SharedPreferencesImpl;->startReloadIfChangedUnexpectedly()V Landroid/app/StatusBarManager;->collapsePanels()V Landroid/app/StatusBarManager;->disable(I)V Landroid/app/StatusBarManager;->expandNotificationsPanel()V @@ -429,6 +466,7 @@ Landroid/content/IContentService$Stub;->asInterface(Landroid/os/IBinder;)Landroi Landroid/content/IContentService$Stub$Proxy;->(Landroid/os/IBinder;)V Landroid/content/Intent;->ACTION_ALARM_CHANGED:Ljava/lang/String; Landroid/content/IntentFilter;->mActions:Ljava/util/ArrayList; +Landroid/content/Intent;->mExtras:Landroid/os/Bundle; Landroid/content/Intent;->putExtra(Ljava/lang/String;Landroid/os/IBinder;)Landroid/content/Intent; Landroid/content/pm/ActivityInfo;->resizeMode:I Landroid/content/pm/ApplicationInfo;->enabledSetting:I @@ -439,18 +477,33 @@ Landroid/content/pm/ApplicationInfo;->primaryCpuAbi:Ljava/lang/String; Landroid/content/pm/ApplicationInfo;->privateFlags:I Landroid/content/pm/ApplicationInfo;->scanPublicSourceDir:Ljava/lang/String; Landroid/content/pm/ApplicationInfo;->scanSourceDir:Ljava/lang/String; +Landroid/content/pm/ApplicationInfo;->secondaryCpuAbi:Ljava/lang/String; Landroid/content/pm/ApplicationInfo;->secondaryNativeLibraryDir:Ljava/lang/String; Landroid/content/pm/ComponentInfo;->getComponentName()Landroid/content/ComponentName; +Landroid/content/pm/IPackageDataObserver$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/pm/IPackageDataObserver; +Landroid/content/pm/IPackageManager;->addPermissionAsync(Landroid/content/pm/PermissionInfo;)Z +Landroid/content/pm/IPackageManager;->addPermission(Landroid/content/pm/PermissionInfo;)Z +Landroid/content/pm/IPackageManager;->getComponentEnabledSetting(Landroid/content/ComponentName;I)I +Landroid/content/pm/IPackageManager;->getInstalledPackages(II)Landroid/content/pm/ParceledListSlice; +Landroid/content/pm/IPackageManager;->getInstallerPackageName(Ljava/lang/String;)Ljava/lang/String; Landroid/content/pm/IPackageManager;->getInstallLocation()I Landroid/content/pm/IPackageManager;->getLastChosenActivity(Landroid/content/Intent;Ljava/lang/String;I)Landroid/content/pm/ResolveInfo; +Landroid/content/pm/IPackageManager;->getProviderInfo(Landroid/content/ComponentName;II)Landroid/content/pm/ProviderInfo; +Landroid/content/pm/IPackageManager;->getReceiverInfo(Landroid/content/ComponentName;II)Landroid/content/pm/ActivityInfo; +Landroid/content/pm/IPackageManager;->getServiceInfo(Landroid/content/ComponentName;II)Landroid/content/pm/ServiceInfo; Landroid/content/pm/IPackageManager;->setApplicationEnabledSetting(Ljava/lang/String;IIILjava/lang/String;)V Landroid/content/pm/IPackageManager;->setComponentEnabledSetting(Landroid/content/ComponentName;III)V +Landroid/content/pm/IPackageManager;->setInstallerPackageName(Ljava/lang/String;Ljava/lang/String;)V Landroid/content/pm/IPackageManager;->setLastChosenActivity(Landroid/content/Intent;Ljava/lang/String;ILandroid/content/IntentFilter;ILandroid/content/ComponentName;)V Landroid/content/pm/IPackageManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/pm/IPackageManager; +Landroid/content/pm/IPackageManager$Stub$Proxy;->getInstalledPackages(II)Landroid/content/pm/ParceledListSlice; Landroid/content/pm/IPackageManager$Stub$Proxy;->getPackageInfo(Ljava/lang/String;II)Landroid/content/pm/PackageInfo; Landroid/content/pm/IPackageManager$Stub$Proxy;->getPackagesForUid(I)[Ljava/lang/String; Landroid/content/pm/IPackageManager$Stub$Proxy;->getSystemSharedLibraryNames()[Ljava/lang/String; +Landroid/content/pm/IPackageMoveObserver$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/pm/IPackageMoveObserver; +Landroid/content/pm/IPackageMoveObserver$Stub;->()V Landroid/content/pm/IPackageStatsObserver$Stub;->()V +Landroid/content/pm/IShortcutService$Stub$Proxy;->(Landroid/os/IBinder;)V Landroid/content/pm/LauncherActivityInfo;->mActivityInfo:Landroid/content/pm/ActivityInfo; Landroid/content/pm/LauncherApps;->mPm:Landroid/content/pm/PackageManager; Landroid/content/pm/LauncherApps;->startShortcut(Ljava/lang/String;Ljava/lang/String;Landroid/graphics/Rect;Landroid/os/Bundle;I)V @@ -475,14 +528,29 @@ Landroid/content/pm/PackageParser;->collectCertificates(Landroid/content/pm/Pack Landroid/content/pm/PackageParser$Component;->className:Ljava/lang/String; Landroid/content/pm/PackageParser$Component;->getComponentName()Landroid/content/ComponentName; Landroid/content/pm/PackageParser$Component;->intents:Ljava/util/ArrayList; +Landroid/content/pm/PackageParser;->generateActivityInfo(Landroid/content/pm/PackageParser$Activity;ILandroid/content/pm/PackageUserState;I)Landroid/content/pm/ActivityInfo; Landroid/content/pm/PackageParser;->generatePackageInfo(Landroid/content/pm/PackageParser$Package;[IIJJLjava/util/Set;Landroid/content/pm/PackageUserState;I)Landroid/content/pm/PackageInfo; Landroid/content/pm/PackageParser;->generatePackageInfo(Landroid/content/pm/PackageParser$Package;[IIJJLjava/util/Set;Landroid/content/pm/PackageUserState;)Landroid/content/pm/PackageInfo; +Landroid/content/pm/PackageParser;->generateProviderInfo(Landroid/content/pm/PackageParser$Provider;ILandroid/content/pm/PackageUserState;I)Landroid/content/pm/ProviderInfo; +Landroid/content/pm/PackageParser;->generateServiceInfo(Landroid/content/pm/PackageParser$Service;ILandroid/content/pm/PackageUserState;I)Landroid/content/pm/ServiceInfo; Landroid/content/pm/PackageParser;->()V +Landroid/content/pm/PackageParser$Instrumentation;->info:Landroid/content/pm/InstrumentationInfo; +Landroid/content/pm/PackageParser$IntentInfo;->banner:I +Landroid/content/pm/PackageParser$IntentInfo;->hasDefault:Z +Landroid/content/pm/PackageParser$IntentInfo;->icon:I +Landroid/content/pm/PackageParser$IntentInfo;->()V +Landroid/content/pm/PackageParser$IntentInfo;->labelRes:I +Landroid/content/pm/PackageParser$IntentInfo;->logo:I +Landroid/content/pm/PackageParser$IntentInfo;->nonLocalizedLabel:Ljava/lang/CharSequence; Landroid/content/pm/PackageParser$Package;->activities:Ljava/util/ArrayList; Landroid/content/pm/PackageParser$Package;->applicationInfo:Landroid/content/pm/ApplicationInfo; +Landroid/content/pm/PackageParser$Package;->instrumentation:Ljava/util/ArrayList; +Landroid/content/pm/PackageParser$Package;->mAppMetaData:Landroid/os/Bundle; Landroid/content/pm/PackageParser$Package;->mVersionCode:I Landroid/content/pm/PackageParser$Package;->mVersionName:Ljava/lang/String; Landroid/content/pm/PackageParser$Package;->packageName:Ljava/lang/String; +Landroid/content/pm/PackageParser$Package;->permissionGroups:Ljava/util/ArrayList; +Landroid/content/pm/PackageParser$Package;->permissions:Ljava/util/ArrayList; Landroid/content/pm/PackageParser$Package;->providers:Ljava/util/ArrayList; Landroid/content/pm/PackageParser$Package;->receivers:Ljava/util/ArrayList; Landroid/content/pm/PackageParser$Package;->requestedPermissions:Ljava/util/ArrayList; @@ -493,6 +561,7 @@ Landroid/content/pm/PackageParser;->parsePackage(Ljava/io/File;I)Landroid/conten Landroid/content/pm/PackageParser;->parsePackage(Ljava/io/File;IZ)Landroid/content/pm/PackageParser$Package; Landroid/content/pm/PackageParser$Provider;->info:Landroid/content/pm/ProviderInfo; Landroid/content/pm/PackageParser$ProviderIntentInfo;->provider:Landroid/content/pm/PackageParser$Provider; +Landroid/content/pm/PackageParser$Service;->info:Landroid/content/pm/ServiceInfo; Landroid/content/pm/PackageParser$ServiceIntentInfo;->service:Landroid/content/pm/PackageParser$Service; Landroid/content/pm/PackageUserState;->()V Landroid/content/pm/ParceledListSlice;->(Ljava/util/List;)V @@ -531,14 +600,18 @@ Landroid/content/res/ColorStateList;->mFactory:Landroid/content/res/ColorStateLi Landroid/content/res/CompatibilityInfo;->applicationScale:F Landroid/content/res/CompatibilityInfo;->DEFAULT_COMPATIBILITY_INFO:Landroid/content/res/CompatibilityInfo; Landroid/content/res/DrawableCache;->getInstance(JLandroid/content/res/Resources;Landroid/content/res/Resources$Theme;)Landroid/graphics/drawable/Drawable; +Landroid/content/res/DrawableCache;->()V Landroid/content/res/ObbInfo;->salt:[B Landroid/content/res/Resources;->getCompatibilityInfo()Landroid/content/res/CompatibilityInfo; +Landroid/content/res/ResourcesImpl;->getAssets()Landroid/content/res/AssetManager; Landroid/content/res/ResourcesImpl;->mAccessLock:Ljava/lang/Object; +Landroid/content/res/ResourcesImpl;->mAnimatorCache:Landroid/content/res/ConfigurationBoundResourceCache; Landroid/content/res/ResourcesImpl;->mAssets:Landroid/content/res/AssetManager; Landroid/content/res/ResourcesImpl;->mColorDrawableCache:Landroid/content/res/DrawableCache; Landroid/content/res/ResourcesImpl;->mConfiguration:Landroid/content/res/Configuration; Landroid/content/res/ResourcesImpl;->mDrawableCache:Landroid/content/res/DrawableCache; Landroid/content/res/ResourcesImpl;->mPreloading:Z +Landroid/content/res/ResourcesImpl;->mStateListAnimatorCache:Landroid/content/res/ConfigurationBoundResourceCache; Landroid/content/res/ResourcesImpl;->sPreloadedColorDrawables:Landroid/util/LongSparseArray; Landroid/content/res/ResourcesImpl;->sPreloadedComplexColors:Landroid/util/LongSparseArray; Landroid/content/res/ResourcesImpl;->sPreloadedDrawables:[Landroid/util/LongSparseArray; @@ -554,6 +627,7 @@ Landroid/content/res/Resources;->mTypedArrayPool:Landroid/util/Pools$Synchronize Landroid/content/res/Resources;->setCompatibilityInfo(Landroid/content/res/CompatibilityInfo;)V Landroid/content/res/Resources;->updateSystemConfiguration(Landroid/content/res/Configuration;Landroid/util/DisplayMetrics;Landroid/content/res/CompatibilityInfo;)V Landroid/content/res/StringBlock;->(JZ)V +Landroid/content/res/ThemedResourceCache;->onConfigurationChange(I)V Landroid/content/res/TypedArray;->extractThemeAttrs()[I Landroid/content/res/TypedArray;->getNonConfigurationString(II)Ljava/lang/String; Landroid/content/res/TypedArray;->getValueAt(ILandroid/util/TypedValue;)Z @@ -572,7 +646,10 @@ Landroid/content/res/XmlBlock;->newParser()Landroid/content/res/XmlResourceParse Landroid/content/res/XmlBlock$Parser;->mBlock:Landroid/content/res/XmlBlock; Landroid/content/res/XmlBlock$Parser;->mParseState:J Landroid/content/SearchRecentSuggestionsProvider;->mSuggestionProjection:[Ljava/lang/String; +Landroid/content/SyncContext;->setStatusText(Ljava/lang/String;)V Landroid/content/SyncStatusInfo;->lastSuccessTime:J +Landroid/content/UriMatcher;->mChildren:Ljava/util/ArrayList; +Landroid/content/UriMatcher;->mText:Ljava/lang/String; Landroid/database/AbstractCursor;->mExtras:Landroid/os/Bundle; Landroid/database/AbstractCursor;->mNotifyUri:Landroid/net/Uri; Landroid/database/AbstractCursor;->mRowIdColumnIndex:I @@ -591,6 +668,7 @@ Landroid/database/sqlite/SQLiteDebug$PagerStats;->memoryUsed:I Landroid/database/sqlite/SQLiteDebug$PagerStats;->pageCacheOverflow:I Landroid/database/sqlite/SQLiteOpenHelper;->mName:Ljava/lang/String; Landroid/ddm/DdmHandleAppName;->getAppName()Ljava/lang/String; +Landroid/graphics/AvoidXfermode$Mode;->AVOID:Landroid/graphics/AvoidXfermode$Mode; Landroid/graphics/AvoidXfermode$Mode;->TARGET:Landroid/graphics/AvoidXfermode$Mode; Landroid/graphics/BaseCanvas;->mNativeCanvasWrapper:J Landroid/graphics/Bitmap$Config;->nativeInt:I @@ -612,10 +690,10 @@ Landroid/graphics/Camera;->native_instance:J Landroid/graphics/Canvas;->(J)V Landroid/graphics/Canvas;->release()V Landroid/graphics/Canvas;->save(I)I -Landroid/graphics/Canvas;->saveLayer(Landroid/graphics/RectF;Landroid/graphics/Paint;I)I -Landroid/graphics/Canvas;->saveLayer(FFFFLandroid/graphics/Paint;I)I -Landroid/graphics/Canvas;->saveLayerAlpha(Landroid/graphics/RectF;II)I Landroid/graphics/Canvas;->saveLayerAlpha(FFFFII)I +Landroid/graphics/Canvas;->saveLayerAlpha(Landroid/graphics/RectF;II)I +Landroid/graphics/Canvas;->saveLayer(FFFFLandroid/graphics/Paint;I)I +Landroid/graphics/Canvas;->saveLayer(Landroid/graphics/RectF;Landroid/graphics/Paint;I)I Landroid/graphics/ColorMatrixColorFilter;->setColorMatrix(Landroid/graphics/ColorMatrix;)V Landroid/graphics/drawable/AnimatedImageDrawable;->onAnimationEnd()V Landroid/graphics/drawable/AnimatedStateListDrawable$AnimatedStateListState;->mStateIds:Landroid/util/SparseIntArray; @@ -628,6 +706,7 @@ Landroid/graphics/drawable/BitmapDrawable;->getTint()Landroid/content/res/ColorS Landroid/graphics/drawable/BitmapDrawable;->getTintMode()Landroid/graphics/PorterDuff$Mode; Landroid/graphics/drawable/BitmapDrawable;->mTargetDensity:I Landroid/graphics/drawable/BitmapDrawable;->setBitmap(Landroid/graphics/Bitmap;)V +Landroid/graphics/drawable/ColorDrawable$ColorState;->mUseColor:I Landroid/graphics/drawable/DrawableContainer$DrawableContainerState;->mConstantPadding:Landroid/graphics/Rect; Landroid/graphics/drawable/DrawableContainer;->getOpticalInsets()Landroid/graphics/Insets; Landroid/graphics/drawable/DrawableContainer;->mDrawableContainerState:Landroid/graphics/drawable/DrawableContainer$DrawableContainerState; @@ -771,6 +850,7 @@ Landroid/hardware/Camera;->openLegacy(II)Landroid/hardware/Camera; Landroid/hardware/Camera;->postEventFromNative(Ljava/lang/Object;IIILjava/lang/Object;)V Landroid/hardware/display/WifiDisplayStatus;->mActiveDisplay:Landroid/hardware/display/WifiDisplay; Landroid/hardware/display/WifiDisplayStatus;->mDisplays:[Landroid/hardware/display/WifiDisplay; +Landroid/hardware/fingerprint/IFingerprintService$Stub$Proxy;->(Landroid/os/IBinder;)V Landroid/hardware/HardwareBuffer;->(J)V Landroid/hardware/HardwareBuffer;->mNativeObject:J Landroid/hardware/input/IInputManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/hardware/input/IInputManager; @@ -849,6 +929,9 @@ Landroid/icu/text/Transliterator;->transliterate(Ljava/lang/String;)Ljava/lang/S Landroid/icu/text/UFormat;->getLocale(Landroid/icu/util/ULocale$Type;)Landroid/icu/util/ULocale; Landroid/icu/util/Calendar;->getLocale(Landroid/icu/util/ULocale$Type;)Landroid/icu/util/ULocale; Landroid/inputmethodservice/InputMethodService;->mExtractEditText:Landroid/inputmethodservice/ExtractEditText; +Landroid/inputmethodservice/InputMethodService;->mRootView:Landroid/view/View; +Landroid/inputmethodservice/InputMethodService;->mSettingsObserver:Landroid/inputmethodservice/InputMethodService$SettingsObserver; +Landroid/inputmethodservice/InputMethodService$SettingsObserver;->shouldShowImeWithHardKeyboard()Z Landroid/location/CountryDetector;->detectCountry()Landroid/location/Country; Landroid/location/Country;->getCountryIso()Ljava/lang/String; Landroid/location/Country;->getSource()I @@ -945,11 +1028,14 @@ Landroid/media/AudioTrack;->mNativeTrackInJavaObj:J Landroid/media/AudioTrack;->mStreamType:I Landroid/media/AudioTrack;->native_release()V Landroid/media/AudioTrack;->postEventFromNative(Ljava/lang/Object;IIILjava/lang/Object;)V +Landroid/media/ExifInterface;->getDateTime()J Landroid/media/IAudioService;->getStreamMaxVolume(I)I Landroid/media/IAudioService;->getStreamVolume(I)I Landroid/media/IAudioService;->setStreamVolume(IIILjava/lang/String;)V Landroid/media/IAudioService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/media/IAudioService; Landroid/media/IAudioService$Stub$Proxy;->(Landroid/os/IBinder;)V +Landroid/media/IMediaScannerService;->scanFile(Ljava/lang/String;Ljava/lang/String;)V +Landroid/media/IMediaScannerService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/media/IMediaScannerService; Landroid/media/IRemoteDisplayCallback;->onStateChanged(Landroid/media/RemoteDisplayState;)V Landroid/media/IVolumeController$Stub;->asInterface(Landroid/os/IBinder;)Landroid/media/IVolumeController; Landroid/media/JetPlayer;->mNativePlayerInJavaObj:J @@ -1060,11 +1146,16 @@ Landroid/net/ConnectivityManager;->TYPE_NONE:I Landroid/net/ConnectivityManager;->TYPE_PROXY:I Landroid/net/ConnectivityManager;->TYPE_WIFI_P2P:I Landroid/net/IConnectivityManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/IConnectivityManager; +Landroid/net/IConnectivityManager$Stub$Proxy;->getActiveLinkProperties()Landroid/net/LinkProperties; +Landroid/net/IConnectivityManager$Stub$Proxy;->getActiveNetworkInfo()Landroid/net/NetworkInfo; +Landroid/net/IConnectivityManager$Stub$Proxy;->getAllNetworkInfo()[Landroid/net/NetworkInfo; Landroid/net/IConnectivityManager$Stub$Proxy;->getAllNetworks()[Landroid/net/Network; Landroid/net/IConnectivityManager$Stub$Proxy;->getTetherableIfaces()[Ljava/lang/String; Landroid/net/IConnectivityManager$Stub$Proxy;->getTetherableUsbRegexs()[Ljava/lang/String; +Landroid/net/IConnectivityManager$Stub$Proxy;->getTetheredIfaces()[Ljava/lang/String; Landroid/net/IConnectivityManager$Stub$Proxy;->(Landroid/os/IBinder;)V Landroid/net/INetworkStatsService$Stub$Proxy;->getMobileIfaces()[Ljava/lang/String; +Landroid/net/INetworkStatsService$Stub$Proxy;->(Landroid/os/IBinder;)V Landroid/net/IpConfiguration;->httpProxy:Landroid/net/ProxyInfo; Landroid/net/LinkProperties;->setHttpProxy(Landroid/net/ProxyInfo;)V Landroid/net/LocalSocketImpl;->inboundFileDescriptors:[Ljava/io/FileDescriptor; @@ -1088,6 +1179,7 @@ Landroid/net/NetworkStats;->txBytes:[J Landroid/net/NetworkStats;->txPackets:[J Landroid/net/NetworkStats;->uid:[I Landroid/net/NetworkTemplate;->buildTemplateWifi()Landroid/net/NetworkTemplate; +Landroid/net/Proxy;->getProxy(Landroid/content/Context;Ljava/lang/String;)Ljava/net/Proxy; Landroid/net/ProxyInfo;->(Ljava/lang/String;ILjava/lang/String;)V Landroid/net/SntpClient;->()V Landroid/net/SSLCertificateSocketFactory;->castToOpenSSLSocket(Ljava/net/Socket;)Lcom/android/org/conscrypt/OpenSSLSocketImpl; @@ -1114,6 +1206,7 @@ Landroid/net/SSLCertificateSocketFactory;->setSoWriteTimeout(Ljava/net/Socket;I) Landroid/net/SSLCertificateSocketFactory;->TAG:Ljava/lang/String; Landroid/net/SSLCertificateSocketFactory;->verifyHostname(Ljava/net/Socket;Ljava/lang/String;)V Landroid/net/SSLSessionCache;->mSessionCache:Lcom/android/org/conscrypt/SSLClientSessionCache; +Landroid/net/TrafficStats;->getMobileIfaces()[Ljava/lang/String; Landroid/net/TrafficStats;->getRxBytes(Ljava/lang/String;)J Landroid/net/TrafficStats;->getStatsService()Landroid/net/INetworkStatsService; Landroid/net/TrafficStats;->getTxBytes(Ljava/lang/String;)J @@ -1122,12 +1215,12 @@ Landroid/net/wifi/IWifiManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/ Landroid/net/wifi/IWifiManager$Stub$Proxy;->(Landroid/os/IBinder;)V Landroid/net/wifi/p2p/WifiP2pGroup;->getNetworkId()I Landroid/net/wifi/p2p/WifiP2pGroupList;->getGroupList()Ljava/util/Collection; +Landroid/net/wifi/p2p/WifiP2pManager$Channel;->mAsyncChannel:Lcom/android/internal/util/AsyncChannel; +Landroid/net/wifi/p2p/WifiP2pManager$Channel;->putListener(Ljava/lang/Object;)I Landroid/net/wifi/p2p/WifiP2pManager;->deletePersistentGroup(Landroid/net/wifi/p2p/WifiP2pManager$Channel;ILandroid/net/wifi/p2p/WifiP2pManager$ActionListener;)V Landroid/net/wifi/p2p/WifiP2pManager;->requestPersistentGroupInfo(Landroid/net/wifi/p2p/WifiP2pManager$Channel;Landroid/net/wifi/p2p/WifiP2pManager$PersistentGroupInfoListener;)V Landroid/net/wifi/p2p/WifiP2pManager;->setDeviceName(Landroid/net/wifi/p2p/WifiP2pManager$Channel;Ljava/lang/String;Landroid/net/wifi/p2p/WifiP2pManager$ActionListener;)V Landroid/net/wifi/p2p/WifiP2pManager;->setWifiP2pChannels(Landroid/net/wifi/p2p/WifiP2pManager$Channel;IILandroid/net/wifi/p2p/WifiP2pManager$ActionListener;)V -Landroid/net/wifi/p2p/WifiP2pManager$Channel;->mAsyncChannel:Lcom/android/internal/util/AsyncChannel; -Landroid/net/wifi/p2p/WifiP2pManager$Channel;->putListener(Ljava/lang/Object;)I Landroid/net/wifi/ScanResult;->anqpDomainId:I Landroid/net/wifi/ScanResult;->anqpLines:Ljava/util/List; Landroid/net/wifi/ScanResult;->distanceCm:I @@ -1157,10 +1250,12 @@ Landroid/net/wifi/ScanResult;->wifiSsid:Landroid/net/wifi/WifiSsid; Landroid/net/wifi/WifiConfiguration;->apBand:I Landroid/net/wifi/WifiConfiguration;->apChannel:I Landroid/net/wifi/WifiConfiguration;->defaultGwMacAddress:Ljava/lang/String; +Landroid/net/wifi/WifiConfiguration;->lastConnectUid:I Landroid/net/wifi/WifiConfiguration;->mIpConfiguration:Landroid/net/IpConfiguration; Landroid/net/wifi/WifiConfiguration;->validatedInternetAccess:Z Landroid/net/wifi/WifiEnterpriseConfig;->getCaCertificateAlias()Ljava/lang/String; Landroid/net/wifi/WifiEnterpriseConfig;->getClientCertificateAlias()Ljava/lang/String; +Landroid/net/wifi/WifiInfo;->DEFAULT_MAC_ADDRESS:Ljava/lang/String; Landroid/net/wifi/WifiInfo;->getMeteredHint()Z Landroid/net/wifi/WifiInfo;->mMacAddress:Ljava/lang/String; Landroid/net/wifi/WifiInfo;->removeDoubleQuotes(Ljava/lang/String;)Ljava/lang/String; @@ -1182,17 +1277,30 @@ Landroid/os/AsyncTask;->mTaskInvoked:Ljava/util/concurrent/atomic/AtomicBoolean; Landroid/os/AsyncTask;->mWorker:Landroid/os/AsyncTask$WorkerRunnable; Landroid/os/AsyncTask;->sDefaultExecutor:Ljava/util/concurrent/Executor; Landroid/os/AsyncTask;->setDefaultExecutor(Ljava/util/concurrent/Executor;)V +Landroid/os/BatteryStats$Counter;->getCountLocked(I)I Landroid/os/BatteryStats;->getUidStats()Landroid/util/SparseArray; Landroid/os/BatteryStats$HistoryItem;->states2:I Landroid/os/BatteryStats;->NUM_DATA_CONNECTION_TYPES:I Landroid/os/BatteryStats;->startIteratingHistoryLocked()Z Landroid/os/BatteryStats$Timer;->getTotalTimeLocked(JI)J +Landroid/os/BatteryStats$Uid;->getAudioTurnedOnTimer()Landroid/os/BatteryStats$Timer; Landroid/os/BatteryStats$Uid;->getFullWifiLockTime(JI)J +Landroid/os/BatteryStats$Uid;->getPackageStats()Landroid/util/ArrayMap; Landroid/os/BatteryStats$Uid;->getProcessStats()Landroid/util/ArrayMap; Landroid/os/BatteryStats$Uid;->getSensorStats()Landroid/util/SparseArray; Landroid/os/BatteryStats$Uid;->getUid()I +Landroid/os/BatteryStats$Uid;->getVideoTurnedOnTimer()Landroid/os/BatteryStats$Timer; Landroid/os/BatteryStats$Uid;->getWifiMulticastTime(JI)J Landroid/os/BatteryStats$Uid;->getWifiScanTime(JI)J +Landroid/os/BatteryStats$Uid$Pkg;->getServiceStats()Landroid/util/ArrayMap; +Landroid/os/BatteryStats$Uid$Pkg;->getWakeupAlarmStats()Landroid/util/ArrayMap; +Landroid/os/BatteryStats$Uid$Pkg$Serv;->getLaunches(I)I +Landroid/os/BatteryStats$Uid$Pkg$Serv;->getStartTime(JI)J +Landroid/os/BatteryStats$Uid$Proc;->countExcessivePowers()I +Landroid/os/BatteryStats$Uid$Proc$ExcessivePower;->overTime:J +Landroid/os/BatteryStats$Uid$Proc$ExcessivePower;->type:I +Landroid/os/BatteryStats$Uid$Proc$ExcessivePower;->usedTime:J +Landroid/os/BatteryStats$Uid$Proc;->getExcessivePower(I)Landroid/os/BatteryStats$Uid$Proc$ExcessivePower; Landroid/os/BatteryStats$Uid$Proc;->getForegroundTime(I)J Landroid/os/BatteryStats$Uid$Proc;->getSystemTime(I)J Landroid/os/BatteryStats$Uid$Proc;->getUserTime(I)J @@ -1239,6 +1347,7 @@ Landroid/os/Debug$MemoryInfo;->otherSwappedOut:I Landroid/os/Debug$MemoryInfo;->otherSwappedOutPss:I Landroid/os/Environment;->buildExternalStorageAppDataDirs(Ljava/lang/String;)[Ljava/io/File; Landroid/os/Environment;->getVendorDirectory()Ljava/io/File; +Landroid/os/Environment;->maybeTranslateEmulatedPathToInternal(Ljava/io/File;)Ljava/io/File; Landroid/os/FileObserver$ObserverThread;->onEvent(IILjava/lang/String;)V Landroid/os/FileUtils;->checksumCrc32(Ljava/io/File;)J Landroid/os/FileUtils;->copyFile(Ljava/io/File;Ljava/io/File;)Z @@ -1250,6 +1359,7 @@ Landroid/os/FileUtils;->setPermissions(Ljava/io/File;III)I Landroid/os/FileUtils;->setPermissions(Ljava/lang/String;III)I Landroid/os/FileUtils;->stringToFile(Ljava/io/File;Ljava/lang/String;)V Landroid/os/FileUtils;->stringToFile(Ljava/lang/String;Ljava/lang/String;)V +Landroid/os/FileUtils;->sync(Ljava/io/FileOutputStream;)Z Landroid/os/Handler;->getIMessenger()Landroid/os/IMessenger; Landroid/os/Handler;->hasCallbacks(Ljava/lang/Runnable;)Z Landroid/os/Handler;->(Z)V @@ -1264,6 +1374,7 @@ Landroid/os/IPowerManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/os/IP Landroid/os/IPowerManager$Stub$Proxy;->(Landroid/os/IBinder;)V Landroid/os/IPowerManager$Stub$Proxy;->isLightDeviceIdleMode()Z Landroid/os/IPowerManager;->userActivity(JII)V +Landroid/os/IServiceManager;->checkService(Ljava/lang/String;)Landroid/os/IBinder; Landroid/os/IServiceManager;->getService(Ljava/lang/String;)Landroid/os/IBinder; Landroid/os/IUserManager$Stub$Proxy;->(Landroid/os/IBinder;)V Landroid/os/Looper;->mQueue:Landroid/os/MessageQueue; @@ -1307,6 +1418,7 @@ Landroid/os/Process;->getUidForPid(I)I Landroid/os/Process;->isIsolated(I)Z Landroid/os/Process;->readProcFile(Ljava/lang/String;[I[Ljava/lang/String;[J[F)Z Landroid/os/Process;->readProcLines(Ljava/lang/String;[Ljava/lang/String;[J)V +Landroid/os/Process;->setArgV0(Ljava/lang/String;)V Landroid/os/SELinux;->isSELinuxEnabled()Z Landroid/os/SELinux;->isSELinuxEnforced()Z Landroid/os/ServiceManager;->addService(Ljava/lang/String;Landroid/os/IBinder;)V @@ -1468,13 +1580,16 @@ Landroid/preference/PreferenceScreen;->mRootAdapter:Landroid/widget/ListAdapter; Landroid/print/PrinterId;->getServiceName()Landroid/content/ComponentName; Landroid/print/PrintJobInfo;->getAdvancedOptions()Landroid/os/Bundle; Landroid/print/PrintJobInfo;->getDocumentInfo()Landroid/print/PrintDocumentInfo; +Landroid/provider/Browser$BookmarkColumns;->DATE:Ljava/lang/String; Landroid/provider/Browser;->BOOKMARKS_URI:Landroid/net/Uri; Landroid/provider/Browser;->canClearHistory(Landroid/content/ContentResolver;)Z Landroid/provider/Browser;->clearHistory(Landroid/content/ContentResolver;)V Landroid/provider/Browser;->clearSearches(Landroid/content/ContentResolver;)V Landroid/provider/Browser;->deleteFromHistory(Landroid/content/ContentResolver;Ljava/lang/String;)V Landroid/provider/Browser;->getVisitedHistory(Landroid/content/ContentResolver;)[Ljava/lang/String; +Landroid/provider/Browser;->SEARCHES_URI:Landroid/net/Uri; Landroid/provider/Browser;->sendString(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;)V +Landroid/provider/Browser;->updateVisitedHistory(Landroid/content/ContentResolver;Ljava/lang/String;Z)V Landroid/provider/CalendarContract$CalendarAlerts;->findNextAlarmTime(Landroid/content/ContentResolver;J)J Landroid/provider/CalendarContract$CalendarAlerts;->rescheduleMissedAlarms(Landroid/content/ContentResolver;Landroid/content/Context;Landroid/app/AlarmManager;)V Landroid/provider/Settings$ContentProviderHolder;->mContentProvider:Landroid/content/IContentProvider; @@ -1702,6 +1817,7 @@ Landroid/R$styleable;->View_visibility:I Landroid/R$styleable;->Window:[I Landroid/R$styleable;->Window_windowBackground:I Landroid/R$styleable;->Window_windowFrame:I +Landroid/security/keystore/AndroidKeyStoreProvider;->getKeyStoreOperationHandle(Ljava/lang/Object;)J Landroid/security/KeyStore;->getInstance()Landroid/security/KeyStore; Landroid/security/keystore/KeychainProtectionParams;->clearSecret()V Landroid/security/keystore/KeychainProtectionParams;->getKeyDerivationParams()Landroid/security/keystore/KeyDerivationParams; @@ -1850,6 +1966,7 @@ Landroid/telephony/SmsMessage;->mWrappedSmsMessage:Lcom/android/internal/telepho Landroid/telephony/SubscriptionManager;->getActiveSubscriptionIdList()[I Landroid/telephony/SubscriptionManager;->getAllSubscriptionInfoCount()I Landroid/telephony/SubscriptionManager;->getAllSubscriptionInfoList()Ljava/util/List; +Landroid/telephony/SubscriptionManager;->getDefaultDataPhoneId()I Landroid/telephony/SubscriptionManager;->getDefaultDataSubscriptionInfo()Landroid/telephony/SubscriptionInfo; Landroid/telephony/SubscriptionManager;->getDefaultSmsPhoneId()I Landroid/telephony/SubscriptionManager;->getDefaultVoiceSubscriptionInfo()Landroid/telephony/SubscriptionInfo; @@ -1889,6 +2006,7 @@ Landroid/telephony/TelephonyManager;->()V Landroid/telephony/TelephonyManager;->isMultiSimEnabled()Z Landroid/telephony/TelephonyManager;->isNetworkRoaming(I)Z Landroid/telephony/TelephonyManager;->isVolteAvailable()Z +Landroid/telephony/TelephonyManager;->mSubscriptionManager:Landroid/telephony/SubscriptionManager; Landroid/text/AndroidBidi;->bidi(I[C[B)I Landroid/text/DynamicLayout;->(Ljava/lang/CharSequence;Ljava/lang/CharSequence;Landroid/text/TextPaint;ILandroid/text/Layout$Alignment;Landroid/text/TextDirectionHeuristic;FFZIIILandroid/text/TextUtils$TruncateAt;I)V Landroid/text/DynamicLayout;->sStaticLayout:Landroid/text/StaticLayout; @@ -1945,6 +2063,7 @@ Landroid/text/StaticLayout$LineBreaks;->widths:[F Landroid/text/StaticLayout;->mColumns:I Landroid/text/StaticLayout;->mLineCount:I Landroid/text/StaticLayout;->mLines:[I +Landroid/text/StaticLayout;->mMaximumVisibleLineCount:I Landroid/text/TextLine;->mCharacterStyleSpanSet:Landroid/text/SpanSet; Landroid/text/TextLine;->mMetricAffectingSpanSpanSet:Landroid/text/SpanSet; Landroid/text/TextLine;->mReplacementSpanSpanSet:Landroid/text/SpanSet; @@ -1976,6 +2095,8 @@ Landroid/util/Pools$SynchronizedPool;->acquire()Ljava/lang/Object; Landroid/util/Pools$SynchronizedPool;->(I)V Landroid/util/Rational;->mDenominator:I Landroid/util/Rational;->mNumerator:I +Landroid/util/Singleton;->get()Ljava/lang/Object; +Landroid/util/Singleton;->()V Landroid/util/Singleton;->mInstance:Ljava/lang/Object; Landroid/util/Slog;->d(Ljava/lang/String;Ljava/lang/String;)I Landroid/util/Slog;->w(Ljava/lang/String;Ljava/lang/String;)I @@ -1984,6 +2105,7 @@ Landroid/util/SparseIntArray;->mSize:I Landroid/util/SparseIntArray;->mValues:[I Landroid/view/accessibility/AccessibilityManager;->getInstance(Landroid/content/Context;)Landroid/view/accessibility/AccessibilityManager; Landroid/view/accessibility/AccessibilityManager;->isHighTextContrastEnabled()Z +Landroid/view/accessibility/AccessibilityManager;->mAccessibilityStateChangeListeners:Landroid/util/ArrayMap; Landroid/view/accessibility/AccessibilityManager;->mIsEnabled:Z Landroid/view/accessibility/AccessibilityManager;->mIsHighTextContrastEnabled:Z Landroid/view/accessibility/AccessibilityManager;->sInstance:Landroid/view/accessibility/AccessibilityManager; @@ -2033,6 +2155,7 @@ Landroid/view/InputEventSender;->dispatchInputEventFinished(IZ)V Landroid/view/inputmethod/InputMethodInfo;->mSubtypes:Landroid/view/inputmethod/InputMethodSubtypeArray; Landroid/view/inputmethod/InputMethodManager;->finishInputLocked()V Landroid/view/inputmethod/InputMethodManager;->focusIn(Landroid/view/View;)V +Landroid/view/inputmethod/InputMethodManager;->focusOut(Landroid/view/View;)V Landroid/view/inputmethod/InputMethodManager;->getInputMethodWindowVisibleHeight()I Landroid/view/inputmethod/InputMethodManager;->mCurId:Ljava/lang/String; Landroid/view/inputmethod/InputMethodManager;->mCurRootView:Landroid/view/View; @@ -2041,6 +2164,7 @@ Landroid/view/inputmethod/InputMethodManager;->mNextServedView:Landroid/view/Vie Landroid/view/inputmethod/InputMethodManager;->mServedView:Landroid/view/View; Landroid/view/inputmethod/InputMethodManager;->mService:Lcom/android/internal/view/IInputMethodManager; Landroid/view/inputmethod/InputMethodManager;->notifyUserAction()V +Landroid/view/inputmethod/InputMethodManager;->peekInstance()Landroid/view/inputmethod/InputMethodManager; Landroid/view/inputmethod/InputMethodManager;->showSoftInputUnchecked(ILandroid/os/ResultReceiver;)V Landroid/view/inputmethod/InputMethodManager;->sInstance:Landroid/view/inputmethod/InputMethodManager; Landroid/view/inputmethod/InputMethodManager;->windowDismissed(Landroid/os/IBinder;)V @@ -2054,6 +2178,7 @@ Landroid/view/IWindowManager;->setShelfHeight(ZI)V Landroid/view/IWindowManager;->setStrictModeVisualIndicatorPreference(Ljava/lang/String;)V Landroid/view/IWindowManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/view/IWindowManager; Landroid/view/IWindowManager$Stub$Proxy;->getBaseDisplayDensity(I)I +Landroid/view/IWindowManager$Stub$Proxy;->getDockedStackSide()I Landroid/view/IWindowManager$Stub$Proxy;->getInitialDisplayDensity(I)I Landroid/view/IWindowManager$Stub$Proxy;->hasNavigationBar()Z Landroid/view/IWindowManager$Stub$Proxy;->(Landroid/os/IBinder;)V @@ -2084,6 +2209,7 @@ Landroid/view/LayoutInflater;->mFactorySet:Z Landroid/view/LayoutInflater;->mPrivateFactory:Landroid/view/LayoutInflater$Factory2; Landroid/view/LayoutInflater;->sConstructorMap:Ljava/util/HashMap; Landroid/view/LayoutInflater;->setPrivateFactory(Landroid/view/LayoutInflater$Factory2;)V +Landroid/view/MotionEvent;->getPointerIdBits()I Landroid/view/MotionEvent;->HISTORY_CURRENT:I Landroid/view/MotionEvent;->mNativePtr:J Landroid/view/MotionEvent;->nativeGetRawAxisValue(JIII)F @@ -2091,6 +2217,7 @@ Landroid/view/MotionEvent;->obtain()Landroid/view/MotionEvent; Landroid/view/MotionEvent$PointerCoords;->mPackedAxisBits:J Landroid/view/MotionEvent$PointerCoords;->mPackedAxisValues:[F Landroid/view/MotionEvent;->scale(F)V +Landroid/view/MotionEvent;->split(I)Landroid/view/MotionEvent; Landroid/view/PointerIcon;->load(Landroid/content/Context;)Landroid/view/PointerIcon; Landroid/view/PointerIcon;->mBitmapFrames:[Landroid/graphics/Bitmap; Landroid/view/PointerIcon;->mBitmap:Landroid/graphics/Bitmap; @@ -2111,6 +2238,8 @@ Landroid/view/RemoteAnimationTarget;->sourceContainerBounds:Landroid/graphics/Re Landroid/view/RemoteAnimationTarget;->taskId:I Landroid/view/RemoteAnimationTarget;->windowConfiguration:Landroid/app/WindowConfiguration; Landroid/view/RenderNodeAnimator;->callOnFinished(Landroid/view/RenderNodeAnimator;)V +Landroid/view/RenderNode;->discardDisplayList()V +Landroid/view/RenderNode;->output()V Landroid/view/ScaleGestureDetector;->mListener:Landroid/view/ScaleGestureDetector$OnScaleGestureListener; Landroid/view/ScaleGestureDetector;->mMinSpan:I Landroid/view/SurfaceControl$PhysicalDisplayInfo;->appVsyncOffsetNanos:J @@ -2145,6 +2274,7 @@ Landroid/view/textclassifier/logging/SmartSelectionEventTracker$SelectionEvent;- Landroid/view/textclassifier/TextClassificationManager;->getTextClassifier(I)Landroid/view/textclassifier/TextClassifier; Landroid/view/textservice/TextServicesManager;->isSpellCheckerEnabled()Z Landroid/view/TextureView;->destroyHardwareLayer()V +Landroid/view/TextureView;->destroyHardwareResources()V Landroid/view/TextureView;->mLayer:Landroid/view/TextureLayer; Landroid/view/TextureView;->mNativeWindow:J Landroid/view/TextureView;->mSurface:Landroid/graphics/SurfaceTexture; @@ -2156,6 +2286,7 @@ Landroid/view/VelocityTracker$Estimator;->xCoeff:[F Landroid/view/VelocityTracker$Estimator;->yCoeff:[F Landroid/view/VelocityTracker;->obtain(Ljava/lang/String;)Landroid/view/VelocityTracker; Landroid/view/View;->applyDrawableToTransparentRegion(Landroid/graphics/drawable/Drawable;Landroid/graphics/Region;)V +Landroid/view/View$AttachInfo;->mContentInsets:Landroid/graphics/Rect; Landroid/view/View$AttachInfo;->mDrawingTime:J Landroid/view/View$AttachInfo;->mStableInsets:Landroid/graphics/Rect; Landroid/view/View;->clearAccessibilityFocus()V @@ -2174,12 +2305,14 @@ Landroid/view/View;->dispatchDetachedFromWindow()V Landroid/view/View;->fitsSystemWindows()Z Landroid/view/View;->getAccessibilityDelegate()Landroid/view/View$AccessibilityDelegate; Landroid/view/View;->getBoundsOnScreen(Landroid/graphics/Rect;)V +Landroid/view/View;->getHorizontalScrollFactor()F Landroid/view/View;->getInverseMatrix()Landroid/graphics/Matrix; Landroid/view/View;->getListenerInfo()Landroid/view/View$ListenerInfo; Landroid/view/View;->getLocationOnScreen()[I Landroid/view/View;->getRawTextAlignment()I Landroid/view/View;->getRawTextDirection()I Landroid/view/View;->getTransitionAlpha()F +Landroid/view/View;->getVerticalScrollFactor()F Landroid/view/View;->getViewRootImpl()Landroid/view/ViewRootImpl; Landroid/view/View;->getWindowDisplayFrame(Landroid/graphics/Rect;)V Landroid/view/ViewGroup;->dispatchViewAdded(Landroid/view/View;)V @@ -2194,18 +2327,23 @@ Landroid/view/ViewGroup;->mChildren:[Landroid/view/View; Landroid/view/ViewGroup;->mFirstTouchTarget:Landroid/view/ViewGroup$TouchTarget; Landroid/view/ViewGroup;->mGroupFlags:I Landroid/view/ViewGroup;->mOnHierarchyChangeListener:Landroid/view/ViewGroup$OnHierarchyChangeListener; +Landroid/view/ViewGroup;->mPersistentDrawingCache:I +Landroid/view/ViewGroup;->offsetChildrenTopAndBottom(I)V Landroid/view/ViewGroup;->resetResolvedDrawables()V Landroid/view/ViewGroup;->resetResolvedLayoutDirection()V Landroid/view/ViewGroup;->resetResolvedPadding()V Landroid/view/ViewGroup;->resetResolvedTextAlignment()V Landroid/view/ViewGroup;->resetResolvedTextDirection()V Landroid/view/ViewGroup;->suppressLayout(Z)V +Landroid/view/View;->includeForAccessibility()Z Landroid/view/View;->initializeScrollbars(Landroid/content/res/TypedArray;)V Landroid/view/View;->internalSetPadding(IIII)V Landroid/view/View;->isPaddingResolved()Z Landroid/view/View;->isVisibleToUser(Landroid/graphics/Rect;)Z Landroid/view/View;->isVisibleToUser()Z +Landroid/view/View$ListenerInfo;->()V Landroid/view/View$ListenerInfo;->mOnClickListener:Landroid/view/View$OnClickListener; +Landroid/view/View$ListenerInfo;->mOnFocusChangeListener:Landroid/view/View$OnFocusChangeListener; Landroid/view/View$ListenerInfo;->mOnLongClickListener:Landroid/view/View$OnLongClickListener; Landroid/view/View$ListenerInfo;->mOnTouchListener:Landroid/view/View$OnTouchListener; Landroid/view/View;->mAccessibilityDelegate:Landroid/view/View$AccessibilityDelegate; @@ -2218,10 +2356,13 @@ Landroid/view/View;->mLeft:I Landroid/view/View;->mListenerInfo:Landroid/view/View$ListenerInfo; Landroid/view/View;->mMinHeight:I Landroid/view/View;->mMinWidth:I +Landroid/view/View;->mPaddingBottom:I Landroid/view/View;->mPaddingLeft:I Landroid/view/View;->mPaddingRight:I +Landroid/view/View;->mPaddingTop:I Landroid/view/View;->mParent:Landroid/view/ViewParent; Landroid/view/View;->mPrivateFlags3:I +Landroid/view/View;->mPrivateFlags:I Landroid/view/View;->mRecreateDisplayList:Z Landroid/view/View;->mResources:Landroid/content/res/Resources; Landroid/view/View;->mRight:I @@ -2234,6 +2375,8 @@ Landroid/view/View;->mTop:I Landroid/view/View;->mUnscaledDrawingCache:Landroid/graphics/Bitmap; Landroid/view/View;->mViewFlags:I Landroid/view/View;->notifySubtreeAccessibilityStateChangedIfNeeded()V +Landroid/view/View;->onDrawVerticalScrollBar(Landroid/graphics/Canvas;Landroid/graphics/drawable/Drawable;IIII)V +Landroid/view/View;->performAccessibilityActionInternal(ILandroid/os/Bundle;)Z Landroid/view/View;->recomputePadding()V Landroid/view/View;->requestAccessibilityFocus()Z Landroid/view/View;->resetDisplayList()V @@ -2294,7 +2437,10 @@ Landroid/view/WindowManager$LayoutParams;->NEEDS_MENU_SET_TRUE:I Landroid/view/WindowManager$LayoutParams;->userActivityTimeout:J Landroid/view/Window;->mAppName:Ljava/lang/String; Landroid/view/Window;->mAppToken:Landroid/os/IBinder; +Landroid/view/Window;->mCallback:Landroid/view/Window$Callback; +Landroid/view/Window;->mContext:Landroid/content/Context; Landroid/view/Window;->mHardwareAccelerated:Z +Landroid/view/Window;->mWindowStyle:Landroid/content/res/TypedArray; Landroid/webkit/IWebViewUpdateService$Stub$Proxy;->(Landroid/os/IBinder;)V Landroid/webkit/WebResourceResponse;->mImmutable:Z Landroid/webkit/WebSyncManager;->mHandler:Landroid/os/Handler; @@ -2307,6 +2453,7 @@ Landroid/webkit/WebViewFactory;->getProvider()Landroid/webkit/WebViewFactoryProv Landroid/webkit/WebViewFactory;->getWebViewContextAndSetProvider()Landroid/content/Context; Landroid/webkit/WebViewFactory;->sPackageInfo:Landroid/content/pm/PackageInfo; Landroid/webkit/WebViewFactory;->sProviderInstance:Landroid/webkit/WebViewFactoryProvider; +Landroid/webkit/WebView;->getTouchIconUrl()Ljava/lang/String; Landroid/webkit/WebView;->getVisibleTitleHeight()I Landroid/webkit/WebView;->isPaused()Z Landroid/webkit/WebView;->mProvider:Landroid/webkit/WebViewProvider; @@ -2328,6 +2475,8 @@ Landroid/widget/AbsListView;->mIsChildViewEnabled:Z Landroid/widget/AbsListView;->mMaximumVelocity:I Landroid/widget/AbsListView;->mMotionPosition:I Landroid/widget/AbsListView;->mOnScrollListener:Landroid/widget/AbsListView$OnScrollListener; +Landroid/widget/AbsListView;->mPendingCheckForLongPress:Landroid/widget/AbsListView$CheckForLongPress; +Landroid/widget/AbsListView;->mPendingCheckForTap:Landroid/widget/AbsListView$CheckForTap; Landroid/widget/AbsListView;->mRecycler:Landroid/widget/AbsListView$RecycleBin; Landroid/widget/AbsListView;->mSelectionTopPadding:I Landroid/widget/AbsListView;->mSelectorPosition:I @@ -2340,6 +2489,8 @@ Landroid/widget/AbsListView;->performLongPress(Landroid/view/View;IJ)Z Landroid/widget/AbsListView$RecycleBin;->clear()V Landroid/widget/AbsListView$RecycleBin;->mRecyclerListener:Landroid/widget/AbsListView$RecyclerListener; Landroid/widget/AbsListView;->reportScrollStateChange(I)V +Landroid/widget/AbsListView$SavedState;->firstId:J +Landroid/widget/AbsListView$SavedState;->viewTop:I Landroid/widget/AbsListView;->smoothScrollBy(IIZZ)V Landroid/widget/AbsListView;->trackMotionScroll(II)Z Landroid/widget/AbsSeekBar;->mIsDragging:Z @@ -2358,7 +2509,9 @@ Landroid/widget/AutoCompleteTextView;->doBeforeTextChanged()V Landroid/widget/AutoCompleteTextView;->ensureImeVisible(Z)V Landroid/widget/AutoCompleteTextView;->mPopup:Landroid/widget/ListPopupWindow; Landroid/widget/AutoCompleteTextView;->setDropDownAlwaysVisible(Z)V +Landroid/widget/AutoCompleteTextView;->setForceIgnoreOutsideTouch(Z)V Landroid/widget/CompoundButton;->mButtonDrawable:Landroid/graphics/drawable/Drawable; +Landroid/widget/CompoundButton;->mOnCheckedChangeListener:Landroid/widget/CompoundButton$OnCheckedChangeListener; Landroid/widget/CursorAdapter;->mChangeObserver:Landroid/widget/CursorAdapter$ChangeObserver; Landroid/widget/CursorAdapter;->mDataSetObserver:Landroid/database/DataSetObserver; Landroid/widget/CursorAdapter;->mDataValid:Z @@ -2369,6 +2522,7 @@ Landroid/widget/Editor;->invalidateTextDisplayList()V Landroid/widget/Editor;->mShowCursor:J Landroid/widget/Editor;->mShowSoftInputOnFocus:Z Landroid/widget/ExpandableListView;->mChildDivider:Landroid/graphics/drawable/Drawable; +Landroid/widget/ExpandableListView;->mGroupIndicator:Landroid/graphics/drawable/Drawable; Landroid/widget/FastScroller;->mContainerRect:Landroid/graphics/Rect; Landroid/widget/FastScroller;->mHeaderCount:I Landroid/widget/FastScroller;->mLongList:Z @@ -2475,13 +2629,17 @@ Landroid/widget/RemoteViews;->mBitmapCache:Landroid/widget/RemoteViews$BitmapCac Landroid/widget/RemoteViews;->mergeRemoteViews(Landroid/widget/RemoteViews;)V Landroid/widget/RemoteViews;->mPortrait:Landroid/widget/RemoteViews; Landroid/widget/RemoteViews$ReflectionAction;->methodName:Ljava/lang/String; +Landroid/widget/RemoteViews$ReflectionAction;->value:Ljava/lang/Object; +Landroid/widget/RemoteViews$SetOnClickPendingIntent;->pendingIntent:Landroid/app/PendingIntent; Landroid/widget/ScrollBarDrawable;->mVerticalThumb:Landroid/graphics/drawable/Drawable; Landroid/widget/ScrollBarDrawable;->setHorizontalThumbDrawable(Landroid/graphics/drawable/Drawable;)V Landroid/widget/ScrollBarDrawable;->setVerticalThumbDrawable(Landroid/graphics/drawable/Drawable;)V +Landroid/widget/Scroller;->mInterpolator:Landroid/view/animation/Interpolator; Landroid/widget/ScrollView;->mChildToScrollTo:Landroid/view/View; Landroid/widget/ScrollView;->mEdgeGlowBottom:Landroid/widget/EdgeEffect; Landroid/widget/ScrollView;->mEdgeGlowTop:Landroid/widget/EdgeEffect; Landroid/widget/ScrollView;->mIsBeingDragged:Z +Landroid/widget/ScrollView;->mMinimumVelocity:I Landroid/widget/ScrollView;->mOverflingDistance:I Landroid/widget/ScrollView;->mOverscrollDistance:I Landroid/widget/ScrollView;->mScroller:Landroid/widget/OverScroller; @@ -2495,7 +2653,11 @@ Landroid/widget/SlidingDrawer;->mTopOffset:I Landroid/widget/Spinner;->mPopup:Landroid/widget/Spinner$SpinnerPopup; Landroid/widget/Switch;->mThumbDrawable:Landroid/graphics/drawable/Drawable; Landroid/widget/Switch;->mTrackDrawable:Landroid/graphics/drawable/Drawable; +Landroid/widget/TabHost$IntentContentStrategy;->getContentView()Landroid/view/View; +Landroid/widget/TabHost$IntentContentStrategy;->tabClosed()V +Landroid/widget/TabHost;->mTabSpecs:Ljava/util/List; Landroid/widget/TabHost$TabSpec;->mContentStrategy:Landroid/widget/TabHost$ContentStrategy; +Landroid/widget/TabWidget;->mSelectedTab:I Landroid/widget/TabWidget;->setTabSelectionListener(Landroid/widget/TabWidget$OnTabSelectionChanged;)V Landroid/widget/TextView;->assumeLayout()V Landroid/widget/TextView;->createEditorIfNeeded()V @@ -2513,7 +2675,11 @@ Landroid/widget/TextView;->mSingleLine:Z Landroid/widget/TextView;->mTextPaint:Landroid/text/TextPaint; Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;Landroid/widget/TextView$BufferType;ZI)V Landroid/widget/Toast;->getService()Landroid/app/INotificationManager; +Landroid/widget/Toast;->getWindowParams()Landroid/view/WindowManager$LayoutParams; +Landroid/widget/Toast;->mTN:Landroid/widget/Toast$TN; Landroid/widget/Toast;->sService:Landroid/app/INotificationManager; +Landroid/widget/Toast$TN;->mNextView:Landroid/view/View; +Landroid/widget/Toast$TN;->mParams:Landroid/view/WindowManager$LayoutParams; Landroid/widget/VideoView2;->getMediaController()Landroid/media/session/MediaController; Landroid/widget/VideoView2$OnViewTypeChangedListener;->onViewTypeChanged(Landroid/view/View;I)V Landroid/widget/VideoView2;->setOnViewTypeChangedListener(Landroid/widget/VideoView2$OnViewTypeChangedListener;)V @@ -2596,6 +2762,7 @@ Lcom/android/internal/app/AlertController$RecycleListView;->(Landroid/cont Lcom/android/internal/app/IAppOpsService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/app/IAppOpsService; Lcom/android/internal/app/IAppOpsService$Stub$Proxy;->checkOperation(IILjava/lang/String;)I Lcom/android/internal/app/IAppOpsService$Stub$Proxy;->(Landroid/os/IBinder;)V +Lcom/android/internal/app/IAppOpsService$Stub$Proxy;->setMode(IILjava/lang/String;I)V Lcom/android/internal/app/IBatteryStats;->getStatistics()[B Lcom/android/internal/app/IBatteryStats$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/app/IBatteryStats; Lcom/android/internal/app/IBatteryStats$Stub$Proxy;->(Landroid/os/IBinder;)V @@ -2623,10 +2790,12 @@ Lcom/android/internal/os/BatteryStatsHelper;->refreshStats(II)V Lcom/android/internal/os/BatteryStatsImpl;->computeBatteryRealtime(JI)J Lcom/android/internal/os/BatteryStatsImpl;->computeBatteryUptime(JI)J Lcom/android/internal/os/BatteryStatsImpl;->CREATOR:Landroid/os/Parcelable$Creator; +Lcom/android/internal/os/BatteryStatsImpl;->getBatteryRealtime(J)J Lcom/android/internal/os/BatteryStatsImpl;->getDischargeAmount(I)I Lcom/android/internal/os/BatteryStatsImpl;->getGlobalWifiRunningTime(JI)J Lcom/android/internal/os/BatteryStatsImpl;->getScreenOnTime(JI)J Lcom/android/internal/os/BatteryStatsImpl;->getUidStats()Landroid/util/SparseArray; +Lcom/android/internal/os/BatteryStatsImpl;->getUidStatsLocked(I)Lcom/android/internal/os/BatteryStatsImpl$Uid; Lcom/android/internal/os/BatteryStatsImpl$Timer;->getCountLocked(I)I Lcom/android/internal/os/BatteryStatsImpl$Timer;->getTotalTimeLocked(JI)J Lcom/android/internal/os/BatteryStatsImpl$Uid;->getProcessStats()Landroid/util/ArrayMap; @@ -2694,6 +2863,18 @@ Lcom/android/internal/R$string;->kilobyteShort:I Lcom/android/internal/R$string;->megabyteShort:I Lcom/android/internal/R$string;->petabyteShort:I Lcom/android/internal/R$string;->terabyteShort:I +Lcom/android/internal/R$styleable;->AbsListView_cacheColorHint:I +Lcom/android/internal/R$styleable;->AbsListView_choiceMode:I +Lcom/android/internal/R$styleable;->AbsListView_drawSelectorOnTop:I +Lcom/android/internal/R$styleable;->AbsListView_fastScrollAlwaysVisible:I +Lcom/android/internal/R$styleable;->AbsListView_fastScrollEnabled:I +Lcom/android/internal/R$styleable;->AbsListView:[I +Lcom/android/internal/R$styleable;->AbsListView_listSelector:I +Lcom/android/internal/R$styleable;->AbsListView_scrollingCache:I +Lcom/android/internal/R$styleable;->AbsListView_smoothScrollbar:I +Lcom/android/internal/R$styleable;->AbsListView_stackFromBottom:I +Lcom/android/internal/R$styleable;->AbsListView_textFilterEnabled:I +Lcom/android/internal/R$styleable;->AbsListView_transcriptMode:I Lcom/android/internal/R$styleable;->AccountAuthenticator_accountPreferences:I Lcom/android/internal/R$styleable;->AccountAuthenticator_accountType:I Lcom/android/internal/R$styleable;->AccountAuthenticator_customTokens:I @@ -2701,6 +2882,28 @@ Lcom/android/internal/R$styleable;->AccountAuthenticator:[I Lcom/android/internal/R$styleable;->AccountAuthenticator_icon:I Lcom/android/internal/R$styleable;->AccountAuthenticator_label:I Lcom/android/internal/R$styleable;->AccountAuthenticator_smallIcon:I +Lcom/android/internal/R$styleable;->AndroidManifestActivity_allowTaskReparenting:I +Lcom/android/internal/R$styleable;->AndroidManifestActivity_configChanges:I +Lcom/android/internal/R$styleable;->AndroidManifestActivity_description:I +Lcom/android/internal/R$styleable;->AndroidManifestActivity_enabled:I +Lcom/android/internal/R$styleable;->AndroidManifestActivity_excludeFromRecents:I +Lcom/android/internal/R$styleable;->AndroidManifestActivity_exported:I +Lcom/android/internal/R$styleable;->AndroidManifestActivity_hardwareAccelerated:I +Lcom/android/internal/R$styleable;->AndroidManifestActivity:[I +Lcom/android/internal/R$styleable;->AndroidManifestActivity_icon:I +Lcom/android/internal/R$styleable;->AndroidManifestActivity_immersive:I +Lcom/android/internal/R$styleable;->AndroidManifestActivity_label:I +Lcom/android/internal/R$styleable;->AndroidManifestActivity_launchMode:I +Lcom/android/internal/R$styleable;->AndroidManifestActivity_logo:I +Lcom/android/internal/R$styleable;->AndroidManifestActivity_name:I +Lcom/android/internal/R$styleable;->AndroidManifestActivity_noHistory:I +Lcom/android/internal/R$styleable;->AndroidManifestActivity_permission:I +Lcom/android/internal/R$styleable;->AndroidManifestActivity_process:I +Lcom/android/internal/R$styleable;->AndroidManifestActivity_screenOrientation:I +Lcom/android/internal/R$styleable;->AndroidManifestActivity_taskAffinity:I +Lcom/android/internal/R$styleable;->AndroidManifestActivity_theme:I +Lcom/android/internal/R$styleable;->AndroidManifestActivity_uiOptions:I +Lcom/android/internal/R$styleable;->AndroidManifestActivity_windowSoftInputMode:I Lcom/android/internal/R$styleable;->AndroidManifestApplication_enabled:I Lcom/android/internal/R$styleable;->AndroidManifestApplication_hardwareAccelerated:I Lcom/android/internal/R$styleable;->AndroidManifestApplication:[I @@ -2712,8 +2915,21 @@ Lcom/android/internal/R$styleable;->AndroidManifestApplication_process:I Lcom/android/internal/R$styleable;->AndroidManifestApplication_supportsRtl:I Lcom/android/internal/R$styleable;->AndroidManifestApplication_theme:I Lcom/android/internal/R$styleable;->AndroidManifestApplication_uiOptions:I +Lcom/android/internal/R$styleable;->AndroidManifestData:[I Lcom/android/internal/R$styleable;->AndroidManifest:[I Lcom/android/internal/R$styleable;->AndroidManifest_installLocation:I +Lcom/android/internal/R$styleable;->AndroidManifestIntentFilter:[I +Lcom/android/internal/R$styleable;->AndroidManifestIntentFilter_priority:I +Lcom/android/internal/R$styleable;->AndroidManifestMetaData:[I +Lcom/android/internal/R$styleable;->AndroidManifestMetaData_name:I +Lcom/android/internal/R$styleable;->AndroidManifestMetaData_resource:I +Lcom/android/internal/R$styleable;->AndroidManifestMetaData_value:I +Lcom/android/internal/R$styleable;->AndroidManifestService_enabled:I +Lcom/android/internal/R$styleable;->AndroidManifestService_exported:I +Lcom/android/internal/R$styleable;->AndroidManifestService:[I +Lcom/android/internal/R$styleable;->AndroidManifestService_name:I +Lcom/android/internal/R$styleable;->AndroidManifestService_permission:I +Lcom/android/internal/R$styleable;->AndroidManifestService_process:I Lcom/android/internal/R$styleable;->AndroidManifest_sharedUserId:I Lcom/android/internal/R$styleable;->AndroidManifestUsesPermission:[I Lcom/android/internal/R$styleable;->AndroidManifestUsesPermission_name:I @@ -2727,6 +2943,7 @@ Lcom/android/internal/R$styleable;->CheckBoxPreference:[I Lcom/android/internal/R$styleable;->CheckBoxPreference_summaryOff:I Lcom/android/internal/R$styleable;->CheckBoxPreference_summaryOn:I Lcom/android/internal/R$styleable;->CompoundButton_button:I +Lcom/android/internal/R$styleable;->CompoundButton_checked:I Lcom/android/internal/R$styleable;->CompoundButton:[I Lcom/android/internal/R$styleable;->DialogPreference_dialogTitle:I Lcom/android/internal/R$styleable;->DialogPreference:[I @@ -2737,6 +2954,15 @@ Lcom/android/internal/R$styleable;->ImageView:[I Lcom/android/internal/R$styleable;->ImageView_src:I Lcom/android/internal/R$styleable;->ListPreference_entries:I Lcom/android/internal/R$styleable;->ListPreference:[I +Lcom/android/internal/R$styleable;->ListView_dividerHeight:I +Lcom/android/internal/R$styleable;->ListView_divider:I +Lcom/android/internal/R$styleable;->ListView_entries:I +Lcom/android/internal/R$styleable;->ListView_footerDividersEnabled:I +Lcom/android/internal/R$styleable;->ListView_headerDividersEnabled:I +Lcom/android/internal/R$styleable;->ListView:[I +Lcom/android/internal/R$styleable;->ListView_overScrollFooter:I +Lcom/android/internal/R$styleable;->ListView_overScrollHeader:I +Lcom/android/internal/R$styleable;->PopupWindow:[I Lcom/android/internal/R$styleable;->Preference_defaultValue:I Lcom/android/internal/R$styleable;->Preference_dependency:I Lcom/android/internal/R$styleable;->Preference_enabled:I @@ -2765,12 +2991,15 @@ Lcom/android/internal/R$styleable;->SyncAdapter_settingsActivity:I Lcom/android/internal/R$styleable;->SyncAdapter_supportsUploading:I Lcom/android/internal/R$styleable;->SyncAdapter_userVisible:I Lcom/android/internal/R$styleable;->TabWidget:[I +Lcom/android/internal/R$styleable;->TextAppearance:[I Lcom/android/internal/R$styleable;->TextView_drawableBottom:I Lcom/android/internal/R$styleable;->TextView_drawableLeft:I Lcom/android/internal/R$styleable;->TextView_drawableRight:I Lcom/android/internal/R$styleable;->TextView_drawableTop:I Lcom/android/internal/R$styleable;->TextView:[I Lcom/android/internal/R$styleable;->TextView_maxLines:I +Lcom/android/internal/R$styleable;->TextView_textColorHint:I +Lcom/android/internal/R$styleable;->TextView_textColor:I Lcom/android/internal/R$styleable;->View_background:I Lcom/android/internal/R$styleable;->ViewGroup_Layout:[I Lcom/android/internal/R$styleable;->ViewGroup_Layout_layout_height:I @@ -2791,24 +3020,35 @@ Lcom/android/internal/telephony/IPhoneSubInfo$Stub;->asInterface(Landroid/os/IBi Lcom/android/internal/telephony/IPhoneSubInfo$Stub$Proxy;->(Landroid/os/IBinder;)V Lcom/android/internal/telephony/ISms$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/ISms; Lcom/android/internal/telephony/ISub$Stub$Proxy;->(Landroid/os/IBinder;)V +Lcom/android/internal/telephony/ITelephony;->answerRingingCall()V Lcom/android/internal/telephony/ITelephony;->call(Ljava/lang/String;Ljava/lang/String;)V +Lcom/android/internal/telephony/ITelephony;->dial(Ljava/lang/String;)V Lcom/android/internal/telephony/ITelephony;->disableDataConnectivity()Z Lcom/android/internal/telephony/ITelephony;->enableDataConnectivity()Z Lcom/android/internal/telephony/ITelephony;->endCall()Z +Lcom/android/internal/telephony/ITelephony;->getCallState()I +Lcom/android/internal/telephony/ITelephony;->getDataState()I Lcom/android/internal/telephony/ITelephony;->isIdle(Ljava/lang/String;)Z Lcom/android/internal/telephony/ITelephony;->silenceRinger()V Lcom/android/internal/telephony/ITelephony$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/ITelephony; Lcom/android/internal/telephony/ITelephony$Stub$Proxy;->endCall()Z Lcom/android/internal/telephony/ITelephony$Stub$Proxy;->(Landroid/os/IBinder;)V +Lcom/android/internal/telephony/ITelephony$Stub;->TRANSACTION_call:I +Lcom/android/internal/telephony/ITelephony$Stub;->TRANSACTION_endCall:I Lcom/android/internal/telephony/ITelephony$Stub;->TRANSACTION_getDeviceId:I +Lcom/android/internal/telephony/SmsRawData;->CREATOR:Landroid/os/Parcelable$Creator; +Lcom/android/internal/telephony/SmsRawData;->([B)V Lcom/android/internal/textservice/ITextServicesManager$Stub$Proxy;->(Landroid/os/IBinder;)V Lcom/android/internal/util/AsyncChannel;->sendMessage(III)V Lcom/android/internal/util/FastPrintWriter;->(Ljava/io/OutputStream;)V Lcom/android/internal/util/XmlUtils;->readMapXml(Ljava/io/InputStream;)Ljava/util/HashMap; +Lcom/android/internal/util/XmlUtils;->skipCurrentTag(Lorg/xmlpull/v1/XmlPullParser;)V +Lcom/android/internal/util/XmlUtils;->writeMapXml(Ljava/util/Map;Ljava/io/OutputStream;)V Lcom/android/internal/view/IInputMethodManager$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/view/IInputMethodManager; Lcom/android/internal/view/IInputMethodManager$Stub$Proxy;->getEnabledInputMethodList()Ljava/util/List; Lcom/android/internal/view/IInputMethodManager$Stub$Proxy;->(Landroid/os/IBinder;)V Lcom/android/internal/view/InputBindResult;->CREATOR:Landroid/os/Parcelable$Creator; +Lcom/android/internal/view/menu/MenuBuilder;->(Landroid/content/Context;)V Lcom/android/internal/view/menu/MenuBuilder;->mContext:Landroid/content/Context; Lcom/android/internal/view/menu/MenuBuilder;->setCurrentMenuInfo(Landroid/view/ContextMenu$ContextMenuInfo;)V Lcom/android/internal/view/menu/MenuBuilder;->setOptionalIconsVisible(Z)V @@ -2864,6 +3104,7 @@ Lcom/android/org/conscrypt/ConscryptSocketBase;->getSoWriteTimeout()I Lcom/android/org/conscrypt/ConscryptSocketBase;->setHandshakeTimeout(I)V Lcom/android/org/conscrypt/ConscryptSocketBase;->setHostname(Ljava/lang/String;)V Lcom/android/org/conscrypt/ConscryptSocketBase;->setSoWriteTimeout(I)V +Lcom/android/org/conscrypt/ConscryptSocketBase;->socket:Ljava/net/Socket; Lcom/android/org/conscrypt/OpenSSLSocketImpl;->getAlpnSelectedProtocol()[B Lcom/android/org/conscrypt/OpenSSLSocketImpl;->getChannelId()[B Lcom/android/org/conscrypt/OpenSSLSocketImpl;->getHostname()Ljava/lang/String; @@ -2886,10 +3127,12 @@ Ldalvik/system/BaseDexClassLoader;->getLdLibraryPath()Ljava/lang/String; Ldalvik/system/BaseDexClassLoader;->pathList:Ldalvik/system/DexPathList; Ldalvik/system/BlockGuard;->getThreadPolicy()Ldalvik/system/BlockGuard$Policy; Ldalvik/system/BlockGuard$Policy;->onNetwork()V +Ldalvik/system/BlockGuard$Policy;->onReadFromDisk()V Ldalvik/system/CloseGuard;->close()V Ldalvik/system/CloseGuard;->get()Ldalvik/system/CloseGuard; Ldalvik/system/CloseGuard;->open(Ljava/lang/String;)V Ldalvik/system/CloseGuard;->warnIfOpen()V +Ldalvik/system/DexFile$DFEnum;->mNameList:[Ljava/lang/String; Ldalvik/system/DexFile;->getClassNameList(Ljava/lang/Object;)[Ljava/lang/String; Ldalvik/system/DexFile;->isBackedByOatFile()Z Ldalvik/system/DexFile;->loadClassBinaryName(Ljava/lang/String;Ljava/lang/ClassLoader;Ljava/util/List;)Ljava/lang/Class; @@ -2898,6 +3141,7 @@ Ldalvik/system/DexFile;->mFileName:Ljava/lang/String; Ldalvik/system/DexFile;->mInternalCookie:Ljava/lang/Object; Ldalvik/system/DexFile;->openDexFile(Ljava/lang/String;Ljava/lang/String;ILjava/lang/ClassLoader;[Ldalvik/system/DexPathList$Element;)Ljava/lang/Object; Ldalvik/system/DexPathList;->addDexPath(Ljava/lang/String;Ljava/io/File;)V +Ldalvik/system/DexPathList;->definingContext:Ljava/lang/ClassLoader; Ldalvik/system/DexPathList;->dexElements:[Ldalvik/system/DexPathList$Element; Ldalvik/system/DexPathList$Element;->dexFile:Ldalvik/system/DexFile; Ldalvik/system/DexPathList$Element;->(Ldalvik/system/DexFile;Ljava/io/File;)V @@ -2918,6 +3162,7 @@ Ldalvik/system/VMDebug;->dumpReferenceTables()V Ldalvik/system/VMRuntime;->addressOf(Ljava/lang/Object;)J Ldalvik/system/VMRuntime;->clearGrowthLimit()V Ldalvik/system/VMRuntime;->getCurrentInstructionSet()Ljava/lang/String; +Ldalvik/system/VMRuntime;->getInstructionSet(Ljava/lang/String;)Ljava/lang/String; Ldalvik/system/VMRuntime;->getRuntime()Ldalvik/system/VMRuntime; Ldalvik/system/VMRuntime;->is64Bit()Z Ldalvik/system/VMRuntime;->newNonMovableArray(Ljava/lang/Class;I)Ljava/lang/Object; @@ -2935,7 +3180,9 @@ Ldalvik/system/VMStack;->getCallingClassLoader()Ljava/lang/ClassLoader; Ldalvik/system/VMStack;->getStackClass2()Ljava/lang/Class; Ljava/io/FileDescriptor;->descriptor:I Ljava/io/FileDescriptor;->getInt$()I +Ljava/io/FileDescriptor;->isSocket$()Z Ljava/io/FileDescriptor;->setInt$(I)V +Ljava/io/File;->fs:Ljava/io/FileSystem; Ljava/io/FileInputStream;->fd:Ljava/io/FileDescriptor; Ljava/io/FileOutputStream;->fd:Ljava/io/FileDescriptor; Ljava/io/ObjectStreamClass;->getConstructorId(Ljava/lang/Class;)J @@ -2945,8 +3192,10 @@ Ljava/lang/AbstractStringBuilder;->value:[C Ljava/lang/Boolean;->value:Z Ljava/lang/Byte;->value:B Ljava/lang/Character;->value:C +Ljava/lang/Class;->accessFlags:I Ljava/lang/Class;->dexCache:Ljava/lang/Object; Ljava/lang/Class;->dexClassDefIndex:I +Ljava/lang/Class;->ifTable:[Ljava/lang/Object; Ljava/lang/ClassLoader;->parent:Ljava/lang/ClassLoader; Ljava/lang/Daemons$Daemon;->isRunning()Z Ljava/lang/Daemons$Daemon;->start()V @@ -3018,6 +3267,7 @@ Ljava/net/Inet6Address$Inet6AddressHolder;->scope_ifname:Ljava/net/NetworkInterf Ljava/net/Inet6Address;->()V Ljava/net/InetAddress;->clearDnsCache()V Ljava/net/InetAddress;->holder:Ljava/net/InetAddress$InetAddressHolder; +Ljava/net/InetAddress;->holder()Ljava/net/InetAddress$InetAddressHolder; Ljava/net/InetAddress$InetAddressHolder;->address:I Ljava/net/InetAddress$InetAddressHolder;->family:I Ljava/net/InetAddress$InetAddressHolder;->hostName:Ljava/lang/String; @@ -3026,6 +3276,8 @@ Ljava/net/InetAddress;->isNumeric(Ljava/lang/String;)Z Ljava/net/InetAddress;->parseNumericAddress(Ljava/lang/String;)Ljava/net/InetAddress; Ljava/net/Socket;->getFileDescriptor$()Ljava/io/FileDescriptor; Ljava/net/Socket;->impl:Ljava/net/SocketImpl; +Ljava/net/SocketImpl;->serverSocket:Ljava/net/ServerSocket; +Ljava/net/SocketImpl;->socket:Ljava/net/Socket; Ljava/net/URI;->host:Ljava/lang/String; Ljava/net/URL;->handler:Ljava/net/URLStreamHandler; Ljava/net/URL;->handlers:Ljava/util/Hashtable; @@ -3060,11 +3312,16 @@ Ljava/util/Collections$SynchronizedMap;->m:Ljava/util/Map; Ljava/util/Collections$UnmodifiableCollection;->c:Ljava/util/Collection; Ljava/util/Collections$UnmodifiableMap;->m:Ljava/util/Map; Ljava/util/concurrent/ConcurrentHashMap$BaseIterator;->hasMoreElements()Z +Ljava/util/concurrent/Executors$RunnableAdapter;->task:Ljava/lang/Runnable; Ljava/util/concurrent/FutureTask;->callable:Ljava/util/concurrent/Callable; +Ljava/util/concurrent/FutureTask;->EXCEPTIONAL:I +Ljava/util/concurrent/FutureTask;->outcome:Ljava/lang/Object; +Ljava/util/concurrent/FutureTask;->state:I Ljava/util/concurrent/LinkedBlockingQueue;->capacity:I Ljava/util/EnumMap;->keyType:Ljava/lang/Class; Ljava/util/EnumSet;->elementType:Ljava/lang/Class; Ljava/util/HashMap$HashIterator;->hasNext()Z +Ljava/util/jar/JarFile;->manifest:Ljava/util/jar/Manifest; Ljava/util/LinkedHashMap;->eldest()Ljava/util/Map$Entry; Ljava/util/LinkedHashMap$LinkedHashIterator;->hasNext()Z Ljava/util/Locale;->createConstant(Ljava/lang/String;Ljava/lang/String;)Ljava/util/Locale; @@ -3087,11 +3344,15 @@ Ljava/util/zip/ZipEntry;->(Ljava/lang/String;Ljava/lang/String;JJJII[BJ)V Ljava/util/zip/ZipFile;->jzfile:J Ljavax/net/ssl/SSLServerSocketFactory;->defaultServerSocketFactory:Ljavax/net/ssl/SSLServerSocketFactory; Ljavax/net/ssl/SSLSocketFactory;->defaultSocketFactory:Ljavax/net/ssl/SSLSocketFactory; +Llibcore/util/BasicLruCache;->map:Ljava/util/LinkedHashMap; Llibcore/util/ZoneInfo;->mTransitions:[J Lorg/apache/http/conn/ssl/SSLSocketFactory;->(Ljavax/net/ssl/SSLSocketFactory;)V Lorg/apache/http/conn/ssl/SSLSocketFactory;->()V +Lorg/ccil/cowan/tagsoup/AttributesImpl;->data:[Ljava/lang/String; +Lorg/ccil/cowan/tagsoup/AttributesImpl;->length:I Lorg/json/JSONArray;->values:Ljava/util/List; Lorg/json/JSONObject;->append(Ljava/lang/String;Ljava/lang/Object;)Lorg/json/JSONObject; Lorg/json/JSONObject;->keySet()Ljava/util/Set; Lorg/json/JSONObject;->writeTo(Lorg/json/JSONStringer;)V +Lorg/w3c/dom/traversal/NodeIterator;->nextNode()Lorg/w3c/dom/Node; Lsun/misc/Unsafe;->theUnsafe:Lsun/misc/Unsafe; -- GitLab From 421e8f63a364960b7164ddd4f5ecc99779f6839e Mon Sep 17 00:00:00 2001 From: jdesprez Date: Thu, 29 Mar 2018 15:45:17 -0700 Subject: [PATCH 105/179] Update AndroidTest.xml to be APCT suite ready Test: atest FrameworksServicesTests Bug: 74440293 Bug: 77290273 Change-Id: I9f20e9979b17985c8cd7cdcefd73f677b8e5ecc1 --- services/tests/servicestests/AndroidTest.xml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/services/tests/servicestests/AndroidTest.xml b/services/tests/servicestests/AndroidTest.xml index 082827c23b53..0ec16b523a1b 100644 --- a/services/tests/servicestests/AndroidTest.xml +++ b/services/tests/servicestests/AndroidTest.xml @@ -14,7 +14,9 @@ limitations under the License. --> - +