Snap for 5033059 from 238c5b95e54d5dc13a777c4c2ddd4cead2355ab1 to qt-release
Change-Id: I25c89ca50cfa8979d4bbb0507921eb3cb469ba37
diff --git a/Android.bp b/Android.bp
index 3e471b6..a64cc81 100644
--- a/Android.bp
+++ b/Android.bp
@@ -706,7 +706,6 @@
// Loaded with System.loadLibrary by android.view.textclassifier
required: [
- "libtextclassifier",
"libmedia2_jni",
],
@@ -810,12 +809,16 @@
java_library {
name: "ext",
installable: true,
- no_framework_libs: true,
+ sdk_version: "core_current",
static_libs: [
"libphonenumber-platform",
"nist-sip",
"tagsoup",
"rappor",
+ "libtextclassifier-java",
+ ],
+ required: [
+ "libtextclassifier",
],
dxflags: ["--core-library"],
}
diff --git a/api/current.txt b/api/current.txt
index 52257c0..f915bb3 100755
--- a/api/current.txt
+++ b/api/current.txt
@@ -42920,6 +42920,7 @@
method public static int getSlotIndex(int);
method public static int[] getSubscriptionIds(int);
method public java.util.List<android.telephony.SubscriptionPlan> getSubscriptionPlans(int);
+ method public boolean isActiveSubscriptionId(int);
method public boolean isNetworkRoaming(int);
method public static boolean isValidSubscriptionId(int);
method public void removeOnOpportunisticSubscriptionsChangedListener(android.telephony.SubscriptionManager.OnOpportunisticSubscriptionsChangedListener);
@@ -51407,7 +51408,7 @@
}
public abstract class CookieManager {
- ctor public CookieManager();
+ ctor public deprecated CookieManager();
method public abstract boolean acceptCookie();
method public abstract boolean acceptThirdPartyCookies(android.webkit.WebView);
method public static boolean allowFileSchemeCookies();
@@ -51507,13 +51508,13 @@
}
public abstract class RenderProcessGoneDetail {
- ctor public RenderProcessGoneDetail();
+ ctor public deprecated RenderProcessGoneDetail();
method public abstract boolean didCrash();
method public abstract int rendererPriorityAtExit();
}
public abstract class SafeBrowsingResponse {
- ctor public SafeBrowsingResponse();
+ ctor public deprecated SafeBrowsingResponse();
method public abstract void backToSafety(boolean);
method public abstract void proceed(boolean);
method public abstract void showInterstitial(boolean);
@@ -51525,7 +51526,7 @@
}
public abstract class ServiceWorkerController {
- ctor public ServiceWorkerController();
+ ctor public deprecated ServiceWorkerController();
method public static android.webkit.ServiceWorkerController getInstance();
method public abstract android.webkit.ServiceWorkerWebSettings getServiceWorkerWebSettings();
method public abstract void setServiceWorkerClient(android.webkit.ServiceWorkerClient);
@@ -51574,7 +51575,7 @@
}
public abstract class TracingController {
- ctor public TracingController();
+ ctor public deprecated TracingController();
method public static android.webkit.TracingController getInstance();
method public abstract boolean isTracing();
method public abstract void start(android.webkit.TracingConfig);
@@ -52114,7 +52115,7 @@
}
public abstract class WebViewDatabase {
- ctor public WebViewDatabase();
+ ctor public deprecated WebViewDatabase();
method public abstract deprecated void clearFormData();
method public abstract void clearHttpAuthUsernamePassword();
method public abstract deprecated void clearUsernamePassword();
diff --git a/api/system-current.txt b/api/system-current.txt
index 1f74cbf..5785e4a 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -5439,6 +5439,7 @@
method public boolean disableDataConnectivity();
method public boolean enableDataConnectivity();
method public void enableVideoCalling(boolean);
+ method public java.lang.String getAidForAppType(int);
method public java.util.List<android.service.carrier.CarrierIdentifier> getAllowedCarriers(int);
method public java.util.List<java.lang.String> getCarrierPackageNamesForIntent(android.content.Intent);
method public java.util.List<java.lang.String> getCarrierPackageNamesForIntentAndPhone(android.content.Intent, int);
@@ -5454,6 +5455,7 @@
method public deprecated boolean getDataEnabled(int);
method public boolean getEmergencyCallbackMode();
method public java.lang.String getIsimDomain();
+ method public int getPreferredNetworkType(int);
method public int getSimApplicationState();
method public int getSimCardState();
method public java.util.List<android.telephony.TelephonyHistogram> getTelephonyHistograms();
@@ -5463,10 +5465,7 @@
method public boolean handlePinMmi(java.lang.String);
method public boolean handlePinMmiForSubscriber(int, java.lang.String);
method public boolean isDataConnectivityPossible();
- method public deprecated boolean isIdle();
- method public deprecated boolean isOffhook();
method public deprecated boolean isRadioOn();
- method public deprecated boolean isRinging();
method public boolean isVideoCallingEnabled();
method public deprecated boolean isVisualVoicemailEnabled(android.telecom.PhoneAccountHandle);
method public boolean needsOtaServiceProvisioning();
@@ -5480,7 +5479,6 @@
method public void setSimPowerStateForSlot(int, int);
method public deprecated void setVisualVoicemailEnabled(android.telecom.PhoneAccountHandle, boolean);
method public void setVoiceActivationState(int);
- method public deprecated void silenceRinger();
method public boolean supplyPin(java.lang.String);
method public int[] supplyPinReportResult(java.lang.String);
method public boolean supplyPuk(java.lang.String, java.lang.String);
@@ -5498,6 +5496,29 @@
field public static final java.lang.String EXTRA_SIM_STATE = "android.telephony.extra.SIM_STATE";
field public static final java.lang.String EXTRA_VISUAL_VOICEMAIL_ENABLED_BY_USER_BOOL = "android.telephony.extra.VISUAL_VOICEMAIL_ENABLED_BY_USER_BOOL";
field public static final java.lang.String EXTRA_VOICEMAIL_SCRAMBLED_PIN_STRING = "android.telephony.extra.VOICEMAIL_SCRAMBLED_PIN_STRING";
+ field public static final int NETWORK_MODE_CDMA_EVDO = 4; // 0x4
+ field public static final int NETWORK_MODE_CDMA_NO_EVDO = 5; // 0x5
+ field public static final int NETWORK_MODE_EVDO_NO_CDMA = 6; // 0x6
+ field public static final int NETWORK_MODE_GLOBAL = 7; // 0x7
+ field public static final int NETWORK_MODE_GSM_ONLY = 1; // 0x1
+ field public static final int NETWORK_MODE_GSM_UMTS = 3; // 0x3
+ field public static final int NETWORK_MODE_LTE_CDMA_EVDO = 8; // 0x8
+ field public static final int NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA = 10; // 0xa
+ field public static final int NETWORK_MODE_LTE_GSM_WCDMA = 9; // 0x9
+ field public static final int NETWORK_MODE_LTE_ONLY = 11; // 0xb
+ field public static final int NETWORK_MODE_LTE_TDSCDMA = 15; // 0xf
+ field public static final int NETWORK_MODE_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA = 22; // 0x16
+ field public static final int NETWORK_MODE_LTE_TDSCDMA_GSM = 17; // 0x11
+ field public static final int NETWORK_MODE_LTE_TDSCDMA_GSM_WCDMA = 20; // 0x14
+ field public static final int NETWORK_MODE_LTE_TDSCDMA_WCDMA = 19; // 0x13
+ field public static final int NETWORK_MODE_LTE_WCDMA = 12; // 0xc
+ field public static final int NETWORK_MODE_TDSCDMA_CDMA_EVDO_GSM_WCDMA = 21; // 0x15
+ field public static final int NETWORK_MODE_TDSCDMA_GSM = 16; // 0x10
+ field public static final int NETWORK_MODE_TDSCDMA_GSM_WCDMA = 18; // 0x12
+ field public static final int NETWORK_MODE_TDSCDMA_ONLY = 13; // 0xd
+ field public static final int NETWORK_MODE_TDSCDMA_WCDMA = 14; // 0xe
+ field public static final int NETWORK_MODE_WCDMA_ONLY = 2; // 0x2
+ field public static final int NETWORK_MODE_WCDMA_PREF = 0; // 0x0
field public static final int SIM_ACTIVATION_STATE_ACTIVATED = 2; // 0x2
field public static final int SIM_ACTIVATION_STATE_ACTIVATING = 1; // 0x1
field public static final int SIM_ACTIVATION_STATE_DEACTIVATED = 3; // 0x3
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 9012c33..2246562 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -148,6 +148,10 @@
public class TelephonyManager {
method public deprecated void answerRingingCall();
method public deprecated boolean endCall();
+ method public deprecated boolean isIdle();
+ method public deprecated boolean isOffhook();
+ method public deprecated boolean isRinging();
+ method public deprecated void silenceRinger();
}
}
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index ffd7d31..1e9c354 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -80,7 +80,8 @@
BatteryLevelChanged battery_level_changed = 30;
ChargingStateChanged charging_state_changed = 31;
PluggedStateChanged plugged_state_changed = 32;
- // 33 - 34 are available
+ InteractiveStateChanged interactive_state_changed = 33;
+ // 34 is available
WakeupAlarmOccurred wakeup_alarm_occurred = 35;
KernelWakeupReported kernel_wakeup_reported = 36;
WifiLockStateChanged wifi_lock_state_changed = 37;
@@ -665,6 +666,20 @@
}
/**
+ * Logs when the device is interactive, according to the PowerManager Notifier.
+ *
+ * Logged from:
+ * frameworks/base/services/core/java/com/android/server/power/Notifier.java
+ */
+message InteractiveStateChanged {
+ enum State {
+ OFF = 0;
+ ON = 1;
+ }
+ optional State state = 1;
+}
+
+/**
* Logs Battery Saver state change.
*
* Logged from:
@@ -2220,6 +2235,11 @@
// SWAP
optional int64 swap_in_bytes = 8;
+
+ // RSS high watermark.
+ // Peak RSS usage of the process. Value is read from the VmHWM field in /proc/PID/status or
+ // from memory.max_usage_in_bytes under /dev/memcg if the device uses per-app memory cgroups.
+ optional int64 rss_high_watermark_in_bytes = 9;
}
/*
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index 5a0172b..66392f8 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -169,7 +169,7 @@
new ResourceHealthManagerPuller(android::util::BATTERY_VOLTAGE)}},
// process_memory_state
{android::util::PROCESS_MEMORY_STATE,
- {{4, 5, 6, 7, 8},
+ {{4, 5, 6, 7, 8, 9},
{2, 3},
1 * NS_PER_SEC,
new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_STATE)}},
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index 0472461..ac16fd3 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -2076,27 +2076,20 @@
Lcom/android/internal/telephony/ISub;->getDefaultSubId()I
Lcom/android/internal/telephony/ISub;->setDefaultDataSubId(I)V
Lcom/android/internal/telephony/ITelephony$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
-Lcom/android/internal/telephony/ITelephony$Stub$Proxy;->endCall()Z
-Lcom/android/internal/telephony/ITelephony$Stub$Proxy;->endCallForSubscriber(I)Z
Lcom/android/internal/telephony/ITelephony$Stub$Proxy;->getDeviceId(Ljava/lang/String;)Ljava/lang/String;
Lcom/android/internal/telephony/ITelephony$Stub$Proxy;->isRadioOn(Ljava/lang/String;)Z
Lcom/android/internal/telephony/ITelephony$Stub$Proxy;->mRemote:Landroid/os/IBinder;
Lcom/android/internal/telephony/ITelephony$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/ITelephony;
Lcom/android/internal/telephony/ITelephony$Stub;->DESCRIPTOR:Ljava/lang/String;
-Lcom/android/internal/telephony/ITelephony$Stub;->TRANSACTION_answerRingingCall:I
Lcom/android/internal/telephony/ITelephony$Stub;->TRANSACTION_call:I
Lcom/android/internal/telephony/ITelephony$Stub;->TRANSACTION_dial:I
-Lcom/android/internal/telephony/ITelephony$Stub;->TRANSACTION_endCall:I
Lcom/android/internal/telephony/ITelephony$Stub;->TRANSACTION_getDeviceId:I
-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;->disableLocationUpdates()V
Lcom/android/internal/telephony/ITelephony;->enableDataConnectivity()Z
Lcom/android/internal/telephony/ITelephony;->enableLocationUpdates()V
-Lcom/android/internal/telephony/ITelephony;->endCall()Z
-Lcom/android/internal/telephony/ITelephony;->endCallForSubscriber(I)Z
Lcom/android/internal/telephony/ITelephony;->getActivePhoneType()I
Lcom/android/internal/telephony/ITelephony;->getCallState()I
Lcom/android/internal/telephony/ITelephony;->getDataActivity()I
@@ -2108,12 +2101,8 @@
Lcom/android/internal/telephony/ITelephony;->hasIccCard()Z
Lcom/android/internal/telephony/ITelephony;->iccCloseLogicalChannel(II)Z
Lcom/android/internal/telephony/ITelephony;->iccTransmitApduLogicalChannel(IIIIIIILjava/lang/String;)Ljava/lang/String;
-Lcom/android/internal/telephony/ITelephony;->isIdle(Ljava/lang/String;)Z
-Lcom/android/internal/telephony/ITelephony;->isIdleForSubscriber(ILjava/lang/String;)Z
Lcom/android/internal/telephony/ITelephony;->isRadioOnForSubscriber(ILjava/lang/String;)Z
-Lcom/android/internal/telephony/ITelephony;->isRinging(Ljava/lang/String;)Z
Lcom/android/internal/telephony/ITelephony;->setRadio(Z)Z
-Lcom/android/internal/telephony/ITelephony;->silenceRinger()V
Lcom/android/internal/telephony/ITelephony;->supplyPin(Ljava/lang/String;)Z
Lcom/android/internal/telephony/ITelephony;->toggleRadioOnOff()V
Lcom/android/internal/telephony/ITelephony;->updateServiceLocation()V
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index be1f2db..294a3ec 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -19,11 +19,14 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ComponentName;
+import android.content.IIntentReceiver;
import android.content.IIntentSender;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.UserInfo;
+import android.os.Bundle;
import android.os.IBinder;
+import android.os.TransactionTooLargeException;
import android.view.RemoteAnimationAdapter;
import java.util.ArrayList;
@@ -232,4 +235,14 @@
public abstract void setBooted(boolean booted);
public abstract boolean isBooted();
public abstract void finishBooting();
+
+ public abstract void tempWhitelistForPendingIntent(int callerPid, int callerUid, int targetUid,
+ long duration, String tag);
+ public abstract int broadcastIntentInPackage(String packageName, int uid, Intent intent,
+ String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData,
+ Bundle resultExtras, String requiredPermission, Bundle bOptions, boolean serialized,
+ boolean sticky, int userId);
+ public abstract ComponentName startServiceInPackage(int uid, Intent service,
+ String resolvedType, boolean fgRequired, String callingPackage, int userId)
+ throws TransactionTooLargeException;
}
diff --git a/core/java/android/app/ProcessMemoryState.java b/core/java/android/app/ProcessMemoryState.java
index e0aed16..9bfdae0 100644
--- a/core/java/android/app/ProcessMemoryState.java
+++ b/core/java/android/app/ProcessMemoryState.java
@@ -32,10 +32,11 @@
public final long rssInBytes;
public final long cacheInBytes;
public final long swapInBytes;
+ public final long rssHighWatermarkInBytes;
public ProcessMemoryState(int uid, String processName, int oomScore, long pgfault,
long pgmajfault, long rssInBytes, long cacheInBytes,
- long swapInBytes) {
+ long swapInBytes, long rssHighWatermarkInBytes) {
this.uid = uid;
this.processName = processName;
this.oomScore = oomScore;
@@ -44,6 +45,7 @@
this.rssInBytes = rssInBytes;
this.cacheInBytes = cacheInBytes;
this.swapInBytes = swapInBytes;
+ this.rssHighWatermarkInBytes = rssHighWatermarkInBytes;
}
private ProcessMemoryState(Parcel in) {
@@ -55,6 +57,7 @@
rssInBytes = in.readLong();
cacheInBytes = in.readLong();
swapInBytes = in.readLong();
+ rssHighWatermarkInBytes = in.readLong();
}
public static final Creator<ProcessMemoryState> CREATOR = new Creator<ProcessMemoryState>() {
@@ -84,5 +87,6 @@
parcel.writeLong(rssInBytes);
parcel.writeLong(cacheInBytes);
parcel.writeLong(swapInBytes);
+ parcel.writeLong(rssHighWatermarkInBytes);
}
}
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index a64eead..8d9533e 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -331,7 +331,6 @@
for (int i = 0; i < numOperations; i++) {
ContentProviderOperation operation = operations.get(i);
Uri uri = operation.getUri();
- userIds[i] = getUserIdFromUri(uri);
uri = validateIncomingUri(uri);
uri = maybeGetUriWithoutUserId(uri);
// Rebuild operation if we changed the Uri above
diff --git a/core/java/android/util/apk/ApkVerityBuilder.java b/core/java/android/util/apk/ApkVerityBuilder.java
index 553511d..edd09f8 100644
--- a/core/java/android/util/apk/ApkVerityBuilder.java
+++ b/core/java/android/util/apk/ApkVerityBuilder.java
@@ -40,7 +40,7 @@
*
* @hide
*/
-abstract class ApkVerityBuilder {
+public abstract class ApkVerityBuilder {
private ApkVerityBuilder() {}
private static final int CHUNK_SIZE_BYTES = 4096; // Typical Linux block size
@@ -51,12 +51,18 @@
private static final String JCA_DIGEST_ALGORITHM = "SHA-256";
private static final byte[] DEFAULT_SALT = new byte[8];
- static class ApkVerityResult {
+ /** Result generated by the builder. */
+ public static class ApkVerityResult {
+ /** Raw fs-verity metadata and Merkle tree ready to be deployed on disk. */
public final ByteBuffer verityData;
+
+ /** Size of the Merkle tree in {@code verityData}. */
public final int merkleTreeSize;
+
+ /** Root hash of the Merkle tree. */
public final byte[] rootHash;
- ApkVerityResult(ByteBuffer verityData, int merkleTreeSize, byte[] rootHash) {
+ private ApkVerityResult(ByteBuffer verityData, int merkleTreeSize, byte[] rootHash) {
this.verityData = verityData;
this.merkleTreeSize = merkleTreeSize;
this.rootHash = rootHash;
@@ -65,19 +71,47 @@
/**
* Generates the 4k, SHA-256 based Merkle tree for the given APK and stores in the {@link
- * ByteBuffer} created by the {@link ByteBufferFactory}. The Merkle tree is suitable to be used
- * as the on-disk format for apk-verity.
+ * ByteBuffer} created by the {@link ByteBufferFactory}. The output is suitable to be used as
+ * the on-disk format for fs-verity to use.
*
* @return ApkVerityResult containing a buffer with the generated Merkle tree stored at the
* front, the tree size, and the calculated root hash.
*/
@NonNull
- static ApkVerityResult generateApkVerityTree(@NonNull RandomAccessFile apk,
+ public static ApkVerityResult generateFsVerityTree(@NonNull RandomAccessFile apk,
+ @NonNull ByteBufferFactory bufferFactory)
+ throws IOException, SecurityException, NoSuchAlgorithmException, DigestException {
+ return generateVerityTree(apk, bufferFactory, null /* signatureInfo */,
+ false /* skipSigningBlock */);
+ }
+
+ /**
+ * Generates the 4k, SHA-256 based Merkle tree for the given APK and stores in the {@link
+ * ByteBuffer} created by the {@link ByteBufferFactory}. The Merkle tree does not cover Signing
+ * Block specificed in {@code signatureInfo}. The output is suitable to be used as the on-disk
+ * format for fs-verity to use (with elide and patch extensions).
+ *
+ * @return ApkVerityResult containing a buffer with the generated Merkle tree stored at the
+ * front, the tree size, and the calculated root hash.
+ */
+ @NonNull
+ public static ApkVerityResult generateApkVerityTree(@NonNull RandomAccessFile apk,
@Nullable SignatureInfo signatureInfo, @NonNull ByteBufferFactory bufferFactory)
throws IOException, SecurityException, NoSuchAlgorithmException, DigestException {
- long signingBlockSize =
- signatureInfo.centralDirOffset - signatureInfo.apkSigningBlockOffset;
- long dataSize = apk.length() - signingBlockSize;
+ return generateVerityTree(apk, bufferFactory, signatureInfo, true /* skipSigningBlock */);
+ }
+
+ @NonNull
+ private static ApkVerityResult generateVerityTree(@NonNull RandomAccessFile apk,
+ @NonNull ByteBufferFactory bufferFactory, @Nullable SignatureInfo signatureInfo,
+ boolean skipSigningBlock)
+ throws IOException, SecurityException, NoSuchAlgorithmException, DigestException {
+ long dataSize = apk.length();
+ if (skipSigningBlock) {
+ long signingBlockSize =
+ signatureInfo.centralDirOffset - signatureInfo.apkSigningBlockOffset;
+ dataSize -= signingBlockSize;
+ }
int[] levelOffset = calculateVerityLevelOffset(dataSize);
int merkleTreeSize = levelOffset[levelOffset.length - 1];
@@ -85,10 +119,11 @@
merkleTreeSize
+ CHUNK_SIZE_BYTES); // maximum size of apk-verity metadata
output.order(ByteOrder.LITTLE_ENDIAN);
-
ByteBuffer tree = slice(output, 0, merkleTreeSize);
- byte[] apkRootHash = generateApkVerityTreeInternal(apk, signatureInfo, DEFAULT_SALT,
- levelOffset, tree);
+ // Only use default salt in legacy case.
+ byte[] salt = skipSigningBlock ? DEFAULT_SALT : null;
+ byte[] apkRootHash = generateVerityTreeInternal(apk, signatureInfo, salt, levelOffset,
+ tree, skipSigningBlock);
return new ApkVerityResult(output, merkleTreeSize, apkRootHash);
}
@@ -138,7 +173,8 @@
throws IOException, SignatureNotFoundException, SecurityException, DigestException,
NoSuchAlgorithmException {
try (RandomAccessFile apk = new RandomAccessFile(apkPath, "r")) {
- ApkVerityResult result = generateApkVerityTree(apk, signatureInfo, bufferFactory);
+ ApkVerityResult result = generateVerityTree(apk, bufferFactory, signatureInfo,
+ true /* skipSigningBlock */);
ByteBuffer footer = slice(result.verityData, result.merkleTreeSize,
result.verityData.limit());
generateApkVerityFooter(apk, signatureInfo, footer);
@@ -170,11 +206,14 @@
private final byte[] mDigestBuffer = new byte[DIGEST_SIZE_BYTES];
private final byte[] mSalt;
- private BufferedDigester(byte[] salt, ByteBuffer output) throws NoSuchAlgorithmException {
+ private BufferedDigester(@Nullable byte[] salt, @NonNull ByteBuffer output)
+ throws NoSuchAlgorithmException {
mSalt = salt;
mOutput = output.slice();
mMd = MessageDigest.getInstance(JCA_DIGEST_ALGORITHM);
- mMd.update(mSalt);
+ if (mSalt != null) {
+ mMd.update(mSalt);
+ }
mBytesDigestedSinceReset = 0;
}
@@ -201,7 +240,9 @@
mMd.digest(mDigestBuffer, 0, mDigestBuffer.length);
mOutput.put(mDigestBuffer);
// After digest, MessageDigest resets automatically, so no need to reset again.
- mMd.update(mSalt);
+ if (mSalt != null) {
+ mMd.update(mSalt);
+ }
mBytesDigestedSinceReset = 0;
}
}
@@ -242,6 +283,26 @@
// thus the syscall overhead is not too big.
private static final int MMAP_REGION_SIZE_BYTES = 1024 * 1024;
+ private static void generateFsVerityDigestAtLeafLevel(RandomAccessFile file, ByteBuffer output)
+ throws IOException, NoSuchAlgorithmException, DigestException {
+ BufferedDigester digester = new BufferedDigester(null /* salt */, output);
+
+ // 1. Digest the whole file by chunks.
+ consumeByChunk(digester,
+ new MemoryMappedFileDataSource(file.getFD(), 0, file.length()),
+ MMAP_REGION_SIZE_BYTES);
+
+ // 2. Pad 0s up to the nearest 4096-byte block before hashing.
+ int lastIncompleteChunkSize = (int) (file.length() % CHUNK_SIZE_BYTES);
+ if (lastIncompleteChunkSize != 0) {
+ digester.consume(ByteBuffer.allocate(CHUNK_SIZE_BYTES - lastIncompleteChunkSize));
+ }
+ digester.assertEmptyBuffer();
+
+ // 3. Fill up the rest of buffer with 0s.
+ digester.fillUpLastOutputChunk();
+ }
+
private static void generateApkVerityDigestAtLeafLevel(RandomAccessFile apk,
SignatureInfo signatureInfo, byte[] salt, ByteBuffer output)
throws IOException, NoSuchAlgorithmException, DigestException {
@@ -288,15 +349,19 @@
}
@NonNull
- private static byte[] generateApkVerityTreeInternal(@NonNull RandomAccessFile apk,
- @Nullable SignatureInfo signatureInfo, @NonNull byte[] salt,
- @NonNull int[] levelOffset, @NonNull ByteBuffer output)
+ private static byte[] generateVerityTreeInternal(@NonNull RandomAccessFile apk,
+ @Nullable SignatureInfo signatureInfo, @Nullable byte[] salt,
+ @NonNull int[] levelOffset, @NonNull ByteBuffer output, boolean skipSigningBlock)
throws IOException, NoSuchAlgorithmException, DigestException {
- assertSigningBlockAlignedAndHasFullPages(signatureInfo);
-
// 1. Digest the apk to generate the leaf level hashes.
- generateApkVerityDigestAtLeafLevel(apk, signatureInfo, salt, slice(output,
- levelOffset[levelOffset.length - 2], levelOffset[levelOffset.length - 1]));
+ if (skipSigningBlock) {
+ assertSigningBlockAlignedAndHasFullPages(signatureInfo);
+ generateApkVerityDigestAtLeafLevel(apk, signatureInfo, salt, slice(output,
+ levelOffset[levelOffset.length - 2], levelOffset[levelOffset.length - 1]));
+ } else {
+ generateFsVerityDigestAtLeafLevel(apk, slice(output,
+ levelOffset[levelOffset.length - 2], levelOffset[levelOffset.length - 1]));
+ }
// 2. Digest the lower level hashes bottom up.
for (int level = levelOffset.length - 3; level >= 0; level--) {
@@ -434,10 +499,11 @@
return levelOffset;
}
- private static void assertSigningBlockAlignedAndHasFullPages(SignatureInfo signatureInfo) {
+ private static void assertSigningBlockAlignedAndHasFullPages(
+ @NonNull SignatureInfo signatureInfo) {
if (signatureInfo.apkSigningBlockOffset % CHUNK_SIZE_BYTES != 0) {
throw new IllegalArgumentException(
- "APK Signing Block does not start at the page boundary: "
+ "APK Signing Block does not start at the page boundary: "
+ signatureInfo.apkSigningBlockOffset);
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 2ee7ab9..9be9ed0 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -239,6 +239,12 @@
final ArrayList<WindowCallbacks> mWindowCallbacks = new ArrayList<>();
@UnsupportedAppUsage
final Context mContext;
+ /**
+ * TODO(b/116349163): Check if we can merge this into {@link #mContext}.
+ */
+ @NonNull
+ private Context mDisplayContext;
+
@UnsupportedAppUsage
final IWindowSession mWindowSession;
@NonNull Display mDisplay;
@@ -532,6 +538,7 @@
public ViewRootImpl(Context context, Display display) {
mContext = context;
+ mDisplayContext = context.createDisplayContext(display);
mWindowSession = WindowManagerGlobal.getWindowSession();
mDisplay = display;
mBasePackageName = context.getBasePackageName();
@@ -1249,6 +1256,7 @@
} else {
mDisplay = preferredDisplay;
}
+ mDisplayContext = mContext.createDisplayContext(mDisplay);
}
void pokeDrawLockIfNeeded() {
@@ -2579,7 +2587,7 @@
.mayUseInputMethod(mWindowAttributes.flags);
if (imTarget != mLastWasImTarget) {
mLastWasImTarget = imTarget;
- InputMethodManager imm = mContext.getSystemService(InputMethodManager.class);
+ InputMethodManager imm = mDisplayContext.getSystemService(InputMethodManager.class);
if (imm != null && imTarget) {
imm.onPreWindowFocus(mView, hasWindowFocus);
imm.onPostWindowFocus(mView, mView.findFocus(),
@@ -2695,7 +2703,7 @@
mLastWasImTarget = WindowManager.LayoutParams
.mayUseInputMethod(mWindowAttributes.flags);
- InputMethodManager imm = mContext.getSystemService(InputMethodManager.class);
+ InputMethodManager imm = mDisplayContext.getSystemService(InputMethodManager.class);
if (imm != null && mLastWasImTarget && !isInLocalFocusMode()) {
imm.onPreWindowFocus(mView, hasWindowFocus);
}
@@ -4329,7 +4337,8 @@
enqueueInputEvent(event, null, 0, true);
} break;
case MSG_CHECK_FOCUS: {
- InputMethodManager imm = mContext.getSystemService(InputMethodManager.class);
+ InputMethodManager imm =
+ mDisplayContext.getSystemService(InputMethodManager.class);
if (imm != null) {
imm.checkFocus();
}
@@ -4871,7 +4880,7 @@
@Override
protected int onProcess(QueuedInputEvent q) {
if (mLastWasImTarget && !isInLocalFocusMode()) {
- InputMethodManager imm = mContext.getSystemService(InputMethodManager.class);
+ InputMethodManager imm = mDisplayContext.getSystemService(InputMethodManager.class);
if (imm != null) {
final InputEvent event = q.mEvent;
if (DEBUG_IMF) Log.v(mTag, "Sending input event to IME: " + event);
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index 29339e9..3e240cf 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -44,6 +44,8 @@
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
+import com.google.android.textclassifier.AnnotatorModel;
+
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
@@ -92,7 +94,7 @@
@GuardedBy("mLock") // Do not access outside this lock.
private ModelFile mModel;
@GuardedBy("mLock") // Do not access outside this lock.
- private TextClassifierImplNative mNative;
+ private AnnotatorModel mNative;
private final Object mLoggerLock = new Object();
@GuardedBy("mLoggerLock") // Do not access outside this lock.
@@ -125,7 +127,7 @@
&& rangeLength <= mSettings.getSuggestSelectionMaxRangeLength()) {
final String localesString = concatenateLocales(request.getDefaultLocales());
final ZonedDateTime refTime = ZonedDateTime.now();
- final TextClassifierImplNative nativeImpl = getNative(request.getDefaultLocales());
+ final AnnotatorModel nativeImpl = getNative(request.getDefaultLocales());
final int start;
final int end;
if (mSettings.isModelDarkLaunchEnabled() && !request.isDarkLaunchAllowed()) {
@@ -134,7 +136,7 @@
} else {
final int[] startEnd = nativeImpl.suggestSelection(
string, request.getStartIndex(), request.getEndIndex(),
- new TextClassifierImplNative.SelectionOptions(localesString));
+ new AnnotatorModel.SelectionOptions(localesString));
start = startEnd[0];
end = startEnd[1];
}
@@ -142,10 +144,10 @@
&& start >= 0 && end <= string.length()
&& start <= request.getStartIndex() && end >= request.getEndIndex()) {
final TextSelection.Builder tsBuilder = new TextSelection.Builder(start, end);
- final TextClassifierImplNative.ClassificationResult[] results =
+ final AnnotatorModel.ClassificationResult[] results =
nativeImpl.classifyText(
string, start, end,
- new TextClassifierImplNative.ClassificationOptions(
+ new AnnotatorModel.ClassificationOptions(
refTime.toInstant().toEpochMilli(),
refTime.getZone().getId(),
localesString));
@@ -184,11 +186,11 @@
final String localesString = concatenateLocales(request.getDefaultLocales());
final ZonedDateTime refTime = request.getReferenceTime() != null
? request.getReferenceTime() : ZonedDateTime.now();
- final TextClassifierImplNative.ClassificationResult[] results =
+ final AnnotatorModel.ClassificationResult[] results =
getNative(request.getDefaultLocales())
.classifyText(
string, request.getStartIndex(), request.getEndIndex(),
- new TextClassifierImplNative.ClassificationOptions(
+ new AnnotatorModel.ClassificationOptions(
refTime.toInstant().toEpochMilli(),
refTime.getZone().getId(),
localesString));
@@ -228,17 +230,17 @@
? request.getEntityConfig().resolveEntityListModifications(
getEntitiesForHints(request.getEntityConfig().getHints()))
: mSettings.getEntityListDefault();
- final TextClassifierImplNative nativeImpl =
+ final AnnotatorModel nativeImpl =
getNative(request.getDefaultLocales());
- final TextClassifierImplNative.AnnotatedSpan[] annotations =
+ final AnnotatorModel.AnnotatedSpan[] annotations =
nativeImpl.annotate(
textString,
- new TextClassifierImplNative.AnnotationOptions(
+ new AnnotatorModel.AnnotationOptions(
refTime.toInstant().toEpochMilli(),
refTime.getZone().getId(),
concatenateLocales(request.getDefaultLocales())));
- for (TextClassifierImplNative.AnnotatedSpan span : annotations) {
- final TextClassifierImplNative.ClassificationResult[] results =
+ for (AnnotatorModel.AnnotatedSpan span : annotations) {
+ final AnnotatorModel.ClassificationResult[] results =
span.getClassification();
if (results.length == 0
|| !entitiesToIdentify.contains(results[0].getCollection())) {
@@ -297,7 +299,7 @@
}
}
- private TextClassifierImplNative getNative(LocaleList localeList)
+ private AnnotatorModel getNative(LocaleList localeList)
throws FileNotFoundException {
synchronized (mLock) {
localeList = localeList == null ? LocaleList.getEmptyLocaleList() : localeList;
@@ -310,7 +312,7 @@
destroyNativeIfExistsLocked();
final ParcelFileDescriptor fd = ParcelFileDescriptor.open(
new File(bestModel.getPath()), ParcelFileDescriptor.MODE_READ_ONLY);
- mNative = new TextClassifierImplNative(fd.getFd());
+ mNative = new AnnotatorModel(fd.getFd());
closeAndLogError(fd);
mModel = bestModel;
}
@@ -398,14 +400,14 @@
}
private TextClassification createClassificationResult(
- TextClassifierImplNative.ClassificationResult[] classifications,
+ AnnotatorModel.ClassificationResult[] classifications,
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);
final int size = classifications.length;
- TextClassifierImplNative.ClassificationResult highestScoringResult = null;
+ AnnotatorModel.ClassificationResult highestScoringResult = null;
float highestScore = Float.MIN_VALUE;
for (int i = 0; i < size; i++) {
builder.setEntityType(classifications[i].getCollection(),
@@ -486,9 +488,9 @@
try {
final ParcelFileDescriptor modelFd = ParcelFileDescriptor.open(
file, ParcelFileDescriptor.MODE_READ_ONLY);
- final int version = TextClassifierImplNative.getVersion(modelFd.getFd());
+ final int version = AnnotatorModel.getVersion(modelFd.getFd());
final String supportedLocalesStr =
- TextClassifierImplNative.getLocales(modelFd.getFd());
+ AnnotatorModel.getLocales(modelFd.getFd());
if (supportedLocalesStr.isEmpty()) {
Log.d(DEFAULT_LOG_TAG, "Ignoring " + file.getAbsolutePath());
return null;
@@ -676,7 +678,7 @@
public static List<LabeledIntent> create(
Context context,
@Nullable Instant referenceTime,
- TextClassifierImplNative.ClassificationResult classification,
+ AnnotatorModel.ClassificationResult classification,
String text) {
final String type = classification.getCollection().trim().toLowerCase(Locale.ENGLISH);
text = text.trim();
diff --git a/core/java/android/view/textclassifier/TextClassifierImplNative.java b/core/java/android/view/textclassifier/TextClassifierImplNative.java
deleted file mode 100644
index 3d4c8f2..0000000
--- a/core/java/android/view/textclassifier/TextClassifierImplNative.java
+++ /dev/null
@@ -1,301 +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 android.view.textclassifier;
-
-import android.content.res.AssetFileDescriptor;
-
-/**
- * Java wrapper for TextClassifier native library interface. This library is used for detecting
- * entities in text.
- */
-final class TextClassifierImplNative {
-
- static {
- System.loadLibrary("textclassifier");
- }
-
- private final long mModelPtr;
-
- /**
- * Creates a new instance of TextClassifierImplNative, using the provided model image, given as
- * a file descriptor.
- */
- TextClassifierImplNative(int fd) {
- mModelPtr = nativeNew(fd);
- if (mModelPtr == 0L) {
- throw new IllegalArgumentException("Couldn't initialize TC from file descriptor.");
- }
- }
-
- /**
- * Creates a new instance of TextClassifierImplNative, using the provided model image, given as
- * a file path.
- */
- TextClassifierImplNative(String path) {
- mModelPtr = nativeNewFromPath(path);
- if (mModelPtr == 0L) {
- throw new IllegalArgumentException("Couldn't initialize TC from given file.");
- }
- }
-
- /**
- * Creates a new instance of TextClassifierImplNative, using the provided model image, given as
- * an AssetFileDescriptor.
- */
- TextClassifierImplNative(AssetFileDescriptor afd) {
- mModelPtr = nativeNewFromAssetFileDescriptor(afd, afd.getStartOffset(), afd.getLength());
- if (mModelPtr == 0L) {
- throw new IllegalArgumentException(
- "Couldn't initialize TC from given AssetFileDescriptor");
- }
- }
-
- /**
- * Given a string context and current selection, computes the SmartSelection suggestion.
- *
- * <p>The begin and end are character indices into the context UTF8 string. selectionBegin is
- * the character index where the selection begins, and selectionEnd is the index of one
- * character past the selection span.
- *
- * <p>The return value is an array of two ints: suggested selection beginning and end, with the
- * same semantics as the input selectionBeginning and selectionEnd.
- */
- public int[] suggestSelection(
- String context, int selectionBegin, int selectionEnd, SelectionOptions options) {
- return nativeSuggestSelection(mModelPtr, context, selectionBegin, selectionEnd, options);
- }
-
- /**
- * Given a string context and current selection, classifies the type of the selected text.
- *
- * <p>The begin and end params are character indices in the context string.
- *
- * <p>Returns an array of ClassificationResult objects with the probability scores for different
- * collections.
- */
- public ClassificationResult[] classifyText(
- String context, int selectionBegin, int selectionEnd, ClassificationOptions options) {
- return nativeClassifyText(mModelPtr, context, selectionBegin, selectionEnd, options);
- }
-
- /**
- * Annotates given input text. The annotations should cover the whole input context except for
- * whitespaces, and are sorted by their position in the context string.
- */
- public AnnotatedSpan[] annotate(String text, AnnotationOptions options) {
- return nativeAnnotate(mModelPtr, text, options);
- }
-
- /** Frees up the allocated memory. */
- public void close() {
- nativeClose(mModelPtr);
- }
-
- /** Returns a comma separated list of locales supported by the model as BCP 47 tags. */
- public static String getLocales(int fd) {
- return nativeGetLocales(fd);
- }
-
- /** Returns the version of the model. */
- public static int getVersion(int fd) {
- return nativeGetVersion(fd);
- }
-
- /** Represents a datetime parsing result from classifyText calls. */
- public static final class DatetimeResult {
- static final int GRANULARITY_YEAR = 0;
- static final int GRANULARITY_MONTH = 1;
- static final int GRANULARITY_WEEK = 2;
- static final int GRANULARITY_DAY = 3;
- static final int GRANULARITY_HOUR = 4;
- static final int GRANULARITY_MINUTE = 5;
- static final int GRANULARITY_SECOND = 6;
-
- private final long mTimeMsUtc;
- private final int mGranularity;
-
- DatetimeResult(long timeMsUtc, int granularity) {
- mGranularity = granularity;
- mTimeMsUtc = timeMsUtc;
- }
-
- public long getTimeMsUtc() {
- return mTimeMsUtc;
- }
-
- public int getGranularity() {
- return mGranularity;
- }
- }
-
- /** Represents a result of classifyText method call. */
- public static final class ClassificationResult {
- private final String mCollection;
- private final float mScore;
- private final DatetimeResult mDatetimeResult;
-
- ClassificationResult(
- String collection, float score, DatetimeResult datetimeResult) {
- mCollection = collection;
- mScore = score;
- mDatetimeResult = datetimeResult;
- }
-
- public String getCollection() {
- if (mCollection.equals(TextClassifier.TYPE_DATE) && mDatetimeResult != null) {
- switch (mDatetimeResult.getGranularity()) {
- case DatetimeResult.GRANULARITY_HOUR:
- // fall through
- case DatetimeResult.GRANULARITY_MINUTE:
- // fall through
- case DatetimeResult.GRANULARITY_SECOND:
- return TextClassifier.TYPE_DATE_TIME;
- default:
- return TextClassifier.TYPE_DATE;
- }
- }
- return mCollection;
- }
-
- public float getScore() {
- return mScore;
- }
-
- public DatetimeResult getDatetimeResult() {
- return mDatetimeResult;
- }
- }
-
- /** Represents a result of Annotate call. */
- public static final class AnnotatedSpan {
- private final int mStartIndex;
- private final int mEndIndex;
- private final ClassificationResult[] mClassification;
-
- AnnotatedSpan(
- int startIndex, int endIndex, ClassificationResult[] classification) {
- mStartIndex = startIndex;
- mEndIndex = endIndex;
- mClassification = classification;
- }
-
- public int getStartIndex() {
- return mStartIndex;
- }
-
- public int getEndIndex() {
- return mEndIndex;
- }
-
- public ClassificationResult[] getClassification() {
- return mClassification;
- }
- }
-
- /** Represents options for the suggestSelection call. */
- public static final class SelectionOptions {
- private final String mLocales;
-
- SelectionOptions(String locales) {
- mLocales = locales;
- }
-
- public String getLocales() {
- return mLocales;
- }
- }
-
- /** Represents options for the classifyText call. */
- public static final class ClassificationOptions {
- private final long mReferenceTimeMsUtc;
- private final String mReferenceTimezone;
- private final String mLocales;
-
- ClassificationOptions(long referenceTimeMsUtc, String referenceTimezone, String locale) {
- mReferenceTimeMsUtc = referenceTimeMsUtc;
- mReferenceTimezone = referenceTimezone;
- mLocales = locale;
- }
-
- public long getReferenceTimeMsUtc() {
- return mReferenceTimeMsUtc;
- }
-
- public String getReferenceTimezone() {
- return mReferenceTimezone;
- }
-
- public String getLocale() {
- return mLocales;
- }
- }
-
- /** Represents options for the Annotate call. */
- public static final class AnnotationOptions {
- private final long mReferenceTimeMsUtc;
- private final String mReferenceTimezone;
- private final String mLocales;
-
- AnnotationOptions(long referenceTimeMsUtc, String referenceTimezone, String locale) {
- mReferenceTimeMsUtc = referenceTimeMsUtc;
- mReferenceTimezone = referenceTimezone;
- mLocales = locale;
- }
-
- public long getReferenceTimeMsUtc() {
- return mReferenceTimeMsUtc;
- }
-
- public String getReferenceTimezone() {
- return mReferenceTimezone;
- }
-
- public String getLocale() {
- return mLocales;
- }
- }
-
- private static native long nativeNew(int fd);
-
- private static native long nativeNewFromPath(String path);
-
- private static native long nativeNewFromAssetFileDescriptor(
- AssetFileDescriptor afd, long offset, long size);
-
- private static native int[] nativeSuggestSelection(
- long context,
- String text,
- int selectionBegin,
- int selectionEnd,
- SelectionOptions options);
-
- private static native ClassificationResult[] nativeClassifyText(
- long context,
- String text,
- int selectionBegin,
- int selectionEnd,
- ClassificationOptions options);
-
- private static native AnnotatedSpan[] nativeAnnotate(
- long context, String text, AnnotationOptions options);
-
- private static native void nativeClose(long context);
-
- private static native String nativeGetLocales(int fd);
-
- private static native int nativeGetVersion(int fd);
-}
diff --git a/core/java/android/webkit/CookieManager.java b/core/java/android/webkit/CookieManager.java
index ae6a2fd..23d1237 100644
--- a/core/java/android/webkit/CookieManager.java
+++ b/core/java/android/webkit/CookieManager.java
@@ -25,6 +25,13 @@
* Cookies are manipulated according to RFC2109.
*/
public abstract class CookieManager {
+ /**
+ * @deprecated This class should not be constructed by applications, use {@link #getInstance}
+ * instead to fetch the singleton instance.
+ */
+ // TODO(ntfschr): mark this as @SystemApi after a year.
+ @Deprecated
+ public CookieManager() {}
@Override
protected Object clone() throws CloneNotSupportedException {
diff --git a/core/java/android/webkit/RenderProcessGoneDetail.java b/core/java/android/webkit/RenderProcessGoneDetail.java
index 0843e26..9beeaa5 100644
--- a/core/java/android/webkit/RenderProcessGoneDetail.java
+++ b/core/java/android/webkit/RenderProcessGoneDetail.java
@@ -22,6 +22,13 @@
**/
public abstract class RenderProcessGoneDetail {
/**
+ * @deprecated This class should not be constructed by applications.
+ */
+ // TODO(ntfschr): mark this as @SystemApi after a year.
+ @Deprecated
+ public RenderProcessGoneDetail() {}
+
+ /**
* Indicates whether the render process was observed to crash, or whether
* it was killed by the system.
*
diff --git a/core/java/android/webkit/SafeBrowsingResponse.java b/core/java/android/webkit/SafeBrowsingResponse.java
index 7839a00..ca33a0c 100644
--- a/core/java/android/webkit/SafeBrowsingResponse.java
+++ b/core/java/android/webkit/SafeBrowsingResponse.java
@@ -27,6 +27,12 @@
* {@link android.webkit.WebView#getSafeBrowsingPrivacyPolicyUrl()}.
*/
public abstract class SafeBrowsingResponse {
+ /**
+ * @deprecated This class should not be constructed by applications.
+ */
+ // TODO(ntfschr): mark this as @SystemApi after a year.
+ @Deprecated
+ public SafeBrowsingResponse() {}
/**
* Display the default interstitial.
diff --git a/core/java/android/webkit/ServiceWorkerController.java b/core/java/android/webkit/ServiceWorkerController.java
index 3517c74..d7e0715 100644
--- a/core/java/android/webkit/ServiceWorkerController.java
+++ b/core/java/android/webkit/ServiceWorkerController.java
@@ -38,6 +38,14 @@
public abstract class ServiceWorkerController {
/**
+ * @deprecated This class should not be constructed by applications, use {@link #getInstance()}
+ * instead to fetch the singleton instance.
+ */
+ // TODO(ntfschr): mark this as @SystemApi after a year.
+ @Deprecated
+ public ServiceWorkerController() {}
+
+ /**
* Returns the default ServiceWorkerController instance. At present there is
* only one ServiceWorkerController instance for all WebView instances,
* however this restriction may be relaxed in the future.
diff --git a/core/java/android/webkit/TracingController.java b/core/java/android/webkit/TracingController.java
index 30f465c..9908182 100644
--- a/core/java/android/webkit/TracingController.java
+++ b/core/java/android/webkit/TracingController.java
@@ -43,6 +43,13 @@
* </pre></p>
*/
public abstract class TracingController {
+ /**
+ * @deprecated This class should not be constructed by applications, use {@link #getInstance}
+ * instead to fetch the singleton instance.
+ */
+ // TODO(ntfschr): mark this as @SystemApi after a year.
+ @Deprecated
+ public TracingController() {}
/**
* Returns the default TracingController instance. At present there is
diff --git a/core/java/android/webkit/WebViewDatabase.java b/core/java/android/webkit/WebViewDatabase.java
index f6166c5..f346c60 100644
--- a/core/java/android/webkit/WebViewDatabase.java
+++ b/core/java/android/webkit/WebViewDatabase.java
@@ -31,6 +31,14 @@
*/
public abstract class WebViewDatabase {
/**
+ * @deprecated This class should not be constructed by applications, use {@link
+ * #getInstance(Context)} instead to fetch the singleton instance.
+ */
+ // TODO(ntfschr): mark this as @SystemApi after a year.
+ @Deprecated
+ public WebViewDatabase() {}
+
+ /**
* @hide Since API level {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}
*/
protected static final String LOGTAG = "webviewdatabase";
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index bbfac44..f95b3ce 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -321,6 +321,12 @@
* @attr ref android.R.styleable#TextView_autoSizeMaxTextSize
* @attr ref android.R.styleable#TextView_autoSizeStepGranularity
* @attr ref android.R.styleable#TextView_autoSizePresetSizes
+ * @attr ref android.R.styleable#TextView_textCursorDrawable
+ * @attr ref android.R.styleable#TextView_textSelectHandle
+ * @attr ref android.R.styleable#TextView_textSelectHandleLeft
+ * @attr ref android.R.styleable#TextView_textSelectHandleRight
+ * @attr ref android.R.styleable#TextView_allowUndo
+ * @attr ref android.R.styleable#TextView_enabled
*/
@RemoteView
public class TextView extends View implements ViewTreeObserver.OnPreDrawListener {
diff --git a/core/java/com/android/internal/app/procstats/IProcessStats.aidl b/core/java/com/android/internal/app/procstats/IProcessStats.aidl
index 44867c7..0c203ab 100644
--- a/core/java/com/android/internal/app/procstats/IProcessStats.aidl
+++ b/core/java/com/android/internal/app/procstats/IProcessStats.aidl
@@ -24,4 +24,14 @@
byte[] getCurrentStats(out List<ParcelFileDescriptor> historic);
ParcelFileDescriptor getStatsOverTime(long minTime);
int getCurrentMemoryState();
+
+ /**
+ * Get stats committed after highWaterMarkMs
+ * @param highWaterMarkMs Report stats committed after this time.
+ * @param section Integer mask to indicate which sections to include in the stats.
+ * @param doAggregate Whether to aggregate the stats or keep them separated.
+ * @param List of Files of individual commits in protobuf binary or one that is merged from them.
+ */
+ long getCommittedStats(long highWaterMarkMs, int section, boolean doAggregate,
+ out List<ParcelFileDescriptor> committedStats);
}
diff --git a/core/java/com/android/internal/app/procstats/ProcessStats.java b/core/java/com/android/internal/app/procstats/ProcessStats.java
index f6e99ba..e7ac566 100644
--- a/core/java/com/android/internal/app/procstats/ProcessStats.java
+++ b/core/java/com/android/internal/app/procstats/ProcessStats.java
@@ -158,6 +158,25 @@
STATE_CACHED_ACTIVITY_CLIENT, STATE_CACHED_EMPTY
};
+ // Should report process stats.
+ public static final int REPORT_PROC_STATS = 0x01;
+ // Should report package process stats.
+ public static final int REPORT_PKG_PROC_STATS = 0x02;
+ // Should report package service stats.
+ public static final int REPORT_PKG_SVC_STATS = 0x04;
+ // Should report package association stats.
+ public static final int REPORT_PKG_ASC_STATS = 0x08;
+ // Should report package stats.
+ public static final int REPORT_PKG_STATS = 0x0E;
+ // Should report all stats.
+ public static final int REPORT_ALL = 0x0F;
+
+ public static final int[] OPTIONS =
+ {REPORT_PROC_STATS, REPORT_PKG_PROC_STATS, REPORT_PKG_SVC_STATS, REPORT_PKG_ASC_STATS,
+ REPORT_PKG_STATS, REPORT_ALL};
+ public static final String[] OPTIONS_STR =
+ {"proc", "pkg-proc", "pkg-svc", "pkg-asc", "pkg-all", "all"};
+
// Current version of the parcel format.
private static final int PARCEL_VERSION = 34;
// In-memory Parcel magic number, used to detect attempts to unmarshall bad data
@@ -1412,7 +1431,7 @@
}
public void dumpLocked(PrintWriter pw, String reqPackage, long now, boolean dumpSummary,
- boolean dumpDetails, boolean dumpAll, boolean activeOnly) {
+ boolean dumpDetails, boolean dumpAll, boolean activeOnly, int section) {
long totalTime = DumpUtils.dumpSingleTime(null, null, mMemFactorDurations, mMemFactor,
mStartTime, now);
boolean sepNeeded = false;
@@ -1421,176 +1440,205 @@
mSysMemUsage.dump(pw, " ", ALL_SCREEN_ADJ, ALL_MEM_ADJ);
sepNeeded = true;
}
- ArrayMap<String, SparseArray<LongSparseArray<PackageState>>> pkgMap = mPackages.getMap();
boolean printedHeader = false;
- for (int ip=0; ip<pkgMap.size(); ip++) {
- final String pkgName = pkgMap.keyAt(ip);
- final SparseArray<LongSparseArray<PackageState>> uids = pkgMap.valueAt(ip);
- for (int iu=0; iu<uids.size(); iu++) {
- final int uid = uids.keyAt(iu);
- final LongSparseArray<PackageState> vpkgs = uids.valueAt(iu);
- for (int iv=0; iv<vpkgs.size(); iv++) {
- final long vers = vpkgs.keyAt(iv);
- final PackageState pkgState = vpkgs.valueAt(iv);
- final int NPROCS = pkgState.mProcesses.size();
- final int NSRVS = pkgState.mServices.size();
- final int NASCS = pkgState.mAssociations.size();
- final boolean pkgMatch = reqPackage == null || reqPackage.equals(pkgName);
- if (!pkgMatch) {
- boolean procMatch = false;
- for (int iproc=0; iproc<NPROCS; iproc++) {
- ProcessState proc = pkgState.mProcesses.valueAt(iproc);
- if (reqPackage.equals(proc.getName())) {
- procMatch = true;
- break;
+ if ((section & REPORT_PKG_STATS) != 0) {
+ ArrayMap<String, SparseArray<LongSparseArray<PackageState>>> pkgMap =
+ mPackages.getMap();
+ for (int ip = 0; ip < pkgMap.size(); ip++) {
+ final String pkgName = pkgMap.keyAt(ip);
+ final SparseArray<LongSparseArray<PackageState>> uids = pkgMap.valueAt(ip);
+ for (int iu = 0; iu < uids.size(); iu++) {
+ final int uid = uids.keyAt(iu);
+ final LongSparseArray<PackageState> vpkgs = uids.valueAt(iu);
+ for (int iv = 0; iv < vpkgs.size(); iv++) {
+ final long vers = vpkgs.keyAt(iv);
+ final PackageState pkgState = vpkgs.valueAt(iv);
+ final int NPROCS = pkgState.mProcesses.size();
+ final int NSRVS = pkgState.mServices.size();
+ final int NASCS = pkgState.mAssociations.size();
+ final boolean pkgMatch = reqPackage == null || reqPackage.equals(pkgName);
+ if (!pkgMatch) {
+ boolean procMatch = false;
+ for (int iproc = 0; iproc < NPROCS; iproc++) {
+ ProcessState proc = pkgState.mProcesses.valueAt(iproc);
+ if (reqPackage.equals(proc.getName())) {
+ procMatch = true;
+ break;
+ }
}
- }
- if (!procMatch) {
- continue;
- }
- }
- if (NPROCS > 0 || NSRVS > 0 || NASCS > 0) {
- if (!printedHeader) {
- if (sepNeeded) pw.println();
- pw.println("Per-Package Stats:");
- printedHeader = true;
- sepNeeded = true;
- }
- pw.print(" * "); pw.print(pkgName); pw.print(" / ");
- UserHandle.formatUid(pw, uid); pw.print(" / v");
- pw.print(vers); pw.println(":");
- }
- if (!dumpSummary || dumpAll) {
- for (int iproc=0; iproc<NPROCS; iproc++) {
- ProcessState proc = pkgState.mProcesses.valueAt(iproc);
- if (!pkgMatch && !reqPackage.equals(proc.getName())) {
+ if (!procMatch) {
continue;
}
- if (activeOnly && !proc.isInUse()) {
- pw.print(" (Not active: ");
- pw.print(pkgState.mProcesses.keyAt(iproc)); pw.println(")");
- continue;
+ }
+ if (NPROCS > 0 || NSRVS > 0 || NASCS > 0) {
+ if (!printedHeader) {
+ if (sepNeeded) pw.println();
+ pw.println("Per-Package Stats:");
+ printedHeader = true;
+ sepNeeded = true;
}
- pw.print(" Process ");
- pw.print(pkgState.mProcesses.keyAt(iproc));
- if (proc.getCommonProcess().isMultiPackage()) {
- pw.print(" (multi, ");
- } else {
- pw.print(" (unique, ");
- }
- pw.print(proc.getDurationsBucketCount());
- pw.print(" entries)");
+ pw.print(" * ");
+ pw.print(pkgName);
+ pw.print(" / ");
+ UserHandle.formatUid(pw, uid);
+ pw.print(" / v");
+ pw.print(vers);
pw.println(":");
- proc.dumpProcessState(pw, " ", ALL_SCREEN_ADJ, ALL_MEM_ADJ,
- ALL_PROC_STATES, now);
- proc.dumpPss(pw, " ", ALL_SCREEN_ADJ, ALL_MEM_ADJ,
- ALL_PROC_STATES, now);
- proc.dumpInternalLocked(pw, " ", dumpAll);
}
- } else {
- ArrayList<ProcessState> procs = new ArrayList<ProcessState>();
- for (int iproc=0; iproc<NPROCS; iproc++) {
- ProcessState proc = pkgState.mProcesses.valueAt(iproc);
- if (!pkgMatch && !reqPackage.equals(proc.getName())) {
- continue;
+ if ((section & REPORT_PKG_PROC_STATS) != 0) {
+ if (!dumpSummary || dumpAll) {
+ for (int iproc = 0; iproc < NPROCS; iproc++) {
+ ProcessState proc = pkgState.mProcesses.valueAt(iproc);
+ if (!pkgMatch && !reqPackage.equals(proc.getName())) {
+ continue;
+ }
+ if (activeOnly && !proc.isInUse()) {
+ pw.print(" (Not active: ");
+ pw.print(pkgState.mProcesses.keyAt(iproc));
+ pw.println(")");
+ continue;
+ }
+ pw.print(" Process ");
+ pw.print(pkgState.mProcesses.keyAt(iproc));
+ if (proc.getCommonProcess().isMultiPackage()) {
+ pw.print(" (multi, ");
+ } else {
+ pw.print(" (unique, ");
+ }
+ pw.print(proc.getDurationsBucketCount());
+ pw.print(" entries)");
+ pw.println(":");
+ proc.dumpProcessState(pw, " ", ALL_SCREEN_ADJ,
+ ALL_MEM_ADJ,
+ ALL_PROC_STATES, now);
+ proc.dumpPss(pw, " ", ALL_SCREEN_ADJ, ALL_MEM_ADJ,
+ ALL_PROC_STATES, now);
+ proc.dumpInternalLocked(pw, " ", dumpAll);
+ }
+ } else {
+ ArrayList<ProcessState> procs = new ArrayList<ProcessState>();
+ for (int iproc = 0; iproc < NPROCS; iproc++) {
+ ProcessState proc = pkgState.mProcesses.valueAt(iproc);
+ if (!pkgMatch && !reqPackage.equals(proc.getName())) {
+ continue;
+ }
+ if (activeOnly && !proc.isInUse()) {
+ continue;
+ }
+ procs.add(proc);
+ }
+ DumpUtils.dumpProcessSummaryLocked(pw, " ", "Prc ", procs,
+ ALL_SCREEN_ADJ, ALL_MEM_ADJ, NON_CACHED_PROC_STATES,
+ now, totalTime);
}
- if (activeOnly && !proc.isInUse()) {
- continue;
+ }
+ if ((section & REPORT_PKG_SVC_STATS) != 0) {
+ for (int isvc = 0; isvc < NSRVS; isvc++) {
+ ServiceState svc = pkgState.mServices.valueAt(isvc);
+ if (!pkgMatch && !reqPackage.equals(svc.getProcessName())) {
+ continue;
+ }
+ if (activeOnly && !svc.isInUse()) {
+ pw.print(" (Not active service: ");
+ pw.print(pkgState.mServices.keyAt(isvc));
+ pw.println(")");
+ continue;
+ }
+ if (dumpAll) {
+ pw.print(" Service ");
+ } else {
+ pw.print(" * Svc ");
+ }
+ pw.print(pkgState.mServices.keyAt(isvc));
+ pw.println(":");
+ pw.print(" Process: ");
+ pw.println(svc.getProcessName());
+ svc.dumpStats(pw, " ", " ", " ",
+ now, totalTime, dumpSummary, dumpAll);
}
- procs.add(proc);
}
- DumpUtils.dumpProcessSummaryLocked(pw, " ", "Prc ", procs,
- ALL_SCREEN_ADJ, ALL_MEM_ADJ, NON_CACHED_PROC_STATES,
- now, totalTime);
- }
- for (int isvc=0; isvc<NSRVS; isvc++) {
- ServiceState svc = pkgState.mServices.valueAt(isvc);
- if (!pkgMatch && !reqPackage.equals(svc.getProcessName())) {
- continue;
+ if ((section & REPORT_PKG_ASC_STATS) != 0) {
+ for (int iasc = 0; iasc < NASCS; iasc++) {
+ AssociationState asc = pkgState.mAssociations.valueAt(iasc);
+ if (!pkgMatch && !reqPackage.equals(asc.getProcessName())) {
+ continue;
+ }
+ if (activeOnly && !asc.isInUse()) {
+ pw.print(" (Not active association: ");
+ pw.print(pkgState.mAssociations.keyAt(iasc));
+ pw.println(")");
+ continue;
+ }
+ if (dumpAll) {
+ pw.print(" Association ");
+ } else {
+ pw.print(" * Asc ");
+ }
+ pw.print(pkgState.mAssociations.keyAt(iasc));
+ pw.println(":");
+ pw.print(" Process: ");
+ pw.println(asc.getProcessName());
+ asc.dumpStats(pw, " ", " ", " ",
+ now, totalTime, dumpDetails, dumpAll);
+ }
}
- if (activeOnly && !svc.isInUse()) {
- pw.print(" (Not active service: ");
- pw.print(pkgState.mServices.keyAt(isvc)); pw.println(")");
- continue;
- }
- if (dumpAll) {
- pw.print(" Service ");
- } else {
- pw.print(" * Svc ");
- }
- pw.print(pkgState.mServices.keyAt(isvc));
- pw.println(":");
- pw.print(" Process: "); pw.println(svc.getProcessName());
- svc.dumpStats(pw, " ", " ", " ",
- now, totalTime, dumpSummary, dumpAll);
- }
- for (int iasc=0; iasc<NASCS; iasc++) {
- AssociationState asc = pkgState.mAssociations.valueAt(iasc);
- if (!pkgMatch && !reqPackage.equals(asc.getProcessName())) {
- continue;
- }
- if (activeOnly && !asc.isInUse()) {
- pw.print(" (Not active association: ");
- pw.print(pkgState.mAssociations.keyAt(iasc)); pw.println(")");
- continue;
- }
- if (dumpAll) {
- pw.print(" Association ");
- } else {
- pw.print(" * Asc ");
- }
- pw.print(pkgState.mAssociations.keyAt(iasc));
- pw.println(":");
- pw.print(" Process: "); pw.println(asc.getProcessName());
- asc.dumpStats(pw, " ", " ", " ",
- now, totalTime, dumpDetails, dumpAll);
}
}
}
}
- ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
- printedHeader = false;
- int numShownProcs = 0, numTotalProcs = 0;
- for (int ip=0; ip<procMap.size(); ip++) {
- String procName = procMap.keyAt(ip);
- SparseArray<ProcessState> uids = procMap.valueAt(ip);
- for (int iu=0; iu<uids.size(); iu++) {
- int uid = uids.keyAt(iu);
- numTotalProcs++;
- final ProcessState proc = uids.valueAt(iu);
- if (!proc.hasAnyData()) {
- continue;
+ if ((section & REPORT_PROC_STATS) != 0) {
+ ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
+ printedHeader = false;
+ int numShownProcs = 0, numTotalProcs = 0;
+ for (int ip = 0; ip < procMap.size(); ip++) {
+ String procName = procMap.keyAt(ip);
+ SparseArray<ProcessState> uids = procMap.valueAt(ip);
+ for (int iu = 0; iu < uids.size(); iu++) {
+ int uid = uids.keyAt(iu);
+ numTotalProcs++;
+ final ProcessState proc = uids.valueAt(iu);
+ if (!proc.hasAnyData()) {
+ continue;
+ }
+ if (!proc.isMultiPackage()) {
+ continue;
+ }
+ if (reqPackage != null && !reqPackage.equals(procName)
+ && !reqPackage.equals(proc.getPackage())) {
+ continue;
+ }
+ numShownProcs++;
+ if (sepNeeded) {
+ pw.println();
+ }
+ sepNeeded = true;
+ if (!printedHeader) {
+ pw.println("Multi-Package Common Processes:");
+ printedHeader = true;
+ }
+ if (activeOnly && !proc.isInUse()) {
+ pw.print(" (Not active: ");
+ pw.print(procName);
+ pw.println(")");
+ continue;
+ }
+ pw.print(" * ");
+ pw.print(procName);
+ pw.print(" / ");
+ UserHandle.formatUid(pw, uid);
+ pw.print(" (");
+ pw.print(proc.getDurationsBucketCount());
+ pw.print(" entries)");
+ pw.println(":");
+ proc.dumpProcessState(pw, " ", ALL_SCREEN_ADJ, ALL_MEM_ADJ,
+ ALL_PROC_STATES, now);
+ proc.dumpPss(pw, " ", ALL_SCREEN_ADJ, ALL_MEM_ADJ, ALL_PROC_STATES, now);
+ proc.dumpInternalLocked(pw, " ", dumpAll);
}
- if (!proc.isMultiPackage()) {
- continue;
- }
- if (reqPackage != null && !reqPackage.equals(procName)
- && !reqPackage.equals(proc.getPackage())) {
- continue;
- }
- numShownProcs++;
- if (sepNeeded) {
- pw.println();
- }
- sepNeeded = true;
- if (!printedHeader) {
- pw.println("Multi-Package Common Processes:");
- printedHeader = true;
- }
- if (activeOnly && !proc.isInUse()) {
- pw.print(" (Not active: "); pw.print(procName); pw.println(")");
- continue;
- }
- pw.print(" * "); pw.print(procName); pw.print(" / ");
- UserHandle.formatUid(pw, uid);
- pw.print(" ("); pw.print(proc.getDurationsBucketCount());
- pw.print(" entries)"); pw.println(":");
- proc.dumpProcessState(pw, " ", ALL_SCREEN_ADJ, ALL_MEM_ADJ,
- ALL_PROC_STATES, now);
- proc.dumpPss(pw, " ", ALL_SCREEN_ADJ, ALL_MEM_ADJ, ALL_PROC_STATES, now);
- proc.dumpInternalLocked(pw, " ", dumpAll);
}
+ pw.print(" Total procs: "); pw.print(numShownProcs);
+ pw.print(" shown of "); pw.print(numTotalProcs); pw.println(" total");
}
if (dumpAll) {
@@ -1598,8 +1646,7 @@
pw.println();
}
sepNeeded = true;
- pw.print(" Total procs: "); pw.print(numShownProcs);
- pw.print(" shown of "); pw.print(numTotalProcs); pw.println(" total");
+
if (mTrackingAssociations.size() > 0) {
pw.println();
pw.println("Tracking associations:");
@@ -1866,7 +1913,10 @@
return outProcs;
}
- public void dumpCheckinLocked(PrintWriter pw, String reqPackage) {
+ /**
+ * Prints checkin style stats dump.
+ */
+ public void dumpCheckinLocked(PrintWriter pw, String reqPackage, int section) {
final long now = SystemClock.uptimeMillis();
final ArrayMap<String, SparseArray<LongSparseArray<PackageState>>> pkgMap =
mPackages.getMap();
@@ -1895,50 +1945,61 @@
}
pw.println();
pw.print("config,"); pw.println(mRuntime);
- for (int ip=0; ip<pkgMap.size(); ip++) {
- final String pkgName = pkgMap.keyAt(ip);
- if (reqPackage != null && !reqPackage.equals(pkgName)) {
- continue;
- }
- final SparseArray<LongSparseArray<PackageState>> uids = pkgMap.valueAt(ip);
- for (int iu=0; iu<uids.size(); iu++) {
- final int uid = uids.keyAt(iu);
- final LongSparseArray<PackageState> vpkgs = uids.valueAt(iu);
- for (int iv=0; iv<vpkgs.size(); iv++) {
- final long vers = vpkgs.keyAt(iv);
- final PackageState pkgState = vpkgs.valueAt(iv);
- final int NPROCS = pkgState.mProcesses.size();
- final int NSRVS = pkgState.mServices.size();
- final int NASCS = pkgState.mAssociations.size();
- for (int iproc=0; iproc<NPROCS; iproc++) {
- ProcessState proc = pkgState.mProcesses.valueAt(iproc);
- proc.dumpPackageProcCheckin(pw, pkgName, uid, vers,
- pkgState.mProcesses.keyAt(iproc), now);
- }
- for (int isvc=0; isvc<NSRVS; isvc++) {
- final String serviceName = DumpUtils.collapseString(pkgName,
- pkgState.mServices.keyAt(isvc));
- final ServiceState svc = pkgState.mServices.valueAt(isvc);
- svc.dumpTimesCheckin(pw, pkgName, uid, vers, serviceName, now);
- }
- for (int iasc=0; iasc<NASCS; iasc++) {
- final String associationName = DumpUtils.collapseString(pkgName,
- pkgState.mAssociations.keyAt(iasc));
- final AssociationState asc = pkgState.mAssociations.valueAt(iasc);
- asc.dumpTimesCheckin(pw, pkgName, uid, vers, associationName, now);
+
+ if ((section & REPORT_PKG_STATS) != 0) {
+ for (int ip = 0; ip < pkgMap.size(); ip++) {
+ final String pkgName = pkgMap.keyAt(ip);
+ if (reqPackage != null && !reqPackage.equals(pkgName)) {
+ continue;
+ }
+ final SparseArray<LongSparseArray<PackageState>> uids = pkgMap.valueAt(ip);
+ for (int iu = 0; iu < uids.size(); iu++) {
+ final int uid = uids.keyAt(iu);
+ final LongSparseArray<PackageState> vpkgs = uids.valueAt(iu);
+ for (int iv = 0; iv < vpkgs.size(); iv++) {
+ final long vers = vpkgs.keyAt(iv);
+ final PackageState pkgState = vpkgs.valueAt(iv);
+ final int NPROCS = pkgState.mProcesses.size();
+ final int NSRVS = pkgState.mServices.size();
+ final int NASCS = pkgState.mAssociations.size();
+ if ((section & REPORT_PKG_PROC_STATS) != 0) {
+ for (int iproc = 0; iproc < NPROCS; iproc++) {
+ ProcessState proc = pkgState.mProcesses.valueAt(iproc);
+ proc.dumpPackageProcCheckin(pw, pkgName, uid, vers,
+ pkgState.mProcesses.keyAt(iproc), now);
+ }
+ }
+ if ((section & REPORT_PKG_SVC_STATS) != 0) {
+ for (int isvc = 0; isvc < NSRVS; isvc++) {
+ final String serviceName = DumpUtils.collapseString(pkgName,
+ pkgState.mServices.keyAt(isvc));
+ final ServiceState svc = pkgState.mServices.valueAt(isvc);
+ svc.dumpTimesCheckin(pw, pkgName, uid, vers, serviceName, now);
+ }
+ }
+ if ((section & REPORT_PKG_ASC_STATS) != 0) {
+ for (int iasc = 0; iasc < NASCS; iasc++) {
+ final String associationName = DumpUtils.collapseString(pkgName,
+ pkgState.mAssociations.keyAt(iasc));
+ final AssociationState asc = pkgState.mAssociations.valueAt(iasc);
+ asc.dumpTimesCheckin(pw, pkgName, uid, vers, associationName, now);
+ }
+ }
}
}
}
}
- ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
- for (int ip=0; ip<procMap.size(); ip++) {
- String procName = procMap.keyAt(ip);
- SparseArray<ProcessState> uids = procMap.valueAt(ip);
- for (int iu=0; iu<uids.size(); iu++) {
- final int uid = uids.keyAt(iu);
- final ProcessState procState = uids.valueAt(iu);
- procState.dumpProcCheckin(pw, procName, uid, now);
+ if ((section & REPORT_PROC_STATS) != 0) {
+ ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
+ for (int ip = 0; ip < procMap.size(); ip++) {
+ String procName = procMap.keyAt(ip);
+ SparseArray<ProcessState> uids = procMap.valueAt(ip);
+ for (int iu = 0; iu < uids.size(); iu++) {
+ final int uid = uids.keyAt(iu);
+ final ProcessState procState = uids.valueAt(iu);
+ procState.dumpProcCheckin(pw, procName, uid, now);
+ }
}
}
pw.print("total");
@@ -2013,9 +2074,10 @@
}
}
- public void writeToProto(ProtoOutputStream proto, long fieldId, long now) {
- final long token = proto.start(fieldId);
-
+ /**
+ * Writes to ProtoOutputStream.
+ */
+ public void writeToProto(ProtoOutputStream proto, long now, int section) {
proto.write(ProcessStatsSectionProto.START_REALTIME_MS, mTimePeriodStartRealtime);
proto.write(ProcessStatsSectionProto.END_REALTIME_MS,
mRunning ? SystemClock.elapsedRealtime() : mTimePeriodEndRealtime);
@@ -2024,15 +2086,15 @@
proto.write(ProcessStatsSectionProto.RUNTIME, mRuntime);
proto.write(ProcessStatsSectionProto.HAS_SWAPPED_PSS, mHasSwappedOutPss);
boolean partial = true;
- if ((mFlags&FLAG_SHUTDOWN) != 0) {
+ if ((mFlags & FLAG_SHUTDOWN) != 0) {
proto.write(ProcessStatsSectionProto.STATUS, ProcessStatsSectionProto.STATUS_SHUTDOWN);
partial = false;
}
- if ((mFlags&FLAG_SYSPROPS) != 0) {
+ if ((mFlags & FLAG_SYSPROPS) != 0) {
proto.write(ProcessStatsSectionProto.STATUS, ProcessStatsSectionProto.STATUS_SYSPROPS);
partial = false;
}
- if ((mFlags&FLAG_COMPLETE) != 0) {
+ if ((mFlags & FLAG_COMPLETE) != 0) {
proto.write(ProcessStatsSectionProto.STATUS, ProcessStatsSectionProto.STATUS_COMPLETE);
partial = false;
}
@@ -2041,31 +2103,34 @@
}
final ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
- for (int ip=0; ip<procMap.size(); ip++) {
- final String procName = procMap.keyAt(ip);
- final SparseArray<ProcessState> uids = procMap.valueAt(ip);
- for (int iu=0; iu<uids.size(); iu++) {
- final int uid = uids.keyAt(iu);
- final ProcessState procState = uids.valueAt(iu);
- procState.writeToProto(proto, ProcessStatsSectionProto.PROCESS_STATS, procName,
- uid, now);
- }
- }
-
- final ArrayMap<String, SparseArray<LongSparseArray<PackageState>>> pkgMap =
- mPackages.getMap();
- for (int ip = 0; ip < pkgMap.size(); ip++) {
- final SparseArray<LongSparseArray<PackageState>> uids = pkgMap.valueAt(ip);
- for (int iu = 0; iu < uids.size(); iu++) {
- final LongSparseArray<PackageState> vers = uids.valueAt(iu);
- for (int iv = 0; iv < vers.size(); iv++) {
- final PackageState pkgState = vers.valueAt(iv);
- pkgState.writeToProto(proto, ProcessStatsSectionProto.PACKAGE_STATS, now);
+ if ((section & REPORT_PROC_STATS) != 0) {
+ for (int ip = 0; ip < procMap.size(); ip++) {
+ final String procName = procMap.keyAt(ip);
+ final SparseArray<ProcessState> uids = procMap.valueAt(ip);
+ for (int iu = 0; iu < uids.size(); iu++) {
+ final int uid = uids.keyAt(iu);
+ final ProcessState procState = uids.valueAt(iu);
+ procState.writeToProto(proto, ProcessStatsSectionProto.PROCESS_STATS, procName,
+ uid, now);
}
}
}
- proto.end(token);
+ if ((section & REPORT_PKG_STATS) != 0) {
+ final ArrayMap<String, SparseArray<LongSparseArray<PackageState>>> pkgMap =
+ mPackages.getMap();
+ for (int ip = 0; ip < pkgMap.size(); ip++) {
+ final SparseArray<LongSparseArray<PackageState>> uids = pkgMap.valueAt(ip);
+ for (int iu = 0; iu < uids.size(); iu++) {
+ final LongSparseArray<PackageState> vers = uids.valueAt(iu);
+ for (int iv = 0; iv < vers.size(); iv++) {
+ final PackageState pkgState = vers.valueAt(iv);
+ pkgState.writeToProto(proto, ProcessStatsSectionProto.PACKAGE_STATS, now,
+ section);
+ }
+ }
+ }
+ }
}
final public static class ProcessStateHolder {
@@ -2110,30 +2175,39 @@
return as;
}
- public void writeToProto(ProtoOutputStream proto, long fieldId, long now) {
+ /**
+ * Writes the containing stats into proto, with options to choose smaller sections.
+ */
+ public void writeToProto(ProtoOutputStream proto, long fieldId, long now, int section) {
final long token = proto.start(fieldId);
proto.write(ProcessStatsPackageProto.PACKAGE, mPackageName);
proto.write(ProcessStatsPackageProto.UID, mUid);
proto.write(ProcessStatsPackageProto.VERSION, mVersionCode);
- for (int ip = 0; ip < mProcesses.size(); ip++) {
- final String procName = mProcesses.keyAt(ip);
- final ProcessState procState = mProcesses.valueAt(ip);
- procState.writeToProto(proto, ProcessStatsPackageProto.PROCESS_STATS, procName,
- mUid, now);
+ if ((section & ProcessStats.REPORT_PKG_PROC_STATS) != 0) {
+ for (int ip = 0; ip < mProcesses.size(); ip++) {
+ final String procName = mProcesses.keyAt(ip);
+ final ProcessState procState = mProcesses.valueAt(ip);
+ procState.writeToProto(proto, ProcessStatsPackageProto.PROCESS_STATS, procName,
+ mUid, now);
+ }
}
- for (int is = 0; is < mServices.size(); is++) {
- final ServiceState serviceState = mServices.valueAt(is);
- serviceState.writeToProto(proto, ProcessStatsPackageProto.SERVICE_STATS,
- now);
+ if ((section & ProcessStats.REPORT_PKG_SVC_STATS) != 0) {
+ for (int is = 0; is < mServices.size(); is++) {
+ final ServiceState serviceState = mServices.valueAt(is);
+ serviceState.writeToProto(proto, ProcessStatsPackageProto.SERVICE_STATS,
+ now);
+ }
}
- for (int ia=0; ia<mAssociations.size(); ia++) {
- final AssociationState ascState = mAssociations.valueAt(ia);
- ascState.writeToProto(proto, ProcessStatsPackageProto.ASSOCIATION_STATS,
- now);
+ if ((section & ProcessStats.REPORT_PKG_ASC_STATS) != 0) {
+ for (int ia = 0; ia < mAssociations.size(); ia++) {
+ final AssociationState ascState = mAssociations.valueAt(ia);
+ ascState.writeToProto(proto, ProcessStatsPackageProto.ASSOCIATION_STATS,
+ now);
+ }
}
proto.end(token);
diff --git a/core/proto/android/server/activitymanagerservice.proto b/core/proto/android/server/activitymanagerservice.proto
index 9d5f0bc..ab50ad1 100644
--- a/core/proto/android/server/activitymanagerservice.proto
+++ b/core/proto/android/server/activitymanagerservice.proto
@@ -130,6 +130,13 @@
option (.android.msg_privacy).dest = DEST_AUTOMATIC;
optional bool keyguard_showing = 1;
+ repeated KeyguardOccludedProto keyguard_occluded_states= 2;
+}
+
+message KeyguardOccludedProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional int32 display_id = 1;
optional bool keyguard_occluded = 2;
}
diff --git a/core/res/res/values-television/themes.xml b/core/res/res/values-television/themes.xml
index 0712cbc..48b59c7 100644
--- a/core/res/res/values-television/themes.xml
+++ b/core/res/res/values-television/themes.xml
@@ -15,7 +15,6 @@
-->
<resources>
<style name="Theme.Dialog.Alert" parent="Theme.Leanback.Light.Dialog.Alert" />
- <style name="Theme.DeviceDefault.Dialog.AppError" parent="Theme.Leanback.Dialog.AppError" />
<style name="Theme.Holo.Dialog.Alert" parent="Theme.Leanback.Dialog.Alert" />
<style name="Theme.Holo.Light.Dialog.Alert" parent="Theme.Leanback.Light.Dialog.Alert" />
<style name="Theme.Material.Dialog.Alert" parent="Theme.Leanback.Dialog.Alert" />
diff --git a/core/res/res/values-television/themes_device_defaults.xml b/core/res/res/values-television/themes_device_defaults.xml
index b92c44e..fdd0624 100644
--- a/core/res/res/values-television/themes_device_defaults.xml
+++ b/core/res/res/values-television/themes_device_defaults.xml
@@ -15,6 +15,7 @@
-->
<resources>
<style name="Theme.DeviceDefault.Dialog.Alert" parent="Theme.Leanback.Dialog.Alert" />
+ <style name="Theme.DeviceDefault.Dialog.AppError" parent="Theme.Leanback.Dialog.AppError" />
<style name="Theme.DeviceDefault.Light.Dialog.Alert" parent="Theme.Leanback.Light.Dialog.Alert" />
<!-- TODO(b/116457731): remove colorBackground from colors_material.xml if not used anymore -->
diff --git a/core/res/res/values-watch/themes.xml b/core/res/res/values-watch/themes.xml
deleted file mode 100644
index 1be47ba..0000000
--- a/core/res/res/values-watch/themes.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 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.
--->
-<resources>
- <!-- Theme for the dialog shown when an app crashes or ANRs. Override to make it dark. -->
- <style name="Theme.DeviceDefault.Dialog.AppError" parent="Theme.DeviceDefault.Dialog.Alert">
- <item name="windowContentTransitions">false</item>
- <item name="windowActivityTransitions">false</item>
- <item name="windowCloseOnTouchOutside">false</item>
- </style>
-</resources>
diff --git a/core/res/res/values-watch/themes_device_defaults.xml b/core/res/res/values-watch/themes_device_defaults.xml
index a7736e7c..bfba312 100644
--- a/core/res/res/values-watch/themes_device_defaults.xml
+++ b/core/res/res/values-watch/themes_device_defaults.xml
@@ -422,6 +422,13 @@
<item name="secondaryContentAlpha">@dimen/secondary_content_alpha_device_default</item>
</style>
+ <!-- Theme for the dialog shown when an app crashes or ANRs. Override to make it dark. -->
+ <style name="Theme.DeviceDefault.Dialog.AppError" parent="Theme.DeviceDefault.Dialog.Alert">
+ <item name="windowContentTransitions">false</item>
+ <item name="windowActivityTransitions">false</item>
+ <item name="windowCloseOnTouchOutside">false</item>
+ </style>
+
<style name="Theme.DeviceDefault.SearchBar" parent="Theme.Material.SearchBar">
<!-- Color palette Dark -->
<item name="colorPrimary">@color/primary_device_default_dark</item>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 1404383..9aebf6c 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3541,4 +3541,13 @@
<!-- Brand value for attestation of misprovisioned device. -->
<string name="config_misprovisionedBrandValue" translatable="false"></string>
+
+ <!-- Pre-scale volume at volume step 1 for Absolute Volume -->
+ <fraction name="config_prescaleAbsoluteVolume_index1">50%</fraction>
+
+ <!-- Pre-scale volume at volume step 2 for Absolute Volume -->
+ <fraction name="config_prescaleAbsoluteVolume_index2">70%</fraction>
+
+ <!-- Pre-scale volume at volume step 3 for Absolute Volume -->
+ <fraction name="config_prescaleAbsoluteVolume_index3">85%</fraction>
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 21f0dad..9f2256a 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3470,4 +3470,9 @@
<java-symbol type="integer" name="db_wal_truncate_size" />
<java-symbol type="integer" name="config_wakeUpDelayDoze" />
<java-symbol type="string" name="config_dozeWakeScreenSensorType" />
+
+ <!-- For Bluetooth AbsoluteVolume -->
+ <java-symbol type="fraction" name="config_prescaleAbsoluteVolume_index1" />
+ <java-symbol type="fraction" name="config_prescaleAbsoluteVolume_index2" />
+ <java-symbol type="fraction" name="config_prescaleAbsoluteVolume_index3" />
</resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
index a710410..58feef5 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
@@ -102,7 +102,7 @@
BluetoothProfile.A2DP);
}
- public boolean isConnectable() {
+ public boolean accessProfileEnabled() {
return true;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
index e13e566..988062d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
@@ -96,7 +96,7 @@
BluetoothProfile.A2DP_SINK);
}
- public boolean isConnectable() {
+ public boolean accessProfileEnabled() {
return true;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index ecaeaf2..750a843 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -34,7 +34,6 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
-import java.util.HashMap;
import java.util.List;
import androidx.annotation.VisibleForTesting;
@@ -59,7 +58,6 @@
private long mHiSyncId;
// Need this since there is no method for getting RSSI
private short mRssi;
- private HashMap<LocalBluetoothProfile, Integer> mProfileConnectionState;
private final List<LocalBluetoothProfile> mProfiles =
new ArrayList<LocalBluetoothProfile>();
@@ -101,7 +99,6 @@
mLocalAdapter = BluetoothAdapter.getDefaultAdapter();
mProfileManager = profileManager;
mDevice = device;
- mProfileConnectionState = new HashMap<>();
fillData();
mHiSyncId = BluetoothHearingAid.HI_SYNC_ID_INVALID;
}
@@ -134,7 +131,6 @@
}
return;
}
- mProfileConnectionState.put(profile, newProfileState);
if (newProfileState == BluetoothProfile.STATE_CONNECTED) {
if (profile instanceof MapProfile) {
profile.setPreferred(mDevice, true);
@@ -226,7 +222,7 @@
int preferredProfiles = 0;
for (LocalBluetoothProfile profile : mProfiles) {
- if (connectAllProfiles ? profile.isConnectable() : profile.isAutoConnectable()) {
+ if (connectAllProfiles ? profile.accessProfileEnabled() : profile.isAutoConnectable()) {
if (profile.isPreferred(mDevice)) {
++preferredProfiles;
connectInt(profile);
@@ -324,22 +320,9 @@
}
public int getProfileConnectionState(LocalBluetoothProfile profile) {
- if (mProfileConnectionState.get(profile) == null) {
- // If cache is empty make the binder call to get the state
- int state = profile.getConnectionStatus(mDevice);
- mProfileConnectionState.put(profile, state);
- }
- return mProfileConnectionState.get(profile);
- }
-
- public void clearProfileConnectionState ()
- {
- if (BluetoothUtils.D) {
- Log.d(TAG," Clearing all connection state for dev:" + mDevice.getName());
- }
- for (LocalBluetoothProfile profile :getProfiles()) {
- mProfileConnectionState.put(profile, BluetoothProfile.STATE_DISCONNECTED);
- }
+ return profile != null
+ ? profile.getConnectionStatus(mDevice)
+ : BluetoothProfile.STATE_DISCONNECTED;
}
// TODO: do any of these need to run async on a background thread?
@@ -661,7 +644,7 @@
List<LocalBluetoothProfile> connectableProfiles =
new ArrayList<LocalBluetoothProfile>();
for (LocalBluetoothProfile profile : mProfiles) {
- if (profile.isConnectable()) {
+ if (profile.accessProfileEnabled()) {
connectableProfiles.add(profile);
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
index 5a64e02..21cf0c2 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
@@ -285,11 +285,6 @@
{
mCachedDevicesMapForHearingAids.remove(cachedDevice.getHiSyncId());
}
- } else {
- // For bonded devices, we need to clear the connection status so that
- // when BT is enabled next time, device connection status shall be retrieved
- // by making a binder call.
- cachedDevice.clearProfileConnectionState();
}
}
for (int i = mHearingAidDevicesNotAddedInCache.size() - 1; i >= 0; i--) {
@@ -297,11 +292,6 @@
if (notCachedDevice.getBondState() != BluetoothDevice.BOND_BONDED) {
notCachedDevice.setJustDiscovered(false);
mHearingAidDevicesNotAddedInCache.remove(i);
- } else {
- // For bonded devices, we need to clear the connection status so that
- // when BT is enabled next time, device connection status shall be retrieved
- // by making a binder call.
- notCachedDevice.clearProfileConnectionState();
}
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
index 2dd8eaf..62507f5 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
@@ -103,7 +103,7 @@
BluetoothProfile.HEADSET);
}
- public boolean isConnectable() {
+ public boolean accessProfileEnabled() {
return true;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
index 1eeb4f0..8bc0acf5 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
@@ -100,7 +100,7 @@
new HearingAidServiceListener(), BluetoothProfile.HEARING_AID);
}
- public boolean isConnectable() {
+ public boolean accessProfileEnabled() {
return false;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java
index 4b6a22c..4879144 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java
@@ -104,7 +104,7 @@
}
@Override
- public boolean isConnectable() {
+ public boolean accessProfileEnabled() {
return true;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java
index c8d4fc8..61e5b6b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java
@@ -94,7 +94,7 @@
}
@Override
- public boolean isConnectable() {
+ public boolean accessProfileEnabled() {
return true;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
index fe6b222..75d16db 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
@@ -93,7 +93,7 @@
BluetoothProfile.HID_HOST);
}
- public boolean isConnectable() {
+ public boolean accessProfileEnabled() {
return true;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfile.java
index 0447f37..4b0ca74 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfile.java
@@ -26,9 +26,9 @@
public interface LocalBluetoothProfile {
/**
- * Returns true if the user can initiate a connection, false otherwise.
+ * Return {@code true} if the user can initiate a connection for this profile in UI.
*/
- boolean isConnectable();
+ boolean accessProfileEnabled();
/**
* Returns true if the user can enable auto connection for this profile.
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
index 7000f9d..0c29f43 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
@@ -290,10 +290,11 @@
}
}
- mEventManager.dispatchProfileConnectionStateChanged(cachedDevice, newState,
- mProfile.getProfileId());
cachedDevice.onProfileStateChanged(mProfile, newState);
cachedDevice.refresh();
+ // Dispatch profile changed after device update
+ mEventManager.dispatchProfileConnectionStateChanged(cachedDevice, newState,
+ mProfile.getProfileId());
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java
index 7ad2e28c..1e22f44 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java
@@ -105,7 +105,7 @@
new MapClientServiceListener(), BluetoothProfile.MAP_CLIENT);
}
- public boolean isConnectable() {
+ public boolean accessProfileEnabled() {
return true;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java
index caea04f..7582024 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java
@@ -104,7 +104,7 @@
BluetoothProfile.MAP);
}
- public boolean isConnectable() {
+ public boolean accessProfileEnabled() {
return true;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java
index dfd1622..e1e5dbe 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java
@@ -32,7 +32,7 @@
// Order of this profile in device profiles list
private static final int ORDINAL = 2;
- public boolean isConnectable() {
+ public boolean accessProfileEnabled() {
return false;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java
index 02afe8d..7b81162 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java
@@ -78,7 +78,7 @@
BluetoothProfile.PAN);
}
- public boolean isConnectable() {
+ public boolean accessProfileEnabled() {
return true;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java
index 8fefb2f..1f15601f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java
@@ -107,7 +107,7 @@
new PbapClientServiceListener(), BluetoothProfile.PBAP_CLIENT);
}
- public boolean isConnectable() {
+ public boolean accessProfileEnabled() {
return true;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java
index e9d8cb5..adef0841 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java
@@ -80,7 +80,7 @@
BluetoothPbap pbap = new BluetoothPbap(context, new PbapServiceListener());
}
- public boolean isConnectable() {
+ public boolean accessProfileEnabled() {
return true;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java
index 61602c6..9a6f104 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java
@@ -106,7 +106,7 @@
BluetoothProfile.SAP);
}
- public boolean isConnectable() {
+ public boolean accessProfileEnabled() {
return true;
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java
index 7baded8..62b5688 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java
@@ -118,7 +118,7 @@
* Test to verify addDevice().
*/
@Test
- public void testAddDevice_validCachedDevices_devicesAdded() {
+ public void addDevice_validCachedDevices_devicesAdded() {
CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
assertThat(cachedDevice1).isNotNull();
CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);
@@ -136,7 +136,7 @@
* Test to verify getName().
*/
@Test
- public void testGetName_validCachedDevice_nameFound() {
+ public void getName_validCachedDevice_nameFound() {
CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
assertThat(cachedDevice1).isNotNull();
assertThat(mCachedDeviceManager.getName(mDevice1)).isEqualTo(DEVICE_ALIAS_1);
@@ -146,7 +146,7 @@
* Test to verify onDeviceNameUpdated().
*/
@Test
- public void testOnDeviceNameUpdated_validName_nameUpdated() {
+ public void onDeviceNameUpdated_validName_nameUpdated() {
CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
assertThat(cachedDevice1).isNotNull();
assertThat(cachedDevice1.getName()).isEqualTo(DEVICE_ALIAS_1);
@@ -161,7 +161,7 @@
* Test to verify clearNonBondedDevices().
*/
@Test
- public void testClearNonBondedDevices_bondedAndNonBondedDevices_nonBondedDevicesCleared() {
+ public void clearNonBondedDevices_bondedAndNonBondedDevices_nonBondedDevicesCleared() {
CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
assertThat(cachedDevice1).isNotNull();
CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);
@@ -193,7 +193,7 @@
* Test to verify clearNonBondedDevices() for hearing aids.
*/
@Test
- public void testClearNonBondedDevices_HearingAids_nonBondedHAsClearedFromCachedDevicesMap() {
+ public void clearNonBondedDevices_HearingAids_nonBondedHAsClearedFromCachedDevicesMap() {
when(mDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
when(mDevice2.getBondState()).thenReturn(BluetoothDevice.BOND_NONE);
@@ -214,7 +214,7 @@
* Test to verify onHiSyncIdChanged() for hearing aid devices with same HiSyncId.
*/
@Test
- public void testOnHiSyncIdChanged_sameHiSyncId_populateInDifferentLists() {
+ public void onHiSyncIdChanged_sameHiSyncId_populateInDifferentLists() {
CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
assertThat(cachedDevice1).isNotNull();
CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);
@@ -247,7 +247,7 @@
* device is connected and other is disconnected. The connected device should be chosen.
*/
@Test
- public void testOnHiSyncIdChanged_sameHiSyncIdAndOneConnected_chooseConnectedDevice() {
+ public void onHiSyncIdChanged_sameHiSyncIdAndOneConnected_chooseConnectedDevice() {
CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
assertThat(cachedDevice1).isNotNull();
CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);
@@ -282,7 +282,7 @@
* Test to verify onHiSyncIdChanged() for hearing aid devices with different HiSyncId.
*/
@Test
- public void testOnHiSyncIdChanged_differentHiSyncId_populateInSameList() {
+ public void onHiSyncIdChanged_differentHiSyncId_populateInSameList() {
CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
assertThat(cachedDevice1).isNotNull();
CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);
@@ -316,7 +316,7 @@
* Test to verify onProfileConnectionStateChanged() for single hearing aid device connection.
*/
@Test
- public void testOnProfileConnectionStateChanged_singleDeviceConnected_visible() {
+ public void onProfileConnectionStateChanged_singleDeviceConnected_visible() {
CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
assertThat(cachedDevice1).isNotNull();
cachedDevice1.onProfileStateChanged(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);
@@ -353,7 +353,7 @@
* devices are disconnected and they get connected.
*/
@Test
- public void testOnProfileConnectionStateChanged_twoDevicesConnected_oneDeviceVisible() {
+ public void onProfileConnectionStateChanged_twoDevicesConnected_oneDeviceVisible() {
CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
assertThat(cachedDevice1).isNotNull();
CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);
@@ -405,7 +405,7 @@
* devices are connected and they get disconnected.
*/
@Test
- public void testOnProfileConnectionStateChanged_twoDevicesDisconnected_oneDeviceVisible() {
+ public void onProfileConnectionStateChanged_twoDevicesDisconnected_oneDeviceVisible() {
CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
assertThat(cachedDevice1).isNotNull();
CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);
@@ -458,7 +458,7 @@
* Test to verify OnDeviceUnpaired() for a paired hearing Aid device pair.
*/
@Test
- public void testOnDeviceUnpaired_bothHearingAidsPaired_removesItsPairFromList() {
+ public void onDeviceUnpaired_bothHearingAidsPaired_removesItsPairFromList() {
CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
assertThat(cachedDevice1).isNotNull();
CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);
@@ -488,7 +488,7 @@
* Test to verify OnDeviceUnpaired() for paired hearing Aid devices which are not a pair.
*/
@Test
- public void testOnDeviceUnpaired_bothHearingAidsNotPaired_doesNotRemoveAnyDeviceFromList() {
+ public void onDeviceUnpaired_bothHearingAidsNotPaired_doesNotRemoveAnyDeviceFromList() {
CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
assertThat(cachedDevice1).isNotNull();
CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);
@@ -532,7 +532,7 @@
* Test to verify addDevice() for hearing aid devices with same HiSyncId.
*/
@Test
- public void testAddDevice_hearingAidDevicesWithSameHiSyncId_populateInDifferentLists() {
+ public void addDevice_hearingAidDevicesWithSameHiSyncId_populateInDifferentLists() {
doAnswer((invocation) -> mHearingAidProfile).when(mLocalProfileManager)
.getHearingAidProfile();
doAnswer((invocation) -> HISYNCID1).when(mHearingAidProfile).getHiSyncId(mDevice1);
@@ -560,7 +560,7 @@
* Test to verify addDevice() for hearing aid devices with different HiSyncId.
*/
@Test
- public void testAddDevice_hearingAidDevicesWithDifferentHiSyncId_populateInSameList() {
+ public void addDevice_hearingAidDevicesWithDifferentHiSyncId_populateInSameList() {
doAnswer((invocation) -> mHearingAidProfile).when(mLocalProfileManager)
.getHearingAidProfile();
doAnswer((invocation) -> HISYNCID1).when(mHearingAidProfile).getHiSyncId(mDevice1);
@@ -592,7 +592,7 @@
* Test to verify getHearingAidPairDeviceSummary() for hearing aid devices with same HiSyncId.
*/
@Test
- public void testGetHearingAidPairDeviceSummary_bothHearingAidsPaired_returnsSummaryOfPair() {
+ public void getHearingAidPairDeviceSummary_bothHearingAidsPaired_returnsSummaryOfPair() {
mCachedDevice1.setHiSyncId(HISYNCID1);
mCachedDevice2.setHiSyncId(HISYNCID1);
mCachedDeviceManager.mCachedDevices.add(mCachedDevice1);
@@ -609,7 +609,7 @@
* HiSyncId.
*/
@Test
- public void testGetHearingAidPairDeviceSummary_bothHearingAidsNotPaired_returnsNull() {
+ public void getHearingAidPairDeviceSummary_bothHearingAidsNotPaired_returnsNull() {
mCachedDevice1.setHiSyncId(HISYNCID1);
mCachedDevice2.setHiSyncId(HISYNCID2);
mCachedDeviceManager.mCachedDevices.add(mCachedDevice1);
@@ -625,7 +625,7 @@
* Test to verify updateHearingAidsDevices().
*/
@Test
- public void testUpdateHearingAidDevices_hiSyncIdAvailable_setsHiSyncId() {
+ public void updateHearingAidDevices_hiSyncIdAvailable_setsHiSyncId() {
doAnswer((invocation) -> mHearingAidProfile).when(mLocalProfileManager)
.getHearingAidProfile();
doAnswer((invocation) -> HISYNCID1).when(mHearingAidProfile).getHiSyncId(mDevice1);
@@ -643,7 +643,7 @@
* Test to verify onBtClassChanged().
*/
@Test
- public void testOnBtClassChanged_validBtClass_classChanged() {
+ public void onBtClassChanged_validBtClass_classChanged() {
CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
assertThat(cachedDevice1).isNotNull();
assertThat(cachedDevice1.getBtClass()).isEqualTo(DEVICE_CLASS_1);
@@ -658,7 +658,7 @@
* Test to verify onDeviceDisappeared().
*/
@Test
- public void testOnDeviceDisappeared_deviceBondedUnbonded_unbondedDeviceDisappeared() {
+ public void onDeviceDisappeared_deviceBondedUnbonded_unbondedDeviceDisappeared() {
CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
assertThat(cachedDevice1).isNotNull();
@@ -673,7 +673,7 @@
* Test to verify onActiveDeviceChanged().
*/
@Test
- public void testOnActiveDeviceChanged_connectedDevices_activeDeviceChanged() {
+ public void onActiveDeviceChanged_connectedDevices_activeDeviceChanged() {
CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
assertThat(cachedDevice1).isNotNull();
CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);
@@ -736,7 +736,7 @@
* Test to verify onActiveDeviceChanged() with A2DP and Hearing Aid.
*/
@Test
- public void testOnActiveDeviceChanged_withA2dpAndHearingAid() {
+ public void onActiveDeviceChanged_withA2dpAndHearingAid() {
CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
assertThat(cachedDevice1).isNotNull();
CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
index c18db11..f6201dd 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
@@ -20,6 +20,7 @@
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
@@ -79,74 +80,74 @@
}
@Test
- public void testGetConnectionSummary_testSingleProfileConnectDisconnect() {
+ public void getConnectionSummary_testSingleProfileConnectDisconnect() {
// Test without battery level
// Set PAN profile to be connected and test connection state summary
- mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_CONNECTED);
+ updateProfileStatus(mPanProfile, BluetoothProfile.STATE_CONNECTED);
assertThat(mCachedDevice.getConnectionSummary()).isNull();
// Set PAN profile to be disconnected and test connection state summary
- mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);
+ updateProfileStatus(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);
assertThat(mCachedDevice.getConnectionSummary()).isNull();
// Test with battery level
mBatteryLevel = 10;
// Set PAN profile to be connected and test connection state summary
- mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_CONNECTED);
+ updateProfileStatus(mPanProfile, BluetoothProfile.STATE_CONNECTED);
assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("10% battery");
// Set PAN profile to be disconnected and test connection state summary
- mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);
+ updateProfileStatus(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);
assertThat(mCachedDevice.getConnectionSummary()).isNull();
// Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level
mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN;
// Set PAN profile to be connected and test connection state summary
- mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_CONNECTED);
+ updateProfileStatus(mPanProfile, BluetoothProfile.STATE_CONNECTED);
assertThat(mCachedDevice.getConnectionSummary()).isNull();
// Set PAN profile to be disconnected and test connection state summary
- mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);
+ updateProfileStatus(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);
assertThat(mCachedDevice.getConnectionSummary()).isNull();
}
@Test
- public void testGetConnectionSummary_testMultipleProfileConnectDisconnect() {
+ public void getConnectionSummary_testMultipleProfileConnectDisconnect() {
mBatteryLevel = 10;
// Set HFP, A2DP and PAN profile to be connected and test connection state summary
- mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
- mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
- mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_CONNECTED);
+ updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
+ updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+ updateProfileStatus(mPanProfile, BluetoothProfile.STATE_CONNECTED);
assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("10% battery");
// Disconnect HFP only and test connection state summary
- mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
+ updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(
"10% battery");
// Disconnect A2DP only and test connection state summary
- mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
- mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
+ updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
+ updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(
"10% battery");
// Disconnect both HFP and A2DP and test connection state summary
- mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
+ updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(
"10% battery");
// Disconnect all profiles and test connection state summary
- mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);
+ updateProfileStatus(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);
assertThat(mCachedDevice.getConnectionSummary()).isNull();
}
@Test
- public void testGetConnectionSummary_testSingleProfileActiveDeviceA2dp() {
+ public void getConnectionSummary_testSingleProfileActiveDeviceA2dp() {
// Test without battery level
// Set A2DP profile to be connected and test connection state summary
- mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+ updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
assertThat(mCachedDevice.getConnectionSummary()).isNull();
// Set device as Active for A2DP and test connection state summary
@@ -159,26 +160,26 @@
"Active, 10% battery");
// Set A2DP profile to be disconnected and test connection state summary
- mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
+ updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
assertThat(mCachedDevice.getConnectionSummary()).isNull();
// Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level
mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN;
// Set A2DP profile to be connected, Active and test connection state summary
- mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+ updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP);
assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active");
// Set A2DP profile to be disconnected and test connection state summary
- mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
+ updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
assertThat(mCachedDevice.getConnectionSummary()).isNull();
}
@Test
- public void testGetConnectionSummary_testSingleProfileActiveDeviceHfp() {
+ public void getConnectionSummary_testSingleProfileActiveDeviceHfp() {
// Test without battery level
// Set HFP profile to be connected and test connection state summary
- mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
+ updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
assertThat(mCachedDevice.getConnectionSummary()).isNull();
// Set device as Active for HFP and test connection state summary
@@ -193,26 +194,26 @@
"Active, 10% battery");
// Set HFP profile to be disconnected and test connection state summary
- mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
+ updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
assertThat(mCachedDevice.getConnectionSummary()).isNull();
// Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level
mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN;
// Set HFP profile to be connected, Active and test connection state summary
- mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
+ updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEADSET);
assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active");
// Set HFP profile to be disconnected and test connection state summary
- mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
+ updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
assertThat(mCachedDevice.getConnectionSummary()).isNull();
}
@Test
- public void testGetConnectionSummary_testSingleProfileActiveDeviceHearingAid() {
+ public void getConnectionSummary_testSingleProfileActiveDeviceHearingAid() {
// Test without battery level
// Set Hearing Aid profile to be connected and test connection state summary
- mCachedDevice.onProfileStateChanged(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);
+ updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);
assertThat(mCachedDevice.getConnectionSummary()).isNull();
// Set device as Active for Hearing Aid and test connection state summary
@@ -227,11 +228,11 @@
}
@Test
- public void testGetConnectionSummary_testMultipleProfilesActiveDevice() {
+ public void getConnectionSummary_testMultipleProfilesActiveDevice() {
// Test without battery level
// Set A2DP and HFP profiles to be connected and test connection state summary
- mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
- mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
+ updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+ updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
assertThat(mCachedDevice.getConnectionSummary()).isNull();
// Set device as Active for A2DP and HFP and test connection state summary
@@ -246,14 +247,14 @@
// Disconnect A2DP only and test connection state summary
mCachedDevice.onActiveDeviceChanged(false, BluetoothProfile.A2DP);
- mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
+ updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(
"10% battery");
// Disconnect HFP only and test connection state summary
mCachedDevice.onActiveDeviceChanged(false, BluetoothProfile.HEADSET);
- mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
- mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+ updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
+ updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP);
assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(
"Active, 10% battery");
@@ -261,15 +262,15 @@
// Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level
mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN;
// Set A2DP and HFP profiles to be connected, Active and test connection state summary
- mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
- mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
+ updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+ updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP);
mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEADSET);
assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active");
// Set A2DP and HFP profiles to be disconnected and test connection state summary
- mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
- mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
+ updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
+ updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
assertThat(mCachedDevice.getConnectionSummary()).isNull();
}
@@ -277,32 +278,32 @@
public void getCarConnectionSummary_singleProfileConnectDisconnect() {
// Test without battery level
// Set PAN profile to be connected and test connection state summary
- mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_CONNECTED);
+ updateProfileStatus(mPanProfile, BluetoothProfile.STATE_CONNECTED);
assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Connected");
// Set PAN profile to be disconnected and test connection state summary
- mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);
+ updateProfileStatus(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);
assertThat(mCachedDevice.getCarConnectionSummary()).isNull();
// Test with battery level
mBatteryLevel = 10;
// Set PAN profile to be connected and test connection state summary
- mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_CONNECTED);
+ updateProfileStatus(mPanProfile, BluetoothProfile.STATE_CONNECTED);
assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Connected, battery 10%");
// Set PAN profile to be disconnected and test connection state summary
- mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);
+ updateProfileStatus(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);
assertThat(mCachedDevice.getCarConnectionSummary()).isNull();
// Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level
mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN;
// Set PAN profile to be connected and test connection state summary
- mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_CONNECTED);
+ updateProfileStatus(mPanProfile, BluetoothProfile.STATE_CONNECTED);
assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Connected");
// Set PAN profile to be disconnected and test connection state summary
- mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);
+ updateProfileStatus(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);
assertThat(mCachedDevice.getCarConnectionSummary()).isNull();
}
@@ -311,29 +312,29 @@
mBatteryLevel = 10;
// Set HFP, A2DP and PAN profile to be connected and test connection state summary
- mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
- mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
- mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_CONNECTED);
+ updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
+ updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+ updateProfileStatus(mPanProfile, BluetoothProfile.STATE_CONNECTED);
assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Connected, battery 10%");
// Disconnect HFP only and test connection state summary
- mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
+ updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo(
"Connected (no phone), battery 10%");
// Disconnect A2DP only and test connection state summary
- mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
- mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
+ updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
+ updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo(
"Connected (no media), battery 10%");
// Disconnect both HFP and A2DP and test connection state summary
- mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
+ updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo(
"Connected (no phone or media), battery 10%");
// Disconnect all profiles and test connection state summary
- mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);
+ updateProfileStatus(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);
assertThat(mCachedDevice.getCarConnectionSummary()).isNull();
}
@@ -341,7 +342,7 @@
public void getCarConnectionSummary_singleProfileActiveDeviceA2dp() {
// Test without battery level
// Set A2DP profile to be connected and test connection state summary
- mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+ updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Connected");
// Set device as Active for A2DP and test connection state summary
@@ -354,18 +355,18 @@
"Connected, battery 10%, active (media)");
// Set A2DP profile to be disconnected and test connection state summary
- mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
+ updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
assertThat(mCachedDevice.getCarConnectionSummary()).isNull();
// Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level
mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN;
// Set A2DP profile to be connected, Active and test connection state summary
- mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+ updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP);
assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Connected, active (media)");
// Set A2DP profile to be disconnected and test connection state summary
- mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
+ updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
assertThat(mCachedDevice.getCarConnectionSummary()).isNull();
}
@@ -373,7 +374,7 @@
public void getCarConnectionSummary_singleProfileActiveDeviceHfp() {
// Test without battery level
// Set HFP profile to be connected and test connection state summary
- mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
+ updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Connected");
// Set device as Active for HFP and test connection state summary
@@ -386,18 +387,18 @@
"Connected, battery 10%, active (phone)");
// Set HFP profile to be disconnected and test connection state summary
- mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
+ updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
assertThat(mCachedDevice.getCarConnectionSummary()).isNull();
// Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level
mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN;
// Set HFP profile to be connected, Active and test connection state summary
- mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
+ updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEADSET);
assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Connected, active (phone)");
// Set HFP profile to be disconnected and test connection state summary
- mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
+ updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
assertThat(mCachedDevice.getCarConnectionSummary()).isNull();
}
@@ -405,7 +406,7 @@
public void getCarConnectionSummary_singleProfileActiveDeviceHearingAid() {
// Test without battery level
// Set Hearing Aid profile to be connected and test connection state summary
- mCachedDevice.onProfileStateChanged(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);
+ updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);
assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Connected");
// Set device as Active for Hearing Aid and test connection state summary
@@ -414,8 +415,7 @@
// Set Hearing Aid profile to be disconnected and test connection state summary
mCachedDevice.onActiveDeviceChanged(false, BluetoothProfile.HEARING_AID);
- mCachedDevice.onProfileStateChanged(mHearingAidProfile,
- BluetoothProfile.STATE_DISCONNECTED);
+ updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_DISCONNECTED);
assertThat(mCachedDevice.getCarConnectionSummary()).isNull();
}
@@ -423,8 +423,8 @@
public void getCarConnectionSummary_multipleProfilesActiveDevice() {
// Test without battery level
// Set A2DP and HFP profiles to be connected and test connection state summary
- mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
- mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
+ updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+ updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Connected");
// Set device as Active for A2DP and HFP and test connection state summary
@@ -439,14 +439,14 @@
// Disconnect A2DP only and test connection state summary
mCachedDevice.onActiveDeviceChanged(false, BluetoothProfile.A2DP);
- mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
+ updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo(
"Connected (no media), battery 10%, active (phone)");
// Disconnect HFP only and test connection state summary
mCachedDevice.onActiveDeviceChanged(false, BluetoothProfile.HEADSET);
- mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
- mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+ updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
+ updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP);
assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo(
"Connected (no phone), battery 10%, active (media)");
@@ -454,21 +454,21 @@
// Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level
mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN;
// Set A2DP and HFP profiles to be connected, Active and test connection state summary
- mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
- mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
+ updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+ updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP);
mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEADSET);
assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Connected, active");
// Set A2DP and HFP profiles to be disconnected and test connection state summary
- mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
- mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
+ updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
+ updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
assertThat(mCachedDevice.getCarConnectionSummary()).isNull();
}
@Test
- public void testDeviceName_testAliasNameAvailable() {
+ public void deviceName_testAliasNameAvailable() {
when(mDevice.getAliasName()).thenReturn(DEVICE_ALIAS);
when(mDevice.getName()).thenReturn(DEVICE_NAME);
CachedBluetoothDevice cachedBluetoothDevice =
@@ -480,7 +480,7 @@
}
@Test
- public void testDeviceName_testNameNotAvailable() {
+ public void deviceName_testNameNotAvailable() {
CachedBluetoothDevice cachedBluetoothDevice =
new CachedBluetoothDevice(mContext, mProfileManager, mDevice);
// Verify device address is returned on getName
@@ -490,7 +490,7 @@
}
@Test
- public void testDeviceName_testRenameDevice() {
+ public void deviceName_testRenameDevice() {
final String[] alias = {DEVICE_ALIAS};
doAnswer(invocation -> alias[0]).when(mDevice).getAliasName();
doAnswer(invocation -> {
@@ -513,7 +513,7 @@
}
@Test
- public void testSetActive() {
+ public void setActive() {
when(mProfileManager.getA2dpProfile()).thenReturn(mA2dpProfile);
when(mProfileManager.getHeadsetProfile()).thenReturn(mHfpProfile);
when(mA2dpProfile.setActiveDevice(any(BluetoothDevice.class))).thenReturn(true);
@@ -521,19 +521,19 @@
assertThat(mCachedDevice.setActive()).isFalse();
- mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+ updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
assertThat(mCachedDevice.setActive()).isTrue();
- mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
- mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
+ updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
+ updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
assertThat(mCachedDevice.setActive()).isTrue();
- mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
+ updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
assertThat(mCachedDevice.setActive()).isFalse();
}
@Test
- public void testIsA2dpDevice_isA2dpDevice() {
+ public void isA2dpDevice_isA2dpDevice() {
when(mProfileManager.getA2dpProfile()).thenReturn(mA2dpProfile);
when(mA2dpProfile.getConnectionStatus(mDevice)).
thenReturn(BluetoothProfile.STATE_CONNECTED);
@@ -542,7 +542,7 @@
}
@Test
- public void testIsA2dpDevice_isNotA2dpDevice() {
+ public void isA2dpDevice_isNotA2dpDevice() {
when(mProfileManager.getA2dpProfile()).thenReturn(mA2dpProfile);
when(mA2dpProfile.getConnectionStatus(mDevice)).
thenReturn(BluetoothProfile.STATE_DISCONNECTING);
@@ -551,7 +551,7 @@
}
@Test
- public void testIsHfpDevice_isHfpDevice() {
+ public void isHfpDevice_isHfpDevice() {
when(mProfileManager.getHeadsetProfile()).thenReturn(mHfpProfile);
when(mHfpProfile.getConnectionStatus(mDevice)).
thenReturn(BluetoothProfile.STATE_CONNECTED);
@@ -637,4 +637,24 @@
verify(mDevice, never()).setAlias(any());
}
+
+ @Test
+ public void getProfileConnectionState_nullProfile_returnDisconnected() {
+ assertThat(mCachedDevice.getProfileConnectionState(null)).isEqualTo(
+ BluetoothProfile.STATE_DISCONNECTED);
+ }
+
+ @Test
+ public void getProfileConnectionState_profileConnected_returnConnected() {
+ doReturn(BluetoothProfile.STATE_CONNECTED).when(mA2dpProfile).getConnectionStatus(
+ any(BluetoothDevice.class));
+
+ assertThat(mCachedDevice.getProfileConnectionState(mA2dpProfile)).isEqualTo(
+ BluetoothProfile.STATE_CONNECTED);
+ }
+
+ private void updateProfileStatus(LocalBluetoothProfile profile, int status) {
+ doReturn(status).when(profile).getConnectionStatus(mDevice);
+ mCachedDevice.onProfileStateChanged(profile, status);
+ }
}
diff --git a/packages/SystemUI/res/layout/qs_detail_buttons.xml b/packages/SystemUI/res/layout/qs_detail_buttons.xml
index 03ed62b..75f43f9 100644
--- a/packages/SystemUI/res/layout/qs_detail_buttons.xml
+++ b/packages/SystemUI/res/layout/qs_detail_buttons.xml
@@ -26,6 +26,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
+ android:minHeight="48dp"
android:minWidth="132dp"
android:textAppearance="@style/TextAppearance.QS.DetailButton"
android:focusable="true" />
@@ -35,6 +36,7 @@
style="@style/QSBorderlessButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:minHeight="48dp"
android:minWidth="88dp"
android:textAppearance="@style/TextAppearance.QS.DetailButton"
android:focusable="true"/>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index b159b39..b8df3c06 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -342,12 +342,11 @@
case SimPuk:
// Shortcut for SIM PIN/PUK to go to directly to user's security screen or home
SecurityMode securityMode = mSecurityModel.getSecurityMode(targetUserId);
- if (securityMode != SecurityMode.None
- || !mLockPatternUtils.isLockScreenDisabled(
+ if (securityMode == SecurityMode.None || mLockPatternUtils.isLockScreenDisabled(
KeyguardUpdateMonitor.getCurrentUser())) {
- showSecurityScreen(securityMode);
- } else {
finish = true;
+ } else {
+ showSecurityScreen(securityMode);
}
break;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java
index 12daff1..9edd65e1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java
@@ -25,6 +25,7 @@
import android.graphics.drawable.Drawable;
import android.nfc.NfcAdapter;
import android.provider.Settings;
+import android.service.quicksettings.Tile;
import android.widget.Switch;
import com.android.internal.logging.MetricsLogger;
@@ -77,6 +78,9 @@
@Override
protected void handleClick() {
+ if (getAdapter() == null) {
+ return;
+ }
if (!getAdapter().isEnabled()) {
getAdapter().enable();
} else {
@@ -96,13 +100,13 @@
@Override
protected void handleUpdateState(BooleanState state, Object arg) {
- final Drawable mEnable = mContext.getDrawable(R.drawable.ic_qs_nfc_enabled);
- final Drawable mDisable = mContext.getDrawable(R.drawable.ic_qs_nfc_disabled);
-
- if (getAdapter() == null) return;
- state.value = getAdapter().isEnabled();
+ state.value = getAdapter() != null && getAdapter().isEnabled();
+ state.state = getAdapter() == null
+ ? Tile.STATE_UNAVAILABLE
+ : state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
+ state.icon = ResourceIcon.get(
+ state.value ? R.drawable.ic_qs_nfc_enabled : R.drawable.ic_qs_nfc_disabled);
state.label = mContext.getString(R.string.quick_settings_nfc_label);
- state.icon = new DrawableIcon(state.value ? mEnable : mDisable);
state.expandedAccessibilityClassName = Switch.class.getName();
state.contentDescription = state.label;
}
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 304a00f..2d03ed0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -17,7 +17,6 @@
package com.android.systemui.statusbar.car;
import android.app.ActivityTaskManager;
-import android.car.user.CarUserManagerHelper;
import android.graphics.PixelFormat;
import android.graphics.drawable.Drawable;
import android.util.Log;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java
index 67e512c..618a4c1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java
@@ -22,7 +22,7 @@
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.app.Dialog;
-import android.car.user.CarUserManagerHelper;
+import android.car.userlib.CarUserManagerHelper;
import android.content.Context;
import android.content.DialogInterface;
import android.content.pm.UserInfo;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButton.java
index 4f957bf..c7ab27b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButton.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButton.java
@@ -67,9 +67,15 @@
}
protected KeyButtonDrawable getNewDrawable() {
- return KeyButtonDrawable.create(getContext(), mIconResId, false /* shadow */);
+ return KeyButtonDrawable.create(getContext().getApplicationContext(), mIconResId,
+ false /* shadow */);
}
+ /**
+ * This context is from the view that could be stale after rotation or config change. To get
+ * correct resources use getApplicationContext() as well.
+ * @return current view context
+ */
protected Context getContext() {
return getCurrentView().getContext();
}
diff --git a/services/backup/java/com/android/server/backup/keyvalue/AgentException.java b/services/backup/java/com/android/server/backup/keyvalue/AgentException.java
new file mode 100644
index 0000000..e2ca351
--- /dev/null
+++ b/services/backup/java/com/android/server/backup/keyvalue/AgentException.java
@@ -0,0 +1,63 @@
+/*
+ * 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.backup.keyvalue;
+
+/**
+ * This represents something wrong with a specific package. For example:
+ * <ul>
+ * <li>Package unknown.
+ * <li>Package is not eligible for backup anymore.
+ * <li>Backup agent timed out.
+ * <li>Backup agent wrote protected keys.
+ * <li>...
+ * </ul>
+ *
+ * @see KeyValueBackupTask
+ * @see TaskException
+ */
+class AgentException extends BackupException {
+ static AgentException transitory() {
+ return new AgentException(/* transitory */ true);
+ }
+
+ static AgentException transitory(Exception cause) {
+ return new AgentException(/* transitory */ true, cause);
+ }
+
+ static AgentException permanent() {
+ return new AgentException(/* transitory */ false);
+ }
+
+ static AgentException permanent(Exception cause) {
+ return new AgentException(/* transitory */ false, cause);
+ }
+
+ private final boolean mTransitory;
+
+ private AgentException(boolean transitory) {
+ mTransitory = transitory;
+ }
+
+ private AgentException(boolean transitory, Exception cause) {
+ super(cause);
+ mTransitory = transitory;
+ }
+
+ boolean isTransitory() {
+ return mTransitory;
+ }
+}
diff --git a/services/backup/java/com/android/server/backup/keyvalue/BackupException.java b/services/backup/java/com/android/server/backup/keyvalue/BackupException.java
new file mode 100644
index 0000000..27b2d35
--- /dev/null
+++ b/services/backup/java/com/android/server/backup/keyvalue/BackupException.java
@@ -0,0 +1,33 @@
+/*
+ * 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.backup.keyvalue;
+
+import android.util.AndroidException;
+
+/**
+ * Key-value backup task exception.
+ *
+ * @see AgentException
+ * @see TaskException
+ */
+class BackupException extends AndroidException {
+ BackupException() {}
+
+ BackupException(Exception cause) {
+ super(cause);
+ }
+}
diff --git a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupReporter.java b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupReporter.java
index a92070c..bb8a1d1 100644
--- a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupReporter.java
+++ b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupReporter.java
@@ -153,16 +153,18 @@
mObserver, packageName, BackupManager.ERROR_BACKUP_NOT_ALLOWED);
}
- void onBindAgentError(SecurityException e) {
- Slog.d(TAG, "Error in bind/backup", e);
- }
-
void onAgentUnknown(String packageName) {
Slog.d(TAG, "Package does not exist, skipping");
BackupObserverUtils.sendBackupOnPackageResult(
mObserver, packageName, BackupManager.ERROR_PACKAGE_NOT_FOUND);
}
+ void onBindAgentError(String packageName, SecurityException e) {
+ Slog.d(TAG, "Error in bind/backup", e);
+ BackupObserverUtils.sendBackupOnPackageResult(
+ mObserver, packageName, BackupManager.ERROR_AGENT_FAILURE);
+ }
+
void onAgentError(String packageName) {
if (MORE_DEBUG) {
Slog.i(TAG, "Agent failure for " + packageName + ", re-staging");
@@ -190,6 +192,8 @@
void onCallAgentDoBackupError(String packageName, boolean callingAgent, Exception e) {
if (callingAgent) {
Slog.e(TAG, "Error invoking agent on " + packageName + ": " + e);
+ BackupObserverUtils.sendBackupOnPackageResult(
+ mObserver, packageName, BackupManager.ERROR_AGENT_FAILURE);
} else {
Slog.e(TAG, "Error before invoking agent on " + packageName + ": " + e);
}
@@ -220,12 +224,8 @@
}
}
- void onReadAgentDataError(String packageName, IOException e) {
- Slog.w(TAG, "Unable read backup data for " + packageName + ": " + e);
- }
-
- void onWriteWidgetDataError(String packageName, IOException e) {
- Slog.w(TAG, "Unable to save widget data for " + packageName + ": " + e);
+ void onAgentDataError(String packageName, IOException e) {
+ Slog.w(TAG, "Unable to read/write agent data for " + packageName + ": " + e);
}
void onDigestError(NoSuchAlgorithmException e) {
@@ -243,16 +243,12 @@
}
}
- void onSendDataToTransport(String packageName) {
+ void onTransportPerformBackup(String packageName) {
if (MORE_DEBUG) {
Slog.v(TAG, "Sending non-empty data to transport for " + packageName);
}
}
- void onNonIncrementalAndNonIncrementalRequired() {
- Slog.e(TAG, "Transport requested non-incremental but already the case");
- }
-
void onEmptyData(PackageInfo packageInfo) {
if (MORE_DEBUG) {
Slog.i(TAG, "No backup data written, not calling transport");
@@ -302,13 +298,20 @@
/* extras */ null);
}
+ void onPackageBackupNonIncrementalAndNonIncrementalRequired(String packageName) {
+ Slog.e(TAG, "Transport requested non-incremental but already the case");
+ BackupObserverUtils.sendBackupOnPackageResult(
+ mObserver, packageName, BackupManager.ERROR_TRANSPORT_ABORTED);
+ EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, packageName);
+ }
+
void onPackageBackupTransportFailure(String packageName) {
BackupObserverUtils.sendBackupOnPackageResult(
mObserver, packageName, BackupManager.ERROR_TRANSPORT_ABORTED);
EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, packageName);
}
- void onPackageBackupError(String packageName, Exception e) {
+ void onPackageBackupTransportError(String packageName, Exception e) {
Slog.e(TAG, "Transport error backing up " + packageName, e);
BackupObserverUtils.sendBackupOnPackageResult(
mObserver, packageName, BackupManager.ERROR_TRANSPORT_ABORTED);
diff --git a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
index e915ce1..6904b3f 100644
--- a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
+++ b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
@@ -16,6 +16,7 @@
package com.android.server.backup.keyvalue;
+import static android.app.ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL;
import static android.os.ParcelFileDescriptor.MODE_CREATE;
import static android.os.ParcelFileDescriptor.MODE_READ_ONLY;
import static android.os.ParcelFileDescriptor.MODE_READ_WRITE;
@@ -25,8 +26,8 @@
import static com.android.server.backup.BackupManagerService.OP_PENDING;
import static com.android.server.backup.BackupManagerService.OP_TYPE_BACKUP;
+import android.annotation.IntDef;
import android.annotation.Nullable;
-import android.app.ApplicationThreadConstants;
import android.app.IBackupAgent;
import android.app.backup.BackupAgent;
import android.app.backup.BackupDataInput;
@@ -47,7 +48,6 @@
import android.os.SELinux;
import android.os.UserHandle;
import android.os.WorkSource;
-import android.util.Pair;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -77,6 +77,8 @@
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
@@ -173,10 +175,8 @@
private static final AtomicInteger THREAD_COUNT = new AtomicInteger();
private static final String BLANK_STATE_FILE_NAME = "blank_state";
private static final String PM_PACKAGE = BackupManagerService.PACKAGE_MANAGER_SENTINEL;
- @VisibleForTesting
- public static final String STAGING_FILE_SUFFIX = ".data";
- @VisibleForTesting
- public static final String NEW_STATE_FILE_SUFFIX = ".new";
+ @VisibleForTesting public static final String STAGING_FILE_SUFFIX = ".data";
+ @VisibleForTesting public static final String NEW_STATE_FILE_SUFFIX = ".new";
/**
* Creates a new {@link KeyValueBackupTask} for key-value backup operation, spins up a new
@@ -244,13 +244,13 @@
private final int mCurrentOpToken;
private final File mStateDirectory;
private final File mDataDirectory;
+ private final File mBlankStateFile;
private final List<String> mOriginalQueue;
private final List<String> mQueue;
private final List<String> mPendingFullBackups;
private final Object mQueueLock;
@Nullable private final DataChangedJournal mJournal;
- private int mStatus;
@Nullable private PerformFullTransportBackupTask mFullBackupTask;
@Nullable private IBackupAgent mAgent;
@Nullable private PackageInfo mCurrentPackage;
@@ -316,6 +316,7 @@
mDataDirectory = mBackupManagerService.getDataDir();
mCurrentOpToken = backupManagerService.generateRandomIntegerToken();
mQueueLock = mBackupManagerService.getQueueLock();
+ mBlankStateFile = new File(mStateDirectory, BLANK_STATE_FILE_NAME);
}
private void registerTask() {
@@ -331,45 +332,43 @@
public void run() {
Process.setThreadPriority(THREAD_PRIORITY);
- boolean processQueue = startTask();
- while (processQueue && !mQueue.isEmpty() && !mCancelled) {
- String packageName = mQueue.remove(0);
- if (PM_PACKAGE.equals(packageName)) {
- processQueue = backupPm();
- } else {
- processQueue = backupPackage(packageName);
+ int status = BackupTransport.TRANSPORT_OK;
+ try {
+ startTask();
+ while (!mQueue.isEmpty() && !mCancelled) {
+ String packageName = mQueue.remove(0);
+ try {
+ if (PM_PACKAGE.equals(packageName)) {
+ backupPm();
+ } else {
+ backupPackage(packageName);
+ }
+ } catch (AgentException e) {
+ if (e.isTransitory()) {
+ // We try again this package in the next backup pass.
+ mBackupManagerService.dataChangedImpl(packageName);
+ }
+ }
}
+ } catch (TaskException e) {
+ if (e.isStateCompromised()) {
+ mBackupManagerService.resetBackupState(mStateDirectory);
+ }
+ revertTask();
+ status = e.getStatus();
}
- finishTask();
+ finishTask(status);
}
- /** Returns whether to consume next queue package. */
- private boolean handleAgentResult(@Nullable PackageInfo packageInfo, RemoteResult result) {
- if (result == RemoteResult.FAILED_THREAD_INTERRUPTED) {
- // Not an explicit cancel, we need to flag it.
- mCancelled = true;
- mReporter.onAgentCancelled(packageInfo);
- cleanUpAgentForAgentError();
- return false;
+ /** Returns transport status. */
+ private int sendDataToTransport(@Nullable PackageInfo packageInfo)
+ throws AgentException, TaskException {
+ try {
+ return sendDataToTransport();
+ } catch (IOException e) {
+ mReporter.onAgentDataError(packageInfo.packageName, e);
+ throw TaskException.causedBy(e);
}
- if (result == RemoteResult.FAILED_CANCELLED) {
- mReporter.onAgentCancelled(packageInfo);
- cleanUpAgentForAgentError();
- return false;
- }
- if (result == RemoteResult.FAILED_TIMED_OUT) {
- mReporter.onAgentTimedOut(packageInfo);
- cleanUpAgentForAgentError();
- return true;
- }
- Preconditions.checkState(result.isPresent());
- long agentResult = result.get();
- if (agentResult == BackupAgent.RESULT_ERROR) {
- mReporter.onAgentResultError(packageInfo);
- cleanUpAgentForAgentError();
- return true;
- }
- return sendDataToTransport();
}
@Override
@@ -378,11 +377,10 @@
@Override
public void operationComplete(long unusedResult) {}
- /** Returns whether to consume next queue package. */
- private boolean startTask() {
+ private void startTask() throws TaskException {
if (mBackupManagerService.isBackupOperationInProgress()) {
mReporter.onSkipBackup();
- return false;
+ throw TaskException.create();
}
// Unfortunately full backup task constructor registers the task with BMS, so we have to
@@ -390,11 +388,9 @@
mFullBackupTask = createFullBackupTask(mPendingFullBackups);
registerTask();
- mStatus = BackupTransport.TRANSPORT_OK;
-
if (mQueue.isEmpty() && mPendingFullBackups.isEmpty()) {
mReporter.onEmptyQueueAtStart();
- return false;
+ return;
}
// We only backup PM if it was explicitly in the queue or if it's incremental.
boolean backupPm = mQueue.remove(PM_PACKAGE) || !mNonIncremental;
@@ -415,20 +411,18 @@
if (pmState.length() <= 0) {
mReporter.onInitializeTransport(transportName);
mBackupManagerService.resetBackupState(mStateDirectory);
- mStatus = transport.initializeDevice();
- mReporter.onTransportInitialized(mStatus);
+ int status = transport.initializeDevice();
+ mReporter.onTransportInitialized(status);
+ if (status != BackupTransport.TRANSPORT_OK) {
+ throw TaskException.stateCompromised();
+ }
}
+ } catch (TaskException e) {
+ throw e;
} catch (Exception e) {
mReporter.onInitializeTransportError(e);
- mStatus = BackupTransport.TRANSPORT_ERROR;
+ throw TaskException.stateCompromised();
}
-
- if (mStatus != BackupTransport.TRANSPORT_OK) {
- mBackupManagerService.resetBackupState(mStateDirectory);
- return false;
- }
-
- return true;
}
private PerformFullTransportBackupTask createFullBackupTask(List<String> packages) {
@@ -446,120 +440,82 @@
mUserInitiated);
}
- /** Returns whether to consume next queue package. */
- private boolean backupPm() {
- RemoteResult agentResult = null;
+ private void backupPm() throws TaskException {
+ mReporter.onStartPackageBackup(PM_PACKAGE);
+ mCurrentPackage = new PackageInfo();
+ mCurrentPackage.packageName = PM_PACKAGE;
+
try {
- mCurrentPackage = new PackageInfo();
- mCurrentPackage.packageName = PM_PACKAGE;
-
- // Since PM is running in the system process we can set up its agent directly.
- BackupAgent pmAgent = mBackupManagerService.makeMetadataAgent();
- mAgent = IBackupAgent.Stub.asInterface(pmAgent.onBind());
-
- Pair<Integer, RemoteResult> statusAndResult = extractAgentData(PM_PACKAGE, mAgent);
- mStatus = statusAndResult.first;
- agentResult = statusAndResult.second;
- } catch (Exception e) {
+ extractPmAgentData(mCurrentPackage);
+ int status = sendDataToTransport(mCurrentPackage);
+ cleanUpAgentForTransportStatus(status);
+ } catch (AgentException | TaskException e) {
mReporter.onExtractPmAgentDataError(e);
- mStatus = BackupTransport.TRANSPORT_ERROR;
+ cleanUpAgentForError(e);
+ // PM agent failure is task failure.
+ throw TaskException.stateCompromised(e);
}
-
- if (mStatus != BackupTransport.TRANSPORT_OK) {
- // In this case either extractAgentData() already made the agent clean-up or we haven't
- // prepared the state for calling the agent, in either case we don't need to clean-up.
- mBackupManagerService.resetBackupState(mStateDirectory);
- return false;
- }
-
- Preconditions.checkNotNull(agentResult);
- return handleAgentResult(mCurrentPackage, agentResult);
}
- /** Returns whether to consume next queue package. */
- private boolean backupPackage(String packageName) {
+ private void backupPackage(String packageName) throws AgentException, TaskException {
mReporter.onStartPackageBackup(packageName);
- mStatus = BackupTransport.TRANSPORT_OK;
+ mCurrentPackage = getPackageForBackup(packageName);
- // Verify that the requested app is eligible for key-value backup.
- RemoteResult agentResult = null;
try {
- mCurrentPackage = mPackageManager.getPackageInfo(
- packageName, PackageManager.GET_SIGNING_CERTIFICATES);
- ApplicationInfo applicationInfo = mCurrentPackage.applicationInfo;
- if (!AppBackupUtils.appIsEligibleForBackup(applicationInfo, mPackageManager)) {
- // The manifest has changed. This won't happen again because the app won't be
- // requesting further backups.
- mReporter.onPackageNotEligibleForBackup(packageName);
- return true;
- }
-
- if (AppBackupUtils.appGetsFullBackup(mCurrentPackage)) {
- // Initially enqueued for key-value backup, but only supports full-backup now.
- mReporter.onPackageEligibleForFullBackup(packageName);
- return true;
- }
-
- if (AppBackupUtils.appIsStopped(applicationInfo)) {
- // Just as it won't receive broadcasts, we won't run it for backup.
- mReporter.onPackageStopped(packageName);
- return true;
- }
-
- try {
- mBackupManagerService.setWorkSource(new WorkSource(applicationInfo.uid));
- IBackupAgent agent =
- mBackupManagerService.bindToAgentSynchronous(
- applicationInfo,
- ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL);
- if (agent != null) {
- mAgent = agent;
- Pair<Integer, RemoteResult> statusAndResult =
- extractAgentData(packageName, agent);
- mStatus = statusAndResult.first;
- agentResult = statusAndResult.second;
- } else {
- // Timeout waiting for the agent to bind.
- mStatus = BackupTransport.AGENT_ERROR;
- }
- } catch (SecurityException e) {
- mReporter.onBindAgentError(e);
- mStatus = BackupTransport.AGENT_ERROR;
- }
- } catch (PackageManager.NameNotFoundException e) {
- mStatus = BackupTransport.AGENT_UNKNOWN;
- } finally {
- mBackupManagerService.setWorkSource(null);
+ extractAgentData(mCurrentPackage);
+ int status = sendDataToTransport(mCurrentPackage);
+ cleanUpAgentForTransportStatus(status);
+ } catch (AgentException | TaskException e) {
+ cleanUpAgentForError(e);
+ throw e;
}
-
- if (mStatus != BackupTransport.TRANSPORT_OK) {
- // In this case either extractAgentData() already made the agent clean-up or we haven't
- // prepared the state for calling the agent, in either case we don't need to clean-up.
- Preconditions.checkState(mAgent == null);
-
- if (mStatus == BackupTransport.AGENT_ERROR) {
- mReporter.onAgentError(packageName);
- mBackupManagerService.dataChangedImpl(packageName);
- mStatus = BackupTransport.TRANSPORT_OK;
- return true;
- }
-
- if (mStatus == BackupTransport.AGENT_UNKNOWN) {
- mReporter.onAgentUnknown(packageName);
- mStatus = BackupTransport.TRANSPORT_OK;
- return true;
- }
-
- // Transport-level failure, re-enqueue everything.
- revertTask();
- return false;
- }
-
- Preconditions.checkNotNull(agentResult);
- return handleAgentResult(mCurrentPackage, agentResult);
}
- private void finishTask() {
+ private PackageInfo getPackageForBackup(String packageName) throws AgentException {
+ final PackageInfo packageInfo;
+ try {
+ packageInfo =
+ mPackageManager.getPackageInfo(
+ packageName, PackageManager.GET_SIGNING_CERTIFICATES);
+ } catch (PackageManager.NameNotFoundException e) {
+ mReporter.onAgentUnknown(packageName);
+ throw AgentException.permanent(e);
+ }
+ ApplicationInfo applicationInfo = packageInfo.applicationInfo;
+ if (!AppBackupUtils.appIsEligibleForBackup(applicationInfo, mPackageManager)) {
+ mReporter.onPackageNotEligibleForBackup(packageName);
+ throw AgentException.permanent();
+ }
+ if (AppBackupUtils.appGetsFullBackup(packageInfo)) {
+ mReporter.onPackageEligibleForFullBackup(packageName);
+ throw AgentException.permanent();
+ }
+ if (AppBackupUtils.appIsStopped(applicationInfo)) {
+ mReporter.onPackageStopped(packageName);
+ throw AgentException.permanent();
+ }
+ return packageInfo;
+ }
+
+ private IBackupAgent bindAgent(PackageInfo packageInfo) throws AgentException {
+ String packageName = packageInfo.packageName;
+ final IBackupAgent agent;
+ try {
+ agent =
+ mBackupManagerService.bindToAgentSynchronous(
+ packageInfo.applicationInfo, BACKUP_MODE_INCREMENTAL);
+ if (agent == null) {
+ mReporter.onAgentError(packageName);
+ throw AgentException.transitory();
+ }
+ } catch (SecurityException e) {
+ mReporter.onBindAgentError(packageName, e);
+ throw AgentException.transitory(e);
+ }
+ return agent;
+ }
+
+ private void finishTask(int status) {
// Mark packages that we couldn't backup as pending backup.
for (String packageName : mQueue) {
mBackupManagerService.dataChangedImpl(packageName);
@@ -576,7 +532,7 @@
// If we succeeded and this is the first time we've done a backup, we can record the current
// backup dataset token.
long currentToken = mBackupManagerService.getCurrentToken();
- if ((mStatus == BackupTransport.TRANSPORT_OK) && (currentToken == 0)) {
+ if ((status == BackupTransport.TRANSPORT_OK) && (currentToken == 0)) {
try {
IBackupTransport transport = mTransportClient.connectOrThrow(callerLogString);
mBackupManagerService.setCurrentToken(transport.getCurrentRestoreSet());
@@ -589,9 +545,14 @@
synchronized (mQueueLock) {
mBackupManagerService.setBackupRunning(false);
- if (mStatus == BackupTransport.TRANSPORT_NOT_INITIALIZED) {
+ if (status == BackupTransport.TRANSPORT_NOT_INITIALIZED) {
mReporter.onTransportNotInitialized();
- triggerTransportInitializationLocked();
+ try {
+ triggerTransportInitializationLocked();
+ } catch (Exception e) {
+ mReporter.onPendingInitializeTransportError(e);
+ status = BackupTransport.TRANSPORT_ERROR;
+ }
}
}
@@ -605,7 +566,7 @@
}
if (!mCancelled
- && mStatus == BackupTransport.TRANSPORT_OK
+ && status == BackupTransport.TRANSPORT_OK
&& mFullBackupTask != null
&& !mPendingFullBackups.isEmpty()) {
mReporter.onStartFullBackup(mPendingFullBackups);
@@ -621,7 +582,7 @@
mFullBackupTask.unregisterTask();
}
mTaskFinishedListener.onFinished(callerLogString);
- mReporter.onBackupFinished(getBackupFinishedStatus(mCancelled, mStatus));
+ mReporter.onBackupFinished(getBackupFinishedStatus(mCancelled, status));
mBackupManagerService.getWakelock().release();
}
@@ -642,17 +603,12 @@
}
@GuardedBy("mQueueLock")
- private void triggerTransportInitializationLocked() {
- try {
- IBackupTransport transport =
- mTransportClient.connectOrThrow("KVBT.triggerTransportInitializationLocked");
- mBackupManagerService.getPendingInits().add(transport.name());
- deletePmStateFile();
- mBackupManagerService.backupNow();
- } catch (Exception e) {
- mReporter.onPendingInitializeTransportError(e);
- mStatus = BackupTransport.TRANSPORT_ERROR;
- }
+ private void triggerTransportInitializationLocked() throws Exception {
+ IBackupTransport transport =
+ mTransportClient.connectOrThrow("KVBT.triggerTransportInitializationLocked");
+ mBackupManagerService.getPendingInits().add(transport.name());
+ deletePmStateFile();
+ mBackupManagerService.backupNow();
}
/** Removes PM state, triggering initialization in the next key-value task. */
@@ -660,35 +616,69 @@
new File(mStateDirectory, PM_PACKAGE).delete();
}
+ /** Same as {@link #extractAgentData(PackageInfo)}, but only for PM package. */
+ private void extractPmAgentData(PackageInfo packageInfo) throws AgentException, TaskException {
+ Preconditions.checkArgument(packageInfo.packageName.equals(PM_PACKAGE));
+ BackupAgent pmAgent = mBackupManagerService.makeMetadataAgent();
+ mAgent = IBackupAgent.Stub.asInterface(pmAgent.onBind());
+ extractAgentData(packageInfo, mAgent);
+ }
+
/**
- * Returns a {@link Pair}. The first of the pair contains the status. In case the status is
- * {@link BackupTransport#TRANSPORT_OK}, the second of the pair contains the agent result,
- * otherwise {@code null}.
+ * Binds to the agent and extracts its backup data. If this method returns, the data in {@code
+ * mBackupData} is ready to be sent to the transport, otherwise it will throw.
+ *
+ * <p>This method leaves agent resources (agent binder, files and file-descriptors) opened that
+ * need to be cleaned up after terminating, either successfully or exceptionally. This clean-up
+ * can be done with methods {@link #cleanUpAgentForTransportStatus(int)} and {@link
+ * #cleanUpAgentForError(BackupException)}, depending on whether data was successfully sent to
+ * the transport or not. It's the caller responsibility to do the clean-up or delegate it.
*/
- private Pair<Integer, RemoteResult> extractAgentData(String packageName, IBackupAgent agent) {
+ private void extractAgentData(PackageInfo packageInfo) throws AgentException, TaskException {
+ mBackupManagerService.setWorkSource(new WorkSource(packageInfo.applicationInfo.uid));
+ try {
+ mAgent = bindAgent(packageInfo);
+ extractAgentData(packageInfo, mAgent);
+ } finally {
+ mBackupManagerService.setWorkSource(null);
+ }
+ }
+
+ /**
+ * Calls agent {@link IBackupAgent#doBackup(ParcelFileDescriptor, ParcelFileDescriptor,
+ * ParcelFileDescriptor, long, IBackupCallback, int)} and waits for the result. If this method
+ * returns, the data in {@code mBackupData} is ready to be sent to the transport, otherwise it
+ * will throw.
+ *
+ * <p>This method creates files and file-descriptors for the agent that need to be deleted and
+ * closed after terminating, either successfully or exceptionally. This clean-up can be done
+ * with methods {@link #cleanUpAgentForTransportStatus(int)} and {@link
+ * #cleanUpAgentForError(BackupException)}, depending on whether data was successfully sent to
+ * the transport or not. It's the caller responsibility to do the clean-up or delegate it.
+ */
+ private void extractAgentData(PackageInfo packageInfo, IBackupAgent agent)
+ throws AgentException, TaskException {
+ String packageName = packageInfo.packageName;
mReporter.onExtractAgentData(packageName);
- File blankStateFile = new File(mStateDirectory, BLANK_STATE_FILE_NAME);
mSavedStateFile = new File(mStateDirectory, packageName);
mBackupDataFile = new File(mDataDirectory, packageName + STAGING_FILE_SUFFIX);
mNewStateFile = new File(mStateDirectory, packageName + NEW_STATE_FILE_SUFFIX);
mReporter.onAgentFilesReady(mBackupDataFile);
- mSavedState = null;
- mBackupData = null;
- mNewState = null;
-
boolean callingAgent = false;
final RemoteResult agentResult;
try {
- File savedStateFileForAgent = (mNonIncremental) ? blankStateFile : mSavedStateFile;
+ File savedStateFileForAgent = (mNonIncremental) ? mBlankStateFile : mSavedStateFile;
// MODE_CREATE to make an empty file if necessary
- mSavedState = ParcelFileDescriptor.open(
- savedStateFileForAgent, MODE_READ_ONLY | MODE_CREATE);
- mBackupData = ParcelFileDescriptor.open(
- mBackupDataFile, MODE_READ_WRITE | MODE_CREATE | MODE_TRUNCATE);
- mNewState = ParcelFileDescriptor.open(
- mNewStateFile, MODE_READ_WRITE | MODE_CREATE | MODE_TRUNCATE);
+ mSavedState =
+ ParcelFileDescriptor.open(savedStateFileForAgent, MODE_READ_ONLY | MODE_CREATE);
+ mBackupData =
+ ParcelFileDescriptor.open(
+ mBackupDataFile, MODE_READ_WRITE | MODE_CREATE | MODE_TRUNCATE);
+ mNewState =
+ ParcelFileDescriptor.open(
+ mNewStateFile, MODE_READ_WRITE | MODE_CREATE | MODE_TRUNCATE);
if (!SELinux.restorecon(mBackupDataFile)) {
mReporter.onRestoreconFailed(mBackupDataFile);
@@ -713,15 +703,40 @@
"doBackup()");
} catch (Exception e) {
mReporter.onCallAgentDoBackupError(packageName, callingAgent, e);
- cleanUpAgentForAgentError();
- // TODO: Remove the check on callingAgent when RemoteCall supports local agent calls.
- int status =
- callingAgent ? BackupTransport.AGENT_ERROR : BackupTransport.TRANSPORT_ERROR;
- return Pair.create(status, null);
+ if (callingAgent) {
+ throw AgentException.transitory(e);
+ } else {
+ throw TaskException.create();
+ }
+ } finally {
+ mBlankStateFile.delete();
}
- blankStateFile.delete();
+ checkAgentResult(packageInfo, agentResult);
+ }
- return Pair.create(BackupTransport.TRANSPORT_OK, agentResult);
+ private void checkAgentResult(PackageInfo packageInfo, RemoteResult result)
+ throws AgentException, TaskException {
+ if (result == RemoteResult.FAILED_THREAD_INTERRUPTED) {
+ // Not an explicit cancel, we need to flag it.
+ mCancelled = true;
+ mReporter.onAgentCancelled(packageInfo);
+ throw TaskException.create();
+ }
+ if (result == RemoteResult.FAILED_CANCELLED) {
+ mReporter.onAgentCancelled(packageInfo);
+ throw TaskException.create();
+ }
+ if (result == RemoteResult.FAILED_TIMED_OUT) {
+ mReporter.onAgentTimedOut(packageInfo);
+ throw AgentException.transitory();
+ }
+ Preconditions.checkState(result.isPresent());
+ long resultCode = result.get();
+ if (resultCode == BackupAgent.RESULT_ERROR) {
+ mReporter.onAgentResultError(packageInfo);
+ throw AgentException.transitory();
+ }
+ Preconditions.checkState(resultCode == BackupAgent.RESULT_SUCCESS);
}
private void agentFail(IBackupAgent agent, String message) {
@@ -801,94 +816,79 @@
}
}
- /** Returns whether to consume next queue package. */
- private boolean sendDataToTransport() {
+ /** Returns transport status. */
+ private int sendDataToTransport() throws AgentException, TaskException, IOException {
Preconditions.checkState(mBackupData != null);
+ checkBackupData(mCurrentPackage.applicationInfo, mBackupDataFile);
String packageName = mCurrentPackage.packageName;
- ApplicationInfo applicationInfo = mCurrentPackage.applicationInfo;
-
- boolean writingWidgetData = false;
- try {
- if (!validateBackupData(applicationInfo, mBackupDataFile)) {
- cleanUpAgentForAgentError();
- return true;
- }
- writingWidgetData = true;
- writeWidgetPayloadIfAppropriate(mBackupData.getFileDescriptor(), packageName);
- } catch (IOException e) {
- if (writingWidgetData) {
- mReporter.onWriteWidgetDataError(packageName, e);
- } else {
- mReporter.onReadAgentDataError(packageName, e);
- }
- cleanUpAgentForAgentError();
- revertTask();
- return false;
- }
+ writeWidgetPayloadIfAppropriate(mBackupData.getFileDescriptor(), packageName);
boolean nonIncremental = mSavedStateFile.length() == 0;
- long size = mBackupDataFile.length();
- if (size > 0) {
- try (ParcelFileDescriptor backupData =
- ParcelFileDescriptor.open(mBackupDataFile, MODE_READ_ONLY)) {
- IBackupTransport transport =
- mTransportClient.connectOrThrow("KVBT.sendDataToTransport()");
- mReporter.onSendDataToTransport(packageName);
- int flags = getPerformBackupFlags(mUserInitiated, nonIncremental);
-
- mStatus = transport.performBackup(mCurrentPackage, backupData, flags);
- if (mStatus == BackupTransport.TRANSPORT_OK) {
- mStatus = transport.finishBackup();
- }
- } catch (Exception e) {
- mReporter.onPackageBackupError(packageName, e);
- mStatus = BackupTransport.TRANSPORT_ERROR;
- }
- } else {
- mReporter.onEmptyData(mCurrentPackage);
- mStatus = BackupTransport.TRANSPORT_OK;
- }
-
- if (nonIncremental
- && mStatus == BackupTransport.TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED) {
- mReporter.onNonIncrementalAndNonIncrementalRequired();
- mStatus = BackupTransport.TRANSPORT_ERROR;
- }
-
-
- boolean processQueue = handleTransportStatus(mStatus, packageName, size);
- // We might report quota exceeded to the agent in handleTransportStatus() above, so we
- // only clean-up after it.
- cleanUpAgentForTransportStatus(mStatus);
- return processQueue;
+ int status = transportPerformBackup(mCurrentPackage, mBackupDataFile, nonIncremental);
+ handleTransportStatus(status, packageName, mBackupDataFile.length());
+ return status;
}
- /** Returns whether to consume next queue package. */
- private boolean handleTransportStatus(int status, String packageName, long size) {
+ private int transportPerformBackup(
+ PackageInfo packageInfo, File backupDataFile, boolean nonIncremental)
+ throws TaskException {
+ String packageName = packageInfo.packageName;
+ long size = backupDataFile.length();
+ if (size <= 0) {
+ mReporter.onEmptyData(packageInfo);
+ return BackupTransport.TRANSPORT_OK;
+ }
+
+ int status;
+ try (ParcelFileDescriptor backupData =
+ ParcelFileDescriptor.open(backupDataFile, MODE_READ_ONLY)) {
+ IBackupTransport transport =
+ mTransportClient.connectOrThrow("KVBT.transportPerformBackup()");
+ mReporter.onTransportPerformBackup(packageName);
+ int flags = getPerformBackupFlags(mUserInitiated, nonIncremental);
+
+ status = transport.performBackup(packageInfo, backupData, flags);
+ if (status == BackupTransport.TRANSPORT_OK) {
+ status = transport.finishBackup();
+ }
+ } catch (Exception e) {
+ mReporter.onPackageBackupTransportError(packageName, e);
+ throw TaskException.causedBy(e);
+ }
+
+ if (nonIncremental && status == BackupTransport.TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED) {
+ mReporter.onPackageBackupNonIncrementalAndNonIncrementalRequired(packageName);
+ throw TaskException.create();
+ }
+
+ return status;
+ }
+
+ private void handleTransportStatus(int status, String packageName, long size)
+ throws TaskException, AgentException {
if (status == BackupTransport.TRANSPORT_OK) {
mReporter.onPackageBackupComplete(packageName, size);
- return true;
- }
- if (status == BackupTransport.TRANSPORT_PACKAGE_REJECTED) {
- mReporter.onPackageBackupRejected(packageName);
- return true;
+ return;
}
if (status == BackupTransport.TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED) {
mReporter.onPackageBackupNonIncrementalRequired(mCurrentPackage);
// Immediately retry the current package.
mQueue.add(0, packageName);
- return true;
+ return;
+ }
+ if (status == BackupTransport.TRANSPORT_PACKAGE_REJECTED) {
+ mReporter.onPackageBackupRejected(packageName);
+ throw AgentException.permanent();
}
if (status == BackupTransport.TRANSPORT_QUOTA_EXCEEDED) {
mReporter.onPackageBackupQuotaExceeded(packageName);
agentDoQuotaExceeded(mAgent, packageName, size);
- return true;
+ throw AgentException.permanent();
}
// Any other error here indicates a transport-level failure.
mReporter.onPackageBackupTransportFailure(packageName);
- revertTask();
- return false;
+ throw TaskException.forStatus(status);
}
private void agentDoQuotaExceeded(@Nullable IBackupAgent agent, String packageName, long size) {
@@ -908,19 +908,17 @@
}
/**
- * For system apps and pseudo-apps always return {@code true}. For regular apps returns whether
- * {@code backupDataFile} doesn't have any protected keys.
- *
- * <p>If the app has attempted to write any protected keys we also crash them.
+ * For system apps and pseudo-apps never throws. For regular apps throws {@link AgentException}
+ * if {@code backupDataFile} has any protected keys, also crashing the app.
*/
- private boolean validateBackupData(
- @Nullable ApplicationInfo applicationInfo, File backupDataFile) throws IOException {
+ private void checkBackupData(@Nullable ApplicationInfo applicationInfo, File backupDataFile)
+ throws IOException, AgentException {
if (applicationInfo == null || (applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
// System apps and pseudo-apps can write what they want.
- return true;
+ return;
}
try (ParcelFileDescriptor backupData =
- ParcelFileDescriptor.open(backupDataFile, MODE_READ_ONLY)) {
+ ParcelFileDescriptor.open(backupDataFile, MODE_READ_ONLY)) {
BackupDataInput backupDataInput = new BackupDataInput(backupData.getFileDescriptor());
while (backupDataInput.readNextHeader()) {
String key = backupDataInput.getKey();
@@ -928,12 +926,11 @@
mReporter.onAgentIllegalKey(mCurrentPackage, key);
// Crash them if they wrote any protected keys.
agentFail(mAgent, "Illegal backup key: " + key);
- return false;
+ throw AgentException.permanent();
}
backupDataInput.skipEntityData();
}
}
- return true;
}
private int getPerformBackupFlags(boolean userInitiated, boolean nonIncremental) {
@@ -1009,44 +1006,39 @@
}
}
- /** Cleans-up after having called the agent. */
+ /**
+ * Cleans up agent resources opened by {@link #extractAgentData(PackageInfo)} for exceptional
+ * case.
+ *
+ * <p>Note: Declaring exception parameter so that the caller only calls this when an exception
+ * is thrown.
+ */
+ private void cleanUpAgentForError(BackupException exception) {
+ cleanUpAgent(StateTransaction.DISCARD_NEW);
+ }
+
+ /**
+ * Cleans up agent resources opened by {@link #extractAgentData(PackageInfo)} according to
+ * transport status returned in {@link #sendDataToTransport(PackageInfo)}.
+ */
private void cleanUpAgentForTransportStatus(int status) {
- updateFiles(status);
- cleanUpAgent();
- }
-
- /** Cleans-up if we failed to call the agent. */
- private void cleanUpAgentForAgentError() {
- mBackupDataFile.delete();
- mNewStateFile.delete();
- cleanUpAgent();
- }
-
- private void updateFiles(int status) {
switch (status) {
case BackupTransport.TRANSPORT_OK:
- mBackupDataFile.delete();
- mNewStateFile.renameTo(mSavedStateFile);
+ cleanUpAgent(StateTransaction.COMMIT_NEW);
break;
case BackupTransport.TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED:
- mSavedStateFile.delete();
- mBackupDataFile.delete();
- mNewStateFile.delete();
+ cleanUpAgent(StateTransaction.DISCARD_ALL);
break;
default:
- // Includes:
- // * BackupTransport.TRANSPORT_PACKAGE_REJECTED
- // * BackupTransport.TRANSPORT_QUOTA_EXCEEDED
- // * BackupTransport.TRANSPORT_ERROR
- mBackupDataFile.delete();
- mNewStateFile.delete();
- break;
+ // All other transport statuses are properly converted to agent or task exceptions.
+ throw new AssertionError();
}
}
- /** Cleans-up file-descriptors and unbinds agent. */
- private void cleanUpAgent() {
- mAgent = null;
+ private void cleanUpAgent(@StateTransaction int stateTransaction) {
+ applyStateTransaction(stateTransaction);
+ mBackupDataFile.delete();
+ mBlankStateFile.delete();
tryCloseFileDescriptor(mSavedState, "old state");
tryCloseFileDescriptor(mBackupData, "backup data");
tryCloseFileDescriptor(mNewState, "new state");
@@ -1058,6 +1050,24 @@
if (mCurrentPackage.applicationInfo != null) {
mBackupManagerService.unbindAgent(mCurrentPackage.applicationInfo);
}
+ mAgent = null;
+ }
+
+ private void applyStateTransaction(@StateTransaction int stateTransaction) {
+ switch (stateTransaction) {
+ case StateTransaction.COMMIT_NEW:
+ mNewStateFile.renameTo(mSavedStateFile);
+ break;
+ case StateTransaction.DISCARD_NEW:
+ mNewStateFile.delete();
+ break;
+ case StateTransaction.DISCARD_ALL:
+ mSavedStateFile.delete();
+ mNewStateFile.delete();
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown state transaction " + stateTransaction);
+ }
}
private void tryCloseFileDescriptor(@Nullable Closeable closeable, String logName) {
@@ -1079,4 +1089,16 @@
mPendingCall = null;
return result;
}
+
+ @IntDef({
+ StateTransaction.COMMIT_NEW,
+ StateTransaction.DISCARD_NEW,
+ StateTransaction.DISCARD_ALL,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ private @interface StateTransaction {
+ int COMMIT_NEW = 0;
+ int DISCARD_NEW = 1;
+ int DISCARD_ALL = 2;
+ }
}
diff --git a/services/backup/java/com/android/server/backup/keyvalue/TaskException.java b/services/backup/java/com/android/server/backup/keyvalue/TaskException.java
new file mode 100644
index 0000000..08d2895
--- /dev/null
+++ b/services/backup/java/com/android/server/backup/keyvalue/TaskException.java
@@ -0,0 +1,83 @@
+/*
+ * 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.backup.keyvalue;
+
+import android.app.backup.BackupTransport;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * The key-value backup task has failed, no more packages will be processed and we shouldn't attempt
+ * any more backups now. These can be caused by transport failures (as opposed to agent failures).
+ *
+ * @see KeyValueBackupTask
+ * @see AgentException
+ */
+class TaskException extends BackupException {
+ private static final int DEFAULT_STATUS = BackupTransport.TRANSPORT_ERROR;
+
+ static TaskException stateCompromised() {
+ return new TaskException(/* stateCompromised */ true, DEFAULT_STATUS);
+ }
+
+ static TaskException stateCompromised(Exception cause) {
+ if (cause instanceof TaskException) {
+ TaskException exception = (TaskException) cause;
+ return new TaskException(cause, /* stateCompromised */ true, exception.getStatus());
+ }
+ return new TaskException(cause, /* stateCompromised */ true, DEFAULT_STATUS);
+ }
+
+ static TaskException forStatus(int status) {
+ Preconditions.checkArgument(
+ status != BackupTransport.TRANSPORT_OK, "Exception based on TRANSPORT_OK");
+ return new TaskException(/* stateCompromised */ false, status);
+ }
+
+ static TaskException causedBy(Exception cause) {
+ if (cause instanceof TaskException) {
+ return (TaskException) cause;
+ }
+ return new TaskException(cause, /* stateCompromised */ false, DEFAULT_STATUS);
+ }
+
+ static TaskException create() {
+ return new TaskException(/* stateCompromised */ false, DEFAULT_STATUS);
+ }
+
+ private final boolean mStateCompromised;
+ private final int mStatus;
+
+ private TaskException(Exception cause, boolean stateCompromised, int status) {
+ super(cause);
+ mStateCompromised = stateCompromised;
+ mStatus = status;
+ }
+
+ private TaskException(boolean stateCompromised, int status) {
+ mStateCompromised = stateCompromised;
+ mStatus = status;
+ }
+
+ boolean isStateCompromised() {
+ return mStateCompromised;
+ }
+
+ int getStatus() {
+ return mStatus;
+ }
+}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 510d333..461d39d 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -629,7 +629,7 @@
return false;
}
- IIntentSender target = mAm.getIntentSenderLocked(
+ IIntentSender target = mAm.mPendingIntentController.getIntentSender(
ActivityManager.INTENT_SENDER_SERVICE, callingPackage,
callingUid, userId, null, null, 0, new Intent[]{service},
new String[]{service.resolveType(mAm.mContext.getContentResolver())},
diff --git a/services/core/java/com/android/server/am/ActivityDisplay.java b/services/core/java/com/android/server/am/ActivityDisplay.java
index 01421c7..fab967c 100644
--- a/services/core/java/com/android/server/am/ActivityDisplay.java
+++ b/services/core/java/com/android/server/am/ActivityDisplay.java
@@ -890,6 +890,8 @@
mRemoved = true;
releaseSelfIfNeeded();
+
+ mSupervisor.getKeyguardController().onDisplayRemoved(mDisplayId);
}
private void releaseSelfIfNeeded() {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 8c7fc84..6e90d5b 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -134,7 +134,6 @@
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SERVICE;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SWITCH;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_UID_OBSERVERS;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_URI_PERMISSION;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
@@ -417,7 +416,6 @@
private static final String TAG_SERVICE = TAG + POSTFIX_SERVICE;
private static final String TAG_SWITCH = TAG + POSTFIX_SWITCH;
private static final String TAG_UID_OBSERVERS = TAG + POSTFIX_UID_OBSERVERS;
- private static final String TAG_URI_PERMISSION = TAG + POSTFIX_URI_PERMISSION;
// Mock "pretend we're idle now" broadcast action to the job scheduler; declared
// here so that while the job scheduler can depend on AMS, the other way around
@@ -563,6 +561,7 @@
String mDeviceOwnerName;
final UserController mUserController;
+ final PendingIntentController mPendingIntentController;
final AppErrors mAppErrors;
@@ -821,12 +820,6 @@
final SparseArray<UidRecord> mValidateUids = new SparseArray<>();
/**
- * Set of IntentSenderRecord objects that are currently active.
- */
- final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords
- = new HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>>();
-
- /**
* Fingerprints (hashCode()) of stack traces that we've
* already logged DropBox entries for. Guarded by itself. If
* something (rogue user app) forces this over
@@ -1426,7 +1419,6 @@
static final int UPDATE_TIME_ZONE = 13;
static final int PROC_START_TIMEOUT_MSG = 20;
static final int KILL_APPLICATION_MSG = 22;
- static final int FINALIZE_PENDING_INTENT_MSG = 23;
static final int SHOW_STRICT_MODE_VIOLATION_UI_MSG = 26;
static final int CHECK_EXCESSIVE_POWER_USE_MSG = 27;
static final int CLEAR_DNS_CACHE_MSG = 28;
@@ -1445,7 +1437,6 @@
static final int IDLE_UIDS_MSG = 58;
static final int HANDLE_TRUST_STORAGE_UPDATE_MSG = 63;
static final int SERVICE_FOREGROUND_TIMEOUT_MSG = 66;
- static final int DISPATCH_PENDING_INTENT_CANCEL_MSG = 67;
static final int PUSH_TEMP_WHITELIST_UI_MSG = 68;
static final int SERVICE_FOREGROUND_CRASH_MSG = 69;
static final int DISPATCH_OOM_ADJ_OBSERVER_MSG = 70;
@@ -1644,21 +1635,6 @@
mServices.serviceForegroundCrash(
(ProcessRecord) msg.obj, msg.getData().getCharSequence(SERVICE_RECORD_KEY));
} break;
- case DISPATCH_PENDING_INTENT_CANCEL_MSG: {
- RemoteCallbackList<IResultReceiver> callbacks
- = (RemoteCallbackList<IResultReceiver>)msg.obj;
- int N = callbacks.beginBroadcast();
- for (int i = 0; i < N; i++) {
- try {
- callbacks.getBroadcastItem(i).send(Activity.RESULT_CANCELED, null);
- } catch (RemoteException e) {
- }
- }
- callbacks.finishBroadcast();
- // We have to clean up the RemoteCallbackList here, because otherwise it will
- // needlessly hold the enclosed callbacks until the remote process dies.
- callbacks.kill();
- } break;
case UPDATE_TIME_ZONE: {
synchronized (ActivityManagerService.this) {
for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
@@ -1738,9 +1714,6 @@
false, userId, reason);
}
} break;
- case FINALIZE_PENDING_INTENT_MSG: {
- ((PendingIntentRecord)msg.obj).completeFinalize();
- } break;
case CHECK_EXCESSIVE_POWER_USE_MSG: {
synchronized (ActivityManagerService.this) {
checkExcessivePowerUsageLocked();
@@ -2354,6 +2327,7 @@
mSystemThread = null;
mUiHandler = injector.getUiHandler(null);
mUserController = null;
+ mPendingIntentController = null;
mProcStartHandlerThread = null;
mProcStartHandler = null;
mHiddenApiBlacklist = null;
@@ -2438,6 +2412,9 @@
mAtmInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
mStackSupervisor = mActivityTaskManager.mStackSupervisor;
+ mPendingIntentController = new PendingIntentController(
+ mHandlerThread.getLooper(), mUserController);
+
mProcessCpuThread = new Thread("CpuTracker") {
@Override
public void run() {
@@ -2508,6 +2485,7 @@
LocalServices.addService(ActivityManagerInternal.class, new LocalService());
mActivityTaskManager.onActivityManagerInternalAdded();
mUgmInternal.onActivityManagerInternalAdded();
+ mPendingIntentController.onActivityManagerInternalAdded();
// Wait for the synchronized block started in mProcessCpuThread,
// so that any other access to mProcessCpuTracker from main thread
// will be blocked during mProcessCpuTracker initialization.
@@ -5511,55 +5489,8 @@
}
if (packageName == null || uninstalling) {
- // Remove pending intents. For now we only do this when force
- // stopping users, because we have some problems when doing this
- // for packages -- app widgets are not currently cleaned up for
- // such packages, so they can be left with bad pending intents.
- if (mIntentSenderRecords.size() > 0) {
- Iterator<WeakReference<PendingIntentRecord>> it
- = mIntentSenderRecords.values().iterator();
- while (it.hasNext()) {
- WeakReference<PendingIntentRecord> wpir = it.next();
- if (wpir == null) {
- it.remove();
- continue;
- }
- PendingIntentRecord pir = wpir.get();
- if (pir == null) {
- it.remove();
- continue;
- }
- if (packageName == null) {
- // Stopping user, remove all objects for the user.
- if (pir.key.userId != userId) {
- // Not the same user, skip it.
- continue;
- }
- } else {
- if (UserHandle.getAppId(pir.uid) != appId) {
- // Different app id, skip it.
- continue;
- }
- if (userId != UserHandle.USER_ALL && pir.key.userId != userId) {
- // Different user, skip it.
- continue;
- }
- if (!pir.key.packageName.equals(packageName)) {
- // Different package, skip it.
- continue;
- }
- }
- if (!doit) {
- return true;
- }
- didSomething = true;
- it.remove();
- makeIntentSenderCanceledLocked(pir);
- if (pir.key.activity != null && pir.key.activity.pendingResults != null) {
- pir.key.activity.pendingResults.remove(pir.ref);
- }
- }
- }
+ didSomething |= mPendingIntentController.removePendingIntentsForPackage(
+ packageName, userId, appId, doit);
}
if (doit) {
@@ -6342,90 +6273,19 @@
}
}
- return getIntentSenderLocked(type, packageName, callingUid, userId,
- token, resultWho, requestCode, intents, resolvedTypes, flags, bOptions);
-
+ if (type == ActivityManager.INTENT_SENDER_ACTIVITY_RESULT) {
+ return mAtmInternal.getIntentSender(type, packageName, callingUid, userId,
+ token, resultWho, requestCode, intents, resolvedTypes, flags, bOptions);
+ }
+ return mPendingIntentController.getIntentSender(type, packageName, callingUid,
+ userId, token, resultWho, requestCode, intents, resolvedTypes, flags,
+ bOptions);
} catch (RemoteException e) {
throw new SecurityException(e);
}
}
}
- IIntentSender getIntentSenderLocked(int type, String packageName,
- int callingUid, int userId, IBinder token, String resultWho,
- int requestCode, Intent[] intents, String[] resolvedTypes, int flags,
- Bundle bOptions) {
- if (DEBUG_MU) Slog.v(TAG_MU, "getIntentSenderLocked(): uid=" + callingUid);
- ActivityRecord activity = null;
- if (type == ActivityManager.INTENT_SENDER_ACTIVITY_RESULT) {
- activity = ActivityRecord.isInStackLocked(token);
- if (activity == null) {
- Slog.w(TAG, "Failed createPendingResult: activity " + token + " not in any stack");
- return null;
- }
- if (activity.finishing) {
- Slog.w(TAG, "Failed createPendingResult: activity " + activity + " is finishing");
- return null;
- }
- }
-
- // We're going to be splicing together extras before sending, so we're
- // okay poking into any contained extras.
- if (intents != null) {
- for (int i = 0; i < intents.length; i++) {
- intents[i].setDefusable(true);
- }
- }
- Bundle.setDefusable(bOptions, true);
-
- final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
- final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
- final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
- flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
- |PendingIntent.FLAG_UPDATE_CURRENT);
-
- PendingIntentRecord.Key key = new PendingIntentRecord.Key(type, packageName, activity,
- resultWho, requestCode, intents, resolvedTypes, flags,
- SafeActivityOptions.fromBundle(bOptions), userId);
- WeakReference<PendingIntentRecord> ref;
- ref = mIntentSenderRecords.get(key);
- PendingIntentRecord rec = ref != null ? ref.get() : null;
- if (rec != null) {
- if (!cancelCurrent) {
- if (updateCurrent) {
- if (rec.key.requestIntent != null) {
- rec.key.requestIntent.replaceExtras(intents != null ?
- intents[intents.length - 1] : null);
- }
- if (intents != null) {
- intents[intents.length-1] = rec.key.requestIntent;
- rec.key.allIntents = intents;
- rec.key.allResolvedTypes = resolvedTypes;
- } else {
- rec.key.allIntents = null;
- rec.key.allResolvedTypes = null;
- }
- }
- return rec;
- }
- makeIntentSenderCanceledLocked(rec);
- mIntentSenderRecords.remove(key);
- }
- if (noCreate) {
- return rec;
- }
- rec = new PendingIntentRecord(this, key, callingUid);
- mIntentSenderRecords.put(key, rec.ref);
- if (type == ActivityManager.INTENT_SENDER_ACTIVITY_RESULT) {
- if (activity.pendingResults == null) {
- activity.pendingResults
- = new HashSet<WeakReference<PendingIntentRecord>>();
- }
- activity.pendingResults.add(rec.ref);
- }
- return rec;
- }
-
@Override
public int sendIntentSender(IIntentSender target, IBinder whitelistToken, int code,
Intent intent, String resolvedType,
@@ -6465,44 +6325,7 @@
@Override
public void cancelIntentSender(IIntentSender sender) {
- if (!(sender instanceof PendingIntentRecord)) {
- return;
- }
- synchronized(this) {
- PendingIntentRecord rec = (PendingIntentRecord)sender;
- try {
- final int uid = AppGlobals.getPackageManager().getPackageUid(rec.key.packageName,
- MATCH_DEBUG_TRIAGED_MISSING, UserHandle.getCallingUserId());
- if (!UserHandle.isSameApp(uid, Binder.getCallingUid())) {
- String msg = "Permission Denial: cancelIntentSender() from pid="
- + Binder.getCallingPid()
- + ", uid=" + Binder.getCallingUid()
- + " is not allowed to cancel package "
- + rec.key.packageName;
- Slog.w(TAG, msg);
- throw new SecurityException(msg);
- }
- } catch (RemoteException e) {
- throw new SecurityException(e);
- }
- cancelIntentSenderLocked(rec, true);
- }
- }
-
- void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) {
- makeIntentSenderCanceledLocked(rec);
- mIntentSenderRecords.remove(rec.key);
- if (cleanActivity && rec.key.activity != null) {
- rec.key.activity.pendingResults.remove(rec.ref);
- }
- }
-
- void makeIntentSenderCanceledLocked(PendingIntentRecord rec) {
- rec.canceled = true;
- RemoteCallbackList<IResultReceiver> callbacks = rec.detachCancelListenersLocked();
- if (callbacks != null) {
- mHandler.obtainMessage(DISPATCH_PENDING_INTENT_CANCEL_MSG, callbacks).sendToTarget();
- }
+ mPendingIntentController.cancelIntentSender(sender);
}
@Override
@@ -10866,7 +10689,7 @@
pw.println("-------------------------------------------------------------------------------");
}
- dumpPendingIntentsLocked(fd, pw, args, opti, dumpAll, dumpPackage);
+ mPendingIntentController.dumpPendingIntents(pw, dumpAll, dumpPackage);
pw.println();
if (dumpAll) {
pw.println("-------------------------------------------------------------------------------");
@@ -11159,7 +10982,7 @@
opti++;
}
synchronized (this) {
- dumpPendingIntentsLocked(fd, pw, args, opti, true, dumpPackage);
+ mPendingIntentController.dumpPendingIntents(pw, true, dumpPackage);
}
} else if ("processes".equals(cmd) || "p".equals(cmd)) {
if (opti < args.length) {
@@ -12857,61 +12680,6 @@
mUgmInternal.dump(pw, dumpAll, dumpPackage);
}
- void dumpPendingIntentsLocked(FileDescriptor fd, PrintWriter pw, String[] args,
- int opti, boolean dumpAll, String dumpPackage) {
- boolean printed = false;
-
- pw.println("ACTIVITY MANAGER PENDING INTENTS (dumpsys activity intents)");
-
- if (mIntentSenderRecords.size() > 0) {
- // Organize these by package name, so they are easier to read.
- final ArrayMap<String, ArrayList<PendingIntentRecord>> byPackage = new ArrayMap<>();
- final ArrayList<WeakReference<PendingIntentRecord>> weakRefs = new ArrayList<>();
- final Iterator<WeakReference<PendingIntentRecord>> it
- = mIntentSenderRecords.values().iterator();
- while (it.hasNext()) {
- WeakReference<PendingIntentRecord> ref = it.next();
- PendingIntentRecord rec = ref != null ? ref.get() : null;
- if (rec == null) {
- weakRefs.add(ref);
- continue;
- }
- if (dumpPackage != null && !dumpPackage.equals(rec.key.packageName)) {
- continue;
- }
- ArrayList<PendingIntentRecord> list = byPackage.get(rec.key.packageName);
- if (list == null) {
- list = new ArrayList<>();
- byPackage.put(rec.key.packageName, list);
- }
- list.add(rec);
- }
- for (int i = 0; i < byPackage.size(); i++) {
- ArrayList<PendingIntentRecord> intents = byPackage.valueAt(i);
- printed = true;
- pw.print(" * "); pw.print(byPackage.keyAt(i));
- pw.print(": "); pw.print(intents.size()); pw.println(" items");
- for (int j = 0; j < intents.size(); j++) {
- pw.print(" #"); pw.print(j); pw.print(": "); pw.println(intents.get(j));
- if (dumpAll) {
- intents.get(j).dump(pw, " ");
- }
- }
- }
- if (weakRefs.size() > 0) {
- printed = true;
- pw.println(" * WEAK REFS:");
- for (int i = 0; i < weakRefs.size(); i++) {
- pw.print(" #"); pw.print(i); pw.print(": "); pw.println(weakRefs.get(i));
- }
- }
- }
-
- if (!printed) {
- pw.println(" (nothing)");
- }
- }
-
private static final int dumpProcessList(PrintWriter pw,
ActivityManagerService service, List list,
String prefix, String normalLabel, String persistentLabel,
@@ -15186,24 +14954,6 @@
}
}
- ComponentName startServiceInPackage(int uid, Intent service, String resolvedType,
- boolean fgRequired, String callingPackage, int userId)
- throws TransactionTooLargeException {
- synchronized(this) {
- if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
- "startServiceInPackage: " + service + " type=" + resolvedType);
- final long origId = Binder.clearCallingIdentity();
- ComponentName res;
- try {
- res = mServices.startServiceLocked(null, service,
- resolvedType, -1, uid, fgRequired, callingPackage, userId);
- } finally {
- Binder.restoreCallingIdentity(origId);
- }
- return res;
- }
- }
-
@Override
public int stopService(IApplicationThread caller, Intent service,
String resolvedType, int userId) {
@@ -20892,7 +20642,8 @@
memoryStat.pgmajfault,
memoryStat.rssInBytes,
memoryStat.cacheInBytes,
- memoryStat.swapInBytes);
+ memoryStat.swapInBytes,
+ memoryStat.rssHighWatermarkInBytes);
processMemoryStates.add(processMemoryState);
}
}
@@ -21091,6 +20842,46 @@
public void finishBooting() {
ActivityManagerService.this.finishBooting();
}
+
+ @Override
+ public void tempWhitelistForPendingIntent(int callerPid, int callerUid, int targetUid,
+ long duration, String tag) {
+ synchronized (ActivityManagerService.this) {
+ ActivityManagerService.this.tempWhitelistForPendingIntentLocked(
+ callerPid, callerUid, targetUid, duration, tag);
+ }
+ }
+
+ @Override
+ public int broadcastIntentInPackage(String packageName, int uid, Intent intent,
+ String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData,
+ Bundle resultExtras, String requiredPermission, Bundle bOptions, boolean serialized,
+ boolean sticky, int userId) {
+ synchronized (ActivityManagerService.this) {
+ return ActivityManagerService.this.broadcastIntentInPackage(packageName, uid,
+ intent, resolvedType, resultTo, resultCode, resultData, resultExtras,
+ requiredPermission, bOptions, serialized, sticky, userId);
+ }
+ }
+
+ @Override
+ public ComponentName startServiceInPackage(int uid, Intent service, String resolvedType,
+ boolean fgRequired, String callingPackage, int userId)
+ throws TransactionTooLargeException {
+ synchronized(ActivityManagerService.this) {
+ if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
+ "startServiceInPackage: " + service + " type=" + resolvedType);
+ final long origId = Binder.clearCallingIdentity();
+ ComponentName res;
+ try {
+ res = mServices.startServiceLocked(null, service,
+ resolvedType, -1, uid, fgRequired, callingPackage, userId);
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ return res;
+ }
+ }
}
/**
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 35a1eb8..63778a4 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -4144,7 +4144,7 @@
for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
PendingIntentRecord rec = apr.get();
if (rec != null) {
- mService.mAm.cancelIntentSenderLocked(rec, false);
+ mService.mPendingIntentController.cancelIntentSender(rec, false);
}
}
r.pendingResults = null;
diff --git a/services/core/java/com/android/server/am/ActivityStartInterceptor.java b/services/core/java/com/android/server/am/ActivityStartInterceptor.java
index 177e2f5..1fb8f87 100644
--- a/services/core/java/com/android/server/am/ActivityStartInterceptor.java
+++ b/services/core/java/com/android/server/am/ActivityStartInterceptor.java
@@ -126,7 +126,7 @@
private IntentSender createIntentSenderForOriginalIntent(int callingUid, int flags) {
Bundle activityOptions = deferCrossProfileAppsAnimationIfNecessary();
- final IIntentSender target = mService.mAm.getIntentSenderLocked(
+ final IIntentSender target = mService.getIntentSenderLocked(
INTENT_SENDER_ACTIVITY, mCallingPackage, callingUid, mUserId, null /*token*/,
null /*resultCode*/, 0 /*requestCode*/,
new Intent[] { mIntent }, new String[] { mResolvedType },
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 7da0519..890aafe 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -783,7 +783,7 @@
if (aInfo != null) {
if (mService.getPackageManagerInternalLocked().isPermissionsReviewRequired(
aInfo.packageName, userId)) {
- IIntentSender target = mService.mAm.getIntentSenderLocked(
+ IIntentSender target = mService.getIntentSenderLocked(
ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage,
callingUid, userId, null, null, 0, new Intent[]{intent},
new String[]{resolvedType}, PendingIntent.FLAG_CANCEL_CURRENT
@@ -1096,7 +1096,7 @@
}
}
- IIntentSender target = mService.mAm.getIntentSenderLocked(
+ IIntentSender target = mService.getIntentSenderLocked(
ActivityManager.INTENT_SENDER_ACTIVITY, "android",
appCallingUid, userId, null, null, 0, new Intent[] { intent },
new String[] { resolvedType }, PendingIntent.FLAG_CANCEL_CURRENT
diff --git a/services/core/java/com/android/server/am/ActivityTaskManagerService.java b/services/core/java/com/android/server/am/ActivityTaskManagerService.java
index 4dc2851..add9f2a 100644
--- a/services/core/java/com/android/server/am/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityTaskManagerService.java
@@ -239,7 +239,9 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
+import java.lang.ref.WeakReference;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
import java.util.Locale;
@@ -276,6 +278,7 @@
UriGrantsManagerInternal mUgmInternal;
private PackageManagerInternal mPmInternal;
private ActivityTaskManagerInternal mInternal;
+ PendingIntentController mPendingIntentController;
/* Global service lock used by the package the owns this service. */
Object mGlobalLock;
ActivityStackSupervisor mStackSupervisor;
@@ -628,6 +631,7 @@
final File systemDir = SystemServiceManager.ensureSystemDir();
mAppWarnings = new AppWarnings(this, mUiContext, mH, mUiHandler, systemDir);
mCompatModePackages = new CompatModePackages(this, systemDir, mH);
+ mPendingIntentController = mAm.mPendingIntentController;
mTempConfig.setToDefaults();
mTempConfig.setLocales(LocaleList.getDefault());
@@ -5019,6 +5023,39 @@
}
+ IIntentSender getIntentSenderLocked(int type, String packageName, int callingUid, int userId,
+ IBinder token, String resultWho, int requestCode, Intent[] intents,
+ String[] resolvedTypes, int flags, Bundle bOptions) {
+
+ ActivityRecord activity = null;
+ if (type == ActivityManager.INTENT_SENDER_ACTIVITY_RESULT) {
+ activity = ActivityRecord.isInStackLocked(token);
+ if (activity == null) {
+ Slog.w(TAG, "Failed createPendingResult: activity " + token + " not in any stack");
+ return null;
+ }
+ if (activity.finishing) {
+ Slog.w(TAG, "Failed createPendingResult: activity " + activity + " is finishing");
+ return null;
+ }
+ }
+
+ final PendingIntentRecord rec = mPendingIntentController.getIntentSender(type, packageName,
+ callingUid, userId, token, resultWho, requestCode, intents, resolvedTypes, flags,
+ bOptions);
+ final boolean noCreate = (flags & PendingIntent.FLAG_NO_CREATE) != 0;
+ if (noCreate) {
+ return rec;
+ }
+ if (type == ActivityManager.INTENT_SENDER_ACTIVITY_RESULT) {
+ if (activity.pendingResults == null) {
+ activity.pendingResults = new HashSet<>();
+ }
+ activity.pendingResults.add(rec.ref);
+ }
+ return rec;
+ }
+
// TODO(b/111541062): Update app time tracking to make it aware of multiple resumed activities
private void startTimeTrackingFocusedActivityLocked() {
final ActivityRecord resumedActivity = mStackSupervisor.getTopResumedActivity();
@@ -5310,6 +5347,31 @@
}
@Override
+ public int startActivitiesInPackage(int uid, String callingPackage, Intent[] intents,
+ String[] resolvedTypes, IBinder resultTo, SafeActivityOptions options, int userId,
+ boolean validateIncomingUser, PendingIntentRecord originatingPendingIntent) {
+ synchronized (mGlobalLock) {
+ return getActivityStartController().startActivitiesInPackage(uid, callingPackage,
+ intents, resolvedTypes, resultTo, options, userId, validateIncomingUser,
+ originatingPendingIntent);
+ }
+ }
+
+ @Override
+ public int startActivityInPackage(int uid, int realCallingPid, int realCallingUid,
+ String callingPackage, Intent intent, String resolvedType, IBinder resultTo,
+ String resultWho, int requestCode, int startFlags, SafeActivityOptions options,
+ int userId, TaskRecord inTask, String reason, boolean validateIncomingUser,
+ PendingIntentRecord originatingPendingIntent) {
+ synchronized (mGlobalLock) {
+ return getActivityStartController().startActivityInPackage(uid, realCallingPid,
+ realCallingUid, callingPackage, intent, resolvedType, resultTo, resultWho,
+ requestCode, startFlags, options, userId, inTask, reason,
+ validateIncomingUser, originatingPendingIntent);
+ }
+ }
+
+ @Override
public int startActivityAsUser(IApplicationThread caller, String callerPacakge,
Intent intent, Bundle options, int userId) {
return ActivityTaskManagerService.this.startActivityAsUser(
@@ -5684,5 +5746,39 @@
}
});
}
+
+ @Override
+ public void sendActivityResult(int callingUid, IBinder activityToken, String resultWho,
+ int requestCode, int resultCode, Intent data) {
+ synchronized (mGlobalLock) {
+ final ActivityRecord r = ActivityRecord.isInStackLocked(activityToken);
+ if (r != null && r.getStack() != null) {
+ r.getStack().sendActivityResultLocked(callingUid, r, resultWho, requestCode,
+ resultCode, data);
+ }
+ }
+ }
+
+ @Override
+ public void clearPendingResultForActivity(IBinder activityToken,
+ WeakReference<PendingIntentRecord> pir) {
+ synchronized (mGlobalLock) {
+ final ActivityRecord r = ActivityRecord.isInStackLocked(activityToken);
+ if (r != null && r.pendingResults != null) {
+ r.pendingResults.remove(pir);
+ }
+ }
+ }
+
+ @Override
+ public IIntentSender getIntentSender(int type, String packageName,
+ int callingUid, int userId, IBinder token, String resultWho,
+ int requestCode, Intent[] intents, String[] resolvedTypes, int flags,
+ Bundle bOptions) {
+ synchronized (mGlobalLock) {
+ return getIntentSenderLocked(type, packageName, callingUid, userId, token,
+ resultWho, requestCode, intents, resolvedTypes, flags, bOptions);
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 16c3235..e2035f6 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -741,7 +741,7 @@
// Show a permission review UI only for explicit broadcast from a foreground app
if (callerForeground && receiverRecord.intent.getComponent() != null) {
- IIntentSender target = mService.getIntentSenderLocked(
+ IIntentSender target = mService.mPendingIntentController.getIntentSender(
ActivityManager.INTENT_SENDER_BROADCAST, receiverRecord.callerPackage,
receiverRecord.callingUid, receiverRecord.userId, null, null, 0,
new Intent[]{receiverRecord.intent},
diff --git a/services/core/java/com/android/server/am/KeyguardController.java b/services/core/java/com/android/server/am/KeyguardController.java
index ee4e36f..cfe2829 100644
--- a/services/core/java/com/android/server/am/KeyguardController.java
+++ b/services/core/java/com/android/server/am/KeyguardController.java
@@ -29,16 +29,20 @@
import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS;
import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_TO_SHADE;
import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
+
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
-import static com.android.server.am.KeyguardControllerProto.KEYGUARD_OCCLUDED;
+import static com.android.server.am.KeyguardControllerProto.KEYGUARD_OCCLUDED_STATES;
import static com.android.server.am.KeyguardControllerProto.KEYGUARD_SHOWING;
+import static com.android.server.am.KeyguardOccludedProto.DISPLAY_ID;
+import static com.android.server.am.KeyguardOccludedProto.KEYGUARD_OCCLUDED;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.Trace;
import android.util.Slog;
+import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
import com.android.internal.policy.IKeyguardDismissCallback;
@@ -58,19 +62,18 @@
private static final String TAG = TAG_WITH_CLASS_NAME ? "KeyguardController" : TAG_AM;
- private final ActivityTaskManagerService mService;
private final ActivityStackSupervisor mStackSupervisor;
private WindowManagerService mWindowManager;
private boolean mKeyguardShowing;
private boolean mAodShowing;
private boolean mKeyguardGoingAway;
- private boolean mOccluded;
private boolean mDismissalRequested;
- private ActivityRecord mDismissingKeyguardActivity;
private int mBeforeUnoccludeTransit;
private int mVisibilityTransactionDepth;
- private SleepToken mSleepToken;
+ // TODO(b/111955725): Support multiple external displays
private int mSecondaryDisplayShowing = INVALID_DISPLAY;
+ private final SparseArray<KeyguardDisplayState> mDisplayStates = new SparseArray<>();
+ private final ActivityTaskManagerService mService;
KeyguardController(ActivityTaskManagerService service,
ActivityStackSupervisor stackSupervisor) {
@@ -87,8 +90,8 @@
* on the given display, false otherwise
*/
boolean isKeyguardOrAodShowing(int displayId) {
- return (mKeyguardShowing || mAodShowing) && !mKeyguardGoingAway &&
- (displayId == DEFAULT_DISPLAY ? !mOccluded : displayId == mSecondaryDisplayShowing);
+ return (mKeyguardShowing || mAodShowing) && !mKeyguardGoingAway
+ && !isDisplayOccluded(displayId);
}
/**
@@ -96,8 +99,7 @@
* display, false otherwise
*/
boolean isKeyguardShowing(int displayId) {
- return mKeyguardShowing && !mKeyguardGoingAway &&
- (displayId == DEFAULT_DISPLAY ? !mOccluded : displayId == mSecondaryDisplayShowing);
+ return mKeyguardShowing && !mKeyguardGoingAway && !isDisplayOccluded(displayId);
}
/**
@@ -133,6 +135,7 @@
if (showingChanged) {
dismissDockedStackIfNeeded();
setKeyguardGoingAway(false);
+ // TODO(b/113840485): Check usage for non-default display
mWindowManager.setKeyguardOrAodShowingOnDefaultDisplay(
isKeyguardOrAodShowing(DEFAULT_DISPLAY));
if (keyguardShowing) {
@@ -248,7 +251,8 @@
// already the dismissing activity, in which case we don't allow it to repeatedly dismiss
// Keyguard.
return dismissKeyguard && canDismissKeyguard() && !mAodShowing
- && (mDismissalRequested || r != mDismissingKeyguardActivity);
+ && (mDismissalRequested
+ || getDisplay(r.getDisplayId()).mDismissingKeyguardActivity != r);
}
/**
@@ -259,44 +263,16 @@
}
private void visibilitiesUpdated() {
- final boolean lastOccluded = mOccluded;
- final ActivityRecord lastDismissingKeyguardActivity = mDismissingKeyguardActivity;
- mOccluded = false;
- mDismissingKeyguardActivity = null;
-
+ boolean requestDismissKeyguard = false;
for (int displayNdx = mStackSupervisor.getChildCount() - 1; displayNdx >= 0; displayNdx--) {
final ActivityDisplay display = mStackSupervisor.getChildAt(displayNdx);
- for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
- final ActivityStack stack = display.getChildAt(stackNdx);
-
- // Only the top activity of the focused stack on the default display may control
- // occluded state.
- if (display.mDisplayId == DEFAULT_DISPLAY
- && mStackSupervisor.isTopDisplayFocusedStack(stack)) {
-
- // A dismissing activity occludes Keyguard in the insecure case for legacy
- // reasons.
- final ActivityRecord topDismissing = stack.getTopDismissingKeyguardActivity();
- mOccluded =
- stack.topActivityOccludesKeyguard()
- || (topDismissing != null
- && stack.topRunningActivityLocked() == topDismissing
- && canShowWhileOccluded(
- true /* dismissKeyguard */,
- false /* showWhenLocked */));
- }
-
- if (mDismissingKeyguardActivity == null
- && stack.getTopDismissingKeyguardActivity() != null) {
- mDismissingKeyguardActivity = stack.getTopDismissingKeyguardActivity();
- }
- }
+ final KeyguardDisplayState state = getDisplay(display.mDisplayId);
+ state.visibilitiesUpdated(this, display);
+ requestDismissKeyguard |= state.mRequestDismissKeyguard;
}
- mOccluded |= mWindowManager.isShowingDream();
- if (mOccluded != lastOccluded) {
- handleOccludedChanged();
- }
- if (mDismissingKeyguardActivity != lastDismissingKeyguardActivity) {
+
+ // Dismissing Keyguard happens globally using the information from all displays.
+ if (requestDismissKeyguard) {
handleDismissKeyguard();
}
}
@@ -305,7 +281,7 @@
* Called when occluded state changed.
*/
private void handleOccludedChanged() {
- mWindowManager.onKeyguardOccludedChanged(mOccluded);
+ mWindowManager.onKeyguardOccludedChanged(isDisplayOccluded(DEFAULT_DISPLAY));
if (isKeyguardLocked()) {
mWindowManager.deferSurfaceLayout();
try {
@@ -322,14 +298,13 @@
}
/**
- * Called when somebody might want to dismiss the Keyguard.
+ * Called when somebody wants to dismiss the Keyguard via the flag.
*/
private void handleDismissKeyguard() {
// We only allow dismissing Keyguard via the flag when Keyguard is secure for legacy
// reasons, because that's how apps used to dismiss Keyguard in the secure case. In the
// insecure case, we actually show it on top of the lockscreen. See #canShowWhileOccluded.
- if (!mOccluded && mDismissingKeyguardActivity != null
- && mWindowManager.isKeyguardSecure()) {
+ if (mWindowManager.isKeyguardSecure()) {
mWindowManager.dismissKeyguard(null /* callback */, null /* message */);
mDismissalRequested = true;
@@ -345,6 +320,10 @@
}
}
+ private boolean isDisplayOccluded(int displayId) {
+ return getDisplay(displayId).mOccluded;
+ }
+
/**
* @return true if Keyguard can be currently dismissed without entering credentials.
*/
@@ -355,12 +334,14 @@
private int resolveOccludeTransit() {
if (mBeforeUnoccludeTransit != TRANSIT_UNSET
&& mWindowManager.getPendingAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE
- && mOccluded) {
+ // TODO(b/113840485): Handle app transition for individual display.
+ && isDisplayOccluded(DEFAULT_DISPLAY)) {
// Reuse old transit in case we are occluding Keyguard again, meaning that we never
// actually occclude/unocclude Keyguard, but just run a normal transition.
return mBeforeUnoccludeTransit;
- } else if (!mOccluded) {
+ // TODO(b/113840485): Handle app transition for individual display.
+ } else if (!isDisplayOccluded(DEFAULT_DISPLAY)) {
// Save transit in case we dismiss/occlude Keyguard shortly after.
mBeforeUnoccludeTransit = mWindowManager.getPendingAppTransition();
@@ -371,7 +352,8 @@
}
private void dismissDockedStackIfNeeded() {
- if (mKeyguardShowing && mOccluded) {
+ // TODO(b/113840485): Handle docked stack for individual display.
+ if (mKeyguardShowing && isDisplayOccluded(DEFAULT_DISPLAY)) {
// The lock screen is currently showing, but is occluded by a window that can
// show on top of the lock screen. In this can we want to dismiss the docked
// stack since it will be complicated/risky to try to put the activity on top
@@ -386,11 +368,116 @@
}
private void updateKeyguardSleepToken() {
- if (mSleepToken == null && isKeyguardOrAodShowing(DEFAULT_DISPLAY)) {
- mSleepToken = mService.acquireSleepToken("Keyguard", DEFAULT_DISPLAY);
- } else if (mSleepToken != null && !isKeyguardOrAodShowing(DEFAULT_DISPLAY)) {
- mSleepToken.release();
- mSleepToken = null;
+ for (int displayNdx = mStackSupervisor.getChildCount() - 1; displayNdx >= 0; displayNdx--) {
+ final ActivityDisplay display = mStackSupervisor.getChildAt(displayNdx);
+ final KeyguardDisplayState state = getDisplay(display.mDisplayId);
+ if (isKeyguardOrAodShowing(display.mDisplayId) && state.mSleepToken == null) {
+ state.acquiredSleepToken();
+ } else if (!isKeyguardOrAodShowing(display.mDisplayId) && state.mSleepToken != null) {
+ state.releaseSleepToken();
+ }
+ }
+ }
+
+ private KeyguardDisplayState getDisplay(int displayId) {
+ if (mDisplayStates.get(displayId) == null) {
+ mDisplayStates.append(displayId,
+ new KeyguardDisplayState(mService, displayId));
+ }
+ return mDisplayStates.get(displayId);
+ }
+
+ void onDisplayRemoved(int displayId) {
+ if (mDisplayStates.get(displayId) != null) {
+ mDisplayStates.get(displayId).onRemoved();
+ mDisplayStates.remove(displayId);
+ }
+ }
+
+ /** Represents Keyguard state per individual display. */
+ private static class KeyguardDisplayState {
+ private final int mDisplayId;
+ private boolean mOccluded;
+ private ActivityRecord mDismissingKeyguardActivity;
+ private boolean mRequestDismissKeyguard;
+ private final ActivityTaskManagerService mService;
+ private SleepToken mSleepToken;
+
+ KeyguardDisplayState(ActivityTaskManagerService service, int displayId) {
+ mService = service;
+ mDisplayId = displayId;
+ }
+
+ void onRemoved() {
+ mDismissingKeyguardActivity = null;
+ releaseSleepToken();
+ }
+
+ void acquiredSleepToken() {
+ if (mSleepToken == null) {
+ mSleepToken = mService.acquireSleepToken("keyguard", mDisplayId);
+ }
+ }
+
+ void releaseSleepToken() {
+ if (mSleepToken != null) {
+ mSleepToken.release();
+ mSleepToken = null;
+ }
+ }
+
+ void visibilitiesUpdated(KeyguardController controller, ActivityDisplay display) {
+ final boolean lastOccluded = mOccluded;
+ final ActivityRecord lastDismissActivity = mDismissingKeyguardActivity;
+ mRequestDismissKeyguard = false;
+ mOccluded = false;
+ mDismissingKeyguardActivity = null;
+
+ // Only the top activity of the focused stack on each display may control it's
+ // occluded state.
+ final ActivityStack focusedStack = display.getFocusedStack();
+ if (focusedStack != null) {
+ final ActivityRecord topDismissing =
+ focusedStack.getTopDismissingKeyguardActivity();
+ mOccluded = focusedStack.topActivityOccludesKeyguard() || (topDismissing != null
+ && focusedStack.topRunningActivityLocked() == topDismissing
+ && controller.canShowWhileOccluded(
+ true /* dismissKeyguard */,
+ false /* showWhenLocked */));
+ if (focusedStack.getTopDismissingKeyguardActivity() != null) {
+ mDismissingKeyguardActivity = focusedStack.getTopDismissingKeyguardActivity();
+ }
+ mOccluded |= controller.mWindowManager.isShowingDream();
+ }
+
+ // TODO(b/113840485): Handle app transition for individual display.
+ // For now, only default display can change occluded.
+ if (lastOccluded != mOccluded && mDisplayId == DEFAULT_DISPLAY) {
+ controller.handleOccludedChanged();
+ }
+ if (lastDismissActivity != mDismissingKeyguardActivity && !mOccluded
+ && mDismissingKeyguardActivity != null
+ && controller.mWindowManager.isKeyguardSecure()) {
+ mRequestDismissKeyguard = true;
+ }
+ }
+
+ void dumpStatus(PrintWriter pw, String prefix) {
+ final StringBuilder sb = new StringBuilder();
+ sb.append(prefix);
+ sb.append(" Occluded=").append(mOccluded)
+ .append(" DismissingKeyguardActivity=")
+ .append(mDismissingKeyguardActivity)
+ .append(" at display=")
+ .append(mDisplayId);
+ pw.println(sb.toString());
+ }
+
+ void writeToProto(ProtoOutputStream proto, long fieldId) {
+ final long token = proto.start(fieldId);
+ proto.write(DISPLAY_ID, mDisplayId);
+ proto.write(KEYGUARD_OCCLUDED, mOccluded);
+ proto.end(token);
}
}
@@ -399,8 +486,7 @@
pw.println(prefix + " mKeyguardShowing=" + mKeyguardShowing);
pw.println(prefix + " mAodShowing=" + mAodShowing);
pw.println(prefix + " mKeyguardGoingAway=" + mKeyguardGoingAway);
- pw.println(prefix + " mOccluded=" + mOccluded);
- pw.println(prefix + " mDismissingKeyguardActivity=" + mDismissingKeyguardActivity);
+ dumpDisplayStates(pw, prefix);
pw.println(prefix + " mDismissalRequested=" + mDismissalRequested);
pw.println(prefix + " mVisibilityTransactionDepth=" + mVisibilityTransactionDepth);
}
@@ -408,7 +494,19 @@
void writeToProto(ProtoOutputStream proto, long fieldId) {
final long token = proto.start(fieldId);
proto.write(KEYGUARD_SHOWING, mKeyguardShowing);
- proto.write(KEYGUARD_OCCLUDED, mOccluded);
+ writeDisplayStatesToProto(proto, KEYGUARD_OCCLUDED_STATES);
proto.end(token);
}
+
+ private void dumpDisplayStates(PrintWriter pw, String prefix) {
+ for (int i = 0; i < mDisplayStates.size(); i++) {
+ mDisplayStates.valueAt(i).dumpStatus(pw, prefix);
+ }
+ }
+
+ private void writeDisplayStatesToProto(ProtoOutputStream proto, long fieldId) {
+ for (int i = 0; i < mDisplayStates.size(); i++) {
+ mDisplayStates.valueAt(i).writeToProto(proto, fieldId);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/am/MemoryStatUtil.java b/services/core/java/com/android/server/am/MemoryStatUtil.java
index aad890b..228c71d 100644
--- a/services/core/java/com/android/server/am/MemoryStatUtil.java
+++ b/services/core/java/com/android/server/am/MemoryStatUtil.java
@@ -37,18 +37,25 @@
* Static utility methods related to {@link MemoryStat}.
*/
final class MemoryStatUtil {
+ static final int BYTES_IN_KILOBYTE = 1024;
+
private static final String TAG = TAG_WITH_CLASS_NAME ? "MemoryStatUtil" : TAG_AM;
/** True if device has per-app memcg */
- private static final Boolean DEVICE_HAS_PER_APP_MEMCG =
+ private static final boolean DEVICE_HAS_PER_APP_MEMCG =
SystemProperties.getBoolean("ro.config.per_app_memcg", false);
/** Path to check if device has memcg */
private static final String MEMCG_TEST_PATH = "/dev/memcg/apps/memory.stat";
/** Path to memory stat file for logging app start memory state */
private static final String MEMORY_STAT_FILE_FMT = "/dev/memcg/apps/uid_%d/pid_%d/memory.stat";
+ /** Path to memory max usage file for logging app memory state */
+ private static final String MEMORY_MAX_USAGE_FILE_FMT =
+ "/dev/memcg/apps/uid_%d/pid_%d/memory.max_usage_in_bytes";
/** Path to procfs stat file for logging app start memory state */
private static final String PROC_STAT_FILE_FMT = "/proc/%d/stat";
+ /** Path to procfs status file for logging app memory state */
+ private static final String PROC_STATUS_FILE_FMT = "/proc/%d/status";
private static final Pattern PGFAULT = Pattern.compile("total_pgfault (\\d+)");
private static final Pattern PGMAJFAULT = Pattern.compile("total_pgmajfault (\\d+)");
@@ -56,6 +63,9 @@
private static final Pattern CACHE_IN_BYTES = Pattern.compile("total_cache (\\d+)");
private static final Pattern SWAP_IN_BYTES = Pattern.compile("total_swap (\\d+)");
+ private static final Pattern RSS_HIGH_WATERMARK_IN_BYTES =
+ Pattern.compile("VmHWM:\\s*(\\d+)\\s*kB");
+
private static final int PGFAULT_INDEX = 9;
private static final int PGMAJFAULT_INDEX = 11;
private static final int RSS_IN_BYTES_INDEX = 23;
@@ -80,8 +90,15 @@
*/
@Nullable
static MemoryStat readMemoryStatFromMemcg(int uid, int pid) {
- final String path = String.format(Locale.US, MEMORY_STAT_FILE_FMT, uid, pid);
- return parseMemoryStatFromMemcg(readFileContents(path));
+ final String statPath = String.format(Locale.US, MEMORY_STAT_FILE_FMT, uid, pid);
+ MemoryStat stat = parseMemoryStatFromMemcg(readFileContents(statPath));
+ if (stat == null) {
+ return null;
+ }
+ String maxUsagePath = String.format(Locale.US, MEMORY_MAX_USAGE_FILE_FMT, uid, pid);
+ stat.rssHighWatermarkInBytes = parseMemoryMaxUsageFromMemCg(
+ readFileContents(maxUsagePath));
+ return stat;
}
/**
@@ -91,8 +108,14 @@
*/
@Nullable
static MemoryStat readMemoryStatFromProcfs(int pid) {
- final String path = String.format(Locale.US, PROC_STAT_FILE_FMT, pid);
- return parseMemoryStatFromProcfs(readFileContents(path));
+ final String statPath = String.format(Locale.US, PROC_STAT_FILE_FMT, pid);
+ MemoryStat stat = parseMemoryStatFromProcfs(readFileContents(statPath));
+ if (stat == null) {
+ return null;
+ }
+ final String statusPath = String.format(Locale.US, PROC_STATUS_FILE_FMT, pid);
+ stat.rssHighWatermarkInBytes = parseVmHWMFromProcfs(readFileContents(statusPath));
+ return stat;
}
private static String readFileContents(String path) {
@@ -113,7 +136,7 @@
/**
* Parses relevant statistics out from the contents of a memory.stat file in memcg.
*/
- @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+ @VisibleForTesting
@Nullable
static MemoryStat parseMemoryStatFromMemcg(String memoryStatContents) {
if (memoryStatContents == null || memoryStatContents.isEmpty()) {
@@ -135,10 +158,18 @@
return memoryStat;
}
+ @VisibleForTesting
+ static long parseMemoryMaxUsageFromMemCg(String memoryMaxUsageContents) {
+ if (memoryMaxUsageContents == null || memoryMaxUsageContents.isEmpty()) {
+ return 0;
+ }
+ return Long.valueOf(memoryMaxUsageContents);
+ }
+
/**
- * Parses relevant statistics out from the contents of a /proc/pid/stat file in procfs.
+ * Parses relevant statistics out from the contents of the /proc/pid/stat file in procfs.
*/
- @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+ @VisibleForTesting
@Nullable
static MemoryStat parseMemoryStatFromProcfs(String procStatContents) {
if (procStatContents == null || procStatContents.isEmpty()) {
@@ -158,6 +189,20 @@
}
/**
+ * Parses RSS high watermark out from the contents of the /proc/pid/status file in procfs. The
+ * returned value is in bytes.
+ */
+ @VisibleForTesting
+ static long parseVmHWMFromProcfs(String procStatusContents) {
+ if (procStatusContents == null || procStatusContents.isEmpty()) {
+ return 0;
+ }
+ Matcher m = RSS_HIGH_WATERMARK_IN_BYTES.matcher(procStatusContents);
+ // Convert value read from /proc/pid/status from kilobytes to bytes.
+ return m.find() ? Long.valueOf(m.group(1)) * BYTES_IN_KILOBYTE : 0;
+ }
+
+ /**
* Returns whether per-app memcg is available on device.
*/
static boolean hasMemcg() {
@@ -175,5 +220,7 @@
long cacheInBytes;
/** Number of bytes of swap usage */
long swapInBytes;
+ /** Number of bytes of peak anonymous and swap cache memory */
+ long rssHighWatermarkInBytes;
}
}
diff --git a/services/core/java/com/android/server/am/PendingIntentController.java b/services/core/java/com/android/server/am/PendingIntentController.java
new file mode 100644
index 0000000..a9c00a7
--- /dev/null
+++ b/services/core/java/com/android/server/am/PendingIntentController.java
@@ -0,0 +1,329 @@
+/*
+ * 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.am;
+
+import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_MU;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+
+import android.app.Activity;
+import android.app.ActivityManagerInternal;
+import android.app.AppGlobals;
+import android.app.PendingIntent;
+import android.content.IIntentSender;
+import android.content.Intent;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteCallbackList;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.ArrayMap;
+import android.util.Slog;
+import com.android.internal.os.IResultReceiver;
+import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.server.LocalServices;
+import com.android.server.wm.ActivityTaskManagerInternal;
+
+import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+
+/**
+ * Helper class for {@link ActivityManagerService} responsible for managing pending intents.
+ *
+ * <p>This class uses {@link #mLock} to synchronize access to internal state and doesn't make use of
+ * {@link ActivityManagerService} lock since there can be direct calls into this class from outside
+ * AM. This helps avoid deadlocks.
+ */
+public class PendingIntentController {
+ private static final String TAG = TAG_WITH_CLASS_NAME ? "PendingIntentController" : TAG_AM;
+ private static final String TAG_MU = TAG + POSTFIX_MU;
+
+ /** Lock for internal state. */
+ final Object mLock = new Object();
+ final Handler mH;
+ ActivityManagerInternal mAmInternal;
+ final UserController mUserController;
+ final ActivityTaskManagerInternal mAtmInternal;
+
+ /** Set of IntentSenderRecord objects that are currently active. */
+ final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords
+ = new HashMap<>();
+
+ PendingIntentController(Looper looper, UserController userController) {
+ mH = new Handler(looper);
+ mAtmInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
+ mUserController = userController;
+ }
+
+ void onActivityManagerInternalAdded() {
+ synchronized (mLock) {
+ mAmInternal = LocalServices.getService(ActivityManagerInternal.class);
+ }
+ }
+
+ PendingIntentRecord getIntentSender(int type, String packageName, int callingUid, int userId,
+ IBinder token, String resultWho, int requestCode, Intent[] intents,
+ String[] resolvedTypes, int flags, Bundle bOptions) {
+ synchronized (mLock) {
+ if (DEBUG_MU) Slog.v(TAG_MU, "getIntentSender(): uid=" + callingUid);
+
+ // We're going to be splicing together extras before sending, so we're
+ // okay poking into any contained extras.
+ if (intents != null) {
+ for (int i = 0; i < intents.length; i++) {
+ intents[i].setDefusable(true);
+ }
+ }
+ Bundle.setDefusable(bOptions, true);
+
+ final boolean noCreate = (flags & PendingIntent.FLAG_NO_CREATE) != 0;
+ final boolean cancelCurrent = (flags & PendingIntent.FLAG_CANCEL_CURRENT) != 0;
+ final boolean updateCurrent = (flags & PendingIntent.FLAG_UPDATE_CURRENT) != 0;
+ flags &= ~(PendingIntent.FLAG_NO_CREATE | PendingIntent.FLAG_CANCEL_CURRENT
+ | PendingIntent.FLAG_UPDATE_CURRENT);
+
+ PendingIntentRecord.Key key = new PendingIntentRecord.Key(type, packageName, token,
+ resultWho, requestCode, intents, resolvedTypes, flags,
+ SafeActivityOptions.fromBundle(bOptions), userId);
+ WeakReference<PendingIntentRecord> ref;
+ ref = mIntentSenderRecords.get(key);
+ PendingIntentRecord rec = ref != null ? ref.get() : null;
+ if (rec != null) {
+ if (!cancelCurrent) {
+ if (updateCurrent) {
+ if (rec.key.requestIntent != null) {
+ rec.key.requestIntent.replaceExtras(intents != null ?
+ intents[intents.length - 1] : null);
+ }
+ if (intents != null) {
+ intents[intents.length - 1] = rec.key.requestIntent;
+ rec.key.allIntents = intents;
+ rec.key.allResolvedTypes = resolvedTypes;
+ } else {
+ rec.key.allIntents = null;
+ rec.key.allResolvedTypes = null;
+ }
+ }
+ return rec;
+ }
+ makeIntentSenderCanceled(rec);
+ mIntentSenderRecords.remove(key);
+ }
+ if (noCreate) {
+ return rec;
+ }
+ rec = new PendingIntentRecord(this, key, callingUid);
+ mIntentSenderRecords.put(key, rec.ref);
+ return rec;
+ }
+ }
+
+ boolean removePendingIntentsForPackage(String packageName, int userId, int appId,
+ boolean doIt) {
+
+ boolean didSomething = false;
+ synchronized (mLock) {
+
+ // Remove pending intents. For now we only do this when force stopping users, because
+ // we have some problems when doing this for packages -- app widgets are not currently
+ // cleaned up for such packages, so they can be left with bad pending intents.
+ if (mIntentSenderRecords.size() <= 0) {
+ return false;
+ }
+
+ Iterator<WeakReference<PendingIntentRecord>> it
+ = mIntentSenderRecords.values().iterator();
+ while (it.hasNext()) {
+ WeakReference<PendingIntentRecord> wpir = it.next();
+ if (wpir == null) {
+ it.remove();
+ continue;
+ }
+ PendingIntentRecord pir = wpir.get();
+ if (pir == null) {
+ it.remove();
+ continue;
+ }
+ if (packageName == null) {
+ // Stopping user, remove all objects for the user.
+ if (pir.key.userId != userId) {
+ // Not the same user, skip it.
+ continue;
+ }
+ } else {
+ if (UserHandle.getAppId(pir.uid) != appId) {
+ // Different app id, skip it.
+ continue;
+ }
+ if (userId != UserHandle.USER_ALL && pir.key.userId != userId) {
+ // Different user, skip it.
+ continue;
+ }
+ if (!pir.key.packageName.equals(packageName)) {
+ // Different package, skip it.
+ continue;
+ }
+ }
+ if (!doIt) {
+ return true;
+ }
+ didSomething = true;
+ it.remove();
+ makeIntentSenderCanceled(pir);
+ if (pir.key.activity != null) {
+ final Message m = PooledLambda.obtainMessage(
+ PendingIntentController::clearPendingResultForActivity, this,
+ pir.key.activity, pir.ref);
+ mH.sendMessage(m);
+ }
+ }
+ }
+
+ return didSomething;
+ }
+
+ public void cancelIntentSender(IIntentSender sender) {
+ if (!(sender instanceof PendingIntentRecord)) {
+ return;
+ }
+ synchronized (mLock) {
+ final PendingIntentRecord rec = (PendingIntentRecord) sender;
+ try {
+ final int uid = AppGlobals.getPackageManager().getPackageUid(rec.key.packageName,
+ MATCH_DEBUG_TRIAGED_MISSING, UserHandle.getCallingUserId());
+ if (!UserHandle.isSameApp(uid, Binder.getCallingUid())) {
+ String msg = "Permission Denial: cancelIntentSender() from pid="
+ + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
+ + " is not allowed to cancel package " + rec.key.packageName;
+ Slog.w(TAG, msg);
+ throw new SecurityException(msg);
+ }
+ } catch (RemoteException e) {
+ throw new SecurityException(e);
+ }
+ cancelIntentSender(rec, true);
+ }
+ }
+
+ public void cancelIntentSender(PendingIntentRecord rec, boolean cleanActivity) {
+ synchronized (mLock) {
+ makeIntentSenderCanceled(rec);
+ mIntentSenderRecords.remove(rec.key);
+ if (cleanActivity && rec.key.activity != null) {
+ final Message m = PooledLambda.obtainMessage(
+ PendingIntentController::clearPendingResultForActivity, this,
+ rec.key.activity, rec.ref);
+ mH.sendMessage(m);
+ }
+ }
+ }
+
+ private void makeIntentSenderCanceled(PendingIntentRecord rec) {
+ rec.canceled = true;
+ final RemoteCallbackList<IResultReceiver> callbacks = rec.detachCancelListenersLocked();
+ if (callbacks != null) {
+ final Message m = PooledLambda.obtainMessage(
+ PendingIntentController::handlePendingIntentCancelled, this, callbacks);
+ mH.sendMessage(m);
+ }
+ }
+
+ private void handlePendingIntentCancelled(RemoteCallbackList<IResultReceiver> callbacks) {
+ int N = callbacks.beginBroadcast();
+ for (int i = 0; i < N; i++) {
+ try {
+ callbacks.getBroadcastItem(i).send(Activity.RESULT_CANCELED, null);
+ } catch (RemoteException e) {
+ // Process is not longer running...whatever.
+ }
+ }
+ callbacks.finishBroadcast();
+ // We have to clean up the RemoteCallbackList here, because otherwise it will
+ // needlessly hold the enclosed callbacks until the remote process dies.
+ callbacks.kill();
+ }
+
+ private void clearPendingResultForActivity(IBinder activityToken,
+ WeakReference<PendingIntentRecord> pir) {
+ mAtmInternal.clearPendingResultForActivity(activityToken, pir);
+ }
+
+ void dumpPendingIntents(PrintWriter pw, boolean dumpAll, String dumpPackage) {
+ synchronized (mLock) {
+ boolean printed = false;
+
+ pw.println("ACTIVITY MANAGER PENDING INTENTS (dumpsys activity intents)");
+
+ if (mIntentSenderRecords.size() > 0) {
+ // Organize these by package name, so they are easier to read.
+ final ArrayMap<String, ArrayList<PendingIntentRecord>> byPackage = new ArrayMap<>();
+ final ArrayList<WeakReference<PendingIntentRecord>> weakRefs = new ArrayList<>();
+ final Iterator<WeakReference<PendingIntentRecord>> it
+ = mIntentSenderRecords.values().iterator();
+ while (it.hasNext()) {
+ WeakReference<PendingIntentRecord> ref = it.next();
+ PendingIntentRecord rec = ref != null ? ref.get() : null;
+ if (rec == null) {
+ weakRefs.add(ref);
+ continue;
+ }
+ if (dumpPackage != null && !dumpPackage.equals(rec.key.packageName)) {
+ continue;
+ }
+ ArrayList<PendingIntentRecord> list = byPackage.get(rec.key.packageName);
+ if (list == null) {
+ list = new ArrayList<>();
+ byPackage.put(rec.key.packageName, list);
+ }
+ list.add(rec);
+ }
+ for (int i = 0; i < byPackage.size(); i++) {
+ ArrayList<PendingIntentRecord> intents = byPackage.valueAt(i);
+ printed = true;
+ pw.print(" * "); pw.print(byPackage.keyAt(i));
+ pw.print(": "); pw.print(intents.size()); pw.println(" items");
+ for (int j = 0; j < intents.size(); j++) {
+ pw.print(" #"); pw.print(j); pw.print(": "); pw.println(intents.get(j));
+ if (dumpAll) {
+ intents.get(j).dump(pw, " ");
+ }
+ }
+ }
+ if (weakRefs.size() > 0) {
+ printed = true;
+ pw.println(" * WEAK REFS:");
+ for (int i = 0; i < weakRefs.size(); i++) {
+ pw.print(" #"); pw.print(i); pw.print(": "); pw.println(weakRefs.get(i));
+ }
+ }
+ }
+
+ if (!printed) {
+ pw.println(" (nothing)");
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index ee1166e..b9c6fa6 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -38,15 +38,16 @@
import android.util.TimeUtils;
import com.android.internal.os.IResultReceiver;
+import com.android.internal.util.function.pooled.PooledLambda;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.Objects;
-final class PendingIntentRecord extends IIntentSender.Stub {
+public final class PendingIntentRecord extends IIntentSender.Stub {
private static final String TAG = TAG_WITH_CLASS_NAME ? "PendingIntentRecord" : TAG_AM;
- final ActivityManagerService owner;
+ final PendingIntentController controller;
final Key key;
final int uid;
final WeakReference<PendingIntentRecord> ref;
@@ -62,7 +63,7 @@
final static class Key {
final int type;
final String packageName;
- final ActivityRecord activity;
+ final IBinder activity;
final String who;
final int requestCode;
final Intent requestIntent;
@@ -76,7 +77,7 @@
private static final int ODD_PRIME_NUMBER = 37;
- Key(int _t, String _p, ActivityRecord _a, String _w,
+ Key(int _t, String _p, IBinder _a, String _w,
int _r, Intent[] _i, String[] _it, int _f, SafeActivityOptions _o, int _userId) {
type = _t;
packageName = _p;
@@ -114,6 +115,7 @@
// + Integer.toHexString(hashCode));
}
+ @Override
public boolean equals(Object otherObj) {
if (otherObj == null) {
return false;
@@ -188,11 +190,11 @@
}
}
- PendingIntentRecord(ActivityManagerService _owner, Key _k, int _u) {
- owner = _owner;
+ PendingIntentRecord(PendingIntentController _controller, Key _k, int _u) {
+ controller = _controller;
key = _k;
uid = _u;
- ref = new WeakReference<PendingIntentRecord>(this);
+ ref = new WeakReference<>(this);
}
void setWhitelistDurationLocked(IBinder whitelistToken, long duration) {
@@ -247,189 +249,196 @@
}
int sendInner(int code, Intent intent, String resolvedType, IBinder whitelistToken,
- IIntentReceiver finishedReceiver,
- String requiredPermission, IBinder resultTo, String resultWho, int requestCode,
- int flagsMask, int flagsValues, Bundle options) {
+ IIntentReceiver finishedReceiver, String requiredPermission, IBinder resultTo,
+ String resultWho, int requestCode, int flagsMask, int flagsValues, Bundle options) {
if (intent != null) intent.setDefusable(true);
if (options != null) options.setDefusable(true);
- synchronized (owner) {
- if (!canceled) {
- sent = true;
- if ((key.flags&PendingIntent.FLAG_ONE_SHOT) != 0) {
- owner.cancelIntentSenderLocked(this, true);
- }
+ Long duration = null;
+ Intent finalIntent = null;
+ Intent[] allIntents = null;
+ String[] allResolvedTypes = null;
+ SafeActivityOptions mergedOptions = null;
+ synchronized (controller.mLock) {
+ if (canceled) {
+ return ActivityManager.START_CANCELED;
+ }
- Intent finalIntent = key.requestIntent != null
- ? new Intent(key.requestIntent) : new Intent();
+ sent = true;
+ if ((key.flags & PendingIntent.FLAG_ONE_SHOT) != 0) {
+ controller.cancelIntentSender(this, true);
+ }
- final boolean immutable = (key.flags & PendingIntent.FLAG_IMMUTABLE) != 0;
- if (!immutable) {
- if (intent != null) {
- int changes = finalIntent.fillIn(intent, key.flags);
- if ((changes & Intent.FILL_IN_DATA) == 0) {
- resolvedType = key.requestResolvedType;
- }
- } else {
+ finalIntent = key.requestIntent != null ? new Intent(key.requestIntent) : new Intent();
+
+ final boolean immutable = (key.flags & PendingIntent.FLAG_IMMUTABLE) != 0;
+ if (!immutable) {
+ if (intent != null) {
+ int changes = finalIntent.fillIn(intent, key.flags);
+ if ((changes & Intent.FILL_IN_DATA) == 0) {
resolvedType = key.requestResolvedType;
}
- flagsMask &= ~Intent.IMMUTABLE_FLAGS;
- flagsValues &= flagsMask;
- finalIntent.setFlags((finalIntent.getFlags() & ~flagsMask) | flagsValues);
} else {
resolvedType = key.requestResolvedType;
}
-
- final int callingUid = Binder.getCallingUid();
- final int callingPid = Binder.getCallingPid();
-
- // Extract options before clearing calling identity
- SafeActivityOptions mergedOptions = key.options;
- if (mergedOptions == null) {
- mergedOptions = SafeActivityOptions.fromBundle(options);
- } else {
- mergedOptions.setCallerOptions(ActivityOptions.fromBundle(options));
- }
-
- final long origId = Binder.clearCallingIdentity();
-
- if (whitelistDuration != null) {
- Long duration = whitelistDuration.get(whitelistToken);
- if (duration != null) {
- int procState = owner.getUidState(callingUid);
- if (!ActivityManager.isProcStateBackground(procState)) {
- StringBuilder tag = new StringBuilder(64);
- tag.append("pendingintent:");
- UserHandle.formatUid(tag, callingUid);
- tag.append(":");
- if (finalIntent.getAction() != null) {
- tag.append(finalIntent.getAction());
- } else if (finalIntent.getComponent() != null) {
- finalIntent.getComponent().appendShortString(tag);
- } else if (finalIntent.getData() != null) {
- tag.append(finalIntent.getData().toSafeString());
- }
- owner.tempWhitelistForPendingIntentLocked(callingPid,
- callingUid, uid, duration, tag.toString());
- } else {
- Slog.w(TAG, "Not doing whitelist " + this + ": caller state="
- + procState);
- }
- }
- }
-
- boolean sendFinish = finishedReceiver != null;
- int userId = key.userId;
- if (userId == UserHandle.USER_CURRENT) {
- userId = owner.mUserController.getCurrentOrTargetUserId();
- }
- int res = START_SUCCESS;
- switch (key.type) {
- case ActivityManager.INTENT_SENDER_ACTIVITY:
- try {
- // Note when someone has a pending intent, even from different
- // users, then there's no need to ensure the calling user matches
- // the target user, so validateIncomingUser is always false below.
-
- if (key.allIntents != null && key.allIntents.length > 1) {
- Intent[] allIntents = new Intent[key.allIntents.length];
- String[] allResolvedTypes = new String[key.allIntents.length];
- System.arraycopy(key.allIntents, 0, allIntents, 0,
- key.allIntents.length);
- if (key.allResolvedTypes != null) {
- System.arraycopy(key.allResolvedTypes, 0, allResolvedTypes, 0,
- key.allResolvedTypes.length);
- }
- allIntents[allIntents.length-1] = finalIntent;
- allResolvedTypes[allResolvedTypes.length-1] = resolvedType;
-
- res = owner.mActivityTaskManager.getActivityStartController().startActivitiesInPackage(
- uid, key.packageName, allIntents, allResolvedTypes,
- resultTo, mergedOptions, userId,
- false /* validateIncomingUser */,
- this /* originatingPendingIntent */);
- } else {
- res = owner.mActivityTaskManager.getActivityStartController().startActivityInPackage(uid,
- callingPid, callingUid, key.packageName, finalIntent,
- resolvedType, resultTo, resultWho, requestCode, 0,
- mergedOptions, userId, null, "PendingIntentRecord",
- false /* validateIncomingUser */,
- this /* originatingPendingIntent */);
- }
- } catch (RuntimeException e) {
- Slog.w(TAG, "Unable to send startActivity intent", e);
- }
- break;
- case ActivityManager.INTENT_SENDER_ACTIVITY_RESULT:
- final ActivityStack stack = key.activity.getStack();
- if (stack != null) {
- stack.sendActivityResultLocked(-1, key.activity, key.who,
- key.requestCode, code, finalIntent);
- }
- break;
- case ActivityManager.INTENT_SENDER_BROADCAST:
- try {
- // If a completion callback has been requested, require
- // that the broadcast be delivered synchronously
- int sent = owner.broadcastIntentInPackage(key.packageName, uid,
- finalIntent, resolvedType, finishedReceiver, code, null, null,
- requiredPermission, options, (finishedReceiver != null),
- false, userId);
- if (sent == ActivityManager.BROADCAST_SUCCESS) {
- sendFinish = false;
- }
- } catch (RuntimeException e) {
- Slog.w(TAG, "Unable to send startActivity intent", e);
- }
- break;
- case ActivityManager.INTENT_SENDER_SERVICE:
- case ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE:
- try {
- owner.startServiceInPackage(uid, finalIntent, resolvedType,
- key.type == ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE,
- key.packageName, userId);
- } catch (RuntimeException e) {
- Slog.w(TAG, "Unable to send startService intent", e);
- } catch (TransactionTooLargeException e) {
- res = ActivityManager.START_CANCELED;
- }
- break;
- }
-
- if (sendFinish && res != ActivityManager.START_CANCELED) {
- try {
- finishedReceiver.performReceive(new Intent(finalIntent), 0,
- null, null, false, false, key.userId);
- } catch (RemoteException e) {
- }
- }
-
- Binder.restoreCallingIdentity(origId);
-
- return res;
+ flagsMask &= ~Intent.IMMUTABLE_FLAGS;
+ flagsValues &= flagsMask;
+ finalIntent.setFlags((finalIntent.getFlags() & ~flagsMask) | flagsValues);
+ } else {
+ resolvedType = key.requestResolvedType;
}
+
+ // Extract options before clearing calling identity
+ mergedOptions = key.options;
+ if (mergedOptions == null) {
+ mergedOptions = SafeActivityOptions.fromBundle(options);
+ } else {
+ mergedOptions.setCallerOptions(ActivityOptions.fromBundle(options));
+ }
+
+ if (whitelistDuration != null) {
+ duration = whitelistDuration.get(whitelistToken);
+ }
+
+ if (key.type == ActivityManager.INTENT_SENDER_ACTIVITY
+ && key.allIntents != null && key.allIntents.length > 1) {
+ // Copy all intents and resolved types while we have the controller lock so we can
+ // use it later when the lock isn't held.
+ allIntents = new Intent[key.allIntents.length];
+ allResolvedTypes = new String[key.allIntents.length];
+ System.arraycopy(key.allIntents, 0, allIntents, 0, key.allIntents.length);
+ if (key.allResolvedTypes != null) {
+ System.arraycopy(key.allResolvedTypes, 0, allResolvedTypes, 0,
+ key.allResolvedTypes.length);
+ }
+ allIntents[allIntents.length - 1] = finalIntent;
+ allResolvedTypes[allResolvedTypes.length - 1] = resolvedType;
+ }
+
}
- return ActivityManager.START_CANCELED;
+ // We don't hold the controller lock beyond this point as we will be calling into AM and WM.
+
+ final int callingUid = Binder.getCallingUid();
+ final int callingPid = Binder.getCallingPid();
+ final long origId = Binder.clearCallingIdentity();
+
+ int res = START_SUCCESS;
+ try {
+ if (duration != null) {
+ int procState = controller.mAmInternal.getUidProcessState(callingUid);
+ if (!ActivityManager.isProcStateBackground(procState)) {
+ StringBuilder tag = new StringBuilder(64);
+ tag.append("pendingintent:");
+ UserHandle.formatUid(tag, callingUid);
+ tag.append(":");
+ if (finalIntent.getAction() != null) {
+ tag.append(finalIntent.getAction());
+ } else if (finalIntent.getComponent() != null) {
+ finalIntent.getComponent().appendShortString(tag);
+ } else if (finalIntent.getData() != null) {
+ tag.append(finalIntent.getData().toSafeString());
+ }
+ controller.mAmInternal.tempWhitelistForPendingIntent(callingPid, callingUid,
+ uid, duration, tag.toString());
+ } else {
+ Slog.w(TAG, "Not doing whitelist " + this + ": caller state=" + procState);
+ }
+ }
+
+ boolean sendFinish = finishedReceiver != null;
+ int userId = key.userId;
+ if (userId == UserHandle.USER_CURRENT) {
+ userId = controller.mUserController.getCurrentOrTargetUserId();
+ }
+
+ switch (key.type) {
+ case ActivityManager.INTENT_SENDER_ACTIVITY:
+ try {
+ // Note when someone has a pending intent, even from different
+ // users, then there's no need to ensure the calling user matches
+ // the target user, so validateIncomingUser is always false below.
+
+ if (key.allIntents != null && key.allIntents.length > 1) {
+ res = controller.mAtmInternal.startActivitiesInPackage(
+ uid, key.packageName, allIntents, allResolvedTypes, resultTo,
+ mergedOptions, userId, false /* validateIncomingUser */,
+ this /* originatingPendingIntent */);
+ } else {
+ res = controller.mAtmInternal.startActivityInPackage(
+ uid, callingPid, callingUid, key.packageName, finalIntent,
+ resolvedType, resultTo, resultWho, requestCode, 0,
+ mergedOptions, userId, null, "PendingIntentRecord",
+ false /* validateIncomingUser */,
+ this /* originatingPendingIntent */);
+ }
+ } catch (RuntimeException e) {
+ Slog.w(TAG, "Unable to send startActivity intent", e);
+ }
+ break;
+ case ActivityManager.INTENT_SENDER_ACTIVITY_RESULT:
+ controller.mAtmInternal.sendActivityResult(-1, key.activity, key.who,
+ key.requestCode, code, finalIntent);
+ break;
+ case ActivityManager.INTENT_SENDER_BROADCAST:
+ try {
+ // If a completion callback has been requested, require
+ // that the broadcast be delivered synchronously
+ int sent = controller.mAmInternal.broadcastIntentInPackage(key.packageName,
+ uid, finalIntent, resolvedType, finishedReceiver, code, null, null,
+ requiredPermission, options, (finishedReceiver != null),
+ false, userId);
+ if (sent == ActivityManager.BROADCAST_SUCCESS) {
+ sendFinish = false;
+ }
+ } catch (RuntimeException e) {
+ Slog.w(TAG, "Unable to send startActivity intent", e);
+ }
+ break;
+ case ActivityManager.INTENT_SENDER_SERVICE:
+ case ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE:
+ try {
+ controller.mAmInternal.startServiceInPackage(uid, finalIntent, resolvedType,
+ key.type == ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE,
+ key.packageName, userId);
+ } catch (RuntimeException e) {
+ Slog.w(TAG, "Unable to send startService intent", e);
+ } catch (TransactionTooLargeException e) {
+ res = ActivityManager.START_CANCELED;
+ }
+ break;
+ }
+
+ if (sendFinish && res != ActivityManager.START_CANCELED) {
+ try {
+ finishedReceiver.performReceive(new Intent(finalIntent), 0,
+ null, null, false, false, key.userId);
+ } catch (RemoteException e) {
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+
+ return res;
}
@Override
protected void finalize() throws Throwable {
try {
if (!canceled) {
- owner.mHandler.sendMessage(owner.mHandler.obtainMessage(
- ActivityManagerService.FINALIZE_PENDING_INTENT_MSG, this));
+ controller.mH.sendMessage(PooledLambda.obtainMessage(
+ PendingIntentRecord::completeFinalize, this));
}
} finally {
super.finalize();
}
}
- public void completeFinalize() {
- synchronized(owner) {
- WeakReference<PendingIntentRecord> current =
- owner.mIntentSenderRecords.get(key);
+ private void completeFinalize() {
+ synchronized(controller.mLock) {
+ WeakReference<PendingIntentRecord> current = controller.mIntentSenderRecords.get(key);
if (current == ref) {
- owner.mIntentSenderRecords.remove(key);
+ controller.mIntentSenderRecords.remove(key);
}
}
}
diff --git a/services/core/java/com/android/server/am/ProcessStatsService.java b/services/core/java/com/android/server/am/ProcessStatsService.java
index 8ce650c..6ffd8a9 100644
--- a/services/core/java/com/android/server/am/ProcessStatsService.java
+++ b/services/core/java/com/android/server/am/ProcessStatsService.java
@@ -23,8 +23,10 @@
import android.os.SystemClock;
import android.os.SystemProperties;
import android.service.procstats.ProcessStatsServiceDumpProto;
+import android.text.format.DateFormat;
import android.util.ArrayMap;
import android.util.AtomicFile;
+import android.util.Log;
import android.util.LongSparseArray;
import android.util.Slog;
import android.util.SparseArray;
@@ -47,6 +49,7 @@
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;
@@ -482,6 +485,23 @@
return finalRes;
}
+ static int parseSectionOptions(String optionsStr) {
+ final String sep = ",";
+ String[] sectionsStr = optionsStr.split(sep);
+ if (sectionsStr.length == 0) {
+ return ProcessStats.REPORT_ALL;
+ }
+ int res = 0;
+ List<String> optionStrList = Arrays.asList(ProcessStats.OPTIONS_STR);
+ for (String sectionStr : sectionsStr) {
+ int optionIndex = optionStrList.indexOf(sectionStr);
+ if (optionIndex != -1) {
+ res |= ProcessStats.OPTIONS[optionIndex];
+ }
+ }
+ return res;
+ }
+
public byte[] getCurrentStats(List<ParcelFileDescriptor> historic) {
mAm.mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.PACKAGE_USAGE_STATS, null);
@@ -514,6 +534,95 @@
return current.marshall();
}
+ /**
+ * Get stats committed after highWaterMarkMs
+ * @param highWaterMarkMs Report stats committed after this time.
+ * @param section Integer mask to indicage which sections to include in the stats.
+ * @param doAggregate Whether to aggregate the stats or keep them separated.
+ * @return List of proto binary of individual commit files or one that is merged from them.
+ */
+ @Override
+ public long getCommittedStats(long highWaterMarkMs, int section, boolean doAggregate,
+ List<ParcelFileDescriptor> committedStats) {
+ mAm.mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.PACKAGE_USAGE_STATS, null);
+
+ ProcessStats mergedStats = new ProcessStats(false);
+ long newHighWaterMark = highWaterMarkMs;
+ mWriteLock.lock();
+ try {
+ ArrayList<String> files = getCommittedFiles(0, false, true);
+ if (files != null) {
+ String highWaterMarkStr =
+ DateFormat.format("yyyy-MM-dd-HH-mm-ss", highWaterMarkMs).toString();
+ ProcessStats stats = new ProcessStats(false);
+ for (int i = files.size() - 1; i >= 0; i--) {
+ String fileName = files.get(i);
+ try {
+ String startTimeStr = fileName.substring(
+ fileName.lastIndexOf(STATE_FILE_PREFIX)
+ + STATE_FILE_PREFIX.length(),
+ fileName.lastIndexOf(STATE_FILE_SUFFIX));
+ if (startTimeStr.compareToIgnoreCase(highWaterMarkStr) > 0) {
+ ParcelFileDescriptor pfd = ParcelFileDescriptor.open(
+ new File(fileName),
+ ParcelFileDescriptor.MODE_READ_ONLY);
+ InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
+ stats.reset();
+ stats.read(is);
+ is.close();
+ if (stats.mTimePeriodStartClock > newHighWaterMark) {
+ newHighWaterMark = stats.mTimePeriodStartClock;
+ }
+ if (doAggregate) {
+ mergedStats.add(stats);
+ } else {
+ committedStats.add(protoToParcelFileDescriptor(stats, section));
+ }
+ if (stats.mReadError != null) {
+ Log.w(TAG, "Failure reading process stats: " + stats.mReadError);
+ continue;
+ }
+ }
+ } catch (IOException e) {
+ Slog.w(TAG, "Failure opening procstat file " + fileName, e);
+ } catch (IndexOutOfBoundsException e) {
+ Slog.w(TAG, "Failure to read and parse commit file " + fileName, e);
+ }
+ }
+ if (doAggregate) {
+ committedStats.add(protoToParcelFileDescriptor(mergedStats, section));
+ }
+ return newHighWaterMark;
+ }
+ } catch (IOException e) {
+ Slog.w(TAG, "Failure opening procstat file", e);
+ } finally {
+ mWriteLock.unlock();
+ }
+ return newHighWaterMark;
+ }
+
+ private ParcelFileDescriptor protoToParcelFileDescriptor(ProcessStats stats, int section)
+ throws IOException {
+ final ParcelFileDescriptor[] fds = ParcelFileDescriptor.createPipe();
+ Thread thr = new Thread("ProcessStats pipe output") {
+ public void run() {
+ try {
+ FileOutputStream fout = new ParcelFileDescriptor.AutoCloseOutputStream(fds[1]);
+ final ProtoOutputStream proto = new ProtoOutputStream(fout);
+ stats.writeToProto(proto, stats.mTimePeriodEndRealtime, section);
+ proto.flush();
+ fout.close();
+ } catch (IOException e) {
+ Slog.w(TAG, "Failure writing pipe", e);
+ }
+ }
+ };
+ thr.start();
+ return fds[0];
+ }
+
public ParcelFileDescriptor getStatsOverTime(long minTime) {
mAm.mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.PACKAGE_USAGE_STATS, null);
@@ -594,7 +703,7 @@
private void dumpAggregatedStats(PrintWriter pw, long aggregateHours, long now,
String reqPackage, boolean isCompact, boolean dumpDetails, boolean dumpFullDetails,
- boolean dumpAll, boolean activeOnly) {
+ boolean dumpAll, boolean activeOnly, int section) {
ParcelFileDescriptor pfd = getStatsOverTime(aggregateHours*60*60*1000
- (ProcessStats.COMMIT_PERIOD/2));
if (pfd == null) {
@@ -609,11 +718,11 @@
return;
}
if (isCompact) {
- stats.dumpCheckinLocked(pw, reqPackage);
+ stats.dumpCheckinLocked(pw, reqPackage, section);
} else {
if (dumpDetails || dumpFullDetails) {
stats.dumpLocked(pw, reqPackage, now, !dumpFullDetails, dumpDetails, dumpAll,
- activeOnly);
+ activeOnly, section);
} else {
stats.dumpSummaryLocked(pw, reqPackage, now, activeOnly);
}
@@ -643,6 +752,8 @@
pw.println(" --max: for -a, max num of historical batches to print.");
pw.println(" --active: only show currently active processes/services.");
pw.println(" --commit: commit current stats to disk and reset to start new stats.");
+ pw.println(" --section: proc|pkg-proc|pkg-svc|pkg-asc|pkg-all|all ");
+ pw.println(" options can be combined to select desired stats");
pw.println(" --reset: reset current stats, without committing.");
pw.println(" --clear: clear all stats; does both --reset and deletes old stats.");
pw.println(" --write: write current in-memory stats to disk.");
@@ -696,6 +807,7 @@
int[] csvMemStats = new int[] { ProcessStats.ADJ_MEM_FACTOR_CRITICAL};
boolean csvSepProcStats = true;
int[] csvProcStats = ProcessStats.ALL_PROC_STATES;
+ int section = ProcessStats.REPORT_ALL;
if (args != null) {
for (int i=0; i<args.length; i++) {
String arg = args[i];
@@ -814,13 +926,14 @@
pw.println("Process stats committed.");
quit = true;
}
- } else if ("--reset".equals(arg)) {
- synchronized (mAm) {
- mProcessStats.resetSafely();
- mAm.requestPssAllProcsLocked(SystemClock.uptimeMillis(), true, false);
- pw.println("Process stats reset.");
- quit = true;
+ } else if ("--section".equals(arg)) {
+ i++;
+ if (i >= args.length) {
+ pw.println("Error: argument required for --section");
+ dumpHelp(pw);
+ return;
}
+ section = parseSectionOptions(args[i]);
} else if ("--clear".equals(arg)) {
synchronized (mAm) {
mProcessStats.resetSafely();
@@ -946,7 +1059,7 @@
} else if (aggregateHours != 0) {
pw.print("AGGREGATED OVER LAST "); pw.print(aggregateHours); pw.println(" HOURS:");
dumpAggregatedStats(pw, aggregateHours, now, reqPackage, isCompact,
- dumpDetails, dumpFullDetails, dumpAll, activeOnly);
+ dumpDetails, dumpFullDetails, dumpAll, activeOnly, section);
return;
} else if (lastIndex > 0) {
pw.print("LAST STATS AT INDEX "); pw.print(lastIndex); pw.println(":");
@@ -968,7 +1081,7 @@
boolean checkedIn = fileStr.endsWith(STATE_FILE_CHECKIN_SUFFIX);
if (isCheckin || isCompact) {
// Don't really need to lock because we uniquely own this object.
- processStats.dumpCheckinLocked(pw, reqPackage);
+ processStats.dumpCheckinLocked(pw, reqPackage, section);
} else {
pw.print("COMMITTED STATS FROM ");
pw.print(processStats.mTimePeriodStartClockStr);
@@ -976,7 +1089,7 @@
pw.println(":");
if (dumpDetails || dumpFullDetails) {
processStats.dumpLocked(pw, reqPackage, now, !dumpFullDetails, dumpDetails,
- dumpAll, activeOnly);
+ dumpAll, activeOnly, section);
if (dumpAll) {
pw.print(" mFile="); pw.println(mFile.getBaseFile());
}
@@ -1015,7 +1128,7 @@
boolean checkedIn = fileStr.endsWith(STATE_FILE_CHECKIN_SUFFIX);
if (isCheckin || isCompact) {
// Don't really need to lock because we uniquely own this object.
- processStats.dumpCheckinLocked(pw, reqPackage);
+ processStats.dumpCheckinLocked(pw, reqPackage, section);
} else {
if (sepNeeded) {
pw.println();
@@ -1031,7 +1144,7 @@
// much crud.
if (dumpFullDetails) {
processStats.dumpLocked(pw, reqPackage, now, false, false,
- false, activeOnly);
+ false, activeOnly, section);
} else {
processStats.dumpSummaryLocked(pw, reqPackage, now, activeOnly);
}
@@ -1054,7 +1167,7 @@
if (!isCheckin) {
synchronized (mAm) {
if (isCompact) {
- mProcessStats.dumpCheckinLocked(pw, reqPackage);
+ mProcessStats.dumpCheckinLocked(pw, reqPackage, section);
} else {
if (sepNeeded) {
pw.println();
@@ -1062,7 +1175,7 @@
pw.println("CURRENT STATS:");
if (dumpDetails || dumpFullDetails) {
mProcessStats.dumpLocked(pw, reqPackage, now, !dumpFullDetails, dumpDetails,
- dumpAll, activeOnly);
+ dumpAll, activeOnly, section);
if (dumpAll) {
pw.print(" mFile="); pw.println(mFile.getBaseFile());
}
@@ -1078,11 +1191,11 @@
}
pw.println("AGGREGATED OVER LAST 24 HOURS:");
dumpAggregatedStats(pw, 24, now, reqPackage, isCompact,
- dumpDetails, dumpFullDetails, dumpAll, activeOnly);
+ dumpDetails, dumpFullDetails, dumpAll, activeOnly, section);
pw.println();
pw.println("AGGREGATED OVER LAST 3 HOURS:");
dumpAggregatedStats(pw, 3, now, reqPackage, isCompact,
- dumpDetails, dumpFullDetails, dumpAll, activeOnly);
+ dumpDetails, dumpFullDetails, dumpAll, activeOnly, section);
}
}
}
@@ -1099,7 +1212,9 @@
if (stats.mReadError != null) {
return;
}
- stats.writeToProto(proto, fieldId, now);
+ final long token = proto.start(fieldId);
+ stats.writeToProto(proto, now, ProcessStats.REPORT_ALL);
+ proto.end(token);
}
private void dumpProto(FileDescriptor fd) {
@@ -1109,7 +1224,9 @@
long now;
synchronized (mAm) {
now = SystemClock.uptimeMillis();
- mProcessStats.writeToProto(proto,ProcessStatsServiceDumpProto.PROCSTATS_NOW, now);
+ final long token = proto.start(ProcessStatsServiceDumpProto.PROCSTATS_NOW);
+ mProcessStats.writeToProto(proto, now, ProcessStats.REPORT_ALL);
+ proto.end(token);
}
// aggregated over last 3 hours procstats
diff --git a/services/core/java/com/android/server/am/SafeActivityOptions.java b/services/core/java/com/android/server/am/SafeActivityOptions.java
index f7de7f4..fa0cb47 100644
--- a/services/core/java/com/android/server/am/SafeActivityOptions.java
+++ b/services/core/java/com/android/server/am/SafeActivityOptions.java
@@ -44,7 +44,7 @@
* the inner options. Also supports having two set of options: Once from the original caller, and
* once from the caller that is overriding it, which happens when sending a {@link PendingIntent}.
*/
-class SafeActivityOptions {
+public class SafeActivityOptions {
private static final String TAG = TAG_WITH_CLASS_NAME ? "SafeActivityOptions" : TAG_AM;
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 9b42d65..ef8cb1c 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -129,7 +129,8 @@
import java.util.ArrayList;
import java.util.Objects;
-class TaskRecord extends ConfigurationContainer implements TaskWindowContainerListener {
+// TODO: Make package private again once move to WM package is complete.
+public class TaskRecord extends ConfigurationContainer implements TaskWindowContainerListener {
private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskRecord" : TAG_AM;
private static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE;
private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS;
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 8caa702..66c7c43 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -627,6 +627,13 @@
// If absolute volume is supported in AVRCP device
private boolean mAvrcpAbsVolSupported = false;
+ // Pre-scale for Bluetooth Absolute Volume
+ private float[] mPrescaleAbsoluteVolume = new float[] {
+ 0.5f, // Pre-scale for index 1
+ 0.7f, // Pre-scale for index 2
+ 0.85f, // Pre-scale for index 3
+ };
+
private static Long mLastDeviceConnectMsgTime = new Long(0);
private NotificationManager mNm;
@@ -878,6 +885,23 @@
mUserManagerInternal.addUserRestrictionsListener(mUserRestrictionsListener);
mRecordMonitor.initMonitor();
+
+ final float[] preScale = new float[3];
+ preScale[0] = mContext.getResources().getFraction(
+ com.android.internal.R.fraction.config_prescaleAbsoluteVolume_index1,
+ 1, 1);
+ preScale[1] = mContext.getResources().getFraction(
+ com.android.internal.R.fraction.config_prescaleAbsoluteVolume_index2,
+ 1, 1);
+ preScale[2] = mContext.getResources().getFraction(
+ com.android.internal.R.fraction.config_prescaleAbsoluteVolume_index3,
+ 1, 1);
+ for (int i = 0; i < preScale.length; i++) {
+ if (0.0f <= preScale[i] && preScale[i] <= 1.0f) {
+ mPrescaleAbsoluteVolume[i] = preScale[i];
+ }
+ }
+
}
public void systemReady() {
@@ -4926,18 +4950,12 @@
if (index == 0) {
// 0% for volume 0
index = 0;
- } else if (index == 1) {
- // 50% for volume 1
- index = (int)(mIndexMax * 0.5) /10;
- } else if (index == 2) {
- // 70% for volume 2
- index = (int)(mIndexMax * 0.70) /10;
- } else if (index == 3) {
- // 85% for volume 3
- index = (int)(mIndexMax * 0.85) /10;
+ } else if (index > 0 && index <= 3) {
+ // Pre-scale for volume steps 1 2 and 3
+ index = (int) (mIndexMax * mPrescaleAbsoluteVolume[index - 1]) / 10;
} else {
// otherwise, full gain
- index = (mIndexMax + 5)/10;
+ index = (mIndexMax + 5) / 10;
}
return index;
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index deeae26..2557f46 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -2828,7 +2828,8 @@
// Assumes it's safe to show starting windows of launched apps while
// the keyguard is being hidden. This is okay because starting windows never show
// secret information.
- if (mKeyguardOccluded) {
+ // TODO(b/113840485): Occluded may not only happen on default display
+ if (displayId == DEFAULT_DISPLAY && mKeyguardOccluded) {
windowFlags |= FLAG_SHOW_WHEN_LOCKED;
}
}
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index 68e636a..5adc248 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -190,6 +190,8 @@
try {
mBatteryStats.noteInteractive(true);
} catch (RemoteException ex) { }
+ StatsLog.write(StatsLog.INTERACTIVE_STATE_CHANGED,
+ StatsLog.INTERACTIVE_STATE_CHANGED__STATE__ON);
}
/**
@@ -401,6 +403,9 @@
try {
mBatteryStats.noteInteractive(interactive);
} catch (RemoteException ex) { }
+ StatsLog.write(StatsLog.INTERACTIVE_STATE_CHANGED,
+ interactive ? StatsLog.INTERACTIVE_STATE_CHANGED__STATE__ON :
+ StatsLog.INTERACTIVE_STATE_CHANGED__STATE__OFF);
// Handle early behaviors.
mInteractive = interactive;
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index bfa03ca..c6e6449 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -966,6 +966,7 @@
e.writeLong(processMemoryState.rssInBytes);
e.writeLong(processMemoryState.cacheInBytes);
e.writeLong(processMemoryState.swapInBytes);
+ e.writeLong(processMemoryState.rssHighWatermarkInBytes);
pulledData.add(e);
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 7d2fc15..bcf9212 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -22,6 +22,7 @@
import android.app.IActivityManager;
import android.app.IApplicationThread;
import android.content.ComponentName;
+import android.content.IIntentSender;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.res.CompatibilityInfo;
@@ -32,8 +33,12 @@
import android.util.SparseIntArray;
import com.android.internal.app.IVoiceInteractor;
+import com.android.server.am.PendingIntentRecord;
+import com.android.server.am.SafeActivityOptions;
+import com.android.server.am.TaskRecord;
import com.android.server.am.WindowProcessController;
+import java.lang.ref.WeakReference;
import java.util.List;
/**
@@ -178,6 +183,27 @@
int userId, Intent[] intents, Bundle bOptions);
/**
+ * Start intents as a package.
+ *
+ * @param uid Make a call as if this UID did.
+ * @param callingPackage Make a call as if this package did.
+ * @param intents Intents to start.
+ * @param userId Start the intents on this user.
+ * @param validateIncomingUser Set true to skip checking {@code userId} with the calling UID.
+ * @param originatingPendingIntent PendingIntentRecord that originated this activity start or
+ * null if not originated by PendingIntent
+ */
+ public abstract int startActivitiesInPackage(int uid, String callingPackage, Intent[] intents,
+ String[] resolvedTypes, IBinder resultTo, SafeActivityOptions options, int userId,
+ boolean validateIncomingUser, PendingIntentRecord originatingPendingIntent);
+
+ public abstract int startActivityInPackage(int uid, int realCallingPid, int realCallingUid,
+ String callingPackage, Intent intent, String resolvedType, IBinder resultTo,
+ String resultWho, int requestCode, int startFlags, SafeActivityOptions options,
+ int userId, TaskRecord inTask, String reason, boolean validateIncomingUser,
+ PendingIntentRecord originatingPendingIntent);
+
+ /**
* Start activity {@code intent} without calling user-id check.
*
* - DO NOT call it with the calling UID cleared.
@@ -297,4 +323,13 @@
* @param displayId The ID of the display showing the IME.
*/
public abstract void onImeWindowSetOnDisplay(int pid, int displayId);
+
+ public abstract void sendActivityResult(int callingUid, IBinder activityToken,
+ String resultWho, int requestCode, int resultCode, Intent data);
+ public abstract void clearPendingResultForActivity(
+ IBinder activityToken, WeakReference<PendingIntentRecord> pir);
+ public abstract IIntentSender getIntentSender(int type, String packageName,
+ int callingUid, int userId, IBinder token, String resultWho,
+ int requestCode, Intent[] intents, String[] resolvedTypes, int flags,
+ Bundle bOptions);
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index eaaf804..236982f 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -2652,6 +2652,12 @@
*/
void setInputMethodWindowLocked(WindowState win) {
mInputMethodWindow = win;
+ // Update display configuration for IME process.
+ if (mInputMethodWindow != null) {
+ final int imePid = mInputMethodWindow.mSession.mPid;
+ mService.mAtmInternal.onImeWindowSetOnDisplay(imePid,
+ mInputMethodWindow.getDisplayId());
+ }
computeImeTarget(true /* updateImeTarget */);
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 7161a70..f7c6d77 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -4535,7 +4535,8 @@
updateSurfacePosition(getPendingTransaction());
}
- private void updateSurfacePosition(Transaction t) {
+ @VisibleForTesting
+ void updateSurfacePosition(Transaction t) {
if (mSurfaceControl == null) {
return;
}
diff --git a/services/robotests/src/com/android/server/backup/keyvalue/AgentExceptionTest.java b/services/robotests/src/com/android/server/backup/keyvalue/AgentExceptionTest.java
new file mode 100644
index 0000000..3730335
--- /dev/null
+++ b/services/robotests/src/com/android/server/backup/keyvalue/AgentExceptionTest.java
@@ -0,0 +1,70 @@
+/*
+ * 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.backup.keyvalue;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.platform.test.annotations.Presubmit;
+
+import com.android.server.testing.FrameworkRobolectricTestRunner;
+import com.android.server.testing.SystemLoaderPackages;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.annotation.Config;
+
+import java.io.IOException;
+
+@RunWith(FrameworkRobolectricTestRunner.class)
+@Config(manifest = Config.NONE, sdk = 26)
+@SystemLoaderPackages({"com.android.server.backup"})
+@Presubmit
+public class AgentExceptionTest {
+ @Test
+ public void testTransitory_isTransitory() throws Exception {
+ AgentException exception = AgentException.transitory();
+
+ assertThat(exception.isTransitory()).isTrue();
+ }
+
+ @Test
+ public void testTransitory_withCause() throws Exception {
+ Exception cause = new IOException();
+
+ AgentException exception = AgentException.transitory(cause);
+
+ assertThat(exception.isTransitory()).isTrue();
+ assertThat(exception.getCause()).isEqualTo(cause);
+ }
+
+ @Test
+ public void testPermanent_isNotTransitory() throws Exception {
+ AgentException exception = AgentException.permanent();
+
+ assertThat(exception.isTransitory()).isFalse();
+ }
+
+ @Test
+ public void testPermanent_withCause() throws Exception {
+ Exception cause = new IOException();
+
+ AgentException exception = AgentException.permanent(cause);
+
+ assertThat(exception.isTransitory()).isFalse();
+ assertThat(exception.getCause()).isEqualTo(cause);
+ }
+}
diff --git a/services/robotests/src/com/android/server/backup/keyvalue/BackupExceptionTest.java b/services/robotests/src/com/android/server/backup/keyvalue/BackupExceptionTest.java
new file mode 100644
index 0000000..5ea74f1
--- /dev/null
+++ b/services/robotests/src/com/android/server/backup/keyvalue/BackupExceptionTest.java
@@ -0,0 +1,45 @@
+/*
+ * 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.backup.keyvalue;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.platform.test.annotations.Presubmit;
+
+import com.android.server.testing.FrameworkRobolectricTestRunner;
+import com.android.server.testing.SystemLoaderPackages;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.annotation.Config;
+
+import java.io.IOException;
+
+@RunWith(FrameworkRobolectricTestRunner.class)
+@Config(manifest = Config.NONE, sdk = 26)
+@SystemLoaderPackages({"com.android.server.backup"})
+@Presubmit
+public class BackupExceptionTest {
+ @Test
+ public void testConstructor_passesCause() {
+ Exception cause = new IOException();
+
+ Exception exception = new BackupException(cause);
+
+ assertThat(exception.getCause()).isEqualTo(cause);
+ }
+}
diff --git a/services/robotests/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java b/services/robotests/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
index b4bc9d1..fb57d68 100644
--- a/services/robotests/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
+++ b/services/robotests/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
@@ -155,9 +155,7 @@
import java.util.concurrent.TimeoutException;
import java.util.stream.Stream;
-// TODO: When returning to RUNNING_QUEUE vs FINAL, RUNNING_QUEUE sets status = OK. Why? Verify?
-// TODO: Check queue in general, behavior w/ multiple packages
-// TODO: Test PM invocation
+// TODO: Test agents timing out
@RunWith(FrameworkRobolectricTestRunner.class)
@Config(
manifest = Config.NONE,
@@ -370,6 +368,47 @@
}
@Test
+ public void testRunTask_whenOnePackage_cleansUpPmFiles() throws Exception {
+ TransportMock transportMock = setUpInitializedTransport(mTransport);
+ setUpAgent(PACKAGE_1);
+ KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
+
+ runTask(task);
+
+ assertCleansUpFiles(mTransport, PM_PACKAGE);
+ }
+
+ @Test
+ public void testRunTask_whenTransportReturnsTransportErrorForPm_cleansUpPmFiles()
+ throws Exception {
+ TransportMock transportMock = setUpInitializedTransport(mTransport);
+ when(transportMock.transport.performBackup(
+ argThat(packageInfo(PM_PACKAGE)), any(), anyInt()))
+ .thenReturn(BackupTransport.TRANSPORT_PACKAGE_REJECTED);
+ setUpAgent(PACKAGE_1);
+ KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
+
+ runTask(task);
+
+ assertCleansUpFiles(mTransport, PM_PACKAGE);
+ }
+
+ @Test
+ public void testRunTask_whenTransportReturnsTransportErrorForPm_resetsBackupState()
+ throws Exception {
+ TransportMock transportMock = setUpInitializedTransport(mTransport);
+ when(transportMock.transport.performBackup(
+ argThat(packageInfo(PM_PACKAGE)), any(), anyInt()))
+ .thenReturn(BackupTransport.TRANSPORT_PACKAGE_REJECTED);
+ setUpAgent(PACKAGE_1);
+ KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
+
+ runTask(task);
+
+ verify(mBackupManagerService).resetBackupState(getStateDirectory(mTransport).toFile());
+ }
+
+ @Test
public void testRunTask_whenOnePackage_updatesBookkeeping() throws Exception {
// Transport has to be initialized to not reset current token
TransportMock transportMock = setUpInitializedTransport(mTransport);
@@ -418,7 +457,7 @@
public void testRunTask_whenNonPmPackageAndNonIncremental_doesNotBackUpPm() throws Exception {
TransportMock transportMock = setUpInitializedTransport(mTransport);
setUpAgentWithData(PACKAGE_1);
- PackageManagerBackupAgent pmAgent = spy(createPmAgent());
+ BackupAgent pmAgent = spy(createPmAgent());
when(mBackupManagerService.makeMetadataAgent()).thenReturn(forward(pmAgent));
KeyValueBackupTask task = createKeyValueBackupTask(transportMock, true, PACKAGE_1);
@@ -431,7 +470,7 @@
public void testRunTask_whenNonPmPackageAndPmAndNonIncremental_backsUpPm() throws Exception {
TransportMock transportMock = setUpInitializedTransport(mTransport);
setUpAgentWithData(PACKAGE_1);
- PackageManagerBackupAgent pmAgent = spy(createPmAgent());
+ BackupAgent pmAgent = spy(createPmAgent());
when(mBackupManagerService.makeMetadataAgent()).thenReturn(forward(pmAgent));
KeyValueBackupTask task =
createKeyValueBackupTask(transportMock, true, PACKAGE_1, PM_PACKAGE);
@@ -445,7 +484,7 @@
public void testRunTask_whenNonPmPackageAndIncremental_backsUpPm() throws Exception {
TransportMock transportMock = setUpInitializedTransport(mTransport);
setUpAgentWithData(PACKAGE_1);
- PackageManagerBackupAgent pmAgent = spy(createPmAgent());
+ BackupAgent pmAgent = spy(createPmAgent());
when(mBackupManagerService.makeMetadataAgent()).thenReturn(forward(pmAgent));
KeyValueBackupTask task = createKeyValueBackupTask(transportMock, false, PACKAGE_1);
@@ -529,6 +568,35 @@
}
@Test
+ public void testRunTask_whenPackageUnknown() throws Exception {
+ TransportMock transportMock = setUpInitializedTransport(mTransport);
+ // Not calling setUpAgent() for PACKAGE_1
+ KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
+
+ runTask(task);
+
+ verify(transportMock.transport, never())
+ .performBackup(argThat(packageInfo(PACKAGE_1)), any(), anyInt());
+ verify(mObserver).onResult(PACKAGE_1.packageName, ERROR_PACKAGE_NOT_FOUND);
+ verify(mObserver).backupFinished(SUCCESS);
+ assertBackupNotPendingFor(PACKAGE_1);
+ }
+
+ @Test
+ public void testRunTask_whenFirstPackageUnknown_callsTransportForSecondPackage()
+ throws Exception {
+ TransportMock transportMock = setUpInitializedTransport(mTransport);
+ // Not calling setUpAgent() for PACKAGE_1
+ setUpAgentWithData(PACKAGE_2);
+ KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1, PACKAGE_2);
+
+ runTask(task);
+
+ verify(transportMock.transport)
+ .performBackup(argThat(packageInfo(PACKAGE_2)), any(), anyInt());
+ }
+
+ @Test
public void testRunTask_whenPackageNotEligibleForBackup() throws Exception {
TransportMock transportMock = setUpInitializedTransport(mTransport);
AgentMock agentMock = setUpAgentWithData(PACKAGE_1.backupNotAllowed());
@@ -545,6 +613,19 @@
}
@Test
+ public void testRunTask_whenFirstPackageNotEligibleForBackup_callsTransportForSecondPackage()
+ throws Exception {
+ TransportMock transportMock = setUpInitializedTransport(mTransport);
+ setUpAgentsWithData(PACKAGE_1.backupNotAllowed(), PACKAGE_2);
+ KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1, PACKAGE_2);
+
+ runTask(task);
+
+ verify(transportMock.transport)
+ .performBackup(argThat(packageInfo(PACKAGE_2)), any(), anyInt());
+ }
+
+ @Test
public void testRunTask_whenPackageDoesFullBackup() throws Exception {
TransportMock transportMock = setUpInitializedTransport(mTransport);
PackageData packageData = fullBackupPackage(1);
@@ -561,6 +642,20 @@
}
@Test
+ public void testRunTask_whenFirstPackageDoesFullBackup_callsTransportForSecondPackage()
+ throws Exception {
+ TransportMock transportMock = setUpInitializedTransport(mTransport);
+ PackageData packageData = fullBackupPackage(1);
+ setUpAgentsWithData(packageData, PACKAGE_2);
+ KeyValueBackupTask task = createKeyValueBackupTask(transportMock, packageData, PACKAGE_2);
+
+ runTask(task);
+
+ verify(transportMock.transport)
+ .performBackup(argThat(packageInfo(PACKAGE_2)), any(), anyInt());
+ }
+
+ @Test
public void testRunTask_whenPackageIsStopped() throws Exception {
TransportMock transportMock = setUpInitializedTransport(mTransport);
AgentMock agentMock = setUpAgentWithData(PACKAGE_1.stopped());
@@ -575,18 +670,16 @@
}
@Test
- public void testRunTask_whenPackageUnknown() throws Exception {
+ public void testRunTask_whenFirstPackageIsStopped_callsTransportForSecondPackage()
+ throws Exception {
TransportMock transportMock = setUpInitializedTransport(mTransport);
- // Not calling setUpAgent()
- KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
+ setUpAgentsWithData(PACKAGE_1.stopped(), PACKAGE_2);
+ KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1, PACKAGE_2);
runTask(task);
- verify(transportMock.transport, never())
- .performBackup(argThat(packageInfo(PACKAGE_1)), any(), anyInt());
- verify(mObserver).onResult(PACKAGE_1.packageName, ERROR_PACKAGE_NOT_FOUND);
- verify(mObserver).backupFinished(SUCCESS);
- assertBackupNotPendingFor(PACKAGE_1);
+ verify(transportMock.transport)
+ .performBackup(argThat(packageInfo(PACKAGE_2)), any(), anyInt());
}
@Test
@@ -629,6 +722,7 @@
verify(mBackupManagerService).setWorkSource(null);
verify(mObserver).onResult(PACKAGE_1.packageName, ERROR_AGENT_FAILURE);
verify(mObserver).backupFinished(BackupManager.SUCCESS);
+ assertBackupPendingFor(PACKAGE_1);
}
@Test
@@ -645,6 +739,7 @@
verify(mBackupManagerService).setWorkSource(null);
verify(mObserver).onResult(PACKAGE_1.packageName, ERROR_AGENT_FAILURE);
verify(mObserver).backupFinished(BackupManager.SUCCESS);
+ assertBackupPendingFor(PACKAGE_1);
}
@Test
@@ -798,7 +893,7 @@
runTask(task);
- assertBackupNotPendingFor(PACKAGE_1);
+ assertBackupPendingFor(PACKAGE_1);
}
@Test
@@ -1140,6 +1235,38 @@
}
@Test
+ public void testRunTask_whenPmAgentWritesData_callsTransportPerformBackupWithAgentData()
+ throws Exception {
+ TransportMock transportMock = setUpInitializedTransport(mTransport);
+ setUpAgent(PACKAGE_1);
+ Path backupDataPath = createTemporaryFile();
+ when(transportMock.transport.performBackup(
+ argThat(packageInfo(PM_PACKAGE)), any(), anyInt()))
+ .then(copyBackupDataTo(backupDataPath));
+ BackupAgent pmAgent = spy(createPmAgent());
+ when(mBackupManagerService.makeMetadataAgent()).thenReturn(forward(pmAgent));
+ agentOnBackupDo(
+ pmAgent,
+ (oldState, dataOutput, newState) -> {
+ writeData(dataOutput, "key1", "data1".getBytes());
+ writeData(dataOutput, "key2", "data2".getBytes());
+ writeState(newState, "newState".getBytes());
+ });
+ KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
+
+ runTask(task);
+
+ verify(transportMock.transport)
+ .performBackup(argThat(packageInfo(PM_PACKAGE)), any(), anyInt());
+ try (FileInputStream inputStream = new FileInputStream(backupDataPath.toFile())) {
+ BackupDataInput backupData = new BackupDataInput(inputStream.getFD());
+ assertDataHasKeyValue(backupData, "key1", "data1".getBytes());
+ assertDataHasKeyValue(backupData, "key2", "data2".getBytes());
+ assertThat(backupData.readNextHeader()).isFalse();
+ }
+ }
+
+ @Test
public void testRunTask_whenPerformBackupSucceeds_callsTransportFinishBackup()
throws Exception {
TransportMock transportMock = setUpInitializedTransport(mTransport);
@@ -1176,6 +1303,50 @@
}
@Test
+ public void testRunTask_whenFinishBackupSucceedsForPm_cleansUp() throws Exception {
+ TransportMock transportMock = setUpInitializedTransport(mTransport);
+ setUpAgent(PACKAGE_1);
+ when(transportMock.transport.finishBackup()).thenReturn(BackupTransport.TRANSPORT_OK);
+ BackupAgent pmAgent = spy(createPmAgent());
+ when(mBackupManagerService.makeMetadataAgent()).thenReturn(forward(pmAgent));
+ agentOnBackupDo(
+ pmAgent,
+ (oldState, dataOutput, newState) -> {
+ writeData(dataOutput, "key", "data".getBytes());
+ writeState(newState, "newState".getBytes());
+ });
+ KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
+
+ runTask(task);
+
+ assertThat(Files.readAllBytes(getStateFile(mTransport, PM_PACKAGE)))
+ .isEqualTo("newState".getBytes());
+ assertCleansUpFiles(mTransport, PM_PACKAGE);
+ // We don't unbind PM
+ verify(mBackupManagerService, never()).unbindAgent(argThat(applicationInfo(PM_PACKAGE)));
+ }
+
+ @Test
+ public void testRunTask_whenFinishBackupSucceedsForPm_doesNotUnbindPm() throws Exception {
+ TransportMock transportMock = setUpInitializedTransport(mTransport);
+ setUpAgent(PACKAGE_1);
+ when(transportMock.transport.finishBackup()).thenReturn(BackupTransport.TRANSPORT_OK);
+ BackupAgent pmAgent = spy(createPmAgent());
+ when(mBackupManagerService.makeMetadataAgent()).thenReturn(forward(pmAgent));
+ agentOnBackupDo(
+ pmAgent,
+ (oldState, dataOutput, newState) -> {
+ writeData(dataOutput, "key", "data".getBytes());
+ writeState(newState, "newState".getBytes());
+ });
+ KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
+
+ runTask(task);
+
+ verify(mBackupManagerService, never()).unbindAgent(argThat(applicationInfo(PM_PACKAGE)));
+ }
+
+ @Test
public void testRunTask_whenFinishBackupSucceeds_logsBackupPackageEvent() throws Exception {
TransportMock transportMock = setUpInitializedTransport(mTransport);
setUpAgentWithData(PACKAGE_1);
@@ -1354,6 +1525,7 @@
public void testRunTask_whenTransportReturnsQuotaExceeded_updatesBookkeeping()
throws Exception {
TransportMock transportMock = setUpInitializedTransport(mTransport);
+ setUpAgentWithData(PACKAGE_1);
when(transportMock.transport.performBackup(
argThat(packageInfo(PACKAGE_1)), any(), anyInt()))
.thenReturn(BackupTransport.TRANSPORT_QUOTA_EXCEEDED);
@@ -1701,9 +1873,9 @@
}
@Test
- public void testRunTask_whenPmAgentFails() throws Exception {
+ public void testRunTask_whenPmAgentFails_reportsCorrectly() throws Exception {
TransportMock transportMock = setUpInitializedTransport(mTransport);
- PackageManagerBackupAgent pmAgent = createThrowingPmAgent(new RuntimeException());
+ BackupAgent pmAgent = createThrowingPmAgent(new RuntimeException());
when(mBackupManagerService.makeMetadataAgent()).thenReturn(pmAgent);
KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
@@ -1718,6 +1890,75 @@
}
@Test
+ public void testRunTask_whenPmAgentFails_revertsTask() throws Exception {
+ TransportMock transportMock = setUpInitializedTransport(mTransport);
+ setUpAgent(PACKAGE_1);
+ BackupAgent pmAgent = createThrowingPmAgent(new RuntimeException());
+ when(mBackupManagerService.makeMetadataAgent()).thenReturn(pmAgent);
+ KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
+
+ runTask(task);
+
+ assertTaskReverted(transportMock, PACKAGE_1);
+ }
+
+ @Test
+ public void testRunTask_whenPmAgentFails_cleansUpFiles() throws Exception {
+ TransportMock transportMock = setUpInitializedTransport(mTransport);
+ setUpAgent(PACKAGE_1);
+ BackupAgent pmAgent = createThrowingPmAgent(new RuntimeException());
+ when(mBackupManagerService.makeMetadataAgent()).thenReturn(pmAgent);
+ KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
+
+ runTask(task);
+
+ assertCleansUpFiles(mTransport, PM_PACKAGE);
+ }
+
+ @Test
+ public void testRunTask_whenPmAgentFails_resetsBackupState() throws Exception {
+ TransportMock transportMock = setUpInitializedTransport(mTransport);
+ setUpAgent(PACKAGE_1);
+ BackupAgent pmAgent = createThrowingPmAgent(new RuntimeException());
+ when(mBackupManagerService.makeMetadataAgent()).thenReturn(pmAgent);
+ KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
+
+ runTask(task);
+
+ verify(mBackupManagerService).resetBackupState(getStateDirectory(mTransport).toFile());
+ }
+
+ @Test
+ public void testRunTask_whenMarkCancelDuringPmOnBackup_resetsBackupState() throws Exception {
+ TransportMock transportMock = setUpInitializedTransport(mTransport);
+ setUpAgent(PACKAGE_1);
+ BackupAgent pmAgent = spy(createPmAgent());
+ when(mBackupManagerService.makeMetadataAgent()).thenReturn(forward(pmAgent));
+ KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
+ agentOnBackupDo(
+ pmAgent, (oldState, dataOutput, newState) -> runInWorkerThread(task::markCancel));
+
+ runTask(task);
+
+ verify(mBackupManagerService).resetBackupState(getStateDirectory(mTransport).toFile());
+ }
+
+ @Test
+ public void testRunTask_whenMarkCancelDuringPmOnBackup_cleansUpFiles() throws Exception {
+ TransportMock transportMock = setUpInitializedTransport(mTransport);
+ setUpAgent(PACKAGE_1);
+ BackupAgent pmAgent = spy(createPmAgent());
+ when(mBackupManagerService.makeMetadataAgent()).thenReturn(forward(pmAgent));
+ KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
+ agentOnBackupDo(
+ pmAgent, (oldState, dataOutput, newState) -> runInWorkerThread(task::markCancel));
+
+ runTask(task);
+
+ assertCleansUpFiles(mTransport, PM_PACKAGE);
+ }
+
+ @Test
public void testRunTask_whenBackupRunning_doesNotThrow() throws Exception {
TransportMock transportMock = setUpInitializedTransport(mTransport);
when(mBackupManagerService.isBackupOperationInProgress()).thenReturn(true);
@@ -1736,7 +1977,7 @@
runTask(task);
- verify(mReporter).onReadAgentDataError(eq(PACKAGE_1.packageName), any());
+ verify(mReporter).onAgentDataError(eq(PACKAGE_1.packageName), any());
}
@Test
@@ -1779,6 +2020,24 @@
}
@Test
+ public void testRunTask_whenMarkCancelDuringAgentOnBackup_cleansUpFiles() throws Exception {
+ TransportMock transportMock = setUpInitializedTransport(mTransport);
+ AgentMock agentMock = setUpAgent(PACKAGE_1);
+ KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
+ agentOnBackupDo(
+ agentMock,
+ (oldState, dataOutput, newState) -> {
+ writeData(dataOutput, "key", "data".getBytes());
+ writeState(newState, "newState".getBytes());
+ runInWorkerThread(task::markCancel);
+ });
+
+ runTask(task);
+
+ assertCleansUpFiles(mTransport, PACKAGE_1);
+ }
+
+ @Test
public void
testRunTask_whenMarkCancelDuringFirstAgentOnBackup_doesNotCallTransportAfterWaitCancel()
throws Exception {
@@ -2293,20 +2552,28 @@
*/
private static void agentOnBackupDo(AgentMock agentMock, BackupAgentOnBackup function)
throws Exception {
- doAnswer(
- (BackupAgentOnBackup)
- (oldState, dataOutput, newState) -> {
- ByteArrayOutputStream outputStream =
- new ByteArrayOutputStream();
- transferStreamedData(
- new FileInputStream(oldState.getFileDescriptor()),
- outputStream);
- agentMock.oldState = outputStream.toByteArray();
- agentMock.oldStateHistory.add(agentMock.oldState);
- function.onBackup(oldState, dataOutput, newState);
- })
- .when(agentMock.agent)
- .onBackup(any(), any(), any());
+ agentOnBackupDo(
+ agentMock.agent,
+ (oldState, dataOutput, newState) -> {
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ transferStreamedData(
+ new FileInputStream(oldState.getFileDescriptor()), outputStream);
+ agentMock.oldState = outputStream.toByteArray();
+ agentMock.oldStateHistory.add(agentMock.oldState);
+ function.onBackup(oldState, dataOutput, newState);
+ });
+ }
+
+ /**
+ * Implements {@code function} for {@link BackupAgent#onBackup(ParcelFileDescriptor,
+ * BackupDataOutput, ParcelFileDescriptor)} of {@code agentMock}.
+ *
+ * @see #agentOnBackupDo(AgentMock, BackupAgentOnBackup)
+ * @see #remoteAgentOnBackupThrows(AgentMock, BackupAgentOnBackup)
+ */
+ private static void agentOnBackupDo(BackupAgent backupAgent, BackupAgentOnBackup function)
+ throws IOException {
+ doAnswer(function).when(backupAgent).onBackup(any(), any(), any());
}
/**
@@ -2400,6 +2667,10 @@
// constructor
assertJournalDoesNotContain(mBackupManagerService.getJournal(), packageName);
assertThat(mBackupManagerService.getPendingBackups()).doesNotContainKey(packageName);
+ // Also verifying BMS is never called since for some cases the package wouldn't be
+ // pending for other reasons (for example it's not eligible for backup). Regardless of
+ // these reasons, we shouldn't mark them as pending backup (call dataChangedImpl()).
+ verify(mBackupManagerService, never()).dataChangedImpl(packageName);
}
}
diff --git a/services/robotests/src/com/android/server/backup/keyvalue/TaskExceptionTest.java b/services/robotests/src/com/android/server/backup/keyvalue/TaskExceptionTest.java
new file mode 100644
index 0000000..4b79657
--- /dev/null
+++ b/services/robotests/src/com/android/server/backup/keyvalue/TaskExceptionTest.java
@@ -0,0 +1,152 @@
+/*
+ * 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.backup.keyvalue;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.expectThrows;
+
+import android.app.backup.BackupTransport;
+import android.platform.test.annotations.Presubmit;
+
+import com.android.server.testing.FrameworkRobolectricTestRunner;
+import com.android.server.testing.SystemLoaderPackages;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.annotation.Config;
+
+import java.io.IOException;
+
+@RunWith(FrameworkRobolectricTestRunner.class)
+@Config(manifest = Config.NONE, sdk = 26)
+@SystemLoaderPackages({"com.android.server.backup"})
+@Presubmit
+public class TaskExceptionTest {
+ @Test
+ public void testStateCompromised() {
+ TaskException exception = TaskException.stateCompromised();
+
+ assertThat(exception.isStateCompromised()).isTrue();
+ assertThat(exception.getStatus()).isEqualTo(BackupTransport.TRANSPORT_ERROR);
+ }
+
+ @Test
+ public void testStateCompromised_whenCauseInstanceOfTaskException() {
+ Exception cause = TaskException.forStatus(BackupTransport.TRANSPORT_NOT_INITIALIZED);
+
+ TaskException exception = TaskException.stateCompromised(cause);
+
+ assertThat(exception.isStateCompromised()).isTrue();
+ assertThat(exception.getStatus()).isEqualTo(BackupTransport.TRANSPORT_NOT_INITIALIZED);
+ assertThat(exception.getCause()).isEqualTo(cause);
+ }
+
+ @Test
+ public void testStateCompromised_whenCauseNotInstanceOfTaskException() {
+ Exception cause = new IOException();
+
+ TaskException exception = TaskException.stateCompromised(cause);
+
+ assertThat(exception.isStateCompromised()).isTrue();
+ assertThat(exception.getStatus()).isEqualTo(BackupTransport.TRANSPORT_ERROR);
+ assertThat(exception.getCause()).isEqualTo(cause);
+ }
+
+ @Test
+ public void testForStatus_whenTransportOk_throws() {
+ expectThrows(
+ IllegalArgumentException.class,
+ () -> TaskException.forStatus(BackupTransport.TRANSPORT_OK));
+ }
+
+ @Test
+ public void testForStatus_whenTransportNotInitialized() {
+ TaskException exception =
+ TaskException.forStatus(BackupTransport.TRANSPORT_NOT_INITIALIZED);
+
+ assertThat(exception.isStateCompromised()).isFalse();
+ assertThat(exception.getStatus()).isEqualTo(BackupTransport.TRANSPORT_NOT_INITIALIZED);
+ }
+
+ @Test
+ public void testCausedBy_whenCauseInstanceOfTaskException_returnsCause() {
+ Exception cause = TaskException.forStatus(BackupTransport.TRANSPORT_NOT_INITIALIZED);
+
+ TaskException exception = TaskException.causedBy(cause);
+
+ assertThat(exception).isEqualTo(cause);
+ }
+
+ @Test
+ public void testCausedBy_whenCauseNotInstanceOfTaskException() {
+ Exception cause = new IOException();
+
+ TaskException exception = TaskException.causedBy(cause);
+
+ assertThat(exception).isNotEqualTo(cause);
+ assertThat(exception.isStateCompromised()).isFalse();
+ assertThat(exception.getStatus()).isEqualTo(BackupTransport.TRANSPORT_ERROR);
+ assertThat(exception.getCause()).isEqualTo(cause);
+ }
+
+ @Test
+ public void testCreate() {
+ TaskException exception = TaskException.create();
+
+ assertThat(exception.isStateCompromised()).isFalse();
+ assertThat(exception.getStatus()).isEqualTo(BackupTransport.TRANSPORT_ERROR);
+ }
+
+ @Test
+ public void testIsStateCompromised_whenStateCompromised_returnsTrue() {
+ TaskException taskException = TaskException.stateCompromised();
+
+ boolean stateCompromised = taskException.isStateCompromised();
+
+ assertThat(stateCompromised).isTrue();
+ }
+
+ @Test
+ public void testIsStateCompromised_whenCreatedWithCreate_returnsFalse() {
+ TaskException taskException = TaskException.create();
+
+ boolean stateCompromised = taskException.isStateCompromised();
+
+ assertThat(stateCompromised).isFalse();
+ }
+
+ @Test
+ public void testGetStatus_whenStatusIsTransportPackageRejected() {
+ TaskException taskException =
+ TaskException.forStatus(BackupTransport.TRANSPORT_PACKAGE_REJECTED);
+
+ int status = taskException.getStatus();
+
+ assertThat(status).isEqualTo(BackupTransport.TRANSPORT_PACKAGE_REJECTED);
+ }
+
+ @Test
+ public void testGetStatus_whenStatusIsTransportNotInitialized() {
+ TaskException taskException =
+ TaskException.forStatus(BackupTransport.TRANSPORT_NOT_INITIALIZED);
+
+ int status = taskException.getStatus();
+
+ assertThat(status).isEqualTo(BackupTransport.TRANSPORT_NOT_INITIALIZED);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java b/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java
index 06c7437..e8a824a 100644
--- a/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java
@@ -16,9 +16,12 @@
package com.android.server.am;
+import static com.android.server.am.MemoryStatUtil.BYTES_IN_KILOBYTE;
import static com.android.server.am.MemoryStatUtil.MemoryStat;
+import static com.android.server.am.MemoryStatUtil.parseMemoryMaxUsageFromMemCg;
import static com.android.server.am.MemoryStatUtil.parseMemoryStatFromMemcg;
import static com.android.server.am.MemoryStatUtil.parseMemoryStatFromProcfs;
+import static com.android.server.am.MemoryStatUtil.parseVmHWMFromProcfs;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
@@ -32,7 +35,7 @@
@RunWith(AndroidJUnit4.class)
@SmallTest
public class MemoryStatUtilTest {
- private String MEMORY_STAT_CONTENTS = String.join(
+ private static final String MEMORY_STAT_CONTENTS = String.join(
"\n",
"cache 96", // keep different from total_cache to catch reading wrong value
"rss 97", // keep different from total_rss to catch reading wrong value
@@ -67,7 +70,7 @@
"total_active_file 81920",
"total_unevictable 0");
- private String PROC_STAT_CONTENTS = String.join(
+ private static final String PROC_STAT_CONTENTS = String.join(
" ",
"1040",
"(system_server)",
@@ -122,14 +125,61 @@
"3198889956",
"0");
+ private static final String PROC_STATUS_CONTENTS = "Name:\tandroid.youtube\n"
+ + "State:\tS (sleeping)\n"
+ + "Tgid:\t12088\n"
+ + "Pid:\t12088\n"
+ + "PPid:\t723\n"
+ + "TracerPid:\t0\n"
+ + "Uid:\t10083\t10083\t10083\t10083\n"
+ + "Gid:\t10083\t10083\t10083\t10083\n"
+ + "Ngid:\t0\n"
+ + "FDSize:\t128\n"
+ + "Groups:\t3003 9997 20083 50083 \n"
+ + "VmPeak:\t 4546844 kB\n"
+ + "VmSize:\t 4542636 kB\n"
+ + "VmLck:\t 0 kB\n"
+ + "VmPin:\t 0 kB\n"
+ + "VmHWM:\t 137668 kB\n" // RSS high watermark
+ + "VmRSS:\t 126776 kB\n"
+ + "RssAnon:\t 37860 kB\n"
+ + "RssFile:\t 88764 kB\n"
+ + "RssShmem:\t 152 kB\n"
+ + "VmData:\t 4125112 kB\n"
+ + "VmStk:\t 8192 kB\n"
+ + "VmExe:\t 24 kB\n"
+ + "VmLib:\t 102432 kB\n"
+ + "VmPTE:\t 1300 kB\n"
+ + "VmPMD:\t 36 kB\n"
+ + "VmSwap:\t 0 kB\n"
+ + "Threads:\t95\n"
+ + "SigQ:\t0/13641\n"
+ + "SigPnd:\t0000000000000000\n"
+ + "ShdPnd:\t0000000000000000\n"
+ + "SigBlk:\t0000000000001204\n"
+ + "SigIgn:\t0000000000000001\n"
+ + "SigCgt:\t00000006400084f8\n"
+ + "CapInh:\t0000000000000000\n"
+ + "CapPrm:\t0000000000000000\n"
+ + "CapEff:\t0000000000000000\n"
+ + "CapBnd:\t0000000000000000\n"
+ + "CapAmb:\t0000000000000000\n"
+ + "Seccomp:\t2\n"
+ + "Cpus_allowed:\tff\n"
+ + "Cpus_allowed_list:\t0-7\n"
+ + "Mems_allowed:\t1\n"
+ + "Mems_allowed_list:\t0\n"
+ + "voluntary_ctxt_switches:\t903\n"
+ + "nonvoluntary_ctxt_switches:\t104\n";
+
@Test
public void testParseMemoryStatFromMemcg_parsesCorrectValues() throws Exception {
MemoryStat stat = parseMemoryStatFromMemcg(MEMORY_STAT_CONTENTS);
- assertEquals(stat.pgfault, 1);
- assertEquals(stat.pgmajfault, 2);
- assertEquals(stat.rssInBytes, 3);
- assertEquals(stat.cacheInBytes, 4);
- assertEquals(stat.swapInBytes, 5);
+ assertEquals(1, stat.pgfault);
+ assertEquals(2, stat.pgmajfault);
+ assertEquals(3, stat.rssInBytes);
+ assertEquals(4, stat.cacheInBytes);
+ assertEquals(5, stat.swapInBytes);
}
@Test
@@ -142,6 +192,18 @@
}
@Test
+ public void testParseMemoryMaxUsageFromMemCg_parsesCorrectValue() {
+ assertEquals(1234, parseMemoryMaxUsageFromMemCg("1234"));
+ }
+
+ @Test
+ public void testParseMemoryMaxUsageFromMemCg_emptyContents() {
+ assertEquals(0, parseMemoryMaxUsageFromMemCg(""));
+
+ assertEquals(0, parseMemoryMaxUsageFromMemCg(null));
+ }
+
+ @Test
public void testParseMemoryStatFromProcfs_parsesCorrectValues() throws Exception {
MemoryStat stat = parseMemoryStatFromProcfs(PROC_STAT_CONTENTS);
assertEquals(1, stat.pgfault);
@@ -159,4 +221,16 @@
stat = parseMemoryStatFromProcfs(null);
assertNull(stat);
}
+
+ @Test
+ public void testParseVmHWMFromProcfs_parsesCorrectValue() {
+ assertEquals(137668, parseVmHWMFromProcfs(PROC_STATUS_CONTENTS) / BYTES_IN_KILOBYTE);
+ }
+
+ @Test
+ public void testParseVmHWMFromProcfs_emptyContents() {
+ assertEquals(0, parseVmHWMFromProcfs(""));
+
+ assertEquals(0, parseVmHWMFromProcfs(null));
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
index fa65212..b7cc9ce 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
@@ -370,22 +370,31 @@
final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class);
app.mHasSurface = true;
- app.mToken.mSurfaceControl = mock(SurfaceControl.class);
+ app.mSurfaceControl = mock(SurfaceControl.class);
try {
app.getFrameLw().set(10, 20, 60, 80);
+ app.updateSurfacePosition(t);
app.seamlesslyRotateIfAllowed(t, ROTATION_0, ROTATION_90, true);
assertTrue(app.mSeamlesslyRotated);
+
+ // Verify we un-rotate the window state surface.
Matrix matrix = new Matrix();
// Un-rotate 90 deg
matrix.setRotate(270);
// Translate it back to origin
matrix.postTranslate(0, mDisplayInfo.logicalWidth);
- verify(t).setMatrix(eq(app.mToken.mSurfaceControl), eq(matrix), any(float[].class));
+ verify(t).setMatrix(eq(app.mSurfaceControl), eq(matrix), any(float[].class));
+
+ // Verify we update the position as well.
+ float[] currentSurfacePos = {app.mLastSurfacePosition.x, app.mLastSurfacePosition.y};
+ matrix.mapPoints(currentSurfacePos);
+ verify(t).setPosition(eq(app.mSurfaceControl), eq(currentSurfacePos[0]),
+ eq(currentSurfacePos[1]));
} finally {
+ app.mSurfaceControl = null;
app.mHasSurface = false;
- app.mToken.mSurfaceControl = null;
}
}
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 26bd4a1..08bc9bc 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -141,6 +141,8 @@
* The caller must specify the {@link #EXTRA_HANDOVER_PHONE_ACCOUNT_HANDLE} to indicate to
* Telecom which {@link PhoneAccountHandle} the {@link Call} should be handed over to.
* @hide
+ * @deprecated Use {@link Call#handoverTo(PhoneAccountHandle, int, Bundle)} and its associated
+ * APIs instead.
*/
public static final String EVENT_REQUEST_HANDOVER =
"android.telecom.event.REQUEST_HANDOVER";
@@ -149,6 +151,8 @@
* Extra key used with the {@link #EVENT_REQUEST_HANDOVER} call event. Specifies the
* {@link PhoneAccountHandle} to which a call should be handed over to.
* @hide
+ * @deprecated Use {@link Call#handoverTo(PhoneAccountHandle, int, Bundle)} and its associated
+ * APIs instead.
*/
public static final String EXTRA_HANDOVER_PHONE_ACCOUNT_HANDLE =
"android.telecom.extra.HANDOVER_PHONE_ACCOUNT_HANDLE";
@@ -161,6 +165,8 @@
* {@link VideoProfile#STATE_BIDIRECTIONAL}, {@link VideoProfile#STATE_RX_ENABLED}, and
* {@link VideoProfile#STATE_TX_ENABLED}.
* @hide
+ * @deprecated Use {@link Call#handoverTo(PhoneAccountHandle, int, Bundle)} and its associated
+ * APIs instead.
*/
public static final String EXTRA_HANDOVER_VIDEO_STATE =
"android.telecom.extra.HANDOVER_VIDEO_STATE";
@@ -176,6 +182,8 @@
* {@link ConnectionService#onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}
* is called to initate the handover.
* @hide
+ * @deprecated Use {@link Call#handoverTo(PhoneAccountHandle, int, Bundle)} and its associated
+ * APIs instead.
*/
public static final String EXTRA_HANDOVER_EXTRAS = "android.telecom.extra.HANDOVER_EXTRAS";
@@ -186,6 +194,8 @@
* <p>
* A handover is initiated with the {@link #EVENT_REQUEST_HANDOVER} call event.
* @hide
+ * @deprecated Use {@link Call#handoverTo(PhoneAccountHandle, int, Bundle)} and its associated
+ * APIs instead.
*/
public static final String EVENT_HANDOVER_COMPLETE =
"android.telecom.event.HANDOVER_COMPLETE";
@@ -198,6 +208,8 @@
* <p>
* A handover is initiated with the {@link #EVENT_REQUEST_HANDOVER} call event.
* @hide
+ * @deprecated Use {@link Call#handoverTo(PhoneAccountHandle, int, Bundle)} and its associated
+ * APIs instead.
*/
public static final String EVENT_HANDOVER_SOURCE_DISCONNECTED =
"android.telecom.event.HANDOVER_SOURCE_DISCONNECTED";
@@ -209,6 +221,8 @@
* <p>
* A handover is initiated with the {@link #EVENT_REQUEST_HANDOVER} call event.
* @hide
+ * @deprecated Use {@link Call#handoverTo(PhoneAccountHandle, int, Bundle)} and its associated
+ * APIs instead.
*/
public static final String EVENT_HANDOVER_FAILED =
"android.telecom.event.HANDOVER_FAILED";
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index d494692..34603a3 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -594,6 +594,8 @@
* {@link Call#EVENT_REQUEST_HANDOVER} that the handover from this {@link Connection} has
* successfully completed.
* @hide
+ * @deprecated Use {@link Call#handoverTo(PhoneAccountHandle, int, Bundle)} and its associated
+ * APIs instead.
*/
public static final String EVENT_HANDOVER_COMPLETE =
"android.telecom.event.HANDOVER_COMPLETE";
@@ -603,6 +605,8 @@
* {@link Call#EVENT_REQUEST_HANDOVER} that the handover from this {@link Connection} has failed
* to complete.
* @hide
+ * @deprecated Use {@link Call#handoverTo(PhoneAccountHandle, int, Bundle)} and its associated
+ * APIs instead.
*/
public static final String EVENT_HANDOVER_FAILED =
"android.telecom.event.HANDOVER_FAILED";
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 777b850..38ee79f 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -1852,6 +1852,19 @@
}
/**
+ * Checks if the supplied subscription ID corresponds to an active subscription.
+ *
+ * @param subscriptionId the subscription ID.
+ * @return {@code true} if the supplied subscription ID corresponds to an active subscription;
+ * {@code false} if it does not correspond to an active subscription; or throw a
+ * SecurityException if the caller hasn't got the right permission.
+ */
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+ public boolean isActiveSubscriptionId(int subscriptionId) {
+ return isActiveSubId(subscriptionId);
+ }
+
+ /**
* @return true if the sub ID is active. i.e. The sub ID corresponds to a known subscription
* and the SIM providing the subscription is present in a slot and in "LOADED" state.
* @hide
@@ -1861,7 +1874,7 @@
try {
ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
if (iSub != null) {
- return iSub.isActiveSubId(subId);
+ return iSub.isActiveSubId(subId, mContext.getOpPackageName());
}
} catch (RemoteException ex) {
}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index d58b932..b80b54a 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -16,6 +16,8 @@
package android.telephony;
+import static android.content.Context.TELECOM_SERVICE;
+
import static com.android.internal.util.Preconditions.checkNotNull;
import android.annotation.IntDef;
@@ -4372,7 +4374,7 @@
* @hide
*/
private ITelecomService getTelecomService() {
- return ITelecomService.Stub.asInterface(ServiceManager.getService(Context.TELECOM_SERVICE));
+ return ITelecomService.Stub.asInterface(ServiceManager.getService(TELECOM_SERVICE));
}
private ITelephonyRegistry getTelephonyRegistry() {
@@ -5402,7 +5404,19 @@
}
}
- // ICC SIM Application Types
+ /**
+ * UICC SIM Application Types
+ * @hide
+ */
+ @IntDef(prefix = { "APPTYPE_" }, value = {
+ APPTYPE_SIM,
+ APPTYPE_USIM,
+ APPTYPE_RUIM,
+ APPTYPE_CSIM,
+ APPTYPE_ISIM
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface UiccAppType{}
/** UICC application type is SIM */
public static final int APPTYPE_SIM = PhoneConstants.APPTYPE_SIM;
/** UICC application type is USIM */
@@ -5413,6 +5427,7 @@
public static final int APPTYPE_CSIM = PhoneConstants.APPTYPE_CSIM;
/** UICC application type is ISIM */
public static final int APPTYPE_ISIM = PhoneConstants.APPTYPE_ISIM;
+
// authContext (parameter P2) when doing UICC challenge,
// per 3GPP TS 31.102 (Section 7.1.2)
/** Authentication type for UICC challenge is EAP SIM. See RFC 4186 for details. */
@@ -5679,6 +5694,202 @@
}
}
+ /** @hide */
+ @IntDef(prefix = { "NETWORK_MODE_" }, value = {
+ NETWORK_MODE_WCDMA_PREF,
+ NETWORK_MODE_GSM_ONLY,
+ NETWORK_MODE_WCDMA_ONLY,
+ NETWORK_MODE_GSM_UMTS,
+ NETWORK_MODE_CDMA_EVDO,
+ NETWORK_MODE_CDMA_NO_EVDO,
+ NETWORK_MODE_EVDO_NO_CDMA,
+ NETWORK_MODE_GLOBAL,
+ NETWORK_MODE_LTE_CDMA_EVDO,
+ NETWORK_MODE_LTE_GSM_WCDMA,
+ NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA,
+ NETWORK_MODE_LTE_ONLY,
+ NETWORK_MODE_LTE_WCDMA,
+ NETWORK_MODE_TDSCDMA_ONLY,
+ NETWORK_MODE_TDSCDMA_WCDMA,
+ NETWORK_MODE_LTE_TDSCDMA,
+ NETWORK_MODE_TDSCDMA_GSM,
+ NETWORK_MODE_LTE_TDSCDMA_GSM,
+ NETWORK_MODE_TDSCDMA_GSM_WCDMA,
+ NETWORK_MODE_LTE_TDSCDMA_WCDMA,
+ NETWORK_MODE_LTE_TDSCDMA_GSM_WCDMA,
+ NETWORK_MODE_TDSCDMA_CDMA_EVDO_GSM_WCDMA,
+ NETWORK_MODE_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface PrefNetworkMode{}
+
+ /**
+ * preferred network mode is GSM/WCDMA (WCDMA preferred).
+ * @hide
+ */
+ @SystemApi
+ public static final int NETWORK_MODE_WCDMA_PREF = RILConstants.NETWORK_MODE_WCDMA_PREF;
+
+ /**
+ * preferred network mode is GSM only.
+ * @hide
+ */
+ @SystemApi
+ public static final int NETWORK_MODE_GSM_ONLY = RILConstants.NETWORK_MODE_GSM_ONLY;
+
+ /**
+ * preferred network mode is WCDMA only.
+ * @hide
+ */
+ @SystemApi
+ public static final int NETWORK_MODE_WCDMA_ONLY = RILConstants.NETWORK_MODE_WCDMA_ONLY;
+
+ /**
+ * preferred network mode is GSM/WCDMA (auto mode, according to PRL).
+ * @hide
+ */
+ @SystemApi
+ public static final int NETWORK_MODE_GSM_UMTS = RILConstants.NETWORK_MODE_GSM_UMTS;
+
+ /**
+ * preferred network mode is CDMA and EvDo (auto mode, according to PRL).
+ * @hide
+ */
+ @SystemApi
+ public static final int NETWORK_MODE_CDMA_EVDO = RILConstants.NETWORK_MODE_CDMA;
+
+ /**
+ * preferred network mode is CDMA only.
+ * @hide
+ */
+ @SystemApi
+ public static final int NETWORK_MODE_CDMA_NO_EVDO = RILConstants.NETWORK_MODE_CDMA_NO_EVDO;
+
+ /**
+ * preferred network mode is EvDo only.
+ * @hide
+ */
+ @SystemApi
+ public static final int NETWORK_MODE_EVDO_NO_CDMA = RILConstants.NETWORK_MODE_EVDO_NO_CDMA;
+
+ /**
+ * preferred network mode is GSM/WCDMA, CDMA, and EvDo (auto mode, according to PRL).
+ * @hide
+ */
+ @SystemApi
+ public static final int NETWORK_MODE_GLOBAL = RILConstants.NETWORK_MODE_GLOBAL;
+
+ /**
+ * preferred network mode is LTE, CDMA and EvDo.
+ * @hide
+ */
+ @SystemApi
+ public static final int NETWORK_MODE_LTE_CDMA_EVDO = RILConstants.NETWORK_MODE_LTE_CDMA_EVDO;
+
+ /**
+ * preferred network mode is LTE, GSM/WCDMA.
+ * @hide
+ */
+ @SystemApi
+ public static final int NETWORK_MODE_LTE_GSM_WCDMA = RILConstants.NETWORK_MODE_LTE_GSM_WCDMA;
+
+ /**
+ * preferred network mode is LTE, CDMA, EvDo, GSM/WCDMA.
+ * @hide
+ */
+ @SystemApi
+ public static final int NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA =
+ RILConstants.NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA;
+
+ /**
+ * preferred network mode is LTE Only.
+ * @hide
+ */
+ @SystemApi
+ public static final int NETWORK_MODE_LTE_ONLY = RILConstants.NETWORK_MODE_LTE_ONLY;
+
+ /**
+ * preferred network mode is LTE/WCDMA.
+ * @hide
+ */
+ @SystemApi
+ public static final int NETWORK_MODE_LTE_WCDMA = RILConstants.NETWORK_MODE_LTE_WCDMA;
+
+ /**
+ * preferred network mode is TD-SCDMA only.
+ * @hide
+ */
+ @SystemApi
+ public static final int NETWORK_MODE_TDSCDMA_ONLY = RILConstants.NETWORK_MODE_TDSCDMA_ONLY;
+
+ /**
+ * preferred network mode is TD-SCDMA and WCDMA.
+ * @hide
+ */
+ @SystemApi
+ public static final int NETWORK_MODE_TDSCDMA_WCDMA = RILConstants.NETWORK_MODE_TDSCDMA_WCDMA;
+
+ /**
+ * preferred network mode is TD-SCDMA and LTE.
+ * @hide
+ */
+ @SystemApi
+ public static final int NETWORK_MODE_LTE_TDSCDMA = RILConstants.NETWORK_MODE_LTE_TDSCDMA;
+
+ /**
+ * preferred network mode is TD-SCDMA and GSM.
+ * @hide
+ */
+ @SystemApi
+ public static final int NETWORK_MODE_TDSCDMA_GSM = RILConstants.NETWORK_MODE_TDSCDMA_GSM;
+
+ /**
+ * preferred network mode is TD-SCDMA,GSM and LTE.
+ * @hide
+ */
+ @SystemApi
+ public static final int NETWORK_MODE_LTE_TDSCDMA_GSM =
+ RILConstants.NETWORK_MODE_LTE_TDSCDMA_GSM;
+
+ /**
+ * preferred network mode is TD-SCDMA, GSM/WCDMA.
+ * @hide
+ */
+ @SystemApi
+ public static final int NETWORK_MODE_TDSCDMA_GSM_WCDMA =
+ RILConstants.NETWORK_MODE_TDSCDMA_GSM_WCDMA;
+
+ /**
+ * preferred network mode is TD-SCDMA, WCDMA and LTE.
+ * @hide
+ */
+ @SystemApi
+ public static final int NETWORK_MODE_LTE_TDSCDMA_WCDMA =
+ RILConstants.NETWORK_MODE_LTE_TDSCDMA_WCDMA;
+
+ /**
+ * preferred network mode is TD-SCDMA, GSM/WCDMA and LTE.
+ * @hide
+ */
+ @SystemApi
+ public static final int NETWORK_MODE_LTE_TDSCDMA_GSM_WCDMA =
+ RILConstants.NETWORK_MODE_LTE_TDSCDMA_GSM_WCDMA;
+
+ /**
+ * preferred network mode is TD-SCDMA,EvDo,CDMA,GSM/WCDMA.
+ * @hide
+ */
+ @SystemApi
+ public static final int NETWORK_MODE_TDSCDMA_CDMA_EVDO_GSM_WCDMA =
+ RILConstants.NETWORK_MODE_TDSCDMA_CDMA_EVDO_GSM_WCDMA;
+ /**
+ * preferred network mode is TD-SCDMA/LTE/GSM/WCDMA, CDMA, and EvDo.
+ * @hide
+ */
+ @SystemApi
+ public static final int NETWORK_MODE_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA =
+ RILConstants.NETWORK_MODE_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA;
+
/**
* Get the preferred network type.
* Used for device configuration by some CDMA operators.
@@ -5687,11 +5898,12 @@
* {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
* app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
- * @return the preferred network type, defined in RILConstants.java.
+ * @return the preferred network type.
* @hide
*/
- @UnsupportedAppUsage
- public int getPreferredNetworkType(int subId) {
+ @RequiresPermission((android.Manifest.permission.MODIFY_PHONE_STATE))
+ @SystemApi
+ public @PrefNetworkMode int getPreferredNetworkType(int subId) {
try {
ITelephony telephony = getITelephony();
if (telephony != null)
@@ -6273,7 +6485,7 @@
}
/**
- * @deprecated Use {@link android.telecom.TelecomManager#endCall()} instead.
+ * @removed Use {@link android.telecom.TelecomManager#endCall()} instead.
* @hide
* @removed
*/
@@ -6285,7 +6497,7 @@
}
/**
- * @deprecated Use {@link android.telecom.TelecomManager#acceptRingingCall} instead
+ * @removed Use {@link android.telecom.TelecomManager#acceptRingingCall} instead
* @hide
* @removed
*/
@@ -6293,26 +6505,22 @@
@SystemApi
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public void answerRingingCall() {
-
+ // No-op
}
/**
- * @deprecated Use {@link android.telecom.TelecomManager#silenceRinger} instead
+ * @removed Use {@link android.telecom.TelecomManager#silenceRinger} instead
* @hide
*/
@Deprecated
@SystemApi
@SuppressLint("Doclava125")
public void silenceRinger() {
- try {
- getTelecomService().silenceRinger(getOpPackageName());
- } catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelecomService#silenceRinger", e);
- }
+ // No-op
}
/**
- * @deprecated Use {@link android.telecom.TelecomManager#isInCall} instead
+ * @removed Use {@link android.telecom.TelecomManager#isInCall} instead
* @hide
*/
@Deprecated
@@ -6322,18 +6530,11 @@
android.Manifest.permission.READ_PHONE_STATE
})
public boolean isOffhook() {
- try {
- ITelephony telephony = getITelephony();
- if (telephony != null)
- return telephony.isOffhook(getOpPackageName());
- } catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#isOffhook", e);
- }
return false;
}
/**
- * @deprecated Use {@link android.telecom.TelecomManager#isRinging} instead
+ * @removed Use {@link android.telecom.TelecomManager#isRinging} instead
* @hide
*/
@Deprecated
@@ -6343,18 +6544,11 @@
android.Manifest.permission.READ_PHONE_STATE
})
public boolean isRinging() {
- try {
- ITelephony telephony = getITelephony();
- if (telephony != null)
- return telephony.isRinging(getOpPackageName());
- } catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#isRinging", e);
- }
return false;
}
/**
- * @deprecated Use {@link android.telecom.TelecomManager#isInCall} instead
+ * @removed Use {@link android.telecom.TelecomManager#isInCall} instead
* @hide
*/
@Deprecated
@@ -6364,13 +6558,6 @@
android.Manifest.permission.READ_PHONE_STATE
})
public boolean isIdle() {
- try {
- ITelephony telephony = getITelephony();
- if (telephony != null)
- return telephony.isIdle(getOpPackageName());
- } catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#isIdle", e);
- }
return true;
}
@@ -7856,26 +8043,23 @@
}
/**
- * Return the application ID for the app type like {@link APPTYPE_CSIM}.
+ * Return the application ID for the uicc application type like {@link #APPTYPE_CSIM}.
+ * All uicc applications are uniquely identified by application ID. See ETSI 102.221 and 101.220
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE}
*
- * Requires that the calling app has READ_PRIVILEGED_PHONE_STATE permission
- *
- * @param appType the uicc app type like {@link APPTYPE_CSIM}
- * @return Application ID for specificied app type or null if no uicc or error.
+ * @param appType the uicc app type.
+ * @return Application ID for specified app type or {@code null} if no uicc or error.
* @hide
*/
- public String getAidForAppType(int appType) {
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public String getAidForAppType(@UiccAppType int appType) {
return getAidForAppType(getSubId(), appType);
}
/**
- * Return the application ID for the app type like {@link APPTYPE_CSIM}.
- *
- * Requires that the calling app has READ_PRIVILEGED_PHONE_STATE permission
- *
- * @param subId the subscription ID that this request applies to.
- * @param appType the uicc app type, like {@link APPTYPE_CSIM}
- * @return Application ID for specificied app type or null if no uicc or error.
+ * same as {@link #getAidForAppType(int)}
* @hide
*/
public String getAidForAppType(int subId, int appType) {
diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl
index 6521f0b..0ccd748 100755
--- a/telephony/java/com/android/internal/telephony/ISub.aidl
+++ b/telephony/java/com/android/internal/telephony/ISub.aidl
@@ -232,5 +232,5 @@
*/
int getSimStateForSlotIndex(int slotIndex);
- boolean isActiveSubId(int subId);
+ boolean isActiveSubId(int subId, String callingPackage);
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index e1c770c..ca2bcff 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -75,116 +75,6 @@
void call(String callingPackage, String number);
/**
- * End call if there is a call in progress, otherwise does nothing.
- *
- * @return whether it hung up
- */
- boolean endCall();
-
- /**
- * End call on particular subId or go to the Home screen
- * @param subId user preferred subId.
- * @return whether it hung up
- */
- boolean endCallForSubscriber(int subId);
-
- /**
- * Answer the currently-ringing call.
- *
- * If there's already a current active call, that call will be
- * automatically put on hold. If both lines are currently in use, the
- * current active call will be ended.
- *
- * TODO: provide a flag to let the caller specify what policy to use
- * if both lines are in use. (The current behavior is hardwired to
- * "answer incoming, end ongoing", which is how the CALL button
- * is specced to behave.)
- *
- * TODO: this should be a oneway call (especially since it's called
- * directly from the key queue thread).
- */
- void answerRingingCall();
-
- /**
- * Answer the currently-ringing call on particular subId .
- *
- * If there's already a current active call, that call will be
- * automatically put on hold. If both lines are currently in use, the
- * current active call will be ended.
- *
- * TODO: provide a flag to let the caller specify what policy to use
- * if both lines are in use. (The current behavior is hardwired to
- * "answer incoming, end ongoing", which is how the CALL button
- * is specced to behave.)
- *
- * TODO: this should be a oneway call (especially since it's called
- * directly from the key queue thread).
- */
- void answerRingingCallForSubscriber(int subId);
-
- /**
- * Silence the ringer if an incoming call is currently ringing.
- * (If vibrating, stop the vibrator also.)
- *
- * It's safe to call this if the ringer has already been silenced, or
- * even if there's no incoming call. (If so, this method will do nothing.)
- *
- * TODO: this should be a oneway call too (see above).
- * (Actually *all* the methods here that return void can
- * probably be oneway.)
- */
- void silenceRinger();
-
- /**
- * Check if we are in either an active or holding call
- * @param callingPackage the name of the package making the call.
- * @return true if the phone state is OFFHOOK.
- */
- boolean isOffhook(String callingPackage);
-
- /**
- * Check if a particular subId has an active or holding call
- *
- * @param subId user preferred subId.
- * @param callingPackage the name of the package making the call.
- * @return true if the phone state is OFFHOOK.
- */
- boolean isOffhookForSubscriber(int subId, String callingPackage);
-
- /**
- * Check if an incoming phone call is ringing or call waiting
- * on a particular subId.
- *
- * @param subId user preferred subId.
- * @param callingPackage the name of the package making the call.
- * @return true if the phone state is RINGING.
- */
- boolean isRingingForSubscriber(int subId, String callingPackage);
-
- /**
- * Check if an incoming phone call is ringing or call waiting.
- * @param callingPackage the name of the package making the call.
- * @return true if the phone state is RINGING.
- */
- boolean isRinging(String callingPackage);
-
- /**
- * Check if the phone is idle.
- * @param callingPackage the name of the package making the call.
- * @return true if the phone state is IDLE.
- */
- boolean isIdle(String callingPackage);
-
- /**
- * Check if the phone is idle on a particular subId.
- *
- * @param subId user preferred subId.
- * @param callingPackage the name of the package making the call.
- * @return true if the phone state is IDLE.
- */
- boolean isIdleForSubscriber(int subId, String callingPackage);
-
- /**
* Check to see if the radio is on or not.
* @param callingPackage the name of the package making the call.
* @return returns true if the radio is on.
diff --git a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
index 4a6fe49..1f60b71 100644
--- a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
+++ b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
@@ -247,8 +247,14 @@
mIterationCycle = false;
// In the "applaunch.txt" file, trail launches is referenced using
// "TRIAL_LAUNCH"
- String appPkgName = mNameToIntent.get(launch.getApp())
- .getComponent().getPackageName();
+ Intent startIntent = mNameToIntent.get(launch.getApp());
+ if (startIntent == null) {
+ Log.w(TAG, "App does not exist: " + launch.getApp());
+ mResult.putString(mNameToResultKey.get(launch.getApp()),
+ "App does not exist");
+ continue;
+ }
+ String appPkgName = startIntent.getComponent().getPackageName();
if (SPEED_PROFILE_FILTER.equals(launch.getCompilerFilter())) {
assertTrue(String.format("Not able to compile the app : %s", appPkgName),
compileApp(VERIFY_FILTER, appPkgName));
diff --git a/tools/aapt2/io/FileStream_test.cpp b/tools/aapt2/io/FileStream_test.cpp
index c0eaa8e..7872738 100644
--- a/tools/aapt2/io/FileStream_test.cpp
+++ b/tools/aapt2/io/FileStream_test.cpp
@@ -41,46 +41,46 @@
ASSERT_FALSE(in.HadError());
EXPECT_THAT(in.ByteCount(), Eq(0u));
- const char* buffer;
+ const void* buffer;
size_t size;
- ASSERT_TRUE(in.Next(reinterpret_cast<const void**>(&buffer), &size)) << in.GetError();
+ ASSERT_TRUE(in.Next(&buffer, &size)) << in.GetError();
ASSERT_THAT(size, Eq(10u));
ASSERT_THAT(buffer, NotNull());
EXPECT_THAT(in.ByteCount(), Eq(10u));
- EXPECT_THAT(StringPiece(buffer, size), Eq("this is a "));
+ EXPECT_THAT(StringPiece(reinterpret_cast<const char*>(buffer), size), Eq("this is a "));
- ASSERT_TRUE(in.Next(reinterpret_cast<const void**>(&buffer), &size));
+ ASSERT_TRUE(in.Next(&buffer, &size));
ASSERT_THAT(size, Eq(10u));
ASSERT_THAT(buffer, NotNull());
EXPECT_THAT(in.ByteCount(), Eq(20u));
- EXPECT_THAT(StringPiece(buffer, size), Eq("cool strin"));
+ EXPECT_THAT(StringPiece(reinterpret_cast<const char*>(buffer), size), Eq("cool strin"));
in.BackUp(5u);
EXPECT_THAT(in.ByteCount(), Eq(15u));
- ASSERT_TRUE(in.Next(reinterpret_cast<const void**>(&buffer), &size));
+ ASSERT_TRUE(in.Next(&buffer, &size));
ASSERT_THAT(size, Eq(5u));
ASSERT_THAT(buffer, NotNull());
ASSERT_THAT(in.ByteCount(), Eq(20u));
- EXPECT_THAT(StringPiece(buffer, size), Eq("strin"));
+ EXPECT_THAT(StringPiece(reinterpret_cast<const char*>(buffer), size), Eq("strin"));
// Backup 1 more than possible. Should clamp.
in.BackUp(11u);
EXPECT_THAT(in.ByteCount(), Eq(10u));
- ASSERT_TRUE(in.Next(reinterpret_cast<const void**>(&buffer), &size));
+ ASSERT_TRUE(in.Next(&buffer, &size));
ASSERT_THAT(size, Eq(10u));
ASSERT_THAT(buffer, NotNull());
ASSERT_THAT(in.ByteCount(), Eq(20u));
- EXPECT_THAT(StringPiece(buffer, size), Eq("cool strin"));
+ EXPECT_THAT(StringPiece(reinterpret_cast<const char*>(buffer), size), Eq("cool strin"));
- ASSERT_TRUE(in.Next(reinterpret_cast<const void**>(&buffer), &size));
+ ASSERT_TRUE(in.Next(&buffer, &size));
ASSERT_THAT(size, Eq(1u));
ASSERT_THAT(buffer, NotNull());
ASSERT_THAT(in.ByteCount(), Eq(21u));
- EXPECT_THAT(StringPiece(buffer, size), Eq("g"));
+ EXPECT_THAT(StringPiece(reinterpret_cast<const char*>(buffer), size), Eq("g"));
- EXPECT_FALSE(in.Next(reinterpret_cast<const void**>(&buffer), &size));
+ EXPECT_FALSE(in.Next(&buffer, &size));
EXPECT_FALSE(in.HadError());
}
@@ -93,25 +93,25 @@
ASSERT_FALSE(out.HadError());
EXPECT_THAT(out.ByteCount(), Eq(0u));
- char* buffer;
+ void* buffer;
size_t size;
- ASSERT_TRUE(out.Next(reinterpret_cast<void**>(&buffer), &size));
+ ASSERT_TRUE(out.Next(&buffer, &size));
ASSERT_THAT(size, Eq(10u));
ASSERT_THAT(buffer, NotNull());
EXPECT_THAT(out.ByteCount(), Eq(10u));
- memcpy(buffer, input.c_str(), size);
+ memcpy(reinterpret_cast<char*>(buffer), input.c_str(), size);
- ASSERT_TRUE(out.Next(reinterpret_cast<void**>(&buffer), &size));
+ ASSERT_TRUE(out.Next(&buffer, &size));
ASSERT_THAT(size, Eq(10u));
ASSERT_THAT(buffer, NotNull());
EXPECT_THAT(out.ByteCount(), Eq(20u));
- memcpy(buffer, input.c_str() + 10u, size);
+ memcpy(reinterpret_cast<char*>(buffer), input.c_str() + 10u, size);
- ASSERT_TRUE(out.Next(reinterpret_cast<void**>(&buffer), &size));
+ ASSERT_TRUE(out.Next(&buffer, &size));
ASSERT_THAT(size, Eq(10u));
ASSERT_THAT(buffer, NotNull());
EXPECT_THAT(out.ByteCount(), Eq(30u));
- buffer[0] = input[20u];
+ reinterpret_cast<char*>(buffer)[0] = input[20u];
out.BackUp(size - 1);
EXPECT_THAT(out.ByteCount(), Eq(21u));