Merge changes I17f77bd9,Iff991ac6
* changes:
Migrate SubsystemSleepStatePuller to jni
Move SubsystemSleepStatePuller
diff --git a/Android.bp b/Android.bp
index ffb4d3a..2318f7b 100644
--- a/Android.bp
+++ b/Android.bp
@@ -734,6 +734,7 @@
"core/java/android/annotation/RequiresPermission.java",
"core/java/android/annotation/SystemApi.java",
"core/java/android/annotation/TestApi.java",
+ "core/java/com/android/internal/annotations/GuardedBy.java",
],
}
// Build ext.jar
diff --git a/apex/blobstore/framework/java/android/app/blob/BlobHandle.java b/apex/blobstore/framework/java/android/app/blob/BlobHandle.java
index f7e6a98..ee0ee98 100644
--- a/apex/blobstore/framework/java/android/app/blob/BlobHandle.java
+++ b/apex/blobstore/framework/java/android/app/blob/BlobHandle.java
@@ -45,6 +45,10 @@
public final class BlobHandle implements Parcelable {
private static final String ALGO_SHA_256 = "SHA-256";
+ private static final String[] SUPPORTED_ALGOS = {
+ ALGO_SHA_256
+ };
+
private static final int LIMIT_BLOB_TAG_LENGTH = 128; // characters
/**
@@ -104,14 +108,9 @@
public static @NonNull BlobHandle create(@NonNull String algorithm, @NonNull byte[] digest,
@NonNull CharSequence label, @CurrentTimeMillisLong long expiryTimeMillis,
@NonNull String tag) {
- Preconditions.checkNotNull(algorithm, "algorithm must not be null");
- Preconditions.checkNotNull(digest, "digest must not be null");
- Preconditions.checkNotNull(label, "label must not be null");
- Preconditions.checkArgumentNonnegative(expiryTimeMillis,
- "expiryTimeMillis must not be negative");
- Preconditions.checkNotNull(tag, "tag must not be null");
- Preconditions.checkArgument(tag.length() <= LIMIT_BLOB_TAG_LENGTH, "tag too long");
- return new BlobHandle(algorithm, digest, label, expiryTimeMillis, tag);
+ final BlobHandle handle = new BlobHandle(algorithm, digest, label, expiryTimeMillis, tag);
+ handle.assertIsValid();
+ return handle;
}
/**
@@ -223,6 +222,17 @@
fout.println("tag: " + tag);
}
+ /** @hide */
+ public void assertIsValid() {
+ Preconditions.checkArgumentIsSupported(SUPPORTED_ALGOS, algorithm);
+ Preconditions.checkByteArrayNotEmpty(digest, "digest");
+ Preconditions.checkStringNotEmpty(label, "label must not be null");
+ Preconditions.checkArgumentNonnegative(expiryTimeMillis,
+ "expiryTimeMillis must not be negative");
+ Preconditions.checkStringNotEmpty(tag, "tag must not be null");
+ Preconditions.checkArgument(tag.length() <= LIMIT_BLOB_TAG_LENGTH, "tag too long");
+ }
+
public static final @NonNull Creator<BlobHandle> CREATOR = new Creator<BlobHandle>() {
@Override
public @NonNull BlobHandle createFromParcel(@NonNull Parcel source) {
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
index fcc30e30..dfe4410 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
@@ -49,6 +49,7 @@
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManagerInternal;
+import android.content.res.ResourceId;
import android.os.Binder;
import android.os.Handler;
import android.os.HandlerThread;
@@ -91,6 +92,7 @@
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
/**
* Service responsible for maintaining and facilitating access to data blobs published by apps.
@@ -658,10 +660,9 @@
@IntRange(from = 1)
public long createSession(@NonNull BlobHandle blobHandle,
@NonNull String packageName) {
- Preconditions.checkNotNull(blobHandle, "blobHandle must not be null");
- Preconditions.checkNotNull(packageName, "packageName must not be null");
- // TODO: verify blobHandle.algorithm is sha-256
- // TODO: assert blobHandle is valid.
+ Objects.requireNonNull(blobHandle, "blobHandle must not be null");
+ blobHandle.assertIsValid();
+ Objects.requireNonNull(packageName, "packageName must not be null");
final int callingUid = Binder.getCallingUid();
verifyCallingPackage(callingUid, packageName);
@@ -682,7 +683,7 @@
@NonNull String packageName) {
Preconditions.checkArgumentPositive(sessionId,
"sessionId must be positive: " + sessionId);
- Preconditions.checkNotNull(packageName, "packageName must not be null");
+ Objects.requireNonNull(packageName, "packageName must not be null");
final int callingUid = Binder.getCallingUid();
verifyCallingPackage(callingUid, packageName);
@@ -695,7 +696,7 @@
@NonNull String packageName) {
Preconditions.checkArgumentPositive(sessionId,
"sessionId must be positive: " + sessionId);
- Preconditions.checkNotNull(packageName, "packageName must not be null");
+ Objects.requireNonNull(packageName, "packageName must not be null");
final int callingUid = Binder.getCallingUid();
verifyCallingPackage(callingUid, packageName);
@@ -706,8 +707,9 @@
@Override
public ParcelFileDescriptor openBlob(@NonNull BlobHandle blobHandle,
@NonNull String packageName) {
- Preconditions.checkNotNull(blobHandle, "blobHandle must not be null");
- Preconditions.checkNotNull(packageName, "packageName must not be null");
+ Objects.requireNonNull(blobHandle, "blobHandle must not be null");
+ blobHandle.assertIsValid();
+ Objects.requireNonNull(packageName, "packageName must not be null");
final int callingUid = Binder.getCallingUid();
verifyCallingPackage(callingUid, packageName);
@@ -727,24 +729,27 @@
@Override
public void acquireLease(@NonNull BlobHandle blobHandle, @IdRes int descriptionResId,
- @CurrentTimeSecondsLong long leaseTimeoutSecs, @NonNull String packageName) {
- Preconditions.checkNotNull(blobHandle, "blobHandle must not be null");
- Preconditions.checkNotNull(packageName, "packageName must not be null");
- Preconditions.checkArgumentPositive(descriptionResId,
- "descriptionResId must be positive; value=" + descriptionResId);
+ @CurrentTimeSecondsLong long leaseExpiryTimeMillis, @NonNull String packageName) {
+ Objects.requireNonNull(blobHandle, "blobHandle must not be null");
+ blobHandle.assertIsValid();
+ Preconditions.checkArgument(ResourceId.isValid(descriptionResId),
+ "descriptionResId is not valid");
+ Preconditions.checkArgumentNonnegative(leaseExpiryTimeMillis,
+ "leaseExpiryTimeMillis must not be negative");
+ Objects.requireNonNull(packageName, "packageName must not be null");
final int callingUid = Binder.getCallingUid();
verifyCallingPackage(callingUid, packageName);
- acquireLeaseInternal(blobHandle, descriptionResId, leaseTimeoutSecs,
+ acquireLeaseInternal(blobHandle, descriptionResId, leaseExpiryTimeMillis,
callingUid, packageName);
}
@Override
public void releaseLease(@NonNull BlobHandle blobHandle, @NonNull String packageName) {
- Preconditions.checkNotNull(blobHandle, "blobHandle must not be null");
- Preconditions.checkNotNull(packageName, "packageName must not be null");
-
+ Objects.requireNonNull(blobHandle, "blobHandle must not be null");
+ blobHandle.assertIsValid();
+ Objects.requireNonNull(packageName, "packageName must not be null");
final int callingUid = Binder.getCallingUid();
verifyCallingPackage(callingUid, packageName);
@@ -754,7 +759,7 @@
@Override
public void waitForIdle(@NonNull RemoteCallback remoteCallback) {
- Preconditions.checkNotNull(remoteCallback, "remoteCallback must not be null");
+ Objects.requireNonNull(remoteCallback, "remoteCallback must not be null");
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP,
"Caller is not allowed to call this; caller=" + Binder.getCallingUid());
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java
index 7d1c166..40f9f58 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java
@@ -62,6 +62,7 @@
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Objects;
/** TODO: add doc */
public class BlobStoreSession extends IBlobStoreSession.Stub {
@@ -155,6 +156,8 @@
@NonNull
public ParcelFileDescriptor openWrite(@BytesLong long offsetBytes,
@BytesLong long lengthBytes) {
+ Preconditions.checkArgumentNonnegative(offsetBytes, "offsetBytes must not be negative");
+
assertCallerIsOwner();
synchronized (mSessionLock) {
if (mState != STATE_OPENED) {
@@ -242,7 +245,7 @@
public void allowPackageAccess(@NonNull String packageName,
@NonNull byte[] certificate) {
assertCallerIsOwner();
- Preconditions.checkNotNull(packageName, "packageName must not be null");
+ Objects.requireNonNull(packageName, "packageName must not be null");
synchronized (mSessionLock) {
if (mState != STATE_OPENED) {
throw new IllegalStateException("Not allowed to change access type in state: "
@@ -280,7 +283,9 @@
public boolean isPackageAccessAllowed(@NonNull String packageName,
@NonNull byte[] certificate) {
assertCallerIsOwner();
- Preconditions.checkNotNull(packageName, "packageName must not be null");
+ Objects.requireNonNull(packageName, "packageName must not be null");
+ Preconditions.checkByteArrayNotEmpty(certificate, "certificate");
+
synchronized (mSessionLock) {
if (mState != STATE_OPENED) {
throw new IllegalStateException("Not allowed to get access type in state: "
diff --git a/apex/statsd/Android.bp b/apex/statsd/Android.bp
index 09ca1d2..1f9f18c 100644
--- a/apex/statsd/Android.bp
+++ b/apex/statsd/Android.bp
@@ -19,8 +19,9 @@
}
apex_defaults {
- // libc.so and libcutils.so are included in the apex
- // native_shared_libs: ["libc", "libcutils"],
+ native_shared_libs: [
+ "libstats_jni",
+ ],
// binaries: ["vold"],
java_libs: [
"framework-statsd",
@@ -44,3 +45,33 @@
// com.android.os.statsd.pk8 (the private key)
certificate: "com.android.os.statsd",
}
+
+
+// JNI library for StatsLog.write
+cc_library_shared {
+ name: "libstats_jni",
+ srcs: ["jni/**/*.cpp"],
+ shared_libs: [
+ "libnativehelper", // Has stable abi - should not be copied into apex.
+ "liblog", // Has a stable abi - should not be copied into apex.
+ ],
+ static_libs: [
+ //TODO: make shared - need libstatssocket to also live in the apex.
+ "libstatssocket",
+ "libcutils", // TODO: remove - needed by libstatssocket
+ ],
+ //TODO: is libc++_static correct?
+ stl: "libc++_static",
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ "-Wno-unused-parameter",
+ ],
+ apex_available: [
+ "com.android.os.statsd",
+ "test_com.android.os.statsd",
+ //TODO (b/148620413): remove platform.
+ "//apex_available:platform",
+ ],
+}
\ No newline at end of file
diff --git a/apex/statsd/aidl/android/os/IStatsCompanionService.aidl b/apex/statsd/aidl/android/os/IStatsCompanionService.aidl
index bdd1da7..b94928f 100644
--- a/apex/statsd/aidl/android/os/IStatsCompanionService.aidl
+++ b/apex/statsd/aidl/android/os/IStatsCompanionService.aidl
@@ -61,4 +61,11 @@
/** Tells StatsCompaionService to grab the uid map snapshot and send it to statsd. */
oneway void triggerUidSnapshot();
+
+ /**
+ * Ask StatsCompanionService if the given permission is allowed for a particular process
+ * and user ID. statsd is incapable of doing this check itself because checkCallingPermission
+ * is not currently supported by libbinder_ndk.
+ */
+ boolean checkPermission(String permission, int pid, int uid);
}
diff --git a/core/jni/android_util_StatsLog.cpp b/apex/statsd/jni/android_util_StatsLog.cpp
similarity index 71%
rename from core/jni/android_util_StatsLog.cpp
rename to apex/statsd/jni/android_util_StatsLog.cpp
index 9225fc2..9d410eb 100644
--- a/core/jni/android_util_StatsLog.cpp
+++ b/apex/statsd/jni/android_util_StatsLog.cpp
@@ -17,12 +17,9 @@
#define LOG_NAMESPACE "StatsLog.tag."
#define LOG_TAG "StatsLog_println"
-#include <assert.h>
-
#include "jni.h"
+#include <log/log.h>
#include <nativehelper/JNIHelp.h>
-#include "utils/misc.h"
-#include "core_jni_helpers.h"
#include "stats_buffer_writer.h"
namespace android {
@@ -57,7 +54,27 @@
int register_android_util_StatsLog(JNIEnv* env)
{
- return RegisterMethodsOrDie(env, "android/util/StatsLog", gMethods, NELEM(gMethods));
+ return jniRegisterNativeMethods(env, "android/util/StatsLog", gMethods, NELEM(gMethods));
}
-
}; // namespace android
+
+/*
+ * JNI Initialization
+ */
+jint JNI_OnLoad(JavaVM* jvm, void* reserved) {
+ JNIEnv* e;
+ int status;
+
+ ALOGV("statsd : loading JNI\n");
+ // Check JNI version
+ if (jvm->GetEnv((void**)&e, JNI_VERSION_1_4)) {
+ ALOGE("JNI version mismatch error");
+ return JNI_ERR;
+ }
+ status = android::register_android_util_StatsLog(e);
+ if (status < 0) {
+ ALOGE("jni statsd registration failure, status: %d", status);
+ return JNI_ERR;
+ }
+ return JNI_VERSION_1_4;
+}
diff --git a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
index 1e92826..3e9a488 100644
--- a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
+++ b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
@@ -516,6 +516,11 @@
}
}
+ @Override // Binder call
+ public boolean checkPermission(String permission, int pid, int uid) {
+ StatsCompanion.enforceStatsCompanionPermission(mContext);
+ return mContext.checkPermission(permission, pid, uid) == PackageManager.PERMISSION_GRANTED;
+ }
// Statsd related code
diff --git a/api/current.txt b/api/current.txt
index 1306bfa..a50a4c2 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -31129,11 +31129,6 @@
field @Deprecated public static final String[] strings;
}
- @Deprecated public static class WifiConfiguration.SuiteBCipher {
- field @Deprecated public static final int ECDHE_ECDSA = 0; // 0x0
- field @Deprecated public static final int ECDHE_RSA = 1; // 0x1
- }
-
public class WifiEnterpriseConfig implements android.os.Parcelable {
ctor public WifiEnterpriseConfig();
ctor public WifiEnterpriseConfig(android.net.wifi.WifiEnterpriseConfig);
@@ -31616,6 +31611,7 @@
method public android.net.wifi.hotspot2.pps.Credential getCredential();
method public android.net.wifi.hotspot2.pps.HomeSp getHomeSp();
method public long getSubscriptionExpirationTimeInMillis();
+ method @NonNull public String getUniqueId() throws java.lang.IllegalStateException;
method public boolean isOsuProvisioned();
method public void setCredential(android.net.wifi.hotspot2.pps.Credential);
method public void setHomeSp(android.net.wifi.hotspot2.pps.HomeSp);
@@ -31796,8 +31792,8 @@
method public boolean isGroupOwner();
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.p2p.WifiP2pGroup> CREATOR;
- field public static final int PERSISTENT_NET_ID = -2; // 0xfffffffe
- field public static final int TEMPORARY_NET_ID = -1; // 0xffffffff
+ field public static final int NETWORK_ID_PERSISTENT = -2; // 0xfffffffe
+ field public static final int NETWORK_ID_TEMPORARY = -1; // 0xffffffff
}
public class WifiP2pInfo implements android.os.Parcelable {
@@ -36944,7 +36940,7 @@
ctor public VibrationAttributes.Builder();
ctor public VibrationAttributes.Builder(@Nullable android.os.VibrationAttributes);
method @NonNull public android.os.VibrationAttributes build();
- method @NonNull public android.os.VibrationAttributes.Builder replaceFlags(int);
+ method @NonNull public android.os.VibrationAttributes.Builder setFlags(int, int);
method @NonNull public android.os.VibrationAttributes.Builder setUsage(int);
}
@@ -46381,7 +46377,6 @@
public final class BarringInfo implements android.os.Parcelable {
method public int describeContents();
method @NonNull public android.telephony.BarringInfo.BarringServiceInfo getBarringServiceInfo(int);
- method public boolean isServiceBarred(int);
method public void writeToParcel(@NonNull android.os.Parcel, int);
field public static final int BARRING_SERVICE_TYPE_CS_FALLBACK = 5; // 0x5
field public static final int BARRING_SERVICE_TYPE_CS_SERVICE = 0; // 0x0
diff --git a/api/system-current.txt b/api/system-current.txt
index 0930f68..83889d4 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1604,7 +1604,7 @@
}
public final class BluetoothHidDevice implements android.bluetooth.BluetoothProfile {
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
}
public final class BluetoothHidHost implements android.bluetooth.BluetoothProfile {
@@ -6233,7 +6233,7 @@
}
public abstract class NetworkAgent {
- ctor public NetworkAgent(@NonNull android.content.Context, @NonNull android.os.Looper, @NonNull String, @NonNull android.net.NetworkCapabilities, @NonNull android.net.LinkProperties, int, @NonNull android.net.NetworkAgentConfig, @Nullable android.net.NetworkProvider);
+ ctor public NetworkAgent(@NonNull android.content.Context, @NonNull android.os.Looper, @NonNull String, @NonNull android.net.NetworkCapabilities, @NonNull android.net.LinkProperties, @NonNull android.net.NetworkScore, @NonNull android.net.NetworkAgentConfig, @Nullable android.net.NetworkProvider);
method @Nullable public android.net.Network getNetwork();
method public void onAddKeepalivePacketFilter(int, @NonNull android.net.KeepalivePacketData);
method public void onAutomaticReconnectDisabled();
@@ -6248,7 +6248,7 @@
method @NonNull public android.net.Network register();
method public void sendLinkProperties(@NonNull android.net.LinkProperties);
method public void sendNetworkCapabilities(@NonNull android.net.NetworkCapabilities);
- method public void sendNetworkScore(int);
+ method public void sendNetworkScore(@NonNull android.net.NetworkScore);
method public void sendSocketKeepaliveEvent(int, int);
method public void setConnected();
method @Deprecated public void setLegacyExtraInfo(@Nullable String);
@@ -6351,6 +6351,55 @@
method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP) public android.net.NetworkRequest.Builder setSignalStrength(int);
}
+ public final class NetworkScore implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public android.net.NetworkScore.Metrics getEndToEndMetrics();
+ method @NonNull public android.net.NetworkScore.Metrics getLinkLayerMetrics();
+ method public int getRange();
+ method @IntRange(from=android.net.NetworkScore.UNKNOWN_SIGNAL_STRENGTH, to=android.net.NetworkScore.MAX_SIGNAL_STRENGTH) public int getSignalStrength();
+ method public boolean hasPolicy(int);
+ method public boolean isExiting();
+ method @NonNull public android.net.NetworkScore withExiting(boolean);
+ method @NonNull public android.net.NetworkScore withSignalStrength(@IntRange(from=android.net.NetworkScore.UNKNOWN_SIGNAL_STRENGTH) int);
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkScore> CREATOR;
+ field public static final int MAX_SIGNAL_STRENGTH = 1000; // 0x3e8
+ field public static final int MIN_SIGNAL_STRENGTH = 0; // 0x0
+ field public static final int POLICY_DEFAULT_SUBSCRIPTION = 8; // 0x8
+ field public static final int POLICY_IGNORE_ON_WIFI = 4; // 0x4
+ field public static final int POLICY_LOCKDOWN_VPN = 1; // 0x1
+ field public static final int POLICY_VPN = 2; // 0x2
+ field public static final int RANGE_CLOSE = 1; // 0x1
+ field public static final int RANGE_LONG = 4; // 0x4
+ field public static final int RANGE_MEDIUM = 3; // 0x3
+ field public static final int RANGE_SHORT = 2; // 0x2
+ field public static final int RANGE_UNKNOWN = 0; // 0x0
+ field public static final int UNKNOWN_SIGNAL_STRENGTH = -1; // 0xffffffff
+ }
+
+ public static class NetworkScore.Builder {
+ ctor public NetworkScore.Builder();
+ method @NonNull public android.net.NetworkScore.Builder addPolicy(int);
+ method @NonNull public android.net.NetworkScore build();
+ method @NonNull public android.net.NetworkScore.Builder clearPolicy(int);
+ method @NonNull public android.net.NetworkScore.Builder setEndToEndMetrics(@NonNull android.net.NetworkScore.Metrics);
+ method @NonNull public android.net.NetworkScore.Builder setExiting(boolean);
+ method @NonNull public android.net.NetworkScore.Builder setLegacyScore(int);
+ method @NonNull public android.net.NetworkScore.Builder setLinkLayerMetrics(@NonNull android.net.NetworkScore.Metrics);
+ method @NonNull public android.net.NetworkScore.Builder setRange(int);
+ method @NonNull public android.net.NetworkScore.Builder setSignalStrength(@IntRange(from=android.net.NetworkScore.UNKNOWN_SIGNAL_STRENGTH, to=android.net.NetworkScore.MAX_SIGNAL_STRENGTH) int);
+ }
+
+ public static class NetworkScore.Metrics {
+ ctor public NetworkScore.Metrics(@IntRange(from=android.net.NetworkScore.Metrics.LATENCY_UNKNOWN) int, @IntRange(from=android.net.NetworkScore.Metrics.BANDWIDTH_UNKNOWN) int, @IntRange(from=android.net.NetworkScore.Metrics.BANDWIDTH_UNKNOWN) int);
+ field public static final int BANDWIDTH_UNKNOWN = -1; // 0xffffffff
+ field @NonNull public static final android.net.NetworkScore.Metrics EMPTY;
+ field public static final int LATENCY_UNKNOWN = -1; // 0xffffffff
+ field @IntRange(from=android.net.NetworkScore.Metrics.BANDWIDTH_UNKNOWN) public final int downlinkBandwidthKBps;
+ field @IntRange(from=android.net.NetworkScore.Metrics.LATENCY_UNKNOWN) public final int latencyMs;
+ field @IntRange(from=android.net.NetworkScore.Metrics.BANDWIDTH_UNKNOWN) public final int uplinkBandwidthKBps;
+ }
+
public class NetworkScoreManager {
method @RequiresPermission(anyOf={android.Manifest.permission.SCORE_NETWORKS, android.Manifest.permission.REQUEST_NETWORK_SCORES}) public boolean clearScores() throws java.lang.SecurityException;
method @RequiresPermission(anyOf={android.Manifest.permission.SCORE_NETWORKS, android.Manifest.permission.REQUEST_NETWORK_SCORES}) public void disableScoring() throws java.lang.SecurityException;
@@ -7465,6 +7514,7 @@
method @Deprecated @NonNull public android.net.wifi.WifiConfiguration.NetworkSelectionStatus getNetworkSelectionStatus();
method @Deprecated @NonNull public String getPrintableSsid();
method @Deprecated @NonNull public android.net.IpConfiguration.ProxySettings getProxySettings();
+ method @Deprecated public int getRecentFailureReason();
method @Deprecated @Nullable public android.net.StaticIpConfiguration getStaticIpConfiguration();
method @Deprecated public boolean hasNoInternetAccess();
method @Deprecated public boolean isEphemeral();
@@ -7482,6 +7532,8 @@
field @Deprecated public static final int METERED_OVERRIDE_NOT_METERED = 2; // 0x2
field @Deprecated public static final int RANDOMIZATION_NONE = 0; // 0x0
field @Deprecated public static final int RANDOMIZATION_PERSISTENT = 1; // 0x1
+ field @Deprecated public static final int RECENT_FAILURE_AP_UNABLE_TO_HANDLE_NEW_STA = 17; // 0x11
+ field @Deprecated public static final int RECENT_FAILURE_NONE = 0; // 0x0
field @Deprecated public boolean allowAutojoin;
field @Deprecated public int apBand;
field @Deprecated public int carrierId;
@@ -7497,7 +7549,6 @@
field @Deprecated public int numAssociation;
field @Deprecated public int numScorerOverride;
field @Deprecated public int numScorerOverrideAndSwitchedNetwork;
- field @Deprecated @NonNull public final android.net.wifi.WifiConfiguration.RecentFailure recentFailure;
field @Deprecated public boolean requirePMF;
field @Deprecated @Nullable public String saePasswordId;
field @Deprecated public boolean shared;
@@ -7543,12 +7594,6 @@
method @Deprecated @NonNull public android.net.wifi.WifiConfiguration.NetworkSelectionStatus.Builder setNetworkSelectionStatus(int);
}
- @Deprecated public static class WifiConfiguration.RecentFailure {
- method @Deprecated public int getAssociationStatus();
- field @Deprecated public static final int NONE = 0; // 0x0
- field @Deprecated public static final int STATUS_AP_UNABLE_TO_HANDLE_NEW_STA = 17; // 0x11
- }
-
public class WifiEnterpriseConfig implements android.os.Parcelable {
method @Nullable public String[] getCaCertificateAliases();
method @NonNull public String getCaPath();
diff --git a/api/test-current.txt b/api/test-current.txt
index e0b5b34..4fd33b8 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -1387,6 +1387,10 @@
method public int getMaxMacroBlocks();
}
+ public final class MediaRoute2Info implements android.os.Parcelable {
+ method @NonNull public String getOriginalId();
+ }
+
public final class PlaybackParams implements android.os.Parcelable {
method public int getAudioStretchMode();
method public android.media.PlaybackParams setAudioStretchMode(int);
@@ -1688,6 +1692,55 @@
field public static final int TRANSPORT_TEST = 7; // 0x7
}
+ public final class NetworkScore implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public android.net.NetworkScore.Metrics getEndToEndMetrics();
+ method @NonNull public android.net.NetworkScore.Metrics getLinkLayerMetrics();
+ method public int getRange();
+ method @IntRange(from=android.net.NetworkScore.UNKNOWN_SIGNAL_STRENGTH, to=android.net.NetworkScore.MAX_SIGNAL_STRENGTH) public int getSignalStrength();
+ method public boolean hasPolicy(int);
+ method public boolean isExiting();
+ method @NonNull public android.net.NetworkScore withExiting(boolean);
+ method @NonNull public android.net.NetworkScore withSignalStrength(@IntRange(from=android.net.NetworkScore.UNKNOWN_SIGNAL_STRENGTH) int);
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkScore> CREATOR;
+ field public static final int MAX_SIGNAL_STRENGTH = 1000; // 0x3e8
+ field public static final int MIN_SIGNAL_STRENGTH = 0; // 0x0
+ field public static final int POLICY_DEFAULT_SUBSCRIPTION = 8; // 0x8
+ field public static final int POLICY_IGNORE_ON_WIFI = 4; // 0x4
+ field public static final int POLICY_LOCKDOWN_VPN = 1; // 0x1
+ field public static final int POLICY_VPN = 2; // 0x2
+ field public static final int RANGE_CLOSE = 1; // 0x1
+ field public static final int RANGE_LONG = 4; // 0x4
+ field public static final int RANGE_MEDIUM = 3; // 0x3
+ field public static final int RANGE_SHORT = 2; // 0x2
+ field public static final int RANGE_UNKNOWN = 0; // 0x0
+ field public static final int UNKNOWN_SIGNAL_STRENGTH = -1; // 0xffffffff
+ }
+
+ public static class NetworkScore.Builder {
+ ctor public NetworkScore.Builder();
+ method @NonNull public android.net.NetworkScore.Builder addPolicy(int);
+ method @NonNull public android.net.NetworkScore build();
+ method @NonNull public android.net.NetworkScore.Builder clearPolicy(int);
+ method @NonNull public android.net.NetworkScore.Builder setEndToEndMetrics(@NonNull android.net.NetworkScore.Metrics);
+ method @NonNull public android.net.NetworkScore.Builder setExiting(boolean);
+ method @NonNull public android.net.NetworkScore.Builder setLegacyScore(int);
+ method @NonNull public android.net.NetworkScore.Builder setLinkLayerMetrics(@NonNull android.net.NetworkScore.Metrics);
+ method @NonNull public android.net.NetworkScore.Builder setRange(int);
+ method @NonNull public android.net.NetworkScore.Builder setSignalStrength(@IntRange(from=android.net.NetworkScore.UNKNOWN_SIGNAL_STRENGTH, to=android.net.NetworkScore.MAX_SIGNAL_STRENGTH) int);
+ }
+
+ public static class NetworkScore.Metrics {
+ ctor public NetworkScore.Metrics(@IntRange(from=android.net.NetworkScore.Metrics.LATENCY_UNKNOWN) int, @IntRange(from=android.net.NetworkScore.Metrics.BANDWIDTH_UNKNOWN) int, @IntRange(from=android.net.NetworkScore.Metrics.BANDWIDTH_UNKNOWN) int);
+ field public static final int BANDWIDTH_UNKNOWN = -1; // 0xffffffff
+ field @NonNull public static final android.net.NetworkScore.Metrics EMPTY;
+ field public static final int LATENCY_UNKNOWN = -1; // 0xffffffff
+ field @IntRange(from=android.net.NetworkScore.Metrics.BANDWIDTH_UNKNOWN) public final int downlinkBandwidthKBps;
+ field @IntRange(from=android.net.NetworkScore.Metrics.LATENCY_UNKNOWN) public final int latencyMs;
+ field @IntRange(from=android.net.NetworkScore.Metrics.BANDWIDTH_UNKNOWN) public final int uplinkBandwidthKBps;
+ }
+
public class NetworkStack {
field public static final String PERMISSION_MAINLINE_NETWORK_STACK = "android.permission.MAINLINE_NETWORK_STACK";
}
diff --git a/cmds/statsd/benchmark/log_event_benchmark.cpp b/cmds/statsd/benchmark/log_event_benchmark.cpp
index bdfdb2e..30dfe32 100644
--- a/cmds/statsd/benchmark/log_event_benchmark.cpp
+++ b/cmds/statsd/benchmark/log_event_benchmark.cpp
@@ -39,7 +39,7 @@
uint8_t msg[LOGGER_ENTRY_MAX_PAYLOAD];
size_t size = createAndParseStatsEvent(msg);
while (state.KeepRunning()) {
- benchmark::DoNotOptimize(LogEvent(msg, size, /*uid=*/ 1000));
+ benchmark::DoNotOptimize(LogEvent(msg, size, /*uid=*/ 1000, /*pid=*/ 1001));
}
}
BENCHMARK(BM_LogEventCreation);
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index c1a8d69..05281f7 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -30,7 +30,6 @@
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
#include <binder/PermissionController.h>
#include <cutils/multiuser.h>
#include <dirent.h>
@@ -77,6 +76,25 @@
return binder::Status::fromExceptionCode(code, String8(msg.c_str()));
}
+
+static bool checkPermission(const char* permission) {
+ sp<IStatsCompanionService> scs = getStatsCompanionService();
+ if (scs == nullptr) {
+ return false;
+ }
+
+ bool success;
+ pid_t pid = IPCThreadState::self()->getCallingPid();
+ uid_t uid = IPCThreadState::self()->getCallingUid();
+
+ binder::Status status = scs->checkPermission(String16(permission), pid, uid, &success);
+ if (!status.isOk()) {
+ return false;
+ }
+ return success;
+}
+
+
binder::Status checkUid(uid_t expectedUid) {
uid_t uid = IPCThreadState::self()->getCallingUid();
if (uid == expectedUid || uid == AID_ROOT) {
@@ -97,11 +115,11 @@
}
// Caller must be granted these permissions
- if (!checkCallingPermission(String16(kPermissionDump))) {
+ if (!checkPermission(kPermissionDump)) {
return exception(binder::Status::EX_SECURITY,
StringPrintf("UID %d / PID %d lacks permission %s", uid, pid, kPermissionDump));
}
- if (!checkCallingPermission(String16(kPermissionUsage))) {
+ if (!checkPermission(kPermissionUsage)) {
return exception(binder::Status::EX_SECURITY,
StringPrintf("UID %d / PID %d lacks permission %s", uid, pid, kPermissionUsage));
}
@@ -285,7 +303,7 @@
* TODO: Come up with a more robust method of enacting <serviceutils/PriorityDumper.h>.
*/
status_t StatsService::dump(int fd, const Vector<String16>& args) {
- if (!checkCallingPermission(String16(kPermissionDump))) {
+ if (!checkPermission(kPermissionDump)) {
return PERMISSION_DENIED;
}
int lastArg = args.size() - 1;
@@ -914,7 +932,7 @@
IPCThreadState* ipc = IPCThreadState::self();
VLOG("StatsService::cmd_clear_puller_cache with Pid %i, Uid %i",
ipc->getCallingPid(), ipc->getCallingUid());
- if (checkCallingPermission(String16(kPermissionDump))) {
+ if (checkPermission(kPermissionDump)) {
int cleared = mPullerManager->ForceClearPullerCache();
dprintf(out, "Puller removed %d cached data!\n", cleared);
return NO_ERROR;
@@ -927,7 +945,7 @@
IPCThreadState* ipc = IPCThreadState::self();
VLOG("StatsService::cmd_print_logs with Pid %i, Uid %i", ipc->getCallingPid(),
ipc->getCallingUid());
- if (checkCallingPermission(String16(kPermissionDump))) {
+ if (checkPermission(kPermissionDump)) {
bool enabled = true;
if (args.size() >= 2) {
enabled = atoi(args[1].c_str()) != 0;
@@ -1314,12 +1332,12 @@
// Root, system, and shell always have access
if (uid != AID_ROOT && uid != AID_SYSTEM && uid != AID_SHELL) {
// Caller must be granted these permissions
- if (!checkCallingPermission(String16(kPermissionDump))) {
+ if (!checkPermission(kPermissionDump)) {
return exception(binder::Status::EX_SECURITY,
StringPrintf("UID %d / PID %d lacks permission %s", uid, pid,
kPermissionDump));
}
- if (!checkCallingPermission(String16(kPermissionUsage))) {
+ if (!checkPermission(kPermissionUsage)) {
return exception(binder::Status::EX_SECURITY,
StringPrintf("UID %d / PID %d lacks permission %s", uid, pid,
kPermissionUsage));
@@ -1410,12 +1428,12 @@
// Root, system, and shell always have access
if (uid != AID_ROOT && uid != AID_SYSTEM && uid != AID_SHELL) {
// Caller must be granted these permissions
- if (!checkCallingPermission(String16(kPermissionDump))) {
+ if (!checkPermission(kPermissionDump)) {
return exception(binder::Status::EX_SECURITY,
StringPrintf("UID %d / PID %d lacks permission %s", uid, pid,
kPermissionDump));
}
- if (!checkCallingPermission(String16(kPermissionUsage))) {
+ if (!checkPermission(kPermissionUsage)) {
return exception(binder::Status::EX_SECURITY,
StringPrintf("UID %d / PID %d lacks permission %s", uid, pid,
kPermissionUsage));
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index d96bb46..12058ca 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -232,8 +232,8 @@
NfcCardemulationOccurred nfc_cardemulation_occurred = 137 [(module) = "nfc"];
NfcTagOccurred nfc_tag_occurred = 138 [(module) = "nfc"];
NfcHceTransactionOccurred nfc_hce_transaction_occurred = 139 [(module) = "nfc"];
- SeStateChanged se_state_changed = 140;
- SeOmapiReported se_omapi_reported = 141;
+ SeStateChanged se_state_changed = 140 [(module) = "secure_element"];
+ SeOmapiReported se_omapi_reported = 141 [(module) = "secure_element"];
BroadcastDispatchLatencyReported broadcast_dispatch_latency_reported =
142 [(module) = "framework"];
AttentionManagerServiceResultReported attention_manager_service_result_reported =
diff --git a/cmds/statsd/src/external/StatsCallbackPuller.cpp b/cmds/statsd/src/external/StatsCallbackPuller.cpp
index 6257771..1a11f0e 100644
--- a/cmds/statsd/src/external/StatsCallbackPuller.cpp
+++ b/cmds/statsd/src/external/StatsCallbackPuller.cpp
@@ -68,7 +68,7 @@
for (const StatsEventParcel& parcel: output) {
shared_ptr<LogEvent> event = make_shared<LogEvent>(
const_cast<uint8_t*>(parcel.buffer.data()), parcel.buffer.size(),
- /*uid=*/-1, /*useNewSchema=*/true);
+ /*uid=*/-1, /*pid=*/-1, /*useNewSchema=*/true);
sharedData->push_back(event);
}
*pullSuccess = success;
diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp
index 3827b9e..9a0693a 100644
--- a/cmds/statsd/src/logd/LogEvent.cpp
+++ b/cmds/statsd/src/logd/LogEvent.cpp
@@ -37,11 +37,12 @@
// Msg is expected to begin at the start of the serialized atom -- it should not
// include the android_log_header_t or the StatsEventTag.
-LogEvent::LogEvent(uint8_t* msg, uint32_t len, uint32_t uid)
+LogEvent::LogEvent(uint8_t* msg, uint32_t len, int32_t uid, int32_t pid)
: mBuf(msg),
mRemainingLen(len),
mLogdTimestampNs(time(nullptr)),
- mLogUid(uid)
+ mLogUid(uid),
+ mLogPid(pid)
{
#ifdef NEW_ENCODING_SCHEME
initNew();
@@ -52,8 +53,13 @@
#endif
}
-LogEvent::LogEvent(uint8_t* msg, uint32_t len, uint32_t uid, bool useNewSchema)
- : mBuf(msg), mRemainingLen(len), mLogdTimestampNs(time(nullptr)), mLogUid(uid) {
+LogEvent::LogEvent(uint8_t* msg, uint32_t len, int32_t uid, int32_t pid, bool useNewSchema)
+ : mBuf(msg),
+ mRemainingLen(len),
+ mLogdTimestampNs(time(nullptr)),
+ mLogUid(uid),
+ mLogPid(pid)
+{
if (useNewSchema) {
initNew();
} else {
@@ -66,6 +72,7 @@
LogEvent::LogEvent(const LogEvent& event) {
mTagId = event.mTagId;
mLogUid = event.mLogUid;
+ mLogPid = event.mLogPid;
mElapsedTimestampNs = event.mElapsedTimestampNs;
mLogdTimestampNs = event.mLogdTimestampNs;
mValues = event.mValues;
@@ -146,6 +153,7 @@
mElapsedTimestampNs = getElapsedRealtimeNs();
mTagId = android::util::BINARY_PUSH_STATE_CHANGED;
mLogUid = android::IPCThreadState::self()->getCallingUid();
+ mLogPid = android::IPCThreadState::self()->getCallingPid();
mValues.push_back(FieldValue(Field(mTagId, getSimpleField(1)), Value(trainName)));
mValues.push_back(FieldValue(Field(mTagId, getSimpleField(2)), Value(trainVersionCode)));
diff --git a/cmds/statsd/src/logd/LogEvent.h b/cmds/statsd/src/logd/LogEvent.h
index 463a1b6..583dae2 100644
--- a/cmds/statsd/src/logd/LogEvent.h
+++ b/cmds/statsd/src/logd/LogEvent.h
@@ -71,12 +71,12 @@
/**
* Read a LogEvent from the socket
*/
- explicit LogEvent(uint8_t* msg, uint32_t len, uint32_t uid);
+ explicit LogEvent(uint8_t* msg, uint32_t len, int32_t uid, int32_t pid);
/**
* Temp constructor to use for pulled atoms until we flip the socket schema.
*/
- explicit LogEvent(uint8_t* msg, uint32_t len, uint32_t uid, bool useNewSchema);
+ explicit LogEvent(uint8_t* msg, uint32_t len, int32_t uid, int32_t pid, bool useNewSchema);
/**
* Constructs a LogEvent with synthetic data for testing. Must call init() before reading.
@@ -123,9 +123,17 @@
*/
inline int GetTagId() const { return mTagId; }
- inline uint32_t GetUid() const {
- return mLogUid;
- }
+ /**
+ * Get the uid of the logging client.
+ * Returns -1 if the uid is unknown/has not been set.
+ */
+ inline int32_t GetUid() const { return mLogUid; }
+
+ /**
+ * Get the pid of the logging client.
+ * Returns -1 if the pid is unknown/has not been set.
+ */
+ inline int32_t GetPid() const { return mLogPid; }
/**
* Get the nth value, starting at 1.
@@ -305,9 +313,14 @@
// The elapsed timestamp set by statsd log writer.
int64_t mElapsedTimestampNs;
+ // The atom tag of the event.
int mTagId;
- uint32_t mLogUid;
+ // The uid of the logging client (defaults to -1).
+ int32_t mLogUid = -1;
+
+ // The pid of the logging client (defaults to -1).
+ int32_t mLogPid = -1;
};
void writeExperimentIdsToProto(const std::vector<int64_t>& experimentIds, std::vector<uint8_t>* protoOut);
diff --git a/cmds/statsd/src/socket/StatsSocketListener.cpp b/cmds/statsd/src/socket/StatsSocketListener.cpp
index 4308a110..cdb4d3a 100755
--- a/cmds/statsd/src/socket/StatsSocketListener.cpp
+++ b/cmds/statsd/src/socket/StatsSocketListener.cpp
@@ -126,9 +126,10 @@
uint8_t* msg = ptr + sizeof(uint32_t);
uint32_t len = n - sizeof(uint32_t);
uint32_t uid = cred->uid;
+ uint32_t pid = cred->pid;
int64_t oldestTimestamp;
- if (!mQueue->push(std::make_unique<LogEvent>(msg, len, uid), &oldestTimestamp)) {
+ if (!mQueue->push(std::make_unique<LogEvent>(msg, len, uid, pid), &oldestTimestamp)) {
StatsdStats::getInstance().noteEventQueueOverflow(oldestTimestamp);
}
diff --git a/cmds/statsd/tests/LogEvent_test.cpp b/cmds/statsd/tests/LogEvent_test.cpp
index 1cf9fb6..35b0396 100644
--- a/cmds/statsd/tests/LogEvent_test.cpp
+++ b/cmds/statsd/tests/LogEvent_test.cpp
@@ -57,9 +57,11 @@
size_t size;
uint8_t* buf = stats_event_get_buffer(event, &size);
- LogEvent logEvent(buf, size, /*uid=*/ 1000);
+ LogEvent logEvent(buf, size, /*uid=*/ 1000, /*pid=*/ 1001);
EXPECT_TRUE(logEvent.isValid());
EXPECT_EQ(100, logEvent.GetTagId());
+ EXPECT_EQ(1000, logEvent.GetUid());
+ EXPECT_EQ(1001, logEvent.GetPid());
const vector<FieldValue>& values = logEvent.getValues();
EXPECT_EQ(4, values.size());
@@ -103,9 +105,11 @@
size_t size;
uint8_t* buf = stats_event_get_buffer(event, &size);
- LogEvent logEvent(buf, size, /*uid=*/ 1000);
+ LogEvent logEvent(buf, size, /*uid=*/ 1000, /*pid=*/ 1001);
EXPECT_TRUE(logEvent.isValid());
EXPECT_EQ(100, logEvent.GetTagId());
+ EXPECT_EQ(1000, logEvent.GetUid());
+ EXPECT_EQ(1001, logEvent.GetPid());
const vector<FieldValue>& values = logEvent.getValues();
EXPECT_EQ(2, values.size());
@@ -136,9 +140,11 @@
size_t size;
uint8_t* buf = stats_event_get_buffer(event, &size);
- LogEvent logEvent(buf, size, /*uid=*/ 1000);
+ LogEvent logEvent(buf, size, /*uid=*/ 1000, /*pid=*/ 1001);
EXPECT_TRUE(logEvent.isValid());
EXPECT_EQ(100, logEvent.GetTagId());
+ EXPECT_EQ(1000, logEvent.GetUid());
+ EXPECT_EQ(1001, logEvent.GetPid());
const vector<FieldValue>& values = logEvent.getValues();
EXPECT_EQ(1, values.size());
@@ -162,9 +168,11 @@
size_t size;
uint8_t* buf = stats_event_get_buffer(event, &size);
- LogEvent logEvent(buf, size, /*uid=*/ 1000);
+ LogEvent logEvent(buf, size, /*uid=*/ 1000, /*pid=*/ 1001);
EXPECT_TRUE(logEvent.isValid());
EXPECT_EQ(100, logEvent.GetTagId());
+ EXPECT_EQ(1000, logEvent.GetUid());
+ EXPECT_EQ(1001, logEvent.GetPid());
const vector<FieldValue>& values = logEvent.getValues();
EXPECT_EQ(1, values.size());
@@ -196,9 +204,11 @@
size_t size;
uint8_t* buf = stats_event_get_buffer(event, &size);
- LogEvent logEvent(buf, size, /*uid=*/ 1000);
+ LogEvent logEvent(buf, size, /*uid=*/ 1000, /*pid=*/ 1001);
EXPECT_TRUE(logEvent.isValid());
EXPECT_EQ(100, logEvent.GetTagId());
+ EXPECT_EQ(1000, logEvent.GetUid());
+ EXPECT_EQ(1001, logEvent.GetPid());
const vector<FieldValue>& values = logEvent.getValues();
EXPECT_EQ(8, values.size()); // 2 FieldValues per key-value pair
@@ -260,9 +270,11 @@
size_t size;
uint8_t* buf = stats_event_get_buffer(event, &size);
- LogEvent logEvent(buf, size, /*uid=*/ 1000);
+ LogEvent logEvent(buf, size, /*uid=*/ 1000, /*pid=*/ 1001);
EXPECT_TRUE(logEvent.isValid());
EXPECT_EQ(100, logEvent.GetTagId());
+ EXPECT_EQ(1000, logEvent.GetUid());
+ EXPECT_EQ(1001, logEvent.GetPid());
const vector<FieldValue>& values = logEvent.getValues();
EXPECT_EQ(4, values.size()); // 2 per attribution node
diff --git a/core/java/android/app/ActivityTaskManager.java b/core/java/android/app/ActivityTaskManager.java
index dd9a2bc..58bff7f 100644
--- a/core/java/android/app/ActivityTaskManager.java
+++ b/core/java/android/app/ActivityTaskManager.java
@@ -158,6 +158,24 @@
}
};
+ /** @hide */
+ @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
+ public static ITaskOrganizerController getTaskOrganizerController() {
+ return ITaskOrganizerControllerSingleton.get();
+ }
+
+ private static final Singleton<ITaskOrganizerController> ITaskOrganizerControllerSingleton =
+ new Singleton<ITaskOrganizerController>() {
+ @Override
+ protected ITaskOrganizerController create() {
+ try {
+ return getService().getTaskOrganizerController();
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+ };
+
/**
* Sets the windowing mode for a specific task. Only works on tasks of type
* {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD}
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index 85fa7c1..503f5c5 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -29,6 +29,7 @@
import android.app.IRequestFinishCallback;
import android.app.IServiceConnection;
import android.app.IStopUserCallback;
+import android.app.ITaskOrganizerController;
import android.app.ITaskStackListener;
import android.app.IUiAutomationConnection;
import android.app.IUidObserver;
@@ -71,7 +72,6 @@
import android.view.ITaskOrganizer;
import android.view.RemoteAnimationDefinition;
import android.view.RemoteAnimationAdapter;
-import android.view.WindowContainerTransaction;
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.os.IResultReceiver;
import com.android.internal.policy.IKeyguardDismissCallback;
@@ -123,8 +123,6 @@
int requestCode, int flags, in ProfilerInfo profilerInfo, in Bundle options,
IBinder permissionToken, boolean ignoreTargetSecurity, int userId);
- void registerTaskOrganizer(in ITaskOrganizer organizer, int windowingMode);
-
boolean isActivityStartAllowedOnDisplay(int displayId, in Intent intent, in String resolvedType,
int userId);
@@ -224,7 +222,6 @@
void setTaskResizeable(int taskId, int resizeableMode);
void toggleFreeformWindowingMode(in IBinder token);
void resizeTask(int taskId, in Rect bounds, int resizeMode);
- void applyContainerTransaction(in WindowContainerTransaction t);
void moveStackToDisplay(int stackId, int displayId);
void removeStack(int stackId);
@@ -364,6 +361,11 @@
in Rect tempOtherTaskBounds, in Rect tempOtherTaskInsetBounds);
/**
+ * Returns an interface enabling the management of task organizers.
+ */
+ ITaskOrganizerController getTaskOrganizerController();
+
+ /**
* Sets whether we are currently in an interactive split screen resize operation where we
* are changing the docked stack size.
*/
diff --git a/core/java/android/app/ITaskOrganizerController.aidl b/core/java/android/app/ITaskOrganizerController.aidl
new file mode 100644
index 0000000..168f782
--- /dev/null
+++ b/core/java/android/app/ITaskOrganizerController.aidl
@@ -0,0 +1,51 @@
+/**
+ * Copyright (c) 2020, 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.app;
+
+import android.app.ActivityManager;
+import android.view.ITaskOrganizer;
+import android.view.IWindowContainer;
+import android.view.WindowContainerTransaction;
+
+/** @hide */
+interface ITaskOrganizerController {
+
+ /**
+ * Register a TaskOrganizer to manage tasks as they enter the given windowing mode.
+ * If there was already a TaskOrganizer for this windowing mode it will be evicted
+ * and receive taskVanished callbacks in the process.
+ */
+ void registerTaskOrganizer(ITaskOrganizer organizer, int windowingMode);
+
+ /** Apply multiple WindowContainer operations at once. */
+ void applyContainerTransaction(in WindowContainerTransaction t);
+
+ /** Creates a persistent root task in WM for a particular windowing-mode. */
+ ActivityManager.RunningTaskInfo createRootTask(int displayId, int windowingMode);
+
+ /** Deletes a persistent root task in WM */
+ boolean deleteRootTask(IWindowContainer task);
+
+ /** Get the root task which contains the current ime target */
+ IWindowContainer getImeTarget(int display);
+
+ /**
+ * Set's the root task to launch new tasks into on a display. {@code null} means no launch root
+ * and thus new tasks just end up directly on the display.
+ */
+ void setLaunchRoot(int displayId, in IWindowContainer root);
+}
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 59c17192..65a5f6b 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -365,11 +365,9 @@
registerService(Context.TETHERING_SERVICE, TetheringManager.class,
new CachedServiceFetcher<TetheringManager>() {
@Override
- public TetheringManager createService(ContextImpl ctx) throws ServiceNotFoundException {
- IBinder b = ServiceManager.getService(Context.TETHERING_SERVICE);
- if (b == null) return null;
-
- return new TetheringManager(ctx, b);
+ public TetheringManager createService(ContextImpl ctx) {
+ return new TetheringManager(
+ ctx, () -> ServiceManager.getService(Context.TETHERING_SERVICE));
}});
diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java
index fe9c640..662ca6e 100644
--- a/core/java/android/app/TaskInfo.java
+++ b/core/java/android/app/TaskInfo.java
@@ -16,6 +16,8 @@
package android.app;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
@@ -25,6 +27,7 @@
import android.os.Parcel;
import android.os.RemoteException;
import android.util.Log;
+import android.view.IWindowContainer;
/**
* Stores information about a particular Task.
@@ -138,6 +141,19 @@
@UnsupportedAppUsage
public final Configuration configuration = new Configuration();
+ /**
+ * Used as an opaque identifier for this task.
+ * @hide
+ */
+ @NonNull
+ public IWindowContainer token;
+
+ /**
+ * The activity type of the top activity in this task.
+ * @hide
+ */
+ public @WindowConfiguration.ActivityType int topActivityType;
+
TaskInfo() {
// Do nothing
}
@@ -160,6 +176,11 @@
}
}
+ /** @hide */
+ public boolean isResizable() {
+ return resizeMode != RESIZE_MODE_UNRESIZEABLE;
+ }
+
/**
* Reads the TaskInfo from a parcel.
*/
@@ -186,6 +207,8 @@
supportsSplitScreenMultiWindow = source.readBoolean();
resizeMode = source.readInt();
configuration.readFromParcel(source);
+ token = IWindowContainer.Stub.asInterface(source.readStrongBinder());
+ topActivityType = source.readInt();
}
/**
@@ -221,6 +244,8 @@
dest.writeBoolean(supportsSplitScreenMultiWindow);
dest.writeInt(resizeMode);
configuration.writeToParcel(dest, flags);
+ dest.writeStrongInterface(token);
+ dest.writeInt(topActivityType);
}
@Override
@@ -234,6 +259,8 @@
+ " numActivities=" + numActivities
+ " lastActiveTime=" + lastActiveTime
+ " supportsSplitScreenMultiWindow=" + supportsSplitScreenMultiWindow
- + " resizeMode=" + resizeMode;
+ + " resizeMode=" + resizeMode
+ + " token=" + token
+ + " topActivityType=" + topActivityType;
}
}
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index e24b040..325fd94 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -2162,6 +2162,33 @@
}
/**
+ * Fetches a list of the most recently connected bluetooth devices ordered by how recently they
+ * were connected with most recently first and least recently last
+ *
+ * @return {@link List} of bonded {@link BluetoothDevice} ordered by how recently they were
+ * connected
+ *
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ public @NonNull List<BluetoothDevice> getMostRecentlyConnectedDevices() {
+ if (getState() != STATE_ON) {
+ return new ArrayList<>();
+ }
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null) {
+ return mService.getMostRecentlyConnectedDevices();
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ return new ArrayList<>();
+ }
+
+ /**
* Return the set of {@link BluetoothDevice} objects that are bonded
* (paired) to the local adapter.
* <p>If Bluetooth state is not {@link #STATE_ON}, this API
diff --git a/core/java/android/bluetooth/BluetoothHidDevice.java b/core/java/android/bluetooth/BluetoothHidDevice.java
index a923be6..b5959c0 100644
--- a/core/java/android/bluetooth/BluetoothHidDevice.java
+++ b/core/java/android/bluetooth/BluetoothHidDevice.java
@@ -706,7 +706,7 @@
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
public boolean setConnectionPolicy(@NonNull BluetoothDevice device,
@ConnectionPolicy int connectionPolicy) {
log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index ce9693d..fa12c08 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -3322,15 +3322,19 @@
// of dependent changes that would conflict throughout the automerger graph. Having this
// temporarily helps with the process of going through with all these dependent changes across
// the entire tree.
+ // STOPSHIP (b/148055573) : remove this before R is released.
/**
* @hide
* Register a NetworkAgent with ConnectivityService.
* @return Network corresponding to NetworkAgent.
+ * @deprecated use the version that takes a NetworkScore and a provider ID.
*/
@RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
+ @Deprecated
public Network registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp,
NetworkCapabilities nc, int score, NetworkAgentConfig config) {
- return registerNetworkAgent(messenger, ni, lp, nc, score, config, NetworkProvider.ID_NONE);
+ final NetworkScore ns = new NetworkScore.Builder().setLegacyScore(score).build();
+ return registerNetworkAgent(messenger, ni, lp, nc, ns, config, NetworkProvider.ID_NONE);
}
/**
@@ -3340,7 +3344,7 @@
*/
@RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
public Network registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp,
- NetworkCapabilities nc, int score, NetworkAgentConfig config, int providerId) {
+ NetworkCapabilities nc, NetworkScore score, NetworkAgentConfig config, int providerId) {
try {
return mService.registerNetworkAgent(messenger, ni, lp, nc, score, config, providerId);
} catch (RemoteException e) {
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 3e9e7fa..0dc66b5 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -26,6 +26,7 @@
import android.net.NetworkInfo;
import android.net.NetworkQuotaInfo;
import android.net.NetworkRequest;
+import android.net.NetworkScore;
import android.net.NetworkState;
import android.net.ISocketKeepaliveCallback;
import android.net.ProxyInfo;
@@ -154,7 +155,7 @@
void declareNetworkRequestUnfulfillable(in NetworkRequest request);
Network registerNetworkAgent(in Messenger messenger, in NetworkInfo ni, in LinkProperties lp,
- in NetworkCapabilities nc, int score, in NetworkAgentConfig config,
+ in NetworkCapabilities nc, in NetworkScore score, in NetworkAgentConfig config,
in int factorySerialNumber);
NetworkRequest requestNetwork(in NetworkCapabilities networkCapabilities,
diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java
index 7cc569a..ddf8dbb 100644
--- a/core/java/android/net/NetworkAgent.java
+++ b/core/java/android/net/NetworkAgent.java
@@ -117,13 +117,6 @@
public static final int EVENT_NETWORK_PROPERTIES_CHANGED = BASE + 3;
/**
- * Centralize the place where base network score, and network score scaling, will be
- * stored, so as we can consistently compare apple and oranges, or wifi, ethernet and LTE
- * @hide
- */
- public static final int WIFI_BASE_SCORE = 60;
-
- /**
* Sent by the NetworkAgent to ConnectivityService to pass the current
* network score.
* obj = network score Integer
@@ -272,7 +265,13 @@
*/
public static final int CMD_REMOVE_KEEPALIVE_PACKET_FILTER = BASE + 17;
+ // STOPSHIP (b/148055573) : remove this before R is released.
+ private static NetworkScore makeNetworkScore(int score) {
+ return new NetworkScore.Builder().setLegacyScore(score).build();
+ }
+
/** @hide TODO: remove and replace usage with the public constructor. */
+ // STOPSHIP (b/148055573) : remove this before R is released.
public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni,
NetworkCapabilities nc, LinkProperties lp, int score) {
this(looper, context, logTag, ni, nc, lp, score, null, NetworkProvider.ID_NONE);
@@ -280,6 +279,7 @@
}
/** @hide TODO: remove and replace usage with the public constructor. */
+ // STOPSHIP (b/148055573) : remove this before R is released.
public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni,
NetworkCapabilities nc, LinkProperties lp, int score, NetworkAgentConfig config) {
this(looper, context, logTag, ni, nc, lp, score, config, NetworkProvider.ID_NONE);
@@ -287,6 +287,7 @@
}
/** @hide TODO: remove and replace usage with the public constructor. */
+ // STOPSHIP (b/148055573) : remove this before R is released.
public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni,
NetworkCapabilities nc, LinkProperties lp, int score, int providerId) {
this(looper, context, logTag, ni, nc, lp, score, null, providerId);
@@ -294,10 +295,12 @@
}
/** @hide TODO: remove and replace usage with the public constructor. */
+ // STOPSHIP (b/148055573) : remove this before R is released.
public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni,
NetworkCapabilities nc, LinkProperties lp, int score, NetworkAgentConfig config,
int providerId) {
- this(looper, context, logTag, nc, lp, score, config, providerId, ni, true /* legacy */);
+ this(looper, context, logTag, nc, lp, makeNetworkScore(score), config, providerId, ni,
+ true /* legacy */);
register();
}
@@ -323,8 +326,9 @@
* @param provider the {@link NetworkProvider} managing this agent.
*/
public NetworkAgent(@NonNull Context context, @NonNull Looper looper, @NonNull String logTag,
- @NonNull NetworkCapabilities nc, @NonNull LinkProperties lp, int score,
- @NonNull NetworkAgentConfig config, @Nullable NetworkProvider provider) {
+ @NonNull NetworkCapabilities nc, @NonNull LinkProperties lp,
+ @NonNull NetworkScore score, @NonNull NetworkAgentConfig config,
+ @Nullable NetworkProvider provider) {
this(looper, context, logTag, nc, lp, score, config,
provider == null ? NetworkProvider.ID_NONE : provider.getProviderId(),
getLegacyNetworkInfo(config), false /* legacy */);
@@ -334,12 +338,12 @@
public final Context context;
public final NetworkCapabilities capabilities;
public final LinkProperties properties;
- public final int score;
+ public final NetworkScore score;
public final NetworkAgentConfig config;
public final NetworkInfo info;
InitialConfiguration(@NonNull Context context, @NonNull NetworkCapabilities capabilities,
- @NonNull LinkProperties properties, int score, @NonNull NetworkAgentConfig config,
- @NonNull NetworkInfo info) {
+ @NonNull LinkProperties properties, @NonNull NetworkScore score,
+ @NonNull NetworkAgentConfig config, @NonNull NetworkInfo info) {
this.context = context;
this.capabilities = capabilities;
this.properties = properties;
@@ -351,7 +355,7 @@
private volatile InitialConfiguration mInitialConfiguration;
private NetworkAgent(@NonNull Looper looper, @NonNull Context context, @NonNull String logTag,
- @NonNull NetworkCapabilities nc, @NonNull LinkProperties lp, int score,
+ @NonNull NetworkCapabilities nc, @NonNull LinkProperties lp, NetworkScore score,
@NonNull NetworkAgentConfig config, int providerId, @NonNull NetworkInfo ni,
boolean legacy) {
mHandler = new NetworkAgentHandler(looper);
@@ -646,22 +650,8 @@
* Must be called by the agent to update the score of this network.
* @param score the new score.
*/
- public void sendNetworkScore(int score) {
- if (score < 0) {
- throw new IllegalArgumentException("Score must be >= 0");
- }
- final NetworkScore ns = new NetworkScore();
- ns.putIntExtension(NetworkScore.LEGACY_SCORE, score);
- updateScore(ns);
- }
-
- /**
- * Must be called by the agent when it has a new {@link NetworkScore} for this network.
- * @param ns the new score.
- * @hide TODO: unhide the NetworkScore class, and rename to sendNetworkScore.
- */
- public void updateScore(@NonNull NetworkScore ns) {
- queueOrSendMessage(EVENT_NETWORK_SCORE_CHANGED, new NetworkScore(ns));
+ public void sendNetworkScore(@NonNull final NetworkScore score) {
+ queueOrSendMessage(EVENT_NETWORK_SCORE_CHANGED, score);
}
/**
diff --git a/core/java/android/net/NetworkScore.aidl b/core/java/android/net/NetworkScore.aidl
new file mode 100644
index 0000000..be9a98b
--- /dev/null
+++ b/core/java/android/net/NetworkScore.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2020, 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.net;
+
+parcelable NetworkScore;
diff --git a/core/java/android/net/NetworkScore.java b/core/java/android/net/NetworkScore.java
index 13f2994..ae17378 100644
--- a/core/java/android/net/NetworkScore.java
+++ b/core/java/android/net/NetworkScore.java
@@ -15,12 +15,18 @@
*/
package android.net;
+import android.annotation.IntDef;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.Objects;
/**
@@ -28,57 +34,392 @@
*
* A NetworkScore object represents the characteristics of a network that affects how good the
* network is considered for a particular use.
+ *
+ * This class is not thread-safe.
* @hide
*/
+@TestApi
+@SystemApi
public final class NetworkScore implements Parcelable {
+ /** An object containing scoring-relevant metrics for a network. */
+ public static class Metrics {
+ /** Value meaning the latency is unknown. */
+ public static final int LATENCY_UNKNOWN = -1;
- // The key of bundle which is used to get the legacy network score of NetworkAgentInfo.
- // TODO: Remove this when the transition to NetworkScore is over.
- public static final String LEGACY_SCORE = "LEGACY_SCORE";
+ /** Value meaning the bandwidth is unknown. */
+ public static final int BANDWIDTH_UNKNOWN = -1;
+
+ /**
+ * Round-trip delay in milliseconds to the relevant destination for this Metrics object.
+ *
+ * LATENCY_UNKNOWN if unknown.
+ */
+ @IntRange(from = LATENCY_UNKNOWN)
+ public final int latencyMs;
+
+ /**
+ * Downlink in kB/s with the relevant destination for this Metrics object.
+ *
+ * BANDWIDTH_UNKNOWN if unknown. If directional bandwidth is unknown, up and downlink
+ * bandwidth can have the same value.
+ */
+ @IntRange(from = BANDWIDTH_UNKNOWN)
+ public final int downlinkBandwidthKBps;
+
+ /**
+ * Uplink in kB/s with the relevant destination for this Metrics object.
+ *
+ * BANDWIDTH_UNKNOWN if unknown. If directional bandwidth is unknown, up and downlink
+ * bandwidth can have the same value.
+ */
+ @IntRange(from = BANDWIDTH_UNKNOWN)
+ public final int uplinkBandwidthKBps;
+
+ /** Constructor */
+ public Metrics(@IntRange(from = LATENCY_UNKNOWN) final int latency,
+ @IntRange(from = BANDWIDTH_UNKNOWN) final int downlinkBandwidth,
+ @IntRange(from = BANDWIDTH_UNKNOWN) final int uplinkBandwidth) {
+ latencyMs = latency;
+ downlinkBandwidthKBps = downlinkBandwidth;
+ uplinkBandwidthKBps = uplinkBandwidth;
+ }
+
+ /** toString */
+ public String toString() {
+ return "latency = " + latencyMs + " downlinkBandwidth = " + downlinkBandwidthKBps
+ + "uplinkBandwidth = " + uplinkBandwidthKBps;
+ }
+
+ @NonNull
+ public static final Metrics EMPTY =
+ new Metrics(LATENCY_UNKNOWN, BANDWIDTH_UNKNOWN, BANDWIDTH_UNKNOWN);
+ }
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, prefix = "POLICY_", value = {
+ POLICY_LOCKDOWN_VPN,
+ POLICY_VPN,
+ POLICY_IGNORE_ON_WIFI,
+ POLICY_DEFAULT_SUBSCRIPTION
+ })
+ public @interface Policy {
+ }
+
+ /**
+ * This network is a VPN with lockdown enabled.
+ *
+ * If a network with this bit is present in the list of candidates and not connected,
+ * no network can satisfy the request.
+ */
+ public static final int POLICY_LOCKDOWN_VPN = 1 << 0;
+
+ /**
+ * This network is a VPN.
+ *
+ * If a network with this bit is present and the request UID is included in the UID ranges
+ * of this network, it outscores all other networks without this bit.
+ */
+ public static final int POLICY_VPN = 1 << 1;
+
+ /**
+ * This network should not be used if a previously validated WiFi network is available.
+ *
+ * If a network with this bit is present and a previously validated WiFi is present too, the
+ * network with this bit is outscored by it. This stays true if the WiFi network
+ * becomes unvalidated : this network will not be considered.
+ */
+ public static final int POLICY_IGNORE_ON_WIFI = 1 << 2;
+
+ /**
+ * This network is the default subscription for this transport.
+ *
+ * If a network with this bit is present, other networks of the same transport without this
+ * bit are outscored by it. A device with two active subscriptions and a setting
+ * to decide the default one would have this policy bit on the network for the default
+ * subscription so that when both are active at the same time, the device chooses the
+ * network associated with the default subscription rather than the one with the best link
+ * quality (which will happen if policy doesn't dictate otherwise).
+ */
+ public static final int POLICY_DEFAULT_SUBSCRIPTION = 1 << 3;
+
+ /**
+ * Policy bits for this network. Filled in by the NetworkAgent.
+ */
+ private final int mPolicy;
+
+ /**
+ * Predicted metrics to the gateway (it contains latency and bandwidth to the gateway).
+ * This is filled by the NetworkAgent with the theoretical values of the link if available,
+ * although they may fill it with predictions from historical data if available.
+ * Note that while this member cannot be null, any and all of its members can be unknown.
+ */
@NonNull
- private final Bundle mExtensions;
+ private final Metrics mLinkLayerMetrics;
- public NetworkScore() {
- mExtensions = new Bundle();
- }
+ /**
+ * Predicted metrics to representative servers.
+ * This is filled by connectivity with (if available) a best-effort estimate of the performance
+ * information to servers the user connects to in similar circumstances, and predicted from
+ * actual measurements if possible.
+ * Note that while this member cannot be null, any and all of its members can be unknown.
+ */
+ @NonNull
+ private final Metrics mEndToEndMetrics;
- public NetworkScore(@NonNull NetworkScore source) {
- mExtensions = new Bundle(source.mExtensions);
+ /** Value meaning the signal strength is unknown. */
+ public static final int UNKNOWN_SIGNAL_STRENGTH = -1;
+
+ /** The smallest meaningful signal strength. */
+ public static final int MIN_SIGNAL_STRENGTH = 0;
+
+ /** The largest meaningful signal strength. */
+ public static final int MAX_SIGNAL_STRENGTH = 1000;
+
+ /**
+ * User-visible measure of the strength of the signal normalized 1~1000.
+ * This represents a measure of the signal strength for this network.
+ * If unknown, this has value UNKNOWN_SIGNAL_STRENGTH.
+ */
+ // A good way to populate this value is to fill it with the number of bars displayed in
+ // the system UI, scaled 0 to 1000. This is what the user sees and it makes sense to them.
+ // Cellular for example could quantize the ASU value (see SignalStrength#getAsuValue) into
+ // this, while WiFi could scale the RSSI (see WifiManager#calculateSignalLevel).
+ @IntRange(from = UNKNOWN_SIGNAL_STRENGTH, to = MAX_SIGNAL_STRENGTH)
+ private final int mSignalStrength;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, prefix = "RANGE_", value = {
+ RANGE_UNKNOWN, RANGE_CLOSE, RANGE_SHORT, RANGE_MEDIUM, RANGE_LONG
+ })
+ public @interface Range {
}
/**
- * Put the value of parcelable inside the bundle by key.
+ * The range of this network is not known.
+ * This can be used by VPN the range of which depends on the range of the underlying network.
*/
- public void putExtension(@Nullable String key, @Nullable Parcelable value) {
- mExtensions.putParcelable(key, value);
+ public static final int RANGE_UNKNOWN = 0;
+
+ /**
+ * This network typically only operates at close range, like an NFC beacon.
+ */
+ public static final int RANGE_CLOSE = 1;
+
+ /**
+ * This network typically operates at a range of a few meters to a few dozen meters, like WiFi.
+ */
+ public static final int RANGE_SHORT = 2;
+
+ /**
+ * This network typically operates at a range of a few dozen to a few hundred meters, like CBRS.
+ */
+ public static final int RANGE_MEDIUM = 3;
+
+ /**
+ * This network typically offers continuous connectivity up to many kilometers away, like LTE.
+ */
+ public static final int RANGE_LONG = 4;
+
+ /**
+ * The typical range of this networking technology.
+ *
+ * This is one of the RANGE_* constants and is filled by the NetworkAgent.
+ * This may be useful when evaluating how desirable a network is, because for two networks that
+ * have equivalent performance and cost, the one that won't lose IP continuity when the user
+ * moves is probably preferable.
+ * Agents should fill this with the largest typical range this technology provides. See the
+ * descriptions of the individual constants for guidance.
+ *
+ * If unknown, this is set to RANGE_UNKNOWN.
+ */
+ @Range private final int mRange;
+
+ /**
+ * A prediction of whether this network is likely to be unusable in a few seconds.
+ *
+ * NetworkAgents set this to true to mean they are aware that usability is limited due to
+ * low signal strength, congestion, or other reasons, and indicates that the system should
+ * only use this network as a last resort. An example would be a WiFi network when the device
+ * is about to move outside of range.
+ *
+ * This is filled by the NetworkAgent. Agents that don't know whether this network is likely
+ * to be unusable soon should set this to false.
+ */
+ private final boolean mExiting;
+
+ /**
+ * The legacy score, as a migration strategy from Q to R.
+ * STOPSHIP : remove this before R ships.
+ */
+ private final int mLegacyScore;
+
+ /**
+ * Create a new NetworkScore object.
+ */
+ private NetworkScore(@Policy final int policy, @Nullable final Metrics l2Perf,
+ @Nullable final Metrics e2ePerf,
+ @IntRange(from = UNKNOWN_SIGNAL_STRENGTH, to = MAX_SIGNAL_STRENGTH)
+ final int signalStrength,
+ @Range final int range, final boolean exiting, final int legacyScore) {
+ mPolicy = policy;
+ mLinkLayerMetrics = null != l2Perf ? l2Perf : Metrics.EMPTY;
+ mEndToEndMetrics = null != e2ePerf ? e2ePerf : Metrics.EMPTY;
+ mSignalStrength = signalStrength;
+ mRange = range;
+ mExiting = exiting;
+ mLegacyScore = legacyScore;
}
/**
- * Put the value of int inside the bundle by key.
+ * Utility function to return a copy of this with a different exiting value.
*/
- public void putIntExtension(@Nullable String key, int value) {
- mExtensions.putInt(key, value);
+ @NonNull public NetworkScore withExiting(final boolean exiting) {
+ return new NetworkScore(mPolicy, mLinkLayerMetrics, mEndToEndMetrics,
+ mSignalStrength, mRange, exiting, mLegacyScore);
}
/**
- * Get the value of non primitive type by key.
+ * Utility function to return a copy of this with a different signal strength.
*/
- public <T extends Parcelable> T getExtension(@Nullable String key) {
- return mExtensions.getParcelable(key);
+ @NonNull public NetworkScore withSignalStrength(
+ @IntRange(from = UNKNOWN_SIGNAL_STRENGTH) final int signalStrength) {
+ return new NetworkScore(mPolicy, mLinkLayerMetrics, mEndToEndMetrics,
+ signalStrength, mRange, mExiting, mLegacyScore);
}
/**
- * Get the value of int by key.
+ * Returns whether this network has a particular policy flag.
+ * @param policy the policy, as one of the POLICY_* constants.
*/
- public int getIntExtension(@Nullable String key) {
- return mExtensions.getInt(key);
+ public boolean hasPolicy(@Policy final int policy) {
+ return 0 != (mPolicy & policy);
}
/**
- * Remove the entry by given key.
+ * Returns the Metrics representing the performance of the link layer.
+ *
+ * This contains the theoretical performance of the link, if available.
+ * Note that while this function cannot return null, any and/or all of the members of the
+ * returned object can be null if unknown.
*/
- public void removeExtension(@Nullable String key) {
- mExtensions.remove(key);
+ @NonNull public Metrics getLinkLayerMetrics() {
+ return mLinkLayerMetrics;
+ }
+
+ /**
+ * Returns the Metrics representing the end-to-end performance of the network.
+ *
+ * This contains the end-to-end performance of the link, if available.
+ * Note that while this function cannot return null, any and/or all of the members of the
+ * returned object can be null if unknown.
+ */
+ @NonNull public Metrics getEndToEndMetrics() {
+ return mEndToEndMetrics;
+ }
+
+ /**
+ * Returns the signal strength of this network normalized 0~1000, or UNKNOWN_SIGNAL_STRENGTH.
+ */
+ @IntRange(from = UNKNOWN_SIGNAL_STRENGTH, to = MAX_SIGNAL_STRENGTH)
+ public int getSignalStrength() {
+ return mSignalStrength;
+ }
+
+ /**
+ * Returns the typical range of this network technology as one of the RANGE_* constants.
+ */
+ @Range public int getRange() {
+ return mRange;
+ }
+
+ /** Returns a prediction of whether this network is likely to be unusable in a few seconds. */
+ public boolean isExiting() {
+ return mExiting;
+ }
+
+ /**
+ * Get the legacy score.
+ * @hide
+ */
+ public int getLegacyScore() {
+ return mLegacyScore;
+ }
+
+ /** Builder for NetworkScore. */
+ public static class Builder {
+ private int mPolicy = 0;
+ @NonNull
+ private Metrics mLinkLayerMetrics = new Metrics(Metrics.LATENCY_UNKNOWN,
+ Metrics.BANDWIDTH_UNKNOWN, Metrics.BANDWIDTH_UNKNOWN);
+ @NonNull
+ private Metrics mEndToMetrics = new Metrics(Metrics.LATENCY_UNKNOWN,
+ Metrics.BANDWIDTH_UNKNOWN, Metrics.BANDWIDTH_UNKNOWN);
+ private int mSignalStrength = UNKNOWN_SIGNAL_STRENGTH;
+ private int mRange = RANGE_UNKNOWN;
+ private boolean mExiting = false;
+ private int mLegacyScore = 0;
+ @NonNull private Bundle mExtensions = new Bundle();
+
+ /** Create a new builder. */
+ public Builder() { }
+
+ /** Add a policy flag. */
+ @NonNull public Builder addPolicy(@Policy final int policy) {
+ mPolicy |= policy;
+ return this;
+ }
+
+ /** Clear a policy flag */
+ @NonNull public Builder clearPolicy(@Policy final int policy) {
+ mPolicy &= ~policy;
+ return this;
+ }
+
+ /** Set the link layer metrics. */
+ @NonNull public Builder setLinkLayerMetrics(@NonNull final Metrics linkLayerMetrics) {
+ mLinkLayerMetrics = linkLayerMetrics;
+ return this;
+ }
+
+ /** Set the end-to-end metrics. */
+ @NonNull public Builder setEndToEndMetrics(@NonNull final Metrics endToEndMetrics) {
+ mEndToMetrics = endToEndMetrics;
+ return this;
+ }
+
+ /** Set the signal strength. */
+ @NonNull public Builder setSignalStrength(
+ @IntRange(from = UNKNOWN_SIGNAL_STRENGTH, to = MAX_SIGNAL_STRENGTH)
+ final int signalStrength) {
+ mSignalStrength = signalStrength;
+ return this;
+ }
+
+ /** Set the range. */
+ @NonNull public Builder setRange(@Range final int range) {
+ mRange = range;
+ return this;
+ }
+
+ /** Set whether this network is exiting. */
+ @NonNull public Builder setExiting(final boolean exiting) {
+ mExiting = exiting;
+ return this;
+ }
+
+ /** Add a parcelable extension. */
+ @NonNull public Builder setLegacyScore(final int legacyScore) {
+ mLegacyScore = legacyScore;
+ return this;
+ }
+
+ /** Build the NetworkScore object represented by this builder. */
+ @NonNull public NetworkScore build() {
+ return new NetworkScore(mPolicy, mLinkLayerMetrics, mEndToMetrics,
+ mSignalStrength, mRange, mExiting, mLegacyScore);
+ }
}
@Override
@@ -88,9 +429,17 @@
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
- synchronized (this) {
- dest.writeBundle(mExtensions);
- }
+ dest.writeInt(mPolicy);
+ dest.writeInt(mLinkLayerMetrics.latencyMs);
+ dest.writeInt(mLinkLayerMetrics.downlinkBandwidthKBps);
+ dest.writeInt(mLinkLayerMetrics.uplinkBandwidthKBps);
+ dest.writeInt(mEndToEndMetrics.latencyMs);
+ dest.writeInt(mEndToEndMetrics.downlinkBandwidthKBps);
+ dest.writeInt(mEndToEndMetrics.uplinkBandwidthKBps);
+ dest.writeInt(mSignalStrength);
+ dest.writeInt(mRange);
+ dest.writeBoolean(mExiting);
+ dest.writeInt(mLegacyScore);
}
public static final @NonNull Creator<NetworkScore> CREATOR = new Creator<NetworkScore>() {
@@ -106,57 +455,52 @@
};
private NetworkScore(@NonNull Parcel in) {
- mExtensions = in.readBundle();
+ mPolicy = in.readInt();
+ mLinkLayerMetrics = new Metrics(in.readInt(), in.readInt(), in.readInt());
+ mEndToEndMetrics = new Metrics(in.readInt(), in.readInt(), in.readInt());
+ mSignalStrength = in.readInt();
+ mRange = in.readInt();
+ mExiting = in.readBoolean();
+ mLegacyScore = in.readInt();
}
- // TODO: Modify this method once new fields are added into this class.
@Override
public boolean equals(@Nullable Object obj) {
if (!(obj instanceof NetworkScore)) {
return false;
}
final NetworkScore other = (NetworkScore) obj;
- return bundlesEqual(mExtensions, other.mExtensions);
+ return mPolicy == other.mPolicy
+ && mLinkLayerMetrics.latencyMs == other.mLinkLayerMetrics.latencyMs
+ && mLinkLayerMetrics.uplinkBandwidthKBps
+ == other.mLinkLayerMetrics.uplinkBandwidthKBps
+ && mEndToEndMetrics.latencyMs == other.mEndToEndMetrics.latencyMs
+ && mEndToEndMetrics.uplinkBandwidthKBps
+ == other.mEndToEndMetrics.uplinkBandwidthKBps
+ && mSignalStrength == other.mSignalStrength
+ && mRange == other.mRange
+ && mExiting == other.mExiting
+ && mLegacyScore == other.mLegacyScore;
}
@Override
public int hashCode() {
- int result = 29;
- for (String key : mExtensions.keySet()) {
- final Object value = mExtensions.get(key);
- // The key may be null, so call Objects.hash() is safer.
- result += 31 * value.hashCode() + 37 * Objects.hash(key);
- }
- return result;
- }
-
- // mExtensions won't be null since the constructor will create it.
- private boolean bundlesEqual(@NonNull Bundle bundle1, @NonNull Bundle bundle2) {
- if (bundle1 == bundle2) {
- return true;
- }
-
- // This is unlikely but it's fine to add this clause here.
- if (null == bundle1 || null == bundle2) {
- return false;
- }
-
- if (bundle1.size() != bundle2.size()) {
- return false;
- }
-
- for (String key : bundle1.keySet()) {
- final Object value1 = bundle1.get(key);
- final Object value2 = bundle2.get(key);
- if (!Objects.equals(value1, value2)) {
- return false;
- }
- }
- return true;
+ return Objects.hash(mPolicy,
+ mLinkLayerMetrics.latencyMs, mLinkLayerMetrics.uplinkBandwidthKBps,
+ mEndToEndMetrics.latencyMs, mEndToEndMetrics.uplinkBandwidthKBps,
+ mSignalStrength, mRange, mExiting, mLegacyScore);
}
/** Convert to a string */
public String toString() {
- return "NetworkScore[" + mExtensions.toString() + "]";
+ return "NetworkScore ["
+ + "Policy = " + mPolicy
+ + " LinkLayerMetrics = " + mLinkLayerMetrics
+ + " EndToEndMetrics = " + mEndToEndMetrics
+ + " SignalStrength = " + mSignalStrength
+ + " Range = " + mRange
+ + " Exiting = " + mExiting
+ + " LegacyScore = " + mLegacyScore
+ + "]";
}
}
diff --git a/core/java/android/os/VibrationAttributes.java b/core/java/android/os/VibrationAttributes.java
index 3e16640..27782fa 100644
--- a/core/java/android/os/VibrationAttributes.java
+++ b/core/java/android/os/VibrationAttributes.java
@@ -391,11 +391,23 @@
* Replaces flags
* @param flags any combination of flags.
* @return the same Builder instance.
+ * @hide
*/
public @NonNull Builder replaceFlags(int flags) {
mFlags = flags;
return this;
}
+
+ /**
+ * Set flags
+ * @param flags combination of flags to be set.
+ * @param mask Bit range that should be changed.
+ * @return the same Builder instance.
+ */
+ public @NonNull Builder setFlags(int flags, int mask) {
+ mFlags = (mFlags & ~mask) | (flags & mask);
+ return this;
+ }
}
}
diff --git a/core/java/android/telephony/PhoneStateListener.java b/core/java/android/telephony/PhoneStateListener.java
index 023f000..531ade0 100644
--- a/core/java/android/telephony/PhoneStateListener.java
+++ b/core/java/android/telephony/PhoneStateListener.java
@@ -168,9 +168,11 @@
public static final int LISTEN_SIGNAL_STRENGTHS = 0x00000100;
/**
- * Listen for always reported changes of the network signal strengths (cellular),
+ * Listen for changes of the network signal strengths (cellular) always reported from modem,
* even in some situations such as the screen of the device is off.
*
+ * @see #onSignalStrengthsChanged
+ *
* @hide
*/
@RequiresPermission(android.Manifest.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH)
diff --git a/core/java/android/timezone/CountryTimeZones.java b/core/java/android/timezone/CountryTimeZones.java
index e5bbdf4..5875761 100644
--- a/core/java/android/timezone/CountryTimeZones.java
+++ b/core/java/android/timezone/CountryTimeZones.java
@@ -56,7 +56,7 @@
*/
@NonNull
public String getTimeZoneId() {
- return mDelegate.timeZoneId;
+ return mDelegate.getTimeZoneId();
}
/**
@@ -187,7 +187,7 @@
* would be a good choice <em>generally</em> when there's no other information available.
*/
public boolean isDefaultTimeZoneBoosted() {
- return mDelegate.getDefaultTimeZoneBoost();
+ return mDelegate.isDefaultTimeZoneBoosted();
}
/**
@@ -220,7 +220,8 @@
mDelegate.lookupByOffsetWithBias(
totalOffsetMillis, isDst, dstOffsetMillis, whenMillis, bias);
return delegateOffsetResult == null ? null :
- new OffsetResult(delegateOffsetResult.mTimeZone, delegateOffsetResult.mOneMatch);
+ new OffsetResult(
+ delegateOffsetResult.getTimeZone(), delegateOffsetResult.isOnlyMatch());
}
/**
diff --git a/core/java/android/timezone/TzDataSetVersion.java b/core/java/android/timezone/TzDataSetVersion.java
index 605155e..efe50a0 100644
--- a/core/java/android/timezone/TzDataSetVersion.java
+++ b/core/java/android/timezone/TzDataSetVersion.java
@@ -111,23 +111,23 @@
/** Returns the major version number. See {@link TzDataSetVersion}. */
public int getFormatMajorVersion() {
- return mDelegate.formatMajorVersion;
+ return mDelegate.getFormatMajorVersion();
}
/** Returns the minor version number. See {@link TzDataSetVersion}. */
public int getFormatMinorVersion() {
- return mDelegate.formatMinorVersion;
+ return mDelegate.getFormatMinorVersion();
}
/** Returns the tzdb version string. See {@link TzDataSetVersion}. */
@NonNull
public String getRulesVersion() {
- return mDelegate.rulesVersion;
+ return mDelegate.getRulesVersion();
}
/** Returns the Android revision. See {@link TzDataSetVersion}. */
public int getRevision() {
- return mDelegate.revision;
+ return mDelegate.getRevision();
}
@Override
diff --git a/core/java/android/util/TimeUtils.java b/core/java/android/util/TimeUtils.java
index c325874..36f4e53 100644
--- a/core/java/android/util/TimeUtils.java
+++ b/core/java/android/util/TimeUtils.java
@@ -81,7 +81,7 @@
}
CountryTimeZones.OffsetResult offsetResult = countryTimeZones.lookupByOffsetWithBias(
offsetMillis, isDst, null /* dstOffsetMillis */, whenMillis, bias);
- return offsetResult != null ? offsetResult.mTimeZone : null;
+ return offsetResult != null ? offsetResult.getTimeZone() : null;
}
/**
@@ -109,8 +109,8 @@
List<String> timeZoneIds = new ArrayList<>();
for (TimeZoneMapping timeZoneMapping : countryTimeZones.getTimeZoneMappings()) {
- if (timeZoneMapping.showInPicker) {
- timeZoneIds.add(timeZoneMapping.timeZoneId);
+ if (timeZoneMapping.isShownInPicker()) {
+ timeZoneIds.add(timeZoneMapping.getTimeZoneId());
}
}
return Collections.unmodifiableList(timeZoneIds);
diff --git a/core/java/android/view/ITaskOrganizer.aidl b/core/java/android/view/ITaskOrganizer.aidl
index e92aafe..5ccdd30 100644
--- a/core/java/android/view/ITaskOrganizer.aidl
+++ b/core/java/android/view/ITaskOrganizer.aidl
@@ -26,8 +26,7 @@
* {@hide}
*/
oneway interface ITaskOrganizer {
- void taskAppeared(in IWindowContainer container,
- in ActivityManager.RunningTaskInfo taskInfo);
+ void taskAppeared(in ActivityManager.RunningTaskInfo taskInfo);
void taskVanished(in IWindowContainer container);
/**
@@ -35,4 +34,19 @@
* ActivityTaskManagerService#applyTaskOrganizerTransaction
*/
void transactionReady(int id, in SurfaceControl.Transaction t);
+
+ /**
+ * Will fire when core attributes of a Task's info change. Relevant properties include the
+ * {@link WindowConfiguration.ActivityType} and whether it is resizable.
+ *
+ * This is used, for example, during split-screen. The flow for starting is: Something sends an
+ * Intent with windowingmode. Then WM finds a matching root task and launches the new task into
+ * it. This causes the root task's info to change because now it has a task when it didn't
+ * before. The default Divider implementation interprets this as a request to enter
+ * split-screen mode and will move all other Tasks into the secondary root task. When WM
+ * applies this change, it triggers an info change in the secondary root task because it now
+ * has children. The Divider impl looks at the info and can see that the secondary root task
+ * has adopted an ActivityType of HOME and proceeds to show the minimized dock UX.
+ */
+ void onTaskInfoChanged(in ActivityManager.RunningTaskInfo info);
}
\ No newline at end of file
diff --git a/core/java/android/view/InsetsSource.java b/core/java/android/view/InsetsSource.java
index 37034ee..77bc25b 100644
--- a/core/java/android/view/InsetsSource.java
+++ b/core/java/android/view/InsetsSource.java
@@ -53,6 +53,9 @@
mType = other.mType;
mFrame = new Rect(other.mFrame);
mVisible = other.mVisible;
+ mVisibleFrame = other.mVisibleFrame != null
+ ? new Rect(other.mVisibleFrame)
+ : null;
}
public void setFrame(Rect frame) {
@@ -165,6 +168,7 @@
public int hashCode() {
int result = mType;
result = 31 * result + mFrame.hashCode();
+ result = 31 * result + (mVisibleFrame != null ? mVisibleFrame.hashCode() : 0);
result = 31 * result + (mVisible ? 1 : 0);
return result;
}
diff --git a/core/java/android/view/WindowContainerTransaction.java b/core/java/android/view/WindowContainerTransaction.java
index c55caa3..33f21f2 100644
--- a/core/java/android/view/WindowContainerTransaction.java
+++ b/core/java/android/view/WindowContainerTransaction.java
@@ -86,6 +86,17 @@
return this;
}
+ /**
+ * Set the smallestScreenWidth of a container.
+ */
+ public WindowContainerTransaction setSmallestScreenWidthDp(IWindowContainer container,
+ int widthDp) {
+ Change cfg = getOrCreateChange(container.asBinder());
+ cfg.mConfiguration.smallestScreenWidthDp = widthDp;
+ cfg.mConfigSetMask |= ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
+ return this;
+ }
+
public Map<IBinder, Change> getChanges() {
return mChanges;
}
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index f13a638..863e8a2 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -2125,8 +2125,9 @@
return new Pair<>(Insets.NONE, insets);
}
- boolean includeIme = (getAttributes().softInputMode & SOFT_INPUT_MASK_ADJUST)
- == SOFT_INPUT_ADJUST_RESIZE;
+ boolean includeIme =
+ (getViewRootImpl().mWindowAttributes.softInputMode & SOFT_INPUT_MASK_ADJUST)
+ == SOFT_INPUT_ADJUST_RESIZE;
Insets insetsToApply;
if (ViewRootImpl.sNewInsetsMode == 0) {
insetsToApply = insets.getSystemWindowInsets();
diff --git a/core/java/com/android/internal/util/Preconditions.java b/core/java/com/android/internal/util/Preconditions.java
index 408a7a8..a87e080 100644
--- a/core/java/com/android/internal/util/Preconditions.java
+++ b/core/java/com/android/internal/util/Preconditions.java
@@ -21,7 +21,9 @@
import android.compat.annotation.UnsupportedAppUsage;
import android.text.TextUtils;
+import java.util.Arrays;
import java.util.Collection;
+import java.util.Objects;
/**
* Simple static methods to be called at the start of your own methods to verify
@@ -497,6 +499,64 @@
}
/**
+ * Ensures that the given byte array is not {@code null}, and contains at least one element.
+ *
+ * @param value an array of elements.
+ * @param valueName the name of the argument to use if the check fails.
+
+ * @return the validated array
+ *
+ * @throws NullPointerException if the {@code value} was {@code null}
+ * @throws IllegalArgumentException if the {@code value} was empty
+ */
+ @NonNull
+ public static byte[] checkByteArrayNotEmpty(final byte[] value, final String valueName) {
+ if (value == null) {
+ throw new NullPointerException(valueName + " must not be null");
+ }
+ if (value.length == 0) {
+ throw new IllegalArgumentException(valueName + " is empty");
+ }
+ return value;
+ }
+
+ /**
+ * Ensures that argument {@code value} is one of {@code supportedValues}.
+ *
+ * @param supportedValues an array of string values
+ * @param value a string value
+ *
+ * @return the validated value
+ *
+ * @throws NullPointerException if either {@code value} or {@code supportedValues} is null
+ * @throws IllegalArgumentException if the {@code value} is not in {@code supportedValues}
+ */
+ @NonNull
+ public static String checkArgumentIsSupported(final String[] supportedValues,
+ final String value) {
+ checkNotNull(value);
+ checkNotNull(supportedValues);
+
+ if (!contains(supportedValues, value)) {
+ throw new IllegalArgumentException(value + "is not supported "
+ + Arrays.toString(supportedValues));
+ }
+ return value;
+ }
+
+ private static boolean contains(String[] values, String value) {
+ if (values == null) {
+ return false;
+ }
+ for (int i = 0; i < values.length; ++i) {
+ if (Objects.equals(value, values[i])) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
* Ensures that all elements in the argument floating point array are within the inclusive range
*
* <p>While this can be used to range check against +/- infinity, note that all NaN numbers
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index a2f514a..c04efa3 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -147,7 +147,6 @@
"android_service_DataLoaderService.cpp",
"android_util_AssetManager.cpp",
"android_util_Binder.cpp",
- "android_util_StatsLog.cpp",
"android_util_MemoryIntArray.cpp",
"android_util_Process.cpp",
"android_util_StringBlock.cpp",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 9783b65..924cd81 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -108,7 +108,6 @@
extern int register_android_app_admin_SecurityLog(JNIEnv* env);
extern int register_android_content_AssetManager(JNIEnv* env);
extern int register_android_util_EventLog(JNIEnv* env);
-extern int register_android_util_StatsLog(JNIEnv* env);
extern int register_android_util_StatsLogInternal(JNIEnv* env);
extern int register_android_util_Log(JNIEnv* env);
extern int register_android_util_MemoryIntArray(JNIEnv* env);
@@ -622,6 +621,8 @@
char jitprithreadweightOptBuf[sizeof("-Xjitprithreadweight:")-1 + PROPERTY_VALUE_MAX];
char jittransitionweightOptBuf[sizeof("-Xjittransitionweight:")-1 + PROPERTY_VALUE_MAX];
char hotstartupsamplesOptsBuf[sizeof("-Xps-hot-startup-method-samples:")-1 + PROPERTY_VALUE_MAX];
+ char saveResolvedClassesDelayMsOptsBuf[
+ sizeof("-Xps-save-resolved-classes-delay-ms:")-1 + PROPERTY_VALUE_MAX];
char madviseRandomOptsBuf[sizeof("-XX:MadviseRandomAccess:")-1 + PROPERTY_VALUE_MAX];
char gctypeOptsBuf[sizeof("-Xgc:")-1 + PROPERTY_VALUE_MAX];
char backgroundgcOptsBuf[sizeof("-XX:BackgroundGC=")-1 + PROPERTY_VALUE_MAX];
@@ -817,6 +818,9 @@
parseRuntimeOption("dalvik.vm.hot-startup-method-samples", hotstartupsamplesOptsBuf,
"-Xps-hot-startup-method-samples:");
+ parseRuntimeOption("dalvik.vm.ps-resolved-classes-delay-ms", saveResolvedClassesDelayMsOptsBuf,
+ "-Xps-save-resolved-classes-delay-ms:");
+
property_get("ro.config.low_ram", propBuf, "");
if (strcmp(propBuf, "true") == 0) {
addOption("-XX:LowMemoryMode");
@@ -1441,7 +1445,6 @@
REG_JNI(register_android_util_EventLog),
REG_JNI(register_android_util_Log),
REG_JNI(register_android_util_MemoryIntArray),
- REG_JNI(register_android_util_StatsLog),
REG_JNI(register_android_util_StatsLogInternal),
REG_JNI(register_android_app_admin_SecurityLog),
REG_JNI(register_android_content_AssetManager),
diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp
index 1fcc8ac..cfd3c09 100644
--- a/core/jni/fd_utils.cpp
+++ b/core/jni/fd_utils.cpp
@@ -51,6 +51,7 @@
"/dev/socket/webview_zygote",
"/dev/socket/heapprofd",
"/sys/kernel/debug/tracing/trace_marker",
+ "/sys/kernel/tracing/trace_marker",
"/system/framework/framework-res.apk",
"/dev/urandom",
"/dev/ion",
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 181a32d..3a1b63d 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -4858,19 +4858,6 @@
<permission android:name="android.permission.ACCESS_SHARED_LIBRARIES"
android:protectionLevel="signature|installer" />
- <!-- Allows an app to log compat change usage.
- @hide <p>Not for use by third-party applications.</p> -->
- <permission android:name="android.permission.LOG_COMPAT_CHANGE"
- android:protectionLevel="signature" />
- <!-- Allows an app to read compat change config.
- @hide <p>Not for use by third-party applications.</p> -->
- <permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG"
- android:protectionLevel="signature" />
- <!-- Allows an app to override compat change config.
- @hide <p>Not for use by third-party applications.</p> -->
- <permission android:name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG"
- android:protectionLevel="signature" />
-
<!-- Allows input events to be monitored. Very dangerous! @hide -->
<permission android:name="android.permission.MONITOR_INPUT"
android:protectionLevel="signature" />
diff --git a/core/tests/coretests/src/android/os/PowerManagerTest.java b/core/tests/coretests/src/android/os/PowerManagerTest.java
index 5cb7852..ea0a0fd 100644
--- a/core/tests/coretests/src/android/os/PowerManagerTest.java
+++ b/core/tests/coretests/src/android/os/PowerManagerTest.java
@@ -214,6 +214,9 @@
}
// Add listener2 on main thread.
mPm.addThermalStatusListener(mListener2);
+ verify(mListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
+ .times(1)).onThermalStatusChanged(status);
+ reset(mListener2);
status = PowerManager.THERMAL_STATUS_MODERATE;
mUiDevice.executeShellCommand("cmd thermalservice override-status "
+ Integer.toString(status));
diff --git a/core/tests/coretests/src/android/view/InsetsStateTest.java b/core/tests/coretests/src/android/view/InsetsStateTest.java
index 20be8c2..79ac2b7 100644
--- a/core/tests/coretests/src/android/view/InsetsStateTest.java
+++ b/core/tests/coretests/src/android/view/InsetsStateTest.java
@@ -213,6 +213,7 @@
@Test
public void testParcelUnparcel() {
mState.getSource(ITYPE_IME).setFrame(new Rect(0, 0, 100, 100));
+ mState.getSource(ITYPE_IME).setVisibleFrame(new Rect(0, 0, 50, 10));
mState.getSource(ITYPE_IME).setVisible(true);
mState.getSource(ITYPE_STATUS_BAR).setFrame(new Rect(0, 0, 100, 100));
Parcel p = Parcel.obtain();
@@ -224,6 +225,16 @@
}
@Test
+ public void testCopy() {
+ mState.getSource(ITYPE_IME).setFrame(new Rect(0, 0, 100, 100));
+ mState.getSource(ITYPE_IME).setVisibleFrame(new Rect(0, 0, 50, 10));
+ mState.getSource(ITYPE_IME).setVisible(true);
+ mState.getSource(ITYPE_STATUS_BAR).setFrame(new Rect(0, 0, 100, 100));
+ mState2.set(mState, true);
+ assertEquals(mState, mState2);
+ }
+
+ @Test
public void testGetDefaultVisibility() {
assertTrue(InsetsState.getDefaultVisibility(ITYPE_STATUS_BAR));
assertTrue(InsetsState.getDefaultVisibility(ITYPE_NAVIGATION_BAR));
diff --git a/data/etc/car/com.android.car.secondaryhome.xml b/data/etc/car/com.android.car.secondaryhome.xml
new file mode 100644
index 0000000..c74b86e
--- /dev/null
+++ b/data/etc/car/com.android.car.secondaryhome.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 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
+ -->
+<permissions>
+ <privapp-permissions package="com.android.car.secondaryhome">
+ <!-- Required to launch app in ActivityView -->
+ <permission name="android.permission.ACTIVITY_EMBEDDING"/>
+ <!-- Required to send notification to current user-->
+ <permission name="android.permission.MANAGE_USERS"/>
+ </privapp-permissions>
+</permissions>
diff --git a/libs/hwui/pipeline/skia/ATraceMemoryDump.cpp b/libs/hwui/pipeline/skia/ATraceMemoryDump.cpp
index 551bdc6..234f42d 100644
--- a/libs/hwui/pipeline/skia/ATraceMemoryDump.cpp
+++ b/libs/hwui/pipeline/skia/ATraceMemoryDump.cpp
@@ -39,14 +39,13 @@
* ATraceMemoryDump calculates memory category first by looking at the "type" string passed to
* dumpStringValue and then by looking at "backingType" passed to setMemoryBacking.
* Only GPU Texture memory is tracked separately and everything else is grouped as one
- * "GPU Memory" category.
+ * "Misc Memory" category.
*/
static std::unordered_map<const char*, const char*> sResourceMap = {
{"malloc", "HWUI CPU Memory"}, // taken from setMemoryBacking(backingType)
{"gl_texture", "HWUI Texture Memory"}, // taken from setMemoryBacking(backingType)
- {"Texture",
- "HWUI Texture Memory"}, // taken from dumpStringValue(value, valueName="type")
- // Uncomment categories below to split "GPU Memory" into more brackets for debugging.
+ {"Texture", "HWUI Texture Memory"}, // taken from dumpStringValue(value, valueName="type")
+ // Uncomment categories below to split "Misc Memory" into more brackets for debugging.
/*{"vk_buffer", "vk_buffer"},
{"gl_renderbuffer", "gl_renderbuffer"},
{"gl_buffer", "gl_buffer"},
@@ -169,8 +168,8 @@
mLastDumpValue = 0;
mLastPurgeableDumpValue = INVALID_MEMORY_SIZE;
mLastDumpName = dumpName;
- // Categories not listed in sResourceMap are reported as "GPU memory"
- mCategory = "HWUI GPU Memory";
+ // Categories not listed in sResourceMap are reported as "Misc Memory"
+ mCategory = "HWUI Misc Memory";
}
} /* namespace skiapipeline */
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 5993e17..699b96a 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -143,10 +143,11 @@
ATRACE_CALL();
if (surface) {
- mNativeSurface = new ReliableSurface{std::move(surface)};
+ mNativeSurface = std::make_unique<ReliableSurface>(std::move(surface));
+ mNativeSurface->init();
if (enableTimeout) {
// TODO: Fix error handling & re-shorten timeout
- ANativeWindow_setDequeueTimeout(mNativeSurface.get(), 4000_ms);
+ ANativeWindow_setDequeueTimeout(mNativeSurface->getNativeWindow(), 4000_ms);
}
} else {
mNativeSurface = nullptr;
@@ -161,8 +162,9 @@
}
ColorMode colorMode = mWideColorGamut ? ColorMode::WideColorGamut : ColorMode::SRGB;
- bool hasSurface = mRenderPipeline->setSurface(mNativeSurface.get(), mSwapBehavior, colorMode,
- mRenderAheadCapacity);
+ bool hasSurface = mRenderPipeline->setSurface(
+ mNativeSurface ? mNativeSurface->getNativeWindow() : nullptr, mSwapBehavior, colorMode,
+ mRenderAheadCapacity);
mFrameNumber = -1;
@@ -203,7 +205,8 @@
void CanvasContext::allocateBuffers() {
if (mNativeSurface) {
- mNativeSurface->allocateBuffers();
+ ANativeWindow* anw = mNativeSurface->getNativeWindow();
+ ANativeWindow_allocateBuffers(anw);
}
}
@@ -428,7 +431,7 @@
presentTime = mCurrentFrameInfo->get(FrameInfoIndex::Vsync) +
(frameIntervalNanos * (renderAhead + 1));
}
- native_window_set_buffers_timestamp(mNativeSurface.get(), presentTime);
+ native_window_set_buffers_timestamp(mNativeSurface->getNativeWindow(), presentTime);
}
void CanvasContext::draw() {
@@ -489,16 +492,18 @@
swap.swapCompletedTime = systemTime(SYSTEM_TIME_MONOTONIC);
swap.vsyncTime = mRenderThread.timeLord().latestVsync();
if (didDraw) {
- nsecs_t dequeueStart = ANativeWindow_getLastDequeueStartTime(mNativeSurface.get());
+ nsecs_t dequeueStart =
+ ANativeWindow_getLastDequeueStartTime(mNativeSurface->getNativeWindow());
if (dequeueStart < mCurrentFrameInfo->get(FrameInfoIndex::SyncStart)) {
// Ignoring dequeue duration as it happened prior to frame render start
// and thus is not part of the frame.
swap.dequeueDuration = 0;
} else {
swap.dequeueDuration =
- ANativeWindow_getLastDequeueDuration(mNativeSurface.get());
+ ANativeWindow_getLastDequeueDuration(mNativeSurface->getNativeWindow());
}
- swap.queueDuration = ANativeWindow_getLastQueueDuration(mNativeSurface.get());
+ swap.queueDuration =
+ ANativeWindow_getLastQueueDuration(mNativeSurface->getNativeWindow());
} else {
swap.dequeueDuration = 0;
swap.queueDuration = 0;
@@ -567,14 +572,16 @@
}
SkISize CanvasContext::getNextFrameSize() const {
- ReliableSurface* surface = mNativeSurface.get();
- if (surface) {
- SkISize size;
- size.fWidth = ANativeWindow_getWidth(surface);
- size.fHeight = ANativeWindow_getHeight(surface);
- return size;
+ static constexpr SkISize defaultFrameSize = {INT32_MAX, INT32_MAX};
+ if (mNativeSurface == nullptr) {
+ return defaultFrameSize;
}
- return {INT32_MAX, INT32_MAX};
+ ANativeWindow* anw = mNativeSurface->getNativeWindow();
+
+ SkISize size;
+ size.fWidth = ANativeWindow_getWidth(anw);
+ size.fHeight = ANativeWindow_getHeight(anw);
+ return size;
}
void CanvasContext::prepareAndDraw(RenderNode* node) {
@@ -702,11 +709,9 @@
if (!mNativeSurface) return false;
if (mHaveNewSurface) return true;
- int width = -1;
- int height = -1;
- ReliableSurface* surface = mNativeSurface.get();
- surface->query(NATIVE_WINDOW_WIDTH, &width);
- surface->query(NATIVE_WINDOW_HEIGHT, &height);
+ ANativeWindow* anw = mNativeSurface->getNativeWindow();
+ const int width = ANativeWindow_getWidth(anw);
+ const int height = ANativeWindow_getHeight(anw);
return width != mLastFrameWidth || height != mLastFrameHeight;
}
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 4490f80..0967b20 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -220,7 +220,7 @@
int32_t mLastFrameHeight = 0;
RenderThread& mRenderThread;
- sp<ReliableSurface> mNativeSurface;
+ std::unique_ptr<ReliableSurface> mNativeSurface;
// stopped indicates the CanvasContext will reject actual redraw operations,
// and defer repaint until it is un-stopped
bool mStopped = false;
diff --git a/libs/hwui/renderthread/ReliableSurface.cpp b/libs/hwui/renderthread/ReliableSurface.cpp
index 864780f..e92500f 100644
--- a/libs/hwui/renderthread/ReliableSurface.cpp
+++ b/libs/hwui/renderthread/ReliableSurface.cpp
@@ -26,64 +26,38 @@
// to propagate this error back to the caller
constexpr bool DISABLE_BUFFER_PREFETCH = true;
-// TODO: Make surface less protected
-// This exists because perform is a varargs, and ANativeWindow has no va_list perform.
-// So wrapping/chaining that is hard. Telling the compiler to ignore protected is easy, so we do
-// that instead
-struct SurfaceExposer : Surface {
- // Make warnings happy
- SurfaceExposer() = delete;
-
- using Surface::cancelBuffer;
- using Surface::dequeueBuffer;
- using Surface::lockBuffer_DEPRECATED;
- using Surface::perform;
- using Surface::queueBuffer;
- using Surface::setBufferCount;
- using Surface::setSwapInterval;
-};
-
-#define callProtected(surface, func, ...) ((*surface).*&SurfaceExposer::func)(__VA_ARGS__)
-
ReliableSurface::ReliableSurface(sp<Surface>&& surface) : mSurface(std::move(surface)) {
LOG_ALWAYS_FATAL_IF(!mSurface, "Error, unable to wrap a nullptr");
-
- ANativeWindow::setSwapInterval = hook_setSwapInterval;
- ANativeWindow::dequeueBuffer = hook_dequeueBuffer;
- ANativeWindow::cancelBuffer = hook_cancelBuffer;
- ANativeWindow::queueBuffer = hook_queueBuffer;
- ANativeWindow::query = hook_query;
- ANativeWindow::perform = hook_perform;
-
- ANativeWindow::dequeueBuffer_DEPRECATED = hook_dequeueBuffer_DEPRECATED;
- ANativeWindow::cancelBuffer_DEPRECATED = hook_cancelBuffer_DEPRECATED;
- ANativeWindow::lockBuffer_DEPRECATED = hook_lockBuffer_DEPRECATED;
- ANativeWindow::queueBuffer_DEPRECATED = hook_queueBuffer_DEPRECATED;
}
ReliableSurface::~ReliableSurface() {
clearReservedBuffer();
+ // Clear out the interceptors for proper hygiene.
+ // As a concrete example, if the underlying ANativeWindow is associated with
+ // an EGLSurface that is still in use, then if we don't clear out the
+ // interceptors then we walk into undefined behavior.
+ ANativeWindow_setCancelBufferInterceptor(mSurface.get(), nullptr, nullptr);
+ ANativeWindow_setDequeueBufferInterceptor(mSurface.get(), nullptr, nullptr);
+ ANativeWindow_setQueueBufferInterceptor(mSurface.get(), nullptr, nullptr);
+ ANativeWindow_setPerformInterceptor(mSurface.get(), nullptr, nullptr);
}
-void ReliableSurface::perform(int operation, va_list args) {
- std::lock_guard _lock{mMutex};
+void ReliableSurface::init() {
+ int result = ANativeWindow_setCancelBufferInterceptor(mSurface.get(), hook_cancelBuffer, this);
+ LOG_ALWAYS_FATAL_IF(result != NO_ERROR, "Failed to set cancelBuffer interceptor: error = %d",
+ result);
- switch (operation) {
- case NATIVE_WINDOW_SET_USAGE:
- mUsage = va_arg(args, uint32_t);
- break;
- case NATIVE_WINDOW_SET_USAGE64:
- mUsage = va_arg(args, uint64_t);
- break;
- case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY:
- /* width */ va_arg(args, uint32_t);
- /* height */ va_arg(args, uint32_t);
- mFormat = va_arg(args, PixelFormat);
- break;
- case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
- mFormat = va_arg(args, PixelFormat);
- break;
- }
+ result = ANativeWindow_setDequeueBufferInterceptor(mSurface.get(), hook_dequeueBuffer, this);
+ LOG_ALWAYS_FATAL_IF(result != NO_ERROR, "Failed to set dequeueBuffer interceptor: error = %d",
+ result);
+
+ result = ANativeWindow_setQueueBufferInterceptor(mSurface.get(), hook_queueBuffer, this);
+ LOG_ALWAYS_FATAL_IF(result != NO_ERROR, "Failed to set queueBuffer interceptor: error = %d",
+ result);
+
+ result = ANativeWindow_setPerformInterceptor(mSurface.get(), hook_perform, this);
+ LOG_ALWAYS_FATAL_IF(result != NO_ERROR, "Failed to set perform interceptor: error = %d",
+ result);
}
int ReliableSurface::reserveNext() {
@@ -111,7 +85,9 @@
int fenceFd = -1;
ANativeWindowBuffer* buffer = nullptr;
- int result = callProtected(mSurface, dequeueBuffer, &buffer, &fenceFd);
+
+ // Note that this calls back into our own hooked method.
+ int result = ANativeWindow_dequeueBuffer(mSurface.get(), &buffer, &fenceFd);
{
std::lock_guard _lock{mMutex};
@@ -138,61 +114,13 @@
mHasDequeuedBuffer = false;
}
if (buffer) {
- callProtected(mSurface, cancelBuffer, buffer, releaseFd);
+ // Note that clearReservedBuffer may be reentrant here, so
+ // mReservedBuffer must be cleared once we reach here to avoid recursing
+ // forever.
+ ANativeWindow_cancelBuffer(mSurface.get(), buffer, releaseFd);
}
}
-int ReliableSurface::cancelBuffer(ANativeWindowBuffer* buffer, int fenceFd) {
- clearReservedBuffer();
- if (isFallbackBuffer(buffer)) {
- if (fenceFd > 0) {
- close(fenceFd);
- }
- return OK;
- }
- int result = callProtected(mSurface, cancelBuffer, buffer, fenceFd);
- return result;
-}
-
-int ReliableSurface::dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd) {
- {
- std::lock_guard _lock{mMutex};
- if (mReservedBuffer) {
- *buffer = mReservedBuffer;
- *fenceFd = mReservedFenceFd.release();
- mReservedBuffer = nullptr;
- return OK;
- }
- }
-
-
- int result = callProtected(mSurface, dequeueBuffer, buffer, fenceFd);
- if (result != OK) {
- ALOGW("dequeueBuffer failed, error = %d; switching to fallback", result);
- *buffer = acquireFallbackBuffer(result);
- *fenceFd = -1;
- return *buffer ? OK : INVALID_OPERATION;
- } else {
- std::lock_guard _lock{mMutex};
- mHasDequeuedBuffer = true;
- }
- return OK;
-}
-
-int ReliableSurface::queueBuffer(ANativeWindowBuffer* buffer, int fenceFd) {
- clearReservedBuffer();
-
- if (isFallbackBuffer(buffer)) {
- if (fenceFd > 0) {
- close(fenceFd);
- }
- return OK;
- }
-
- int result = callProtected(mSurface, queueBuffer, buffer, fenceFd);
- return result;
-}
-
bool ReliableSurface::isFallbackBuffer(const ANativeWindowBuffer* windowBuffer) const {
if (!mScratchBuffer || !windowBuffer) {
return false;
@@ -229,82 +157,95 @@
return AHardwareBuffer_to_ANativeWindowBuffer(newBuffer);
}
-Surface* ReliableSurface::getWrapped(const ANativeWindow* window) {
- return getSelf(window)->mSurface.get();
-}
+int ReliableSurface::hook_dequeueBuffer(ANativeWindow* window,
+ ANativeWindow_dequeueBufferFn dequeueBuffer, void* data,
+ ANativeWindowBuffer** buffer, int* fenceFd) {
+ ReliableSurface* rs = reinterpret_cast<ReliableSurface*>(data);
+ {
+ std::lock_guard _lock{rs->mMutex};
+ if (rs->mReservedBuffer) {
+ *buffer = rs->mReservedBuffer;
+ *fenceFd = rs->mReservedFenceFd.release();
+ rs->mReservedBuffer = nullptr;
+ return OK;
+ }
+ }
-int ReliableSurface::hook_setSwapInterval(ANativeWindow* window, int interval) {
- return callProtected(getWrapped(window), setSwapInterval, interval);
-}
-
-int ReliableSurface::hook_dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer,
- int* fenceFd) {
- return getSelf(window)->dequeueBuffer(buffer, fenceFd);
-}
-
-int ReliableSurface::hook_cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer,
- int fenceFd) {
- return getSelf(window)->cancelBuffer(buffer, fenceFd);
-}
-
-int ReliableSurface::hook_queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer,
- int fenceFd) {
- return getSelf(window)->queueBuffer(buffer, fenceFd);
-}
-
-int ReliableSurface::hook_dequeueBuffer_DEPRECATED(ANativeWindow* window,
- ANativeWindowBuffer** buffer) {
- ANativeWindowBuffer* buf;
- int fenceFd = -1;
- int result = window->dequeueBuffer(window, &buf, &fenceFd);
+ int result = dequeueBuffer(window, buffer, fenceFd);
if (result != OK) {
- return result;
+ ALOGW("dequeueBuffer failed, error = %d; switching to fallback", result);
+ *buffer = rs->acquireFallbackBuffer(result);
+ *fenceFd = -1;
+ return *buffer ? OK : INVALID_OPERATION;
+ } else {
+ std::lock_guard _lock{rs->mMutex};
+ rs->mHasDequeuedBuffer = true;
}
- sp<Fence> fence(new Fence(fenceFd));
- int waitResult = fence->waitForever("dequeueBuffer_DEPRECATED");
- if (waitResult != OK) {
- ALOGE("dequeueBuffer_DEPRECATED: Fence::wait returned an error: %d", waitResult);
- window->cancelBuffer(window, buf, -1);
- return waitResult;
- }
- *buffer = buf;
- return result;
-}
-
-int ReliableSurface::hook_cancelBuffer_DEPRECATED(ANativeWindow* window,
- ANativeWindowBuffer* buffer) {
- return window->cancelBuffer(window, buffer, -1);
-}
-
-int ReliableSurface::hook_lockBuffer_DEPRECATED(ANativeWindow* window,
- ANativeWindowBuffer* buffer) {
- // This method is a no-op in Surface as well
return OK;
}
-int ReliableSurface::hook_queueBuffer_DEPRECATED(ANativeWindow* window,
- ANativeWindowBuffer* buffer) {
- return window->queueBuffer(window, buffer, -1);
+int ReliableSurface::hook_cancelBuffer(ANativeWindow* window,
+ ANativeWindow_cancelBufferFn cancelBuffer, void* data,
+ ANativeWindowBuffer* buffer, int fenceFd) {
+ ReliableSurface* rs = reinterpret_cast<ReliableSurface*>(data);
+ rs->clearReservedBuffer();
+ if (rs->isFallbackBuffer(buffer)) {
+ if (fenceFd > 0) {
+ close(fenceFd);
+ }
+ return OK;
+ }
+ return cancelBuffer(window, buffer, fenceFd);
}
-int ReliableSurface::hook_query(const ANativeWindow* window, int what, int* value) {
- return getWrapped(window)->query(what, value);
+int ReliableSurface::hook_queueBuffer(ANativeWindow* window,
+ ANativeWindow_queueBufferFn queueBuffer, void* data,
+ ANativeWindowBuffer* buffer, int fenceFd) {
+ ReliableSurface* rs = reinterpret_cast<ReliableSurface*>(data);
+ rs->clearReservedBuffer();
+
+ if (rs->isFallbackBuffer(buffer)) {
+ if (fenceFd > 0) {
+ close(fenceFd);
+ }
+ return OK;
+ }
+
+ return queueBuffer(window, buffer, fenceFd);
}
-int ReliableSurface::hook_perform(ANativeWindow* window, int operation, ...) {
+int ReliableSurface::hook_perform(ANativeWindow* window, ANativeWindow_performFn perform,
+ void* data, int operation, va_list args) {
// Drop the reserved buffer if there is one since this (probably) mutated buffer dimensions
// TODO: Filter to things that only affect the reserved buffer
// TODO: Can we mutate the reserved buffer in some cases?
- getSelf(window)->clearReservedBuffer();
- va_list args;
- va_start(args, operation);
- int result = callProtected(getWrapped(window), perform, operation, args);
- va_end(args);
+ ReliableSurface* rs = reinterpret_cast<ReliableSurface*>(data);
+ rs->clearReservedBuffer();
- va_start(args, operation);
- getSelf(window)->perform(operation, args);
- va_end(args);
+ va_list argsCopy;
+ va_copy(argsCopy, args);
+ int result = perform(window, operation, argsCopy);
+ {
+ std::lock_guard _lock{rs->mMutex};
+
+ switch (operation) {
+ case ANATIVEWINDOW_PERFORM_SET_USAGE:
+ rs->mUsage = va_arg(args, uint32_t);
+ break;
+ case ANATIVEWINDOW_PERFORM_SET_USAGE64:
+ rs->mUsage = va_arg(args, uint64_t);
+ break;
+ case ANATIVEWINDOW_PERFORM_SET_BUFFERS_GEOMETRY:
+ /* width */ va_arg(args, uint32_t);
+ /* height */ va_arg(args, uint32_t);
+ rs->mFormat = va_arg(args, PixelFormat);
+ break;
+ case ANATIVEWINDOW_PERFORM_SET_BUFFERS_FORMAT:
+ rs->mFormat = va_arg(args, PixelFormat);
+ break;
+ }
+ }
return result;
}
diff --git a/libs/hwui/renderthread/ReliableSurface.h b/libs/hwui/renderthread/ReliableSurface.h
index f768df3..3247253 100644
--- a/libs/hwui/renderthread/ReliableSurface.h
+++ b/libs/hwui/renderthread/ReliableSurface.h
@@ -16,6 +16,7 @@
#pragma once
+#include <apex/window.h>
#include <gui/Surface.h>
#include <utils/Macros.h>
#include <utils/StrongPointer.h>
@@ -24,16 +25,21 @@
namespace android::uirenderer::renderthread {
-class ReliableSurface : public ANativeObjectBase<ANativeWindow, ReliableSurface, RefBase> {
+class ReliableSurface {
PREVENT_COPY_AND_ASSIGN(ReliableSurface);
public:
ReliableSurface(sp<Surface>&& surface);
~ReliableSurface();
- int reserveNext();
+ // Performs initialization that is not safe to do in the constructor.
+ // For instance, registering ANativeWindow interceptors with ReliableSurface
+ // passed as the data pointer is not safe.
+ void init();
- void allocateBuffers() { mSurface->allocateBuffers(); }
+ ANativeWindow* getNativeWindow() { return mSurface.get(); }
+
+ int reserveNext();
int query(int what, int* value) const { return mSurface->query(what, value); }
@@ -61,7 +67,7 @@
}
private:
- const sp<Surface> mSurface;
+ sp<Surface> mSurface;
mutable std::mutex mMutex;
@@ -78,27 +84,20 @@
ANativeWindowBuffer* acquireFallbackBuffer(int error);
void clearReservedBuffer();
- void perform(int operation, va_list args);
- int cancelBuffer(ANativeWindowBuffer* buffer, int fenceFd);
- int dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd);
- int queueBuffer(ANativeWindowBuffer* buffer, int fenceFd);
+ // ANativeWindow hooks. When an ANativeWindow_* method is called on the
+ // underlying ANativeWindow, these methods will intercept the original call.
+ // For example, an EGL driver would call into these hooks instead of the
+ // original methods.
+ static int hook_cancelBuffer(ANativeWindow* window, ANativeWindow_cancelBufferFn cancelBuffer,
+ void* data, ANativeWindowBuffer* buffer, int fenceFd);
+ static int hook_dequeueBuffer(ANativeWindow* window,
+ ANativeWindow_dequeueBufferFn dequeueBuffer, void* data,
+ ANativeWindowBuffer** buffer, int* fenceFd);
+ static int hook_queueBuffer(ANativeWindow* window, ANativeWindow_queueBufferFn queueBuffer,
+ void* data, ANativeWindowBuffer* buffer, int fenceFd);
- static Surface* getWrapped(const ANativeWindow*);
-
- // ANativeWindow hooks
- static int hook_cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd);
- static int hook_dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer,
- int* fenceFd);
- static int hook_queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd);
-
- static int hook_perform(ANativeWindow* window, int operation, ...);
- static int hook_query(const ANativeWindow* window, int what, int* value);
- static int hook_setSwapInterval(ANativeWindow* window, int interval);
-
- static int hook_cancelBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer* buffer);
- static int hook_dequeueBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer** buffer);
- static int hook_lockBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer* buffer);
- static int hook_queueBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer* buffer);
+ static int hook_perform(ANativeWindow* window, ANativeWindow_performFn perform, void* data,
+ int operation, va_list args);
};
}; // namespace android::uirenderer::renderthread
diff --git a/media/java/android/media/MediaRoute2Info.java b/media/java/android/media/MediaRoute2Info.java
index dd01243..dace091 100644
--- a/media/java/android/media/MediaRoute2Info.java
+++ b/media/java/android/media/MediaRoute2Info.java
@@ -21,6 +21,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.TestApi;
import android.net.Uri;
import android.os.Bundle;
import android.os.Parcel;
@@ -360,6 +361,7 @@
* @hide
*/
@NonNull
+ @TestApi
public String getOriginalId() {
return mId;
}
diff --git a/media/java/android/media/audiopolicy/AudioVolumeGroupChangeHandler.java b/media/java/android/media/audiopolicy/AudioVolumeGroupChangeHandler.java
index 074188e..adf4d3d 100644
--- a/media/java/android/media/audiopolicy/AudioVolumeGroupChangeHandler.java
+++ b/media/java/android/media/audiopolicy/AudioVolumeGroupChangeHandler.java
@@ -157,9 +157,7 @@
Handler handler = eventHandler.handler();
if (handler != null) {
Message m = handler.obtainMessage(what, arg1, arg2, obj);
- if (what != AUDIOVOLUMEGROUP_EVENT_NEW_LISTENER) {
- handler.removeMessages(what);
- }
+ // Do not remove previous messages, as we would lose notification of group changes
handler.sendMessage(m);
}
}
diff --git a/native/android/Android.bp b/native/android/Android.bp
index 0c6f507..34ab7a0 100644
--- a/native/android/Android.bp
+++ b/native/android/Android.bp
@@ -64,6 +64,7 @@
"libgui",
"libharfbuzz_ng", // Only for including hb.h via minikin
"libsensor",
+ "libstats_jni",
"libandroid_runtime",
"libminikin",
"libnetd_client",
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index 97b861b..a8f1d2c 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -23,6 +23,8 @@
AChoreographer_postFrameCallbackDelayed; # introduced=24
AChoreographer_postFrameCallback64; # introduced=29
AChoreographer_postFrameCallbackDelayed64; # introduced=29
+ AChoreographer_registerRefreshRateCallback; # introduced=30
+ AChoreographer_unregisterRefreshRateCallback; # introduced=30
AConfiguration_copy;
AConfiguration_delete;
AConfiguration_diff;
diff --git a/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java b/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java
index aac7fc3..d48aa24 100644
--- a/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java
+++ b/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java
@@ -402,7 +402,7 @@
private static List<String> extractTimeZoneIds(List<TimeZoneMapping> timeZoneMappings) {
final List<String> zoneIds = new ArrayList<>(timeZoneMappings.size());
for (TimeZoneMapping timeZoneMapping : timeZoneMappings) {
- zoneIds.add(timeZoneMapping.timeZoneId);
+ zoneIds.add(timeZoneMapping.getTimeZoneId());
}
return Collections.unmodifiableList(zoneIds);
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index 84dde05..44e70f4 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -654,7 +654,7 @@
}
}
}
- return oldMetering == mIsScoredNetworkMetered;
+ return oldMetering != mIsScoredNetworkMetered;
}
/**
@@ -1170,8 +1170,8 @@
} else { // In range, not disabled.
if (mConfig != null) { // Is saved network
// Last attempt to connect to this failed. Show reason why
- switch (mConfig.recentFailure.getAssociationStatus()) {
- case WifiConfiguration.RecentFailure.STATUS_AP_UNABLE_TO_HANDLE_NEW_STA:
+ switch (mConfig.getRecentFailureReason()) {
+ case WifiConfiguration.RECENT_FAILURE_AP_UNABLE_TO_HANDLE_NEW_STA:
summary.append(mContext.getString(
R.string.wifi_ap_unable_to_handle_new_sta));
break;
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
index db18213a..9934e59 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
@@ -41,13 +41,13 @@
import android.util.Base64;
import android.util.Slog;
import android.util.SparseIntArray;
-import android.util.StatsLog;
import android.util.TimeUtils;
import android.util.Xml;
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.FrameworkStatsLog;
import libcore.io.IoUtils;
@@ -429,8 +429,9 @@
mSettings.put(name, newState);
}
- StatsLog.write(StatsLog.SETTING_CHANGED, name, value, newState.value, oldValue, tag,
- makeDefault, getUserIdFromKey(mKey), StatsLog.SETTING_CHANGED__REASON__UPDATED);
+ FrameworkStatsLog.write(FrameworkStatsLog.SETTING_CHANGED, name, value, newState.value,
+ oldValue, tag, makeDefault, getUserIdFromKey(mKey),
+ FrameworkStatsLog.SETTING_CHANGED__REASON__UPDATED);
addHistoricalOperationLocked(HISTORICAL_OPERATION_UPDATE, newState);
@@ -489,9 +490,9 @@
if (key.startsWith(prefix) && !keyValues.containsKey(key)) {
Setting oldState = mSettings.remove(key);
- StatsLog.write(StatsLog.SETTING_CHANGED, key, /* value= */ "", /* newValue= */ "",
- oldState.value, /* tag */ "", false, getUserIdFromKey(mKey),
- StatsLog.SETTING_CHANGED__REASON__DELETED);
+ FrameworkStatsLog.write(FrameworkStatsLog.SETTING_CHANGED, key,
+ /* value= */ "", /* newValue= */ "", oldState.value, /* tag */ "", false,
+ getUserIdFromKey(mKey), FrameworkStatsLog.SETTING_CHANGED__REASON__DELETED);
addHistoricalOperationLocked(HISTORICAL_OPERATION_DELETE, oldState);
changedKeys.add(key); // key was removed
}
@@ -516,9 +517,9 @@
continue;
}
- StatsLog.write(StatsLog.SETTING_CHANGED, key, value, state.value, oldValue,
- /* tag */ null, /* make default */ false,
- getUserIdFromKey(mKey), StatsLog.SETTING_CHANGED__REASON__UPDATED);
+ FrameworkStatsLog.write(FrameworkStatsLog.SETTING_CHANGED, key, value, state.value,
+ oldValue, /* tag */ null, /* make default */ false,
+ getUserIdFromKey(mKey), FrameworkStatsLog.SETTING_CHANGED__REASON__UPDATED);
addHistoricalOperationLocked(HISTORICAL_OPERATION_UPDATE, state);
}
@@ -544,9 +545,9 @@
Setting oldState = mSettings.remove(name);
- StatsLog.write(StatsLog.SETTING_CHANGED, name, /* value= */ "", /* newValue= */ "",
- oldState.value, /* tag */ "", false, getUserIdFromKey(mKey),
- StatsLog.SETTING_CHANGED__REASON__DELETED);
+ FrameworkStatsLog.write(FrameworkStatsLog.SETTING_CHANGED, name, /* value= */ "",
+ /* newValue= */ "", oldState.value, /* tag */ "", false, getUserIdFromKey(mKey),
+ FrameworkStatsLog.SETTING_CHANGED__REASON__DELETED);
updateMemoryUsagePerPackageLocked(oldState.packageName, oldState.value,
null, oldState.defaultValue, null);
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 7d2b85d..84d9bb6 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -219,6 +219,9 @@
<!-- Permission required for CTS test - CrossProfileAppsHostSideTest -->
<uses-permission android:name="android.permission.INTERACT_ACROSS_PROFILES"/>
+ <!-- permissions required for CTS test - PhoneStateListenerTest -->
+ <uses-permission android:name="android.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH" />
+
<!-- Permission required for CTS test - UiModeManagerTest -->
<uses-permission android:name="android.permission.ENTER_CAR_MODE_PRIORITIZED"/>
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
index dd1856a..c9c38d3 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
@@ -30,17 +30,17 @@
import android.widget.TextView;
import com.android.internal.R;
-import com.android.internal.colorextraction.ColorExtractor.GradientColors;
import com.android.internal.colorextraction.drawable.ScrimDrawable;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.settingslib.Utils;
import com.android.systemui.Dependency;
-import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.plugins.GlobalActions;
import com.android.systemui.plugins.GlobalActionsPanelPlugin;
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.shared.plugins.PluginManager;
+import com.android.systemui.statusbar.BlurUtils;
import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.ExtensionController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -59,6 +59,7 @@
private final KeyguardStateController mKeyguardStateController;
private final DeviceProvisionedController mDeviceProvisionedController;
private final ExtensionController.Extension<GlobalActionsPanelPlugin> mPanelExtension;
+ private final BlurUtils mBlurUtils;
private GlobalActionsPanelPlugin mPlugin;
private final CommandQueue mCommandQueue;
private GlobalActionsDialog mGlobalActionsDialog;
@@ -68,13 +69,14 @@
@Inject
public GlobalActionsImpl(Context context, CommandQueue commandQueue,
- Lazy<GlobalActionsDialog> globalActionsDialogLazy) {
+ Lazy<GlobalActionsDialog> globalActionsDialogLazy, BlurUtils blurUtils) {
mContext = context;
mGlobalActionsDialogLazy = globalActionsDialogLazy;
mKeyguardStateController = Dependency.get(KeyguardStateController.class);
mDeviceProvisionedController = Dependency.get(DeviceProvisionedController.class);
mPluginManager = Dependency.get(PluginManager.class);
mCommandQueue = commandQueue;
+ mBlurUtils = blurUtils;
mCommandQueue.addCallback(this);
mPanelExtension = Dependency.get(ExtensionController.class)
.newExtension(GlobalActionsPanelPlugin.class)
@@ -110,7 +112,6 @@
@Override
public void showShutdownUi(boolean isReboot, String reason) {
ScrimDrawable background = new ScrimDrawable();
- background.setAlpha((int) (SHUTDOWN_SCRIM_ALPHA * 255));
Dialog d = new Dialog(mContext,
com.android.systemui.R.style.Theme_SystemUI_Dialog_GlobalActions);
@@ -160,8 +161,13 @@
reasonView.setText(rebootReasonMessage);
}
- GradientColors colors = Dependency.get(SysuiColorExtractor.class).getNeutralColors();
- background.setColor(colors.getMainColor(), false);
+ if (mBlurUtils.supportsBlursOnWindows()) {
+ background.setAlpha((int) (ScrimController.GRADIENT_SCRIM_ALPHA_BUSY * 255));
+ mBlurUtils.applyBlur(d.getWindow().getDecorView().getViewRootImpl(),
+ mBlurUtils.radiusForRatio(1));
+ } else {
+ background.setAlpha((int) (SHUTDOWN_SCRIM_ALPHA * 255));
+ }
d.show();
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
index e6082dd..e7e1ba8 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
@@ -106,7 +106,7 @@
// Initialize screenshot notification smart actions provider.
mSmartActionsEnabled = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI,
- SystemUiDeviceConfigFlags.ENABLE_SCREENSHOT_NOTIFICATION_SMART_ACTIONS, false);
+ SystemUiDeviceConfigFlags.ENABLE_SCREENSHOT_NOTIFICATION_SMART_ACTIONS, true);
if (mSmartActionsEnabled) {
mSmartActionsProvider =
SystemUIFactory.getInstance()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
index 5cfb4b3..333b4a7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -274,7 +274,7 @@
@Test
public void testRemoveBubble_withDismissedNotif() {
- mEntryListener.onNotificationAdded(mRow.getEntry());
+ mEntryListener.onPendingEntryAdded(mRow.getEntry());
mBubbleController.updateBubble(mRow.getEntry());
assertTrue(mBubbleController.hasBubbles());
@@ -317,7 +317,7 @@
assertFalse(mBubbleController.isStackExpanded());
// Mark it as a bubble and add it explicitly
- mEntryListener.onNotificationAdded(mRow.getEntry());
+ mEntryListener.onPendingEntryAdded(mRow.getEntry());
mBubbleController.updateBubble(mRow.getEntry());
// We should have bubbles & their notifs should not be suppressed
@@ -347,8 +347,8 @@
@Test
public void testCollapseAfterChangingExpandedBubble() {
// Mark it as a bubble and add it explicitly
- mEntryListener.onNotificationAdded(mRow.getEntry());
- mEntryListener.onNotificationAdded(mRow2.getEntry());
+ mEntryListener.onPendingEntryAdded(mRow.getEntry());
+ mEntryListener.onPendingEntryAdded(mRow2.getEntry());
mBubbleController.updateBubble(mRow.getEntry());
mBubbleController.updateBubble(mRow2.getEntry());
@@ -390,7 +390,7 @@
@Test
public void testExpansionRemovesShowInShadeAndDot() {
// Mark it as a bubble and add it explicitly
- mEntryListener.onNotificationAdded(mRow.getEntry());
+ mEntryListener.onPendingEntryAdded(mRow.getEntry());
mBubbleController.updateBubble(mRow.getEntry());
// We should have bubbles & their notifs should not be suppressed
@@ -416,7 +416,7 @@
@Test
public void testUpdateWhileExpanded_DoesntChangeShowInShadeAndDot() {
// Mark it as a bubble and add it explicitly
- mEntryListener.onNotificationAdded(mRow.getEntry());
+ mEntryListener.onPendingEntryAdded(mRow.getEntry());
mBubbleController.updateBubble(mRow.getEntry());
// We should have bubbles & their notifs should not be suppressed
@@ -452,8 +452,8 @@
@Test
public void testRemoveLastExpandedCollapses() {
// Mark it as a bubble and add it explicitly
- mEntryListener.onNotificationAdded(mRow.getEntry());
- mEntryListener.onNotificationAdded(mRow2.getEntry());
+ mEntryListener.onPendingEntryAdded(mRow.getEntry());
+ mEntryListener.onPendingEntryAdded(mRow2.getEntry());
mBubbleController.updateBubble(mRow.getEntry());
mBubbleController.updateBubble(mRow2.getEntry());
verify(mBubbleStateChangeListener).onHasBubblesChanged(true);
@@ -496,7 +496,7 @@
Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE, false /* enableFlag */);
// Add the auto expand bubble
- mEntryListener.onNotificationAdded(mRow.getEntry());
+ mEntryListener.onPendingEntryAdded(mRow.getEntry());
mBubbleController.updateBubble(mRow.getEntry());
// Expansion shouldn't change
@@ -514,7 +514,7 @@
Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE, true /* enableFlag */);
// Add the auto expand bubble
- mEntryListener.onNotificationAdded(mRow.getEntry());
+ mEntryListener.onPendingEntryAdded(mRow.getEntry());
mBubbleController.updateBubble(mRow.getEntry());
// Expansion should change
@@ -532,7 +532,7 @@
Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION, true /* enableFlag */);
// Add the suppress notif bubble
- mEntryListener.onNotificationAdded(mRow.getEntry());
+ mEntryListener.onPendingEntryAdded(mRow.getEntry());
mBubbleController.updateBubble(mRow.getEntry());
// Notif should be suppressed because we were foreground
@@ -576,7 +576,7 @@
public void testExpandStackAndSelectBubble_removedFirst() {
final String key = mRow.getEntry().getKey();
- mEntryListener.onNotificationAdded(mRow.getEntry());
+ mEntryListener.onPendingEntryAdded(mRow.getEntry());
mBubbleController.updateBubble(mRow.getEntry());
// Simulate notification cancellation.
@@ -588,7 +588,7 @@
@Test
public void testMarkNewNotificationAsShowInShade() {
- mEntryListener.onNotificationAdded(mRow.getEntry());
+ mEntryListener.onPendingEntryAdded(mRow.getEntry());
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
mRow.getEntry()));
@@ -598,7 +598,7 @@
@Test
public void testAddNotif_notBubble() {
- mEntryListener.onNotificationAdded(mNonBubbleNotifRow.getEntry());
+ mEntryListener.onPendingEntryAdded(mNonBubbleNotifRow.getEntry());
mEntryListener.onPreEntryUpdated(mNonBubbleNotifRow.getEntry());
verify(mBubbleStateChangeListener, never()).onHasBubblesChanged(anyBoolean());
@@ -643,7 +643,7 @@
@Test
public void testRemoveBubble_succeeds_appCancel() {
- mEntryListener.onNotificationAdded(mRow.getEntry());
+ mEntryListener.onPendingEntryAdded(mRow.getEntry());
mBubbleController.updateBubble(mRow.getEntry());
assertTrue(mBubbleController.hasBubbles());
@@ -658,7 +658,7 @@
@Test
public void removeBubble_fails_clearAll() {
- mEntryListener.onNotificationAdded(mRow.getEntry());
+ mEntryListener.onPendingEntryAdded(mRow.getEntry());
mBubbleController.updateBubble(mRow.getEntry());
assertTrue(mBubbleController.hasBubbles());
@@ -681,7 +681,7 @@
@Test
public void removeBubble_fails_userDismissNotif() {
- mEntryListener.onNotificationAdded(mRow.getEntry());
+ mEntryListener.onPendingEntryAdded(mRow.getEntry());
mBubbleController.updateBubble(mRow.getEntry());
assertTrue(mBubbleController.hasBubbles());
@@ -704,7 +704,7 @@
@Test
public void removeBubble_succeeds_userDismissBubble_userDimissNotif() {
- mEntryListener.onNotificationAdded(mRow.getEntry());
+ mEntryListener.onPendingEntryAdded(mRow.getEntry());
mBubbleController.updateBubble(mRow.getEntry());
assertTrue(mBubbleController.hasBubbles());
@@ -730,7 +730,7 @@
mock(BubbleController.NotificationSuppressionChangedListener.class);
mBubbleData.setSuppressionChangedListener(listener);
- mEntryListener.onNotificationAdded(mRow.getEntry());
+ mEntryListener.onPendingEntryAdded(mRow.getEntry());
assertTrue(mBubbleController.hasBubbles());
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
@@ -753,7 +753,7 @@
mock(BubbleController.NotificationSuppressionChangedListener.class);
mBubbleData.setSuppressionChangedListener(listener);
- mEntryListener.onNotificationAdded(mRow.getEntry());
+ mEntryListener.onPendingEntryAdded(mRow.getEntry());
assertTrue(mBubbleController.hasBubbles());
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
diff --git a/packages/Tethering/common/TetheringLib/jarjar-rules.txt b/packages/Tethering/common/TetheringLib/jarjar-rules.txt
index 35e0f88..1403bba 100644
--- a/packages/Tethering/common/TetheringLib/jarjar-rules.txt
+++ b/packages/Tethering/common/TetheringLib/jarjar-rules.txt
@@ -1 +1,2 @@
rule android.annotation.** com.android.networkstack.tethering.annotation.@1
+rule com.android.internal.annotations.** com.android.networkstack.tethering.annotation.@1
\ No newline at end of file
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
index 37ce1d57..53a358f 100644
--- a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
+++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
@@ -30,6 +30,9 @@
import android.util.ArrayMap;
import android.util.Log;
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
@@ -37,6 +40,7 @@
import java.util.List;
import java.util.Objects;
import java.util.concurrent.Executor;
+import java.util.function.Supplier;
/**
* This class provides the APIs to control the tethering service.
@@ -50,17 +54,23 @@
public class TetheringManager {
private static final String TAG = TetheringManager.class.getSimpleName();
private static final int DEFAULT_TIMEOUT_MS = 60_000;
+ private static final long CONNECTOR_POLL_INTERVAL_MILLIS = 200L;
- private static TetheringManager sInstance;
+ @GuardedBy("mConnectorWaitQueue")
+ @Nullable
+ private ITetheringConnector mConnector;
+ @GuardedBy("mConnectorWaitQueue")
+ @NonNull
+ private final List<ConnectorConsumer> mConnectorWaitQueue = new ArrayList<>();
+ private final Supplier<IBinder> mConnectorSupplier;
- private final ITetheringConnector mConnector;
private final TetheringCallbackInternal mCallback;
private final Context mContext;
private final ArrayMap<TetheringEventCallback, ITetheringEventCallback>
mTetheringEventCallbacks = new ArrayMap<>();
- private TetheringConfigurationParcel mTetheringConfiguration;
- private TetherStatesParcel mTetherStatesParcel;
+ private volatile TetheringConfigurationParcel mTetheringConfiguration;
+ private volatile TetherStatesParcel mTetherStatesParcel;
/**
* Broadcast Action: A tetherable connection has come or gone.
@@ -162,29 +172,139 @@
/**
* Create a TetheringManager object for interacting with the tethering service.
*
+ * @param context Context for the manager.
+ * @param connectorSupplier Supplier for the manager connector; may return null while the
+ * service is not connected.
* {@hide}
*/
- public TetheringManager(@NonNull final Context context, @NonNull final IBinder service) {
+ public TetheringManager(@NonNull final Context context,
+ @NonNull Supplier<IBinder> connectorSupplier) {
mContext = context;
- mConnector = ITetheringConnector.Stub.asInterface(service);
mCallback = new TetheringCallbackInternal();
+ mConnectorSupplier = connectorSupplier;
final String pkgName = mContext.getOpPackageName();
+
+ final IBinder connector = mConnectorSupplier.get();
+ // If the connector is available on start, do not start a polling thread. This introduces
+ // differences in the thread that sends the oneway binder calls to the service between the
+ // first few seconds after boot and later, but it avoids always having differences between
+ // the first usage of TetheringManager from a process and subsequent usages (so the
+ // difference is only on boot). On boot binder calls may be queued until the service comes
+ // up and be sent from a worker thread; later, they are always sent from the caller thread.
+ // Considering that it's just oneway binder calls, and ordering is preserved, this seems
+ // better than inconsistent behavior persisting after boot.
+ if (connector != null) {
+ mConnector = ITetheringConnector.Stub.asInterface(connector);
+ } else {
+ startPollingForConnector();
+ }
+
Log.i(TAG, "registerTetheringEventCallback:" + pkgName);
+ getConnector(c -> c.registerTetheringEventCallback(mCallback, pkgName));
+ }
+
+ private void startPollingForConnector() {
+ new Thread(() -> {
+ while (true) {
+ try {
+ Thread.sleep(200);
+ } catch (InterruptedException e) {
+ // Not much to do here, the system needs to wait for the connector
+ }
+
+ final IBinder connector = mConnectorSupplier.get();
+ if (connector != null) {
+ onTetheringConnected(ITetheringConnector.Stub.asInterface(connector));
+ return;
+ }
+ }
+ }).start();
+ }
+
+ private interface ConnectorConsumer {
+ void onConnectorAvailable(ITetheringConnector connector) throws RemoteException;
+ }
+
+ private void onTetheringConnected(ITetheringConnector connector) {
+ // Process the connector wait queue in order, including any items that are added
+ // while processing.
+ //
+ // 1. Copy the queue to a local variable under lock.
+ // 2. Drain the local queue with the lock released (otherwise, enqueuing future commands
+ // would block on the lock).
+ // 3. Acquire the lock again. If any new tasks were queued during step 2, goto 1.
+ // If not, set mConnector to non-null so future tasks are run immediately, not queued.
+ //
+ // For this to work, all calls to the tethering service must use getConnector(), which
+ // ensures that tasks are added to the queue with the lock held.
+ //
+ // Once mConnector is set to non-null, it will never be null again. If the network stack
+ // process crashes, no recovery is possible.
+ // TODO: evaluate whether it is possible to recover from network stack process crashes
+ // (though in most cases the system will have crashed when the network stack process
+ // crashes).
+ do {
+ final List<ConnectorConsumer> localWaitQueue;
+ synchronized (mConnectorWaitQueue) {
+ localWaitQueue = new ArrayList<>(mConnectorWaitQueue);
+ mConnectorWaitQueue.clear();
+ }
+
+ // Allow more tasks to be added at the end without blocking while draining the queue.
+ for (ConnectorConsumer task : localWaitQueue) {
+ try {
+ task.onConnectorAvailable(connector);
+ } catch (RemoteException e) {
+ // Most likely the network stack process crashed, which is likely to crash the
+ // system. Keep processing other requests but report the error loudly.
+ Log.wtf(TAG, "Error processing request for the tethering connector", e);
+ }
+ }
+
+ synchronized (mConnectorWaitQueue) {
+ if (mConnectorWaitQueue.size() == 0) {
+ mConnector = connector;
+ return;
+ }
+ }
+ } while (true);
+ }
+
+ /**
+ * Asynchronously get the ITetheringConnector to execute some operation.
+ *
+ * <p>If the connector is already available, the operation will be executed on the caller's
+ * thread. Otherwise it will be queued and executed on a worker thread. The operation should be
+ * limited to performing oneway binder calls to minimize differences due to threading.
+ */
+ private void getConnector(ConnectorConsumer consumer) {
+ final ITetheringConnector connector;
+ synchronized (mConnectorWaitQueue) {
+ connector = mConnector;
+ if (connector == null) {
+ mConnectorWaitQueue.add(consumer);
+ return;
+ }
+ }
+
try {
- mConnector.registerTetheringEventCallback(mCallback, pkgName);
+ consumer.onConnectorAvailable(connector);
} catch (RemoteException e) {
throw new IllegalStateException(e);
}
}
private interface RequestHelper {
- void runRequest(IIntResultListener listener);
+ void runRequest(ITetheringConnector connector, IIntResultListener listener);
}
+ // Used to dispatch legacy ConnectivityManager methods that expect tethering to be able to
+ // return results and perform operations synchronously.
+ // TODO: remove once there are no callers of these legacy methods.
private class RequestDispatcher {
private final ConditionVariable mWaiting;
- public int mRemoteResult;
+ public volatile int mRemoteResult;
private final IIntResultListener mListener = new IIntResultListener.Stub() {
@Override
@@ -199,7 +319,7 @@
}
int waitForResult(final RequestHelper request) {
- request.runRequest(mListener);
+ getConnector(c -> request.runRequest(c, mListener));
if (!mWaiting.block(DEFAULT_TIMEOUT_MS)) {
throw new IllegalStateException("Callback timeout");
}
@@ -222,7 +342,7 @@
}
private class TetheringCallbackInternal extends ITetheringEventCallback.Stub {
- private int mError = TETHER_ERROR_NO_ERROR;
+ private volatile int mError = TETHER_ERROR_NO_ERROR;
private final ConditionVariable mWaitForCallback = new ConditionVariable();
@Override
@@ -280,9 +400,9 @@
Log.i(TAG, "tether caller:" + callerPkg);
final RequestDispatcher dispatcher = new RequestDispatcher();
- return dispatcher.waitForResult(listener -> {
+ return dispatcher.waitForResult((connector, listener) -> {
try {
- mConnector.tether(iface, callerPkg, listener);
+ connector.tether(iface, callerPkg, listener);
} catch (RemoteException e) {
throw new IllegalStateException(e);
}
@@ -304,9 +424,9 @@
final RequestDispatcher dispatcher = new RequestDispatcher();
- return dispatcher.waitForResult(listener -> {
+ return dispatcher.waitForResult((connector, listener) -> {
try {
- mConnector.untether(iface, callerPkg, listener);
+ connector.untether(iface, callerPkg, listener);
} catch (RemoteException e) {
throw new IllegalStateException(e);
}
@@ -330,9 +450,9 @@
final RequestDispatcher dispatcher = new RequestDispatcher();
- return dispatcher.waitForResult(listener -> {
+ return dispatcher.waitForResult((connector, listener) -> {
try {
- mConnector.setUsbTethering(enable, callerPkg, listener);
+ connector.setUsbTethering(enable, callerPkg, listener);
} catch (RemoteException e) {
throw new IllegalStateException(e);
}
@@ -467,11 +587,7 @@
});
}
};
- try {
- mConnector.startTethering(request.getParcel(), callerPkg, listener);
- } catch (RemoteException e) {
- throw new IllegalStateException(e);
- }
+ getConnector(c -> c.startTethering(request.getParcel(), callerPkg, listener));
}
/**
@@ -509,15 +625,15 @@
final String callerPkg = mContext.getOpPackageName();
Log.i(TAG, "stopTethering caller:" + callerPkg);
- final RequestDispatcher dispatcher = new RequestDispatcher();
-
- dispatcher.waitForResult(listener -> {
- try {
- mConnector.stopTethering(type, callerPkg, listener);
- } catch (RemoteException e) {
- throw new IllegalStateException(e);
+ getConnector(c -> c.stopTethering(type, callerPkg, new IIntResultListener.Stub() {
+ @Override
+ public void onResult(int resultCode) {
+ // TODO: provide an API to obtain result
+ // This has never been possible as stopTethering has always been void and never
+ // taken a callback object. The only indication that callers have is if the call
+ // results in a TETHER_STATE_CHANGE broadcast.
}
- });
+ }));
}
/**
@@ -591,12 +707,8 @@
final String callerPkg = mContext.getOpPackageName();
Log.i(TAG, "getLatestTetheringEntitlementResult caller:" + callerPkg);
- try {
- mConnector.requestLatestTetheringEntitlementResult(type, receiver, showEntitlementUi,
- callerPkg);
- } catch (RemoteException e) {
- throw new IllegalStateException(e);
- }
+ getConnector(c -> c.requestLatestTetheringEntitlementResult(
+ type, receiver, showEntitlementUi, callerPkg));
}
/**
@@ -832,11 +944,7 @@
});
}
};
- try {
- mConnector.registerTetheringEventCallback(remoteCallback, callerPkg);
- } catch (RemoteException e) {
- throw new IllegalStateException(e);
- }
+ getConnector(c -> c.registerTetheringEventCallback(remoteCallback, callerPkg));
mTetheringEventCallbacks.put(callback, remoteCallback);
}
}
@@ -860,11 +968,8 @@
if (remoteCallback == null) {
throw new IllegalArgumentException("callback was not registered.");
}
- try {
- mConnector.unregisterTetheringEventCallback(remoteCallback, callerPkg);
- } catch (RemoteException e) {
- throw new IllegalStateException(e);
- }
+
+ getConnector(c -> c.unregisterTetheringEventCallback(remoteCallback, callerPkg));
}
}
@@ -1002,9 +1107,9 @@
final String callerPkg = mContext.getOpPackageName();
final RequestDispatcher dispatcher = new RequestDispatcher();
- final int ret = dispatcher.waitForResult(listener -> {
+ final int ret = dispatcher.waitForResult((connector, listener) -> {
try {
- mConnector.isTetheringSupported(callerPkg, listener);
+ connector.isTetheringSupported(callerPkg, listener);
} catch (RemoteException e) {
throw new IllegalStateException(e);
}
@@ -1027,13 +1132,14 @@
final String callerPkg = mContext.getOpPackageName();
Log.i(TAG, "stopAllTethering caller:" + callerPkg);
- final RequestDispatcher dispatcher = new RequestDispatcher();
- dispatcher.waitForResult(listener -> {
- try {
- mConnector.stopAllTethering(callerPkg, listener);
- } catch (RemoteException e) {
- throw new IllegalStateException(e);
+ getConnector(c -> c.stopAllTethering(callerPkg, new IIntResultListener.Stub() {
+ @Override
+ public void onResult(int resultCode) {
+ // TODO: add an API parameter to send result to caller.
+ // This has never been possible as stopAllTethering has always been void and never
+ // taken a callback object. The only indication that callers have is if the call
+ // results in a TETHER_STATE_CHANGE broadcast.
}
- });
+ }));
}
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index d933e9d..2982dc9 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -5537,20 +5537,6 @@
return nri.request.requestId == mDefaultRequest.requestId;
}
- // TODO : remove this method. It's a stopgap measure to help sheperding a number of dependent
- // changes that would conflict throughout the automerger graph. Having this method temporarily
- // helps with the process of going through with all these dependent changes across the entire
- // tree.
- /**
- * Register a new agent. {@see #registerNetworkAgent} below.
- */
- public Network registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo,
- LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
- int currentScore, NetworkAgentConfig networkAgentConfig) {
- return registerNetworkAgent(messenger, networkInfo, linkProperties, networkCapabilities,
- currentScore, networkAgentConfig, NetworkProvider.ID_NONE);
- }
-
/**
* Register a new agent with ConnectivityService to handle a network.
*
@@ -5569,7 +5555,7 @@
*/
public Network registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo,
LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
- int currentScore, NetworkAgentConfig networkAgentConfig, int providerId) {
+ NetworkScore currentScore, NetworkAgentConfig networkAgentConfig, int providerId) {
enforceNetworkFactoryPermission();
LinkProperties lp = new LinkProperties(linkProperties);
@@ -5577,12 +5563,10 @@
// TODO: Instead of passing mDefaultRequest, provide an API to determine whether a Network
// satisfies mDefaultRequest.
final NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities);
- final NetworkScore ns = new NetworkScore();
- ns.putIntExtension(NetworkScore.LEGACY_SCORE, currentScore);
final NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(),
new Network(mNetIdManager.reserveNetId()), new NetworkInfo(networkInfo), lp, nc,
- ns, mContext, mTrackerHandler, new NetworkAgentConfig(networkAgentConfig), this,
- mNetd, mDnsResolver, mNMS, providerId);
+ currentScore, mContext, mTrackerHandler, new NetworkAgentConfig(networkAgentConfig),
+ this, mNetd, mDnsResolver, mNMS, providerId);
// Make sure the network capabilities reflect what the agent info says.
nai.getAndSetNetworkCapabilities(mixInCapabilities(nai, nc));
final String extraInfo = networkInfo.getExtraInfo();
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 36dd017..139a871 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -897,6 +897,13 @@
if ((events & PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH)
!= 0) {
updateReportSignalStrengthDecision(r.subId);
+ try {
+ if (mSignalStrength[phoneId] != null) {
+ r.callback.onSignalStrengthsChanged(mSignalStrength[phoneId]);
+ }
+ } catch (RemoteException ex) {
+ remove(r.binder);
+ }
}
if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO)) {
try {
@@ -1326,9 +1333,10 @@
log("notifySignalStrengthForPhoneId: r=" + r + " subId=" + subId
+ " phoneId=" + phoneId + " ss=" + signalStrength);
}
- if (r.matchPhoneStateListenerEvent(
- PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) &&
- idMatch(r.subId, subId, phoneId)) {
+ if ((r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_SIGNAL_STRENGTHS)
+ || r.matchPhoneStateListenerEvent(
+ PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH))
+ && idMatch(r.subId, subId, phoneId)) {
try {
if (DBG) {
log("notifySignalStrengthForPhoneId: callback.onSsS r=" + r
@@ -1341,7 +1349,7 @@
}
}
if (r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_SIGNAL_STRENGTH) &&
- idMatch(r.subId, subId, phoneId)){
+ idMatch(r.subId, subId, phoneId)) {
try {
int gsmSignalStrength = signalStrength.getGsmSignalStrength();
int ss = (gsmSignalStrength == 99 ? -1 : gsmSignalStrength);
@@ -2542,6 +2550,11 @@
android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION, null);
}
+ if ((events & PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH) != 0) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH, null);
+ }
+
if ((events & READ_PRIVILEGED_PHONE_STATE_PERMISSION_MASK) != 0) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, null);
@@ -2657,7 +2670,8 @@
}
}
- if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0) {
+ if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0
+ || (events & PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH) != 0) {
try {
if (mSignalStrength[phoneId] != null) {
SignalStrength signalStrength = mSignalStrength[phoneId];
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 8cf620d..6560777 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -355,7 +355,6 @@
import com.android.server.firewall.IntentFirewall;
import com.android.server.job.JobSchedulerInternal;
import com.android.server.pm.Installer;
-import com.android.server.pm.Installer.InstallerException;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
import com.android.server.uri.GrantUri;
import com.android.server.uri.UriGrantsManagerInternal;
@@ -5270,26 +5269,6 @@
mCallFinishBooting = false;
}
- ArraySet<String> completedIsas = new ArraySet<String>();
- for (String abi : Build.SUPPORTED_ABIS) {
- ZYGOTE_PROCESS.establishZygoteConnectionForAbi(abi);
- final String instructionSet = VMRuntime.getInstructionSet(abi);
- if (!completedIsas.contains(instructionSet)) {
- try {
- mInstaller.markBootComplete(VMRuntime.getInstructionSet(abi));
- } catch (InstallerException e) {
- if (!VMRuntime.didPruneDalvikCache()) {
- // This is technically not the right filter, as different zygotes may
- // have made different pruning decisions. But the log is best effort,
- // anyways.
- Slog.w(TAG, "Unable to mark boot complete for abi: " + abi + " (" +
- e.getMessage() +")");
- }
- }
- completedIsas.add(instructionSet);
- }
- }
-
// Let the ART runtime in zygote and system_server know that the boot completed.
ZYGOTE_PROCESS.bootCompleted();
VMRuntime.bootCompleted();
@@ -6876,6 +6855,7 @@
}
}
+ ProcessRecord dyingProc = null;
if (cpr != null && cpr.proc != null) {
providerRunning = !cpr.proc.killed;
@@ -6885,14 +6865,9 @@
// (See the commit message on I2c4ba1e87c2d47f2013befff10c49b3dc337a9a7 to see
// how to test this case.)
if (cpr.proc.killed && cpr.proc.killedByAm) {
- final long iden = Binder.clearCallingIdentity();
- try {
- mProcessList.killProcAndWaitIfNecessaryLocked(cpr.proc, false,
- cpr.uid == cpr.proc.uid || cpr.proc.isolated,
- "getContentProviderImpl: %s (killedByAm)", startTime);
- } finally {
- Binder.restoreCallingIdentity(iden);
- }
+ Slog.wtf(TAG, cpr.proc.toString() + " was killed by AM but isn't really dead");
+ // Now we are going to wait for the death before starting the new process.
+ dyingProc = cpr.proc;
}
}
@@ -6993,18 +6968,18 @@
// has been killed on us. We need to wait for a new
// process to be started, and make sure its death
// doesn't kill our process.
- Slog.i(TAG, "Existing provider " + cpr.name.flattenToShortString()
+ Slog.wtf(TAG, "Existing provider " + cpr.name.flattenToShortString()
+ " is crashing; detaching " + r);
boolean lastRef = decProviderCountLocked(conn, cpr, token, stable);
- mProcessList.killProcAndWaitIfNecessaryLocked(cpr.proc,
- false, true, "getContentProviderImpl: %s", startTime);
if (!lastRef) {
// This wasn't the last ref our process had on
- // the provider... we have now been killed, bail.
+ // the provider... we will be killed during cleaning up, bail.
return null;
}
+ // We'll just start a new process to host the content provider
providerRunning = false;
conn = null;
+ dyingProc = cpr.proc;
} else {
cpr.proc.verifiedAdj = cpr.proc.setAdj;
}
@@ -7080,7 +7055,7 @@
checkTime(startTime, "getContentProviderImpl: before getProviderByClass");
cpr = mProviderMap.getProviderByClass(comp, userId);
checkTime(startTime, "getContentProviderImpl: after getProviderByClass");
- final boolean firstClass = cpr == null;
+ boolean firstClass = cpr == null;
if (firstClass) {
final long ident = Binder.clearCallingIdentity();
@@ -7111,6 +7086,13 @@
} finally {
Binder.restoreCallingIdentity(ident);
}
+ } else if (dyingProc == cpr.proc) {
+ // The old stable connection's client should be killed during proc cleaning up,
+ // so do not re-use the old ContentProviderRecord, otherwise the new clients
+ // could get killed unexpectedly.
+ cpr = new ContentProviderRecord(cpr);
+ // This is sort of "firstClass"
+ firstClass = true;
}
checkTime(startTime, "getContentProviderImpl: now have ContentProviderRecord");
@@ -14270,10 +14252,19 @@
cpr.launchingApp = null;
cpr.notifyAll();
}
- mProviderMap.removeProviderByClass(cpr.name, UserHandle.getUserId(cpr.uid));
+ final int userId = UserHandle.getUserId(cpr.uid);
+ // Don't remove from provider map if it doesn't match
+ // could be a new content provider is starting
+ if (mProviderMap.getProviderByClass(cpr.name, userId) == cpr) {
+ mProviderMap.removeProviderByClass(cpr.name, userId);
+ }
String names[] = cpr.info.authority.split(";");
for (int j = 0; j < names.length; j++) {
- mProviderMap.removeProviderByName(names[j], UserHandle.getUserId(cpr.uid));
+ // Don't remove from provider map if it doesn't match
+ // could be a new content provider is starting
+ if (mProviderMap.getProviderByName(names[j], userId) == cpr) {
+ mProviderMap.removeProviderByName(names[j], userId);
+ }
}
}
@@ -14368,6 +14359,10 @@
// Remove published content providers.
for (int i = app.pubProviders.size() - 1; i >= 0; i--) {
ContentProviderRecord cpr = app.pubProviders.valueAt(i);
+ if (cpr.proc != app) {
+ // If the hosting process record isn't really us, bail out
+ continue;
+ }
final boolean alwaysRemove = app.bad || !allowRestart;
final boolean inLaunching = removeDyingProviderLocked(app, cpr, alwaysRemove);
if (!alwaysRemove && inLaunching && cpr.hasConnectionOrHandle()) {
@@ -14453,6 +14448,27 @@
mUiHandler.obtainMessage(DISPATCH_PROCESS_DIED_UI_MSG, app.pid, app.info.uid,
null).sendToTarget();
+ // If this is a precede instance of another process instance
+ allowRestart = true;
+ synchronized (app) {
+ if (app.mSuccessor != null) {
+ // We don't allow restart with this ProcessRecord now,
+ // because we have created a new one already.
+ allowRestart = false;
+ // If it's persistent, add the successor to mPersistentStartingProcesses
+ if (app.isPersistent() && !app.removed) {
+ if (mPersistentStartingProcesses.indexOf(app.mSuccessor) < 0) {
+ mPersistentStartingProcesses.add(app.mSuccessor);
+ }
+ }
+ // clean up the field so the successor's proc starter could proceed.
+ app.mSuccessor.mPrecedence = null;
+ app.mSuccessor = null;
+ // Notify if anyone is waiting for it.
+ app.notifyAll();
+ }
+ }
+
// If the caller is restarting this app, then leave it in its
// current lists and let the caller take care of it.
if (restarting) {
@@ -14482,7 +14498,7 @@
mAtmInternal.onCleanUpApplicationRecord(app.getWindowProcessController());
mProcessList.noteProcessDiedLocked(app);
- if (restart && !app.isolated) {
+ if (restart && allowRestart && !app.isolated) {
// We have components that still need to be running in the
// process, so re-launch it.
if (index < 0) {
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 7c36a7e..b19f2b3 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -1842,26 +1842,9 @@
if (mService.mConstants.FLAG_PROCESS_START_ASYNC) {
if (DEBUG_PROCESSES) Slog.i(TAG_PROCESSES,
"Posting procStart msg for " + app.toShortString());
- mService.mProcStartHandler.post(() -> {
- try {
- final Process.ProcessStartResult startResult = startProcess(app.hostingRecord,
- entryPoint, app, app.startUid, gids, runtimeFlags, mountExternal,
- app.seInfo, requiredAbi, instructionSet, invokeWith, app.startTime);
- synchronized (mService) {
- handleProcessStartedLocked(app, startResult, startSeq);
- }
- } catch (RuntimeException e) {
- synchronized (mService) {
- Slog.e(ActivityManagerService.TAG, "Failure starting process "
- + app.processName, e);
- mPendingStarts.remove(startSeq);
- app.pendingStart = false;
- mService.forceStopPackageLocked(app.info.packageName,
- UserHandle.getAppId(app.uid),
- false, false, true, false, false, app.userId, "start failure");
- }
- }
- });
+ mService.mProcStartHandler.post(() -> handleProcessStart(
+ app, entryPoint, gids, runtimeFlags, mountExternal, requiredAbi,
+ instructionSet, invokeWith, startSeq));
return true;
} else {
try {
@@ -1882,6 +1865,66 @@
}
}
+ /**
+ * Main handler routine to start the given process from the ProcStartHandler.
+ *
+ * <p>Note: this function doesn't hold the global AM lock intentionally.</p>
+ */
+ private void handleProcessStart(final ProcessRecord app, final String entryPoint,
+ final int[] gids, final int runtimeFlags, final int mountExternal,
+ final String requiredAbi, final String instructionSet,
+ final String invokeWith, final long startSeq) {
+ // If there is a precede instance of the process, wait for its death with a timeout.
+ // Use local reference since we are not using locks here
+ final ProcessRecord precedence = app.mPrecedence;
+ if (precedence != null) {
+ final int pid = precedence.pid;
+ long now = System.currentTimeMillis();
+ final long end = now + PROC_KILL_TIMEOUT;
+ try {
+ Process.waitForProcessDeath(pid, PROC_KILL_TIMEOUT);
+ // It's killed successfully, but we'd make sure the cleanup work is done.
+ synchronized (precedence) {
+ if (app.mPrecedence != null) {
+ now = System.currentTimeMillis();
+ if (now < end) {
+ try {
+ precedence.wait(end - now);
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+ if (app.mPrecedence != null) {
+ // The cleanup work hasn't be done yet, let's log it and continue.
+ Slog.w(TAG, precedence + " has died, but its cleanup isn't done");
+ }
+ }
+ } catch (Exception e) {
+ // It's still alive...
+ Slog.wtf(TAG, precedence.toString() + " refused to die, but we need to launch "
+ + app);
+ }
+ }
+ try {
+ final Process.ProcessStartResult startResult = startProcess(app.hostingRecord,
+ entryPoint, app, app.startUid, gids, runtimeFlags, mountExternal,
+ app.seInfo, requiredAbi, instructionSet, invokeWith, app.startTime);
+ synchronized (mService) {
+ handleProcessStartedLocked(app, startResult, startSeq);
+ }
+ } catch (RuntimeException e) {
+ synchronized (mService) {
+ Slog.e(ActivityManagerService.TAG, "Failure starting process "
+ + app.processName, e);
+ mPendingStarts.remove(startSeq);
+ app.pendingStart = false;
+ mService.forceStopPackageLocked(app.info.packageName,
+ UserHandle.getAppId(app.uid),
+ false, false, true, false, false, app.userId, "start failure");
+ }
+ }
+ }
+
@GuardedBy("mService")
public void killAppZygoteIfNeededLocked(AppZygote appZygote, boolean force) {
final ApplicationInfo appInfo = appZygote.getAppInfo();
@@ -2136,6 +2179,7 @@
+ " app=" + app + " knownToBeDead=" + knownToBeDead
+ " thread=" + (app != null ? app.thread : null)
+ " pid=" + (app != null ? app.pid : -1));
+ ProcessRecord precedence = null;
if (app != null && app.pid > 0) {
if ((!knownToBeDead && !app.killed) || app.thread == null) {
// We already have the app running, or are waiting for it to
@@ -2150,9 +2194,15 @@
// An application record is attached to a previous process,
// clean it up now.
if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES, "App died: " + app);
- // do the killing
- killProcAndWaitIfNecessaryLocked(app, true, app.uid == info.uid || app.isolated,
- "startProcess: bad proc running, killing: %s", startTime);
+ checkSlow(startTime, "startProcess: bad proc running, killing");
+ ProcessList.killProcessGroup(app.uid, app.pid);
+ checkSlow(startTime, "startProcess: done killing old proc");
+
+ Slog.wtf(TAG_PROCESSES, app.toString() + " is attached to a previous process");
+ // We are not going to re-use the ProcessRecord, as we haven't dealt with the cleanup
+ // routine of it yet, but we'd set it as the precedence of the new process.
+ precedence = app;
+ app = null;
}
if (app == null) {
@@ -2166,6 +2216,10 @@
app.crashHandler = crashHandler;
app.isolatedEntryPoint = entryPoint;
app.isolatedEntryPointArgs = entryPointArgs;
+ if (precedence != null) {
+ app.mPrecedence = precedence;
+ precedence.mSuccessor = app;
+ }
checkSlow(startTime, "startProcess: done creating new process record");
} else {
// If this is a new package in the process, add the package to the list
@@ -2193,44 +2247,6 @@
return success ? app : null;
}
- /**
- * Kill (if asked to) and wait for the given process died if necessary
- * @param app - The process record to kill
- * @param doKill - Kill the given process record
- * @param wait - Wait for the death of the given process
- * @param formatString - The log message for slow operation
- * @param startTime - The start timestamp of the operation
- */
- @GuardedBy("mService")
- void killProcAndWaitIfNecessaryLocked(final ProcessRecord app, final boolean doKill,
- final boolean wait, final String formatString, final long startTime) {
-
- checkSlow(startTime, String.format(formatString, "before appDied"));
-
- if (doKill) {
- // do the killing
- ProcessList.killProcessGroup(app.uid, app.pid);
- noteAppKill(app, ApplicationExitInfo.REASON_OTHER,
- ApplicationExitInfo.SUBREASON_UNKNOWN,
- String.format(formatString, ""));
- }
-
- // wait for the death
- if (wait) {
- try {
- Process.waitForProcessDeath(app.pid, PROC_KILL_TIMEOUT);
- } catch (Exception e) {
- // Maybe the process goes into zombie, use an expensive API to check again.
- if (mService.isProcessAliveLocked(app)) {
- Slog.w(TAG, String.format(formatString,
- "waiting for app killing timed out"));
- }
- }
- }
-
- checkSlow(startTime, String.format(formatString, "after appDied"));
- }
-
@GuardedBy("mService")
private String isProcStartValidLocked(ProcessRecord app, long expectedStartSeq) {
StringBuilder sb = null;
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index b0c0aae..fc33c25 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -320,6 +320,14 @@
// set of disabled compat changes for the process (all others are enabled)
long[] mDisabledCompatChanges;
+ // The precede instance of the process, which would exist when the previous process is killed
+ // but not fully dead yet; in this case, the new instance of the process should be held until
+ // this precede instance is fully dead.
+ volatile ProcessRecord mPrecedence;
+ // The succeeding instance of the process, which is going to be started after this process
+ // is killed successfully.
+ volatile ProcessRecord mSuccessor;
+
// Cached task info for OomAdjuster
private static final int VALUE_INVALID = -1;
private static final int VALUE_FALSE = 0;
diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java
index 8d26176..7f7c9c4 100644
--- a/services/core/java/com/android/server/compat/CompatConfig.java
+++ b/services/core/java/com/android/server/compat/CompatConfig.java
@@ -35,6 +35,7 @@
import com.android.internal.compat.OverrideAllowedState;
import com.android.server.compat.config.Change;
import com.android.server.compat.config.XmlParser;
+import com.android.server.pm.ApexManager;
import org.xmlpull.v1.XmlPullParserException;
@@ -45,6 +46,7 @@
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.HashSet;
+import java.util.List;
import java.util.Set;
import javax.xml.datatype.DatatypeConfigurationException;
@@ -369,12 +371,18 @@
Environment.getRootDirectory(), "etc", "compatconfig"));
config.initConfigFromLib(Environment.buildPath(
Environment.getRootDirectory(), "system_ext", "etc", "compatconfig"));
+
+ List<ApexManager.ActiveApexInfo> apexes = ApexManager.getInstance().getActiveApexInfos();
+ for (ApexManager.ActiveApexInfo apex : apexes) {
+ config.initConfigFromLib(Environment.buildPath(
+ apex.apexDirectory, "etc", "compatconfig"));
+ }
return config;
}
void initConfigFromLib(File libraryDir) {
if (!libraryDir.exists() || !libraryDir.isDirectory()) {
- Slog.e(TAG, "No directory " + libraryDir + ", skipping");
+ Slog.d(TAG, "No directory " + libraryDir + ", skipping");
return;
}
for (File f : libraryDir.listFiles()) {
diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java
index 4d5af9a..bb8b12e 100644
--- a/services/core/java/com/android/server/compat/PlatformCompat.java
+++ b/services/core/java/com/android/server/compat/PlatformCompat.java
@@ -16,11 +16,6 @@
package com.android.server.compat;
-import static android.Manifest.permission.LOG_COMPAT_CHANGE;
-import static android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG;
-import static android.Manifest.permission.READ_COMPAT_CHANGE_CONFIG;
-import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-
import android.app.ActivityManager;
import android.app.IActivityManager;
import android.content.Context;
@@ -73,14 +68,12 @@
@Override
public void reportChange(long changeId, ApplicationInfo appInfo) {
- checkCompatChangeLogPermission();
reportChange(changeId, appInfo.uid,
StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__LOGGED);
}
@Override
public void reportChangeByPackageName(long changeId, String packageName, int userId) {
- checkCompatChangeLogPermission();
ApplicationInfo appInfo = getApplicationInfo(packageName, userId);
if (appInfo == null) {
return;
@@ -90,13 +83,11 @@
@Override
public void reportChangeByUid(long changeId, int uid) {
- checkCompatChangeLogPermission();
reportChange(changeId, uid, StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__LOGGED);
}
@Override
public boolean isChangeEnabled(long changeId, ApplicationInfo appInfo) {
- checkCompatChangeReadPermission();
if (mCompatConfig.isChangeEnabled(changeId, appInfo)) {
reportChange(changeId, appInfo.uid,
StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__ENABLED);
@@ -109,7 +100,6 @@
@Override
public boolean isChangeEnabledByPackageName(long changeId, String packageName, int userId) {
- checkCompatChangeReadPermission();
ApplicationInfo appInfo = getApplicationInfo(packageName, userId);
if (appInfo == null) {
return true;
@@ -119,7 +109,6 @@
@Override
public boolean isChangeEnabledByUid(long changeId, int uid) {
- checkCompatChangeReadPermission();
String[] packages = mContext.getPackageManager().getPackagesForUid(uid);
if (packages == null || packages.length == 0) {
return true;
@@ -152,7 +141,6 @@
@Override
public void setOverrides(CompatibilityChangeConfig overrides, String packageName)
throws RemoteException, SecurityException {
- checkCompatChangeOverridePermission();
mCompatConfig.addOverrides(overrides, packageName);
killPackage(packageName);
}
@@ -160,13 +148,11 @@
@Override
public void setOverridesForTest(CompatibilityChangeConfig overrides, String packageName)
throws RemoteException, SecurityException {
- checkCompatChangeOverridePermission();
mCompatConfig.addOverrides(overrides, packageName);
}
@Override
public void clearOverrides(String packageName) throws RemoteException, SecurityException {
- checkCompatChangeOverridePermission();
mCompatConfig.removePackageOverrides(packageName);
killPackage(packageName);
}
@@ -174,14 +160,12 @@
@Override
public void clearOverridesForTest(String packageName)
throws RemoteException, SecurityException {
- checkCompatChangeOverridePermission();
mCompatConfig.removePackageOverrides(packageName);
}
@Override
public boolean clearOverride(long changeId, String packageName)
throws RemoteException, SecurityException {
- checkCompatChangeOverridePermission();
boolean existed = mCompatConfig.removeOverride(changeId, packageName);
killPackage(packageName);
return existed;
@@ -189,13 +173,11 @@
@Override
public CompatibilityChangeConfig getAppConfig(ApplicationInfo appInfo) {
- checkCompatChangeReadPermission();
return mCompatConfig.getAppConfig(appInfo);
}
@Override
public CompatibilityChangeInfo[] listAllChanges() {
- checkCompatChangeReadPermission();
return mCompatConfig.dumpChanges();
}
@@ -234,7 +216,6 @@
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- checkCompatChangeReadPermission();
if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, "platform_compat", pw)) return;
mCompatConfig.dumpConfig(pw);
}
@@ -292,25 +273,4 @@
Binder.restoreCallingIdentity(identity);
}
}
-
- private void checkCompatChangeLogPermission() throws SecurityException {
- if (mContext.checkCallingOrSelfPermission(LOG_COMPAT_CHANGE)
- != PERMISSION_GRANTED) {
- throw new SecurityException("Cannot log compat change usage");
- }
- }
-
- private void checkCompatChangeReadPermission() throws SecurityException {
- if (mContext.checkCallingOrSelfPermission(READ_COMPAT_CHANGE_CONFIG)
- != PERMISSION_GRANTED) {
- throw new SecurityException("Cannot read compat change");
- }
- }
-
- private void checkCompatChangeOverridePermission() throws SecurityException {
- if (mContext.checkCallingOrSelfPermission(OVERRIDE_COMPAT_CHANGE_CONFIG)
- != PERMISSION_GRANTED) {
- throw new SecurityException("Cannot override compat change");
- }
- }
}
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index d66aec5..3cfe916 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -483,7 +483,7 @@
return ConnectivityConstants.EXPLICITLY_SELECTED_NETWORK_SCORE;
}
- int score = mNetworkScore.getIntExtension(NetworkScore.LEGACY_SCORE);
+ int score = mNetworkScore.getLegacyScore();
if (!lastValidated && !pretendValidated && !ignoreWifiUnvalidationPenalty() && !isVPN()) {
score -= ConnectivityConstants.UNVALIDATED_SCORE_PENALTY;
}
diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java
index decb1f9..96532f4 100644
--- a/services/core/java/com/android/server/display/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/DisplayModeDirector.java
@@ -1050,6 +1050,7 @@
public void dumpLocked(PrintWriter pw) {
pw.println(" BrightnessObserver");
+ pw.println(" mAmbientLux: " + mAmbientLux);
pw.println(" mRefreshRateInZone: " + mRefreshRateInZone);
for (int d: mDisplayBrightnessThresholds) {
@@ -1059,6 +1060,8 @@
for (int d: mAmbientBrightnessThresholds) {
pw.println(" mAmbientBrightnessThreshold: " + d);
}
+
+ mLightSensorListener.dumpLocked(pw);
}
public void onDisplayChanged(int displayId) {
@@ -1222,6 +1225,10 @@
final private static int INJECT_EVENTS_INTERVAL_MS = LIGHT_SENSOR_RATE_MS;
private float mLastSensorData;
+ public void dumpLocked(PrintWriter pw) {
+ pw.println(" mLastSensorData: " + mLastSensorData);
+ }
+
@Override
public void onSensorChanged(SensorEvent event) {
mLastSensorData = event.values[0];
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 7104790..68cc014 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2735,7 +2735,7 @@
// TODO(b/144152069): Remove informative toast
mUiHandler.post(() -> Toast.makeText(getContext(),
"Background custom toast blocked for package " + pkg + ".\n"
- + "See go/r-toast-block.",
+ + "See g.co/dev/toast.",
Toast.LENGTH_SHORT).show());
Slog.w(TAG, "Blocking custom toast from package " + pkg
+ " due to package not in the foreground");
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index 90afeff..4ff37a2 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -95,6 +95,7 @@
* Returns an instance of either {@link ApexManagerImpl} or {@link ApexManagerFlattenedApex}
* depending on whether this device supports APEX, i.e. {@link ApexProperties#updatable()}
* evaluates to {@code true}.
+ * @hide
*/
public static ApexManager getInstance() {
return sApexManagerSingleton.get();
@@ -102,8 +103,9 @@
/**
* Minimal information about APEX mount points and the original APEX package they refer to.
+ * @hide
*/
- static class ActiveApexInfo {
+ public static class ActiveApexInfo {
@Nullable public final String apexModuleName;
public final File apexDirectory;
public final File preInstalledApexPath;
@@ -130,8 +132,10 @@
/**
* Returns {@link ActiveApexInfo} records relative to all active APEX packages.
+ *
+ * @hide
*/
- abstract List<ActiveApexInfo> getActiveApexInfos();
+ public abstract List<ActiveApexInfo> getActiveApexInfos();
abstract void systemReady(Context context);
@@ -362,7 +366,7 @@
}
@Override
- List<ActiveApexInfo> getActiveApexInfos() {
+ public List<ActiveApexInfo> getActiveApexInfos() {
synchronized (mLock) {
if (mActiveApexInfosCache == null) {
try {
@@ -798,7 +802,7 @@
*/
private static final class ApexManagerFlattenedApex extends ApexManager {
@Override
- List<ActiveApexInfo> getActiveApexInfos() {
+ public List<ActiveApexInfo> getActiveApexInfos() {
// There is no apexd running in case of flattened apex
// We look up the /apex directory and identify the active APEX modules from there.
// As "preinstalled" path, we just report /system since in the case of flattened APEX
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
index c712431..ba7583f 100644
--- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -36,9 +36,9 @@
import android.os.storage.StorageManager;
import android.util.ArraySet;
import android.util.Log;
-import android.util.StatsLog;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.FrameworkStatsLog;
import com.android.server.LocalServices;
import com.android.server.PinnerService;
import com.android.server.pm.dex.DexManager;
@@ -444,7 +444,7 @@
}
if (dex_opt_performed) {
- StatsLog.write(StatsLog.APP_DOWNGRADED, pkg, package_size_before,
+ FrameworkStatsLog.write(FrameworkStatsLog.APP_DOWNGRADED, pkg, package_size_before,
getPackageSize(pm, pkg), /*aggressive=*/ false);
}
return dex_opt_performed;
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index f962eed..40ea6cf 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -450,16 +450,6 @@
}
}
- public void markBootComplete(String instructionSet) throws InstallerException {
- assertValidInstructionSet(instructionSet);
- if (!checkBeforeRemote()) return;
- try {
- mInstalld.markBootComplete(instructionSet);
- } catch (Exception e) {
- throw InstallerException.from(e);
- }
- }
-
public void freeCache(String uuid, long targetFreeBytes, long cacheReservedBytes, int flags)
throws InstallerException {
if (!checkBeforeRemote()) return;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 02ec472..93a0506 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -288,7 +288,6 @@
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
-import android.util.StatsLog;
import android.util.TimingsTraceLog;
import android.util.Xml;
import android.util.apk.ApkSignatureVerifier;
@@ -310,6 +309,7 @@
import com.android.internal.util.ConcurrentUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.server.AttributeCache;
@@ -2163,7 +2163,8 @@
getPackageExternalStorageType(volume, isExternal(res.pkg));
// If the package was installed externally, log it.
if (packageExternalStorageType != StorageEnums.UNKNOWN) {
- StatsLog.write(StatsLog.APP_INSTALL_ON_EXTERNAL_STORAGE_REPORTED,
+ FrameworkStatsLog.write(
+ FrameworkStatsLog.APP_INSTALL_ON_EXTERNAL_STORAGE_REPORTED,
packageExternalStorageType, res.pkg.getPackageName());
}
}
@@ -19706,9 +19707,7 @@
if (packageName == null) {
return null;
}
- if (getPackageInfo(packageName, MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE
- | MATCH_DIRECT_BOOT_UNAWARE | MATCH_DISABLED_COMPONENTS,
- UserHandle.getCallingUserId()) == null) {
+ if (getPackageInfo(packageName, MATCH_FACTORY_ONLY, UserHandle.USER_SYSTEM) == null) {
return null;
}
return packageName;
@@ -22179,13 +22178,15 @@
if (!isPreviousLocationExternal && isExternal(pkg)) {
// Move from internal to external storage.
- StatsLog.write(StatsLog.APP_MOVED_STORAGE_REPORTED, packageExternalStorageType,
- StatsLog.APP_MOVED_STORAGE_REPORTED__MOVE_TYPE__TO_EXTERNAL,
+ FrameworkStatsLog.write(FrameworkStatsLog.APP_MOVED_STORAGE_REPORTED,
+ packageExternalStorageType,
+ FrameworkStatsLog.APP_MOVED_STORAGE_REPORTED__MOVE_TYPE__TO_EXTERNAL,
packageName);
} else if (isPreviousLocationExternal && !isExternal(pkg)) {
// Move from external to internal storage.
- StatsLog.write(StatsLog.APP_MOVED_STORAGE_REPORTED, packageExternalStorageType,
- StatsLog.APP_MOVED_STORAGE_REPORTED__MOVE_TYPE__TO_INTERNAL,
+ FrameworkStatsLog.write(FrameworkStatsLog.APP_MOVED_STORAGE_REPORTED,
+ packageExternalStorageType,
+ FrameworkStatsLog.APP_MOVED_STORAGE_REPORTED__MOVE_TYPE__TO_INTERNAL,
packageName);
}
}
diff --git a/services/core/java/com/android/server/timezone/RulesManagerService.java b/services/core/java/com/android/server/timezone/RulesManagerService.java
index cdf8ea3..bbd1ae6 100644
--- a/services/core/java/com/android/server/timezone/RulesManagerService.java
+++ b/services/core/java/com/android/server/timezone/RulesManagerService.java
@@ -198,7 +198,7 @@
Slog.w(TAG, "Failed to read staged distro.", e);
}
}
- return new RulesState(baseVersion.rulesVersion, DISTRO_FORMAT_VERSION_SUPPORTED,
+ return new RulesState(baseVersion.getRulesVersion(), DISTRO_FORMAT_VERSION_SUPPORTED,
operationInProgress, stagedOperationStatus, stagedDistroRulesVersion,
distroStatus, installedDistroRulesVersion);
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index dda11f9..b05c250 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -3074,7 +3074,11 @@
mStackSupervisor.getActivityMetricsLogger().notifyActivityRemoved(this);
waitingToShow = false;
- boolean delayed = isAnimating(TRANSITION | CHILDREN);
+ // Defer removal of this activity when either a child is animating, or app transition is on
+ // going. App transition animation might be applied on the parent stack not on the activity,
+ // but the actual frame buffer is associated with the activity, so we have to keep the
+ // activity while a parent is animating.
+ boolean delayed = isAnimating(TRANSITION | PARENTS | CHILDREN);
if (getDisplayContent().mClosingApps.contains(this)) {
delayed = true;
} else if (getDisplayContent().mAppTransition.isTransitionSet()) {
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index ddf0117..0d72d84 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -341,6 +341,9 @@
private static final int TRANSLUCENT_TIMEOUT_MSG = FIRST_ACTIVITY_STACK_MSG + 1;
+ // TODO(task-hierarchy): remove when tiles can be actual parents
+ TaskTile mTile = null;
+
private final Handler mHandler;
private class ActivityStackHandler extends Handler {
@@ -638,11 +641,20 @@
}
@Override
+ public void resolveOverrideConfiguration(Configuration newParentConfig) {
+ super.resolveOverrideConfiguration(newParentConfig);
+ if (mTile != null) {
+ // If this is a virtual child of a tile, simulate the parent-child relationship
+ mTile.updateResolvedConfig(getResolvedOverrideConfiguration());
+ }
+ }
+
+ @Override
public void onConfigurationChanged(Configuration newParentConfig) {
// Calling Task#onConfigurationChanged() for leaf task since the ops in this method are
// particularly for ActivityStack, like preventing bounds changes when inheriting certain
// windowing mode.
- if (!isRootTask()) {
+ if (!isRootTask() || this instanceof TaskTile) {
super.onConfigurationChanged(newParentConfig);
return;
}
@@ -3944,7 +3956,6 @@
? ((WindowContainer) newParent).getDisplayContent() : null;
final DisplayContent oldDisplay = oldParent != null
? ((WindowContainer) oldParent).getDisplayContent() : null;
-
super.onParentChanged(newParent, oldParent);
if (display != null && inSplitScreenPrimaryWindowingMode()
@@ -3963,6 +3974,11 @@
if (oldDisplay != null && oldDisplay.isRemoving()) {
postReparent();
}
+ if (mTile != null && getSurfaceControl() != null) {
+ // by now, the TaskStack should already have been reparented, so we can reparent its
+ // surface here
+ reparentSurfaceControl(getPendingTransaction(), mTile.getSurfaceControl());
+ }
}
void reparent(DisplayContent newParent, boolean onTop) {
@@ -4000,7 +4016,16 @@
@Override
void getRelativeDisplayedPosition(Point outPos) {
- super.getRelativeDisplayedPosition(outPos);
+ // check for tile which is "virtually" a parent.
+ if (mTile != null) {
+ final Rect dispBounds = getDisplayedBounds();
+ outPos.set(dispBounds.left, dispBounds.top);
+ final Rect parentBounds = mTile.getBounds();
+ outPos.offset(-parentBounds.left, -parentBounds.top);
+ } else {
+ super.getRelativeDisplayedPosition(outPos);
+ }
+
final int outset = getStackOutset();
outPos.x -= outset;
outPos.y -= outset;
@@ -4010,6 +4035,16 @@
if (mSurfaceControl == null) {
return;
}
+ if (mTile != null) {
+ // Tile controls crop, so the app needs to be able to draw its background outside of
+ // the stack bounds for when the tile crop gets bigger than the stack.
+ if (mLastSurfaceSize.equals(0, 0)) {
+ return;
+ }
+ transaction.setWindowCrop(mSurfaceControl, null);
+ mLastSurfaceSize.set(0, 0);
+ return;
+ }
final Rect stackBounds = getDisplayedBounds();
int width = stackBounds.width();
@@ -4033,6 +4068,9 @@
@Override
void onDisplayChanged(DisplayContent dc) {
+ if (mTile != null && dc != mTile.getDisplay()) {
+ mTile.removeChild(this);
+ }
super.onDisplayChanged(dc);
if (isRootTask()) {
updateSurfaceBounds();
@@ -4848,6 +4886,42 @@
return shouldSleepActivities() || mAtmService.mShuttingDown;
}
+ TaskTile getTile() {
+ return mTile;
+ }
+
+ /**
+ * Don't call this directly. instead use {@link TaskTile#addChild} or
+ * {@link TaskTile#removeChild}.
+ */
+ void setTile(TaskTile tile) {
+ TaskTile origTile = mTile;
+ mTile = tile;
+ final ConfigurationContainer parent = getParent();
+ if (parent != null) {
+ onConfigurationChanged(parent.getConfiguration());
+ }
+
+ // Reparent to tile surface or back to original parent
+ if (getSurfaceControl() == null) {
+ return;
+ }
+ if (mTile != null) {
+ reparentSurfaceControl(getPendingTransaction(), mTile.getSurfaceControl());
+ } else if (mTile == null && origTile != null) {
+ reparentSurfaceControl(getPendingTransaction(), getParentSurfaceControl());
+ }
+ }
+
+ @Override
+ void removeImmediately() {
+ // TODO(task-hierarchy): remove this override when tiles are in hierarchy
+ if (mTile != null) {
+ mTile.removeChild(this);
+ }
+ super.removeImmediately();
+ }
+
@Override
public void dumpDebug(ProtoOutputStream proto, long fieldId,
@WindowTraceLogLevel int logLevel) {
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 362e781..a513ef8 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -1711,6 +1711,7 @@
* invisible as well and added to the stopping list. After which we process the
* stopping list by handling the idle.
*/
+ stack.cancelAnimation();
stack.mForceHidden = true;
stack.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS);
stack.mForceHidden = false;
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index f019013..d6e7077 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -144,6 +144,7 @@
import android.app.IAssistDataReceiver;
import android.app.INotificationManager;
import android.app.IRequestFinishCallback;
+import android.app.ITaskOrganizerController;
import android.app.ITaskStackListener;
import android.app.Notification;
import android.app.NotificationManager;
@@ -225,10 +226,8 @@
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
import android.view.IRecentsAnimationRunner;
-import android.view.ITaskOrganizer;
import android.view.RemoteAnimationAdapter;
import android.view.RemoteAnimationDefinition;
-import android.view.WindowContainerTransaction;
import android.view.WindowManager;
import com.android.internal.R;
@@ -292,7 +291,6 @@
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
-import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -344,10 +342,6 @@
/** This activity is being relaunched due to a free-resize operation. */
public static final int RELAUNCH_REASON_FREE_RESIZE = 2;
- /** Flag indicating that an applied transaction may have effected lifecycle */
- private static final int TRANSACT_EFFECTS_CLIENT_CONFIG = 1;
- private static final int TRANSACT_EFFECTS_LIFECYCLE = 1 << 1;
-
Context mContext;
/**
@@ -669,8 +663,7 @@
/**
* Stores the registration and state of TaskOrganizers in use.
*/
- TaskOrganizerController mTaskOrganizerController =
- new TaskOrganizerController(this, mGlobalLock);
+ TaskOrganizerController mTaskOrganizerController = new TaskOrganizerController(this);
private int mDeviceOwnerUid = Process.INVALID_UID;
@@ -1286,15 +1279,6 @@
}
@Override
- public final void registerTaskOrganizer(ITaskOrganizer organizer, int windowingMode) {
- enforceCallerIsRecentsOrHasPermission(
- MANAGE_ACTIVITY_STACKS, "registerTaskOrganizer()");
- synchronized (mGlobalLock) {
- mTaskOrganizerController.registerTaskOrganizer(organizer, windowingMode);
- }
- }
-
- @Override
public IBinder requestStartActivityPermissionToken(IBinder delegatorToken) {
int callingUid = Binder.getCallingUid();
if (UserHandle.getAppId(callingUid) != SYSTEM_UID) {
@@ -3304,116 +3288,6 @@
}
}
- private int sanitizeAndApplyChange(WindowContainer container,
- WindowContainerTransaction.Change change) {
- if (!(container instanceof Task || container instanceof ActivityStack)) {
- throw new RuntimeException("Invalid token in task transaction");
- }
- // The "client"-facing API should prevent bad changes; however, just in case, sanitize
- // masks here.
- int configMask = change.getConfigSetMask();
- int windowMask = change.getWindowSetMask();
- configMask &= ActivityInfo.CONFIG_WINDOW_CONFIGURATION
- | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
- windowMask &= WindowConfiguration.WINDOW_CONFIG_BOUNDS;
- int effects = 0;
- if (configMask != 0) {
- Configuration c = new Configuration(container.getRequestedOverrideConfiguration());
- c.setTo(change.getConfiguration(), configMask, windowMask);
- container.onRequestedOverrideConfigurationChanged(c);
- // TODO(b/145675353): remove the following once we could apply new bounds to the
- // pinned stack together with its children.
- resizePinnedStackIfNeeded(container, configMask, windowMask, c);
- effects |= TRANSACT_EFFECTS_CLIENT_CONFIG;
- }
- if ((change.getChangeMask() & WindowContainerTransaction.Change.CHANGE_FOCUSABLE) != 0) {
- if (container.setFocusable(change.getFocusable())) {
- effects |= TRANSACT_EFFECTS_LIFECYCLE;
- }
- }
- return effects;
- }
-
- private void resizePinnedStackIfNeeded(ConfigurationContainer container, int configMask,
- int windowMask, Configuration config) {
- if ((container instanceof ActivityStack)
- && ((configMask & ActivityInfo.CONFIG_WINDOW_CONFIGURATION) != 0)
- && ((windowMask & WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0)) {
- final ActivityStack stack = (ActivityStack) container;
- if (stack.inPinnedWindowingMode()) {
- stack.resize(config.windowConfiguration.getBounds(),
- null /* tempTaskBounds */, null /* tempTaskInsetBounds */,
- PRESERVE_WINDOWS, true /* deferResume */);
- }
- }
- }
-
- private int applyWindowContainerChange(WindowContainer wc,
- WindowContainerTransaction.Change c) {
- int effects = sanitizeAndApplyChange(wc, c);
-
- Rect enterPipBounds = c.getEnterPipBounds();
- if (enterPipBounds != null) {
- Task tr = (Task) wc;
- mStackSupervisor.updatePictureInPictureMode(tr,
- enterPipBounds, true);
- }
- return effects;
- }
-
- @Override
- public void applyContainerTransaction(WindowContainerTransaction t) {
- mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "applyContainerTransaction()");
- if (t == null) {
- return;
- }
- long ident = Binder.clearCallingIdentity();
- try {
- synchronized (mGlobalLock) {
- int effects = 0;
- deferWindowLayout();
- try {
- ArraySet<WindowContainer> haveConfigChanges = new ArraySet<>();
- Iterator<Map.Entry<IBinder, WindowContainerTransaction.Change>> entries =
- t.getChanges().entrySet().iterator();
- while (entries.hasNext()) {
- final Map.Entry<IBinder, WindowContainerTransaction.Change> entry =
- entries.next();
- final WindowContainer wc = WindowContainer.RemoteToken.fromBinder(
- entry.getKey()).getContainer();
- int containerEffect = applyWindowContainerChange(wc, entry.getValue());
- effects |= containerEffect;
- // Lifecycle changes will trigger ensureConfig for everything.
- if ((effects & TRANSACT_EFFECTS_LIFECYCLE) == 0
- && (containerEffect & TRANSACT_EFFECTS_CLIENT_CONFIG) != 0) {
- haveConfigChanges.add(wc);
- }
- }
- if ((effects & TRANSACT_EFFECTS_LIFECYCLE) != 0) {
- // Already calls ensureActivityConfig
- mRootWindowContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS);
- } else if ((effects & TRANSACT_EFFECTS_CLIENT_CONFIG) != 0) {
- final PooledConsumer f = PooledLambda.obtainConsumer(
- ActivityRecord::ensureActivityConfiguration,
- PooledLambda.__(ActivityRecord.class), 0,
- false /* preserveWindow */);
- try {
- for (int i = haveConfigChanges.size() - 1; i >= 0; --i) {
- haveConfigChanges.valueAt(i).forAllActivities(f);
- }
- } finally {
- f.recycle();
- }
- }
- } finally {
- continueWindowLayout();
- }
- }
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
@Override
public boolean releaseActivityInstance(IBinder token) {
synchronized (mGlobalLock) {
@@ -4442,6 +4316,13 @@
}
}
+ @Override
+ public ITaskOrganizerController getTaskOrganizerController() {
+ mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS,
+ "getTaskOrganizerController()");
+ return mTaskOrganizerController;
+ }
+
/**
* Check that we have the features required for VR-related API calls, and throw an exception if
* not.
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index 3927d5f..0798a91 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -431,6 +431,8 @@
while (!candidates.isEmpty()) {
final WindowContainer current = candidates.removeFirst();
final WindowContainer parent = current.getParent();
+ siblings.clear();
+ siblings.add(current);
boolean canPromote = true;
if (parent == null) {
@@ -468,12 +470,11 @@
//
// [Task] +- [ActivityRecord1] (visible, in opening apps)
// +- [ActivityRecord2] (visible, not in opening apps)
- siblings.clear();
for (int j = 0; j < parent.getChildCount(); ++j) {
final WindowContainer sibling = parent.getChildAt(j);
- if (sibling == current || candidates.remove(sibling)) {
+ if (candidates.remove(sibling)) {
siblings.add(sibling);
- } else if (sibling.isVisible()) {
+ } else if (sibling != current && sibling.isVisible()) {
canPromote = false;
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 6e479b2..9f4cd88 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -207,6 +207,7 @@
import android.view.Gravity;
import android.view.IDisplayWindowInsetsController;
import android.view.ISystemGestureExclusionListener;
+import android.view.ITaskOrganizer;
import android.view.IWindow;
import android.view.InputChannel;
import android.view.InputDevice;
@@ -664,6 +665,9 @@
private final RootWindowContainer.FindTaskResult
mTmpFindTaskResult = new RootWindowContainer.FindTaskResult();
+ // When non-null, new stacks get put into this tile.
+ TaskTile mLaunchTile = null;
+
private final Consumer<WindowState> mUpdateWindowsForAnimator = w -> {
WindowStateAnimator winAnimator = w.mWinAnimator;
final ActivityRecord activity = w.mActivityRecord;
@@ -4275,8 +4279,15 @@
@VisibleForTesting
ActivityStack getTopStack() {
- return mTaskContainers.getChildCount() > 0
- ? mTaskContainers.getChildAt(mTaskContainers.getChildCount() - 1) : null;
+ // TODO(task-hierarchy): Just grab index -1 once tiles are in hierarchy.
+ for (int i = mTaskContainers.getChildCount() - 1; i >= 0; --i) {
+ final ActivityStack child = mTaskContainers.getChildAt(i);
+ if (child instanceof TaskTile) {
+ continue;
+ }
+ return child;
+ }
+ return null;
}
int getIndexOf(ActivityStack stack) {
@@ -4318,6 +4329,10 @@
}
private void addStackReferenceIfNeeded(ActivityStack stack) {
+ // TODO(task-hierarchy): Remove when tiles are in hierarchy.
+ if (stack instanceof TaskTile) {
+ return;
+ }
if (stack.isActivityTypeHome()) {
if (mRootHomeTask != null) {
if (!stack.isDescendantOf(mRootHomeTask)) {
@@ -4735,6 +4750,17 @@
mSplitScreenDividerAnchor = null;
}
}
+
+ @Override
+ void onChildPositionChanged(WindowContainer child) {
+ // TODO(task-hierarchy): Move functionality to TaskTile when it's a proper parent.
+ TaskTile tile = ((ActivityStack) child).getTile();
+ if (tile == null) {
+ return;
+ }
+ mAtmService.mTaskOrganizerController.dispatchTaskInfoChanged(
+ tile, false /* force */);
+ }
}
private final class AboveAppWindowContainers extends NonAppWindowContainers {
@@ -6271,6 +6297,10 @@
}
boolean isTopNotPinnedStack(ActivityStack stack) {
+ // TODO(task-hierarchy): Remove when tiles are in hierarchy.
+ if (stack instanceof TaskTile) {
+ return false;
+ }
for (int i = getStackCount() - 1; i >= 0; --i) {
final ActivityStack current = getStackAt(i);
if (!current.inPinnedWindowingMode()) {
@@ -6685,6 +6715,19 @@
return getHomeActivityForUser(mRootWindowContainer.mCurrentUser);
}
+ // TODO(task-hierarchy): Remove when tiles are in hierarchy.
+ void addTile(TaskTile tile) {
+ mTaskContainers.addChild(tile, POSITION_BOTTOM);
+ ITaskOrganizer organizer = mAtmService.mTaskOrganizerController.getTaskOrganizer(
+ tile.getWindowingMode());
+ tile.setTaskOrganizer(organizer);
+ }
+
+ // TODO(task-hierarchy): Remove when tiles are in hierarchy.
+ void removeTile(TaskTile tile) {
+ mTaskContainers.removeChild(tile);
+ }
+
@Nullable
ActivityRecord getHomeActivityForUser(int userId) {
final ActivityStack homeStack = getRootHomeTask();
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index da77314..efe79b3 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -526,7 +526,7 @@
mService.mH.removeCallbacks(mDisplayRotationHandlerTimeout);
mIsWaitingForRemoteRotation = false;
mDisplayContent.sendNewConfiguration();
- mService.mAtmService.applyContainerTransaction(t);
+ mService.mAtmService.mTaskOrganizerController.applyContainerTransaction(t);
}
}
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index 568966a..289ac4c 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -60,6 +60,8 @@
w.notifyInsetsChanged();
}
};
+ private final InsetsControlTarget mEmptyImeControlTarget = () -> {
+ };
InsetsStateController(DisplayContent displayContent) {
mDisplayContent = displayContent;
@@ -182,7 +184,10 @@
}
void onImeControlTargetChanged(@Nullable InsetsControlTarget imeTarget) {
- onControlChanged(ITYPE_IME, imeTarget);
+
+ // Make sure that we always have a control target for the IME, even if the IME target is
+ // null. Otherwise there is no leash that will hide it and IME becomes "randomly" visible.
+ onControlChanged(ITYPE_IME, imeTarget != null ? imeTarget : mEmptyImeControlTarget);
notifyPendingInsetsControlChanged();
}
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index 647be0f..9770947 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -388,11 +388,12 @@
// surfaces needs to be done immediately.
mWindowManager.executeAppTransition();
- // After reordering the stacks, reset the minimized state. At this point, either
- // the target activity is now top-most and we will stay minimized (if in
- // split-screen), or we will have returned to the app, and the minimized state
- // should be reset
- mWindowManager.checkSplitScreenMinimizedChanged(true /* animate */);
+ if (targetStack.getTile() != null) {
+ // Client state may have changed during the recents animation, so force
+ // send task info so the client can synchronize its state.
+ mService.mTaskOrganizerController.dispatchTaskInfoChanged(
+ targetStack.mTile, true /* force */);
+ }
} catch (Exception e) {
Slog.e(TAG, "Failed to clean up recents activity", e);
throw e;
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index e6fd512..a13399b 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -1012,6 +1012,9 @@
mWmService.scheduleAnimationLocked();
+ // Send any pending task-info changes that were queued-up during a layout deferment
+ mWmService.mAtmService.mTaskOrganizerController.dispatchPendingTaskInfoChanges();
+
if (DEBUG_WINDOW_TRACE) Slog.e(TAG,
"performSurfacePlacementInner exit: animating="
+ mWmService.mAnimator.isAnimating());
@@ -2959,6 +2962,12 @@
case ACTIVITY_TYPE_RECENTS: return r.isActivityTypeRecents();
case ACTIVITY_TYPE_ASSISTANT: return r.isActivityTypeAssistant();
}
+ // TODO(task-hierarchy): Find another way to differentiate tile from normal stack once it is
+ // part of the hierarchy
+ if (stack instanceof TaskTile) {
+ // Don't launch directly into tiles.
+ return false;
+ }
// There is a 1-to-1 relationship between stack and task when not in
// primary split-windowing mode.
if (stack.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 36cae1f..271f559 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -1257,7 +1257,7 @@
if (affinityIntent != null) return affinityIntent;
// Probably a task that contains other tasks, so return the intent for the top task?
final Task topTask = getTopMostTask();
- return topTask != null ? topTask.getBaseIntent() : null;
+ return (topTask != this && topTask != null) ? topTask.getBaseIntent() : null;
}
/** Returns the first non-finishing activity from the bottom. */
@@ -3214,7 +3214,8 @@
info.taskId = mTaskId;
info.displayId = getDisplayId();
info.isRunning = getTopNonFinishingActivity() != null;
- info.baseIntent = new Intent(getBaseIntent());
+ final Intent baseIntent = getBaseIntent();
+ info.baseIntent = baseIntent == null ? new Intent() : baseIntent;
info.baseActivity = mReuseActivitiesReport.base != null
? mReuseActivitiesReport.base.intent.getComponent()
: null;
@@ -3229,6 +3230,10 @@
info.supportsSplitScreenMultiWindow = supportsSplitScreenWindowingMode();
info.resizeMode = mResizeMode;
info.configuration.setTo(getConfiguration());
+ info.token = mRemoteToken;
+ // Get's the first non-undefined activity type among this and children. Can't use
+ // configuration.windowConfiguration because that would only be this level.
+ info.topActivityType = getActivityType();
}
/**
@@ -3375,7 +3380,7 @@
if (affinity != null) {
sb.append(" A=");
sb.append(affinity);
- } else if (intent != null) {
+ } else if (intent != null && intent.getComponent() != null) {
sb.append(" I=");
sb.append(intent.getComponent().flattenToShortString());
} else if (affinityIntent != null && affinityIntent.getComponent() != null) {
@@ -3865,7 +3870,12 @@
boolean isControlledByTaskOrganizer() {
final Task rootTask = getRootTask();
- return rootTask == this && rootTask.mTaskOrganizer != null;
+ return rootTask == this && rootTask.mTaskOrganizer != null
+ // TODO(task-hierarchy): Figure out how to control nested tasks.
+ // For now, if this is in a tile let WM drive.
+ && !(rootTask instanceof TaskTile)
+ && !(rootTask instanceof ActivityStack
+ && ((ActivityStack) rootTask).getTile() != null);
}
@Override
@@ -3893,6 +3903,9 @@
}
void setTaskOrganizer(ITaskOrganizer organizer) {
+ if (mTaskOrganizer == organizer) {
+ return;
+ }
// Let the old organizer know it has lost control.
if (mTaskOrganizer != null) {
sendTaskVanished();
@@ -3918,8 +3931,6 @@
public void updateSurfacePosition() {
// Avoid fighting with the TaskOrganizer over Surface position.
if (isControlledByTaskOrganizer()) {
- getPendingTransaction().setPosition(mSurfaceControl, 0, 0);
- scheduleAnimation();
return;
} else {
super.updateSurfacePosition();
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 66c65e2..44a6fc9 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -16,26 +16,51 @@
package com.android.server.wm;
-import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
+
+import android.annotation.Nullable;
+import android.app.ActivityManager.RunningTaskInfo;
+import android.app.ITaskOrganizerController;
+import android.app.WindowConfiguration;
+import android.content.pm.ActivityInfo;
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
+import android.util.ArraySet;
import android.util.Slog;
import android.view.ITaskOrganizer;
-import android.view.SurfaceControl;
+import android.view.IWindowContainer;
+import android.view.WindowContainerTransaction;
+
+import com.android.internal.util.function.pooled.PooledConsumer;
+import com.android.internal.util.function.pooled.PooledLambda;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.WeakHashMap;
/**
* Stores the TaskOrganizers associated with a given windowing mode and
* their associated state.
*/
-class TaskOrganizerController {
+class TaskOrganizerController extends ITaskOrganizerController.Stub {
private static final String TAG = "TaskOrganizerController";
- private WindowManagerGlobalLock mGlobalLock;
+ /** Flag indicating that an applied transaction may have effected lifecycle */
+ private static final int TRANSACT_EFFECTS_CLIENT_CONFIG = 1;
+ private static final int TRANSACT_EFFECTS_LIFECYCLE = 1 << 1;
+
+ private final WindowManagerGlobalLock mGlobalLock;
private class DeathRecipient implements IBinder.DeathRecipient {
int mWindowingMode;
@@ -87,11 +112,20 @@
final HashMap<Integer, ITaskOrganizer> mTaskOrganizersByPendingSyncId = new HashMap();
+ private final WeakHashMap<Task, RunningTaskInfo> mLastSentTaskInfos = new WeakHashMap<>();
+ private final ArrayList<Task> mPendingTaskInfoChanges = new ArrayList<>();
+
final ActivityTaskManagerService mService;
- TaskOrganizerController(ActivityTaskManagerService atm, WindowManagerGlobalLock lock) {
+ RunningTaskInfo mTmpTaskInfo;
+
+ TaskOrganizerController(ActivityTaskManagerService atm) {
mService = atm;
- mGlobalLock = lock;
+ mGlobalLock = atm.mGlobalLock;
+ }
+
+ private void enforceStackPermission(String func) {
+ mService.mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, func);
}
private void clearIfNeeded(int windowingMode) {
@@ -106,26 +140,35 @@
* If there was already a TaskOrganizer for this windowing mode it will be evicted
* and receive taskVanished callbacks in the process.
*/
- void registerTaskOrganizer(ITaskOrganizer organizer, int windowingMode) {
- if (windowingMode != WINDOWING_MODE_PINNED &&
- windowingMode != WINDOWING_MODE_MULTI_WINDOW) {
- throw new UnsupportedOperationException(
- "As of now only Pinned and Multiwindow windowing modes are"
- + " supported for registerTaskOrganizer");
-
+ @Override
+ public void registerTaskOrganizer(ITaskOrganizer organizer, int windowingMode) {
+ if (windowingMode != WINDOWING_MODE_PINNED
+ && windowingMode != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
+ && windowingMode != WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
+ && windowingMode != WINDOWING_MODE_MULTI_WINDOW) {
+ throw new UnsupportedOperationException("As of now only Pinned/Split/Multiwindow"
+ + " windowing modes are supported for registerTaskOrganizer");
}
- clearIfNeeded(windowingMode);
- DeathRecipient dr = new DeathRecipient(organizer, windowingMode);
+ enforceStackPermission("registerTaskOrganizer()");
+ final long origId = Binder.clearCallingIdentity();
try {
- organizer.asBinder().linkToDeath(dr, 0);
- } catch (RemoteException e) {
- Slog.e(TAG, "TaskOrganizer failed to register death recipient");
+ synchronized (mGlobalLock) {
+ clearIfNeeded(windowingMode);
+ DeathRecipient dr = new DeathRecipient(organizer, windowingMode);
+ try {
+ organizer.asBinder().linkToDeath(dr, 0);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "TaskOrganizer failed to register death recipient");
+ }
+
+ final TaskOrganizerState state = new TaskOrganizerState(organizer, dr);
+ mTaskOrganizersForWindowingMode.put(windowingMode, state);
+
+ mTaskOrganizerStates.put(organizer, state);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
}
-
- final TaskOrganizerState state = new TaskOrganizerState(organizer, dr);
- mTaskOrganizersForWindowingMode.put(windowingMode, state);
-
- mTaskOrganizerStates.put(organizer, state);
}
ITaskOrganizer getTaskOrganizer(int windowingMode) {
@@ -138,7 +181,7 @@
private void sendTaskAppeared(ITaskOrganizer organizer, Task task) {
try {
- organizer.taskAppeared(task.getRemoteToken(), task.getTaskInfo());
+ organizer.taskAppeared(task.getTaskInfo());
} catch (Exception e) {
Slog.e(TAG, "Exception sending taskAppeared callback" + e);
}
@@ -167,4 +210,254 @@
// we do this AFTER sending taskVanished.
state.removeTask(task);
}
+
+ @Override
+ public RunningTaskInfo createRootTask(int displayId, int windowingMode) {
+ enforceStackPermission("createRootTask()");
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ synchronized (mGlobalLock) {
+ DisplayContent display = mService.mRootWindowContainer.getDisplayContent(displayId);
+ if (display == null) {
+ return null;
+ }
+ final int nextId = display.getNextStackId();
+ TaskTile tile = new TaskTile(mService, nextId, windowingMode);
+ display.addTile(tile);
+ RunningTaskInfo out = new RunningTaskInfo();
+ tile.fillTaskInfo(out);
+ mLastSentTaskInfos.put(tile, out);
+ return out;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
+ @Override
+ public boolean deleteRootTask(IWindowContainer token) {
+ enforceStackPermission("deleteRootTask()");
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ synchronized (mGlobalLock) {
+ TaskTile tile = TaskTile.forToken(token.asBinder());
+ if (tile == null) {
+ return false;
+ }
+ tile.removeImmediately();
+ return true;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
+ void dispatchPendingTaskInfoChanges() {
+ if (mService.mWindowManager.mWindowPlacerLocked.isLayoutDeferred()) {
+ return;
+ }
+ for (int i = 0, n = mPendingTaskInfoChanges.size(); i < n; ++i) {
+ dispatchTaskInfoChanged(mPendingTaskInfoChanges.get(i), false /* force */);
+ }
+ mPendingTaskInfoChanges.clear();
+ }
+
+ void dispatchTaskInfoChanged(Task task, boolean force) {
+ if (!force && mService.mWindowManager.mWindowPlacerLocked.isLayoutDeferred()) {
+ // Defer task info reporting while layout is deferred. This is because layout defer
+ // blocks tend to do lots of re-ordering which can mess up animations in receivers.
+ mPendingTaskInfoChanges.remove(task);
+ mPendingTaskInfoChanges.add(task);
+ return;
+ }
+ RunningTaskInfo lastInfo = mLastSentTaskInfos.get(task);
+ if (mTmpTaskInfo == null) {
+ mTmpTaskInfo = new RunningTaskInfo();
+ }
+ task.fillTaskInfo(mTmpTaskInfo);
+ boolean changed = lastInfo == null
+ || mTmpTaskInfo.topActivityType != lastInfo.topActivityType
+ || mTmpTaskInfo.isResizable() != lastInfo.isResizable();
+ if (!(changed || force)) {
+ return;
+ }
+ final RunningTaskInfo newInfo = mTmpTaskInfo;
+ mLastSentTaskInfos.put(task, mTmpTaskInfo);
+ // Since we've stored this, clean up the reference so a new one will be created next time.
+ // Transferring it this way means we only have to construct new RunningTaskInfos when they
+ // change.
+ mTmpTaskInfo = null;
+
+ if (task.mTaskOrganizer != null) {
+ try {
+ task.mTaskOrganizer.onTaskInfoChanged(newInfo);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+
+ @Override
+ public IWindowContainer getImeTarget(int displayId) {
+ enforceStackPermission("getImeTarget()");
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ synchronized (mGlobalLock) {
+ DisplayContent dc = mService.mWindowManager.mRoot
+ .getDisplayContent(displayId);
+ if (dc == null || dc.mInputMethodTarget == null) {
+ return null;
+ }
+ // Avoid WindowState#getRootTask() so we don't attribute system windows to a task.
+ final Task task = dc.mInputMethodTarget.getTask();
+ if (task == null) {
+ return null;
+ }
+ ActivityStack rootTask = (ActivityStack) task.getRootTask();
+ final TaskTile tile = rootTask.getTile();
+ if (tile != null) {
+ rootTask = tile;
+ }
+ return rootTask.mRemoteToken;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
+ @Override
+ public void setLaunchRoot(int displayId, @Nullable IWindowContainer tile) {
+ enforceStackPermission("setLaunchRoot()");
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ synchronized (mGlobalLock) {
+ DisplayContent display = mService.mRootWindowContainer.getDisplayContent(displayId);
+ if (display == null) {
+ return;
+ }
+ TaskTile taskTile = tile == null ? null : TaskTile.forToken(tile.asBinder());
+ if (taskTile == null) {
+ display.mLaunchTile = null;
+ return;
+ }
+ if (taskTile.getDisplay() != display) {
+ throw new RuntimeException("Can't set launch root for display " + displayId
+ + " to task on display " + taskTile.getDisplay().getDisplayId());
+ }
+ display.mLaunchTile = taskTile;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
+ private int sanitizeAndApplyChange(WindowContainer container,
+ WindowContainerTransaction.Change change) {
+ if (!(container instanceof Task)) {
+ throw new RuntimeException("Invalid token in task transaction");
+ }
+ // The "client"-facing API should prevent bad changes; however, just in case, sanitize
+ // masks here.
+ int configMask = change.getConfigSetMask();
+ int windowMask = change.getWindowSetMask();
+ configMask &= ActivityInfo.CONFIG_WINDOW_CONFIGURATION
+ | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
+ windowMask &= WindowConfiguration.WINDOW_CONFIG_BOUNDS;
+ int effects = 0;
+ if (configMask != 0) {
+ Configuration c = new Configuration(container.getRequestedOverrideConfiguration());
+ c.setTo(change.getConfiguration(), configMask, windowMask);
+ container.onRequestedOverrideConfigurationChanged(c);
+ // TODO(b/145675353): remove the following once we could apply new bounds to the
+ // pinned stack together with its children.
+ resizePinnedStackIfNeeded(container, configMask, windowMask, c);
+ effects |= TRANSACT_EFFECTS_CLIENT_CONFIG;
+ }
+ if ((change.getChangeMask() & WindowContainerTransaction.Change.CHANGE_FOCUSABLE) != 0) {
+ if (container.setFocusable(change.getFocusable())) {
+ effects |= TRANSACT_EFFECTS_LIFECYCLE;
+ }
+ }
+ return effects;
+ }
+
+ private void resizePinnedStackIfNeeded(ConfigurationContainer container, int configMask,
+ int windowMask, Configuration config) {
+ if ((container instanceof ActivityStack)
+ && ((configMask & ActivityInfo.CONFIG_WINDOW_CONFIGURATION) != 0)
+ && ((windowMask & WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0)) {
+ final ActivityStack stack = (ActivityStack) container;
+ if (stack.inPinnedWindowingMode()) {
+ stack.resize(config.windowConfiguration.getBounds(),
+ null /* tempTaskBounds */, null /* tempTaskInsetBounds */,
+ PRESERVE_WINDOWS, true /* deferResume */);
+ }
+ }
+ }
+
+ private int applyWindowContainerChange(WindowContainer wc,
+ WindowContainerTransaction.Change c) {
+ int effects = sanitizeAndApplyChange(wc, c);
+
+ Rect enterPipBounds = c.getEnterPipBounds();
+ if (enterPipBounds != null) {
+ Task tr = (Task) wc;
+ mService.mStackSupervisor.updatePictureInPictureMode(tr,
+ enterPipBounds, true);
+ }
+ return effects;
+ }
+
+ @Override
+ public void applyContainerTransaction(WindowContainerTransaction t) {
+ enforceStackPermission("applyContainerTransaction()");
+ if (t == null) {
+ return;
+ }
+ long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mGlobalLock) {
+ int effects = 0;
+ mService.deferWindowLayout();
+ try {
+ ArraySet<WindowContainer> haveConfigChanges = new ArraySet<>();
+ Iterator<Map.Entry<IBinder, WindowContainerTransaction.Change>> entries =
+ t.getChanges().entrySet().iterator();
+ while (entries.hasNext()) {
+ final Map.Entry<IBinder, WindowContainerTransaction.Change> entry =
+ entries.next();
+ final WindowContainer wc = WindowContainer.RemoteToken.fromBinder(
+ entry.getKey()).getContainer();
+ int containerEffect = applyWindowContainerChange(wc, entry.getValue());
+ effects |= containerEffect;
+ // Lifecycle changes will trigger ensureConfig for everything.
+ if ((effects & TRANSACT_EFFECTS_LIFECYCLE) == 0
+ && (containerEffect & TRANSACT_EFFECTS_CLIENT_CONFIG) != 0) {
+ haveConfigChanges.add(wc);
+ }
+ }
+ if ((effects & TRANSACT_EFFECTS_LIFECYCLE) != 0) {
+ // Already calls ensureActivityConfig
+ mService.mRootWindowContainer.ensureActivitiesVisible(
+ null, 0, PRESERVE_WINDOWS);
+ } else if ((effects & TRANSACT_EFFECTS_CLIENT_CONFIG) != 0) {
+ final PooledConsumer f = PooledLambda.obtainConsumer(
+ ActivityRecord::ensureActivityConfiguration,
+ PooledLambda.__(ActivityRecord.class), 0,
+ false /* preserveWindow */);
+ try {
+ for (int i = haveConfigChanges.size() - 1; i >= 0; --i) {
+ haveConfigChanges.valueAt(i).forAllActivities(f);
+ }
+ } finally {
+ f.recycle();
+ }
+ }
+ } finally {
+ mService.continueWindowLayout();
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
index e47eaee..f4e4245 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -36,7 +36,6 @@
import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
-
import static com.android.internal.policy.DecorView.NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES;
import static com.android.internal.policy.DecorView.STATUS_BAR_COLOR_VIEW_ATTRIBUTES;
import static com.android.internal.policy.DecorView.getColorViewLeftInset;
@@ -188,8 +187,9 @@
return null;
}
sysUiVis = topFullscreenOpaqueWindow.getSystemUiVisibility();
- windowFlags = topFullscreenOpaqueWindow.getAttrs().flags;
- windowPrivateFlags = topFullscreenOpaqueWindow.getAttrs().privateFlags;
+ WindowManager.LayoutParams attrs = topFullscreenOpaqueWindow.mAttrs;
+ windowFlags = attrs.flags;
+ windowPrivateFlags = attrs.privateFlags;
layoutParams.packageName = mainWindow.getAttrs().packageName;
layoutParams.windowAnimations = mainWindow.getAttrs().windowAnimations;
@@ -204,6 +204,14 @@
layoutParams.width = LayoutParams.MATCH_PARENT;
layoutParams.height = LayoutParams.MATCH_PARENT;
layoutParams.systemUiVisibility = sysUiVis;
+ layoutParams.insetsFlags.behavior
+ = topFullscreenOpaqueWindow.mAttrs.insetsFlags.behavior;
+ layoutParams.insetsFlags.appearance
+ = topFullscreenOpaqueWindow.mAttrs.insetsFlags.appearance;
+ layoutParams.setFitInsetsTypes(attrs.getFitInsetsTypes());
+ layoutParams.setFitInsetsSides(attrs.getFitInsetsSides());
+ layoutParams.setFitInsetsIgnoringVisibility(attrs.isFitInsetsIgnoringVisibility());
+
layoutParams.setTitle(String.format(TITLE_FORMAT, task.mTaskId));
final TaskDescription td = task.getTaskDescription();
diff --git a/services/core/java/com/android/server/wm/TaskTile.java b/services/core/java/com/android/server/wm/TaskTile.java
new file mode 100644
index 0000000..add11d6
--- /dev/null
+++ b/services/core/java/com/android/server/wm/TaskTile.java
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2020 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.wm;
+
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+
+import android.app.ActivityManager;
+import android.app.TaskInfo;
+import android.app.WindowConfiguration;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.os.IBinder;
+import android.util.Slog;
+import android.view.SurfaceControl;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+
+/**
+ * A Tile. Right now this acts as a proxy for manipulating non-child stacks. Eventually, this
+ * can become an actual parent.
+ */
+// TODO(task-hierarchy): Remove when tasks can nest >2 or when single tasks can handle their
+// own lifecycles.
+public class TaskTile extends ActivityStack {
+ private static final String TAG = "TaskTile";
+ final ArrayList<WindowContainer> mChildren = new ArrayList<>();
+
+ private static ActivityInfo createEmptyActivityInfo() {
+ ActivityInfo info = new ActivityInfo();
+ info.applicationInfo = new ApplicationInfo();
+ return info;
+ }
+
+ TaskTile(ActivityTaskManagerService atmService, int id, int windowingMode) {
+ super(atmService, id, new Intent() /*intent*/, null /*affinityIntent*/, null /*affinity*/,
+ null /*rootAffinity*/, null /*realActivity*/, null /*origActivity*/,
+ false /*rootWasReset*/, false /*autoRemoveRecents*/, false /*askedCompatMode*/,
+ 0 /*userId*/, 0 /*effectiveUid*/, null /*lastDescription*/,
+ System.currentTimeMillis(), true /*neverRelinquishIdentity*/,
+ new ActivityManager.TaskDescription(), id, INVALID_TASK_ID, INVALID_TASK_ID,
+ 0 /*taskAffiliationColor*/, 0 /*callingUid*/, "" /*callingPackage*/,
+ RESIZE_MODE_RESIZEABLE, false /*supportsPictureInPicture*/,
+ false /*_realActivitySuspended*/, false /*userSetupComplete*/, INVALID_MIN_SIZE,
+ INVALID_MIN_SIZE, createEmptyActivityInfo(), null /*voiceSession*/,
+ null /*voiceInteractor*/, null /*stack*/);
+ getRequestedOverrideConfiguration().windowConfiguration.setWindowingMode(windowingMode);
+ }
+
+ @Override
+ void onDisplayChanged(DisplayContent dc) {
+ mDisplayContent = null;
+ if (dc != null) {
+ dc.getPendingTransaction().merge(getPendingTransaction());
+ }
+ mDisplayContent = dc;
+ // Virtual parent, so don't notify children.
+ }
+
+ /**
+ * If there is a disconnection, this will clean up any vestigial surfaces left on the tile
+ * leash by moving known children to a new surfacecontrol and then removing the old one.
+ */
+ void cleanupSurfaces() {
+ if (mSurfaceControl == null) {
+ return;
+ }
+ SurfaceControl oldSurface = mSurfaceControl;
+ WindowContainer parentWin = getParent();
+ if (parentWin == null) {
+ return;
+ }
+ mSurfaceControl = parentWin.makeChildSurface(null).setName("TaskTile " + mTaskId + " - "
+ + getRequestedOverrideWindowingMode()).setContainerLayer().build();
+ SurfaceControl.Transaction t = parentWin.getPendingTransaction();
+ t.show(mSurfaceControl);
+ for (int i = 0; i < mChildren.size(); ++i) {
+ if (mChildren.get(i).getSurfaceControl() == null) {
+ continue;
+ }
+ mChildren.get(i).reparentSurfaceControl(t, mSurfaceControl);
+ }
+ t.remove(oldSurface);
+ }
+
+ @Override
+ protected void addChild(WindowContainer child, Comparator<WindowContainer> comparator) {
+ throw new RuntimeException("Improper use of addChild() on Tile");
+ }
+
+ @Override
+ void addChild(WindowContainer child, int index) {
+ mChildren.add(child);
+ if (child instanceof ActivityStack) {
+ ((ActivityStack) child).setTile(this);
+ }
+ mAtmService.mTaskOrganizerController.dispatchTaskInfoChanged(
+ this, false /* force */);
+ }
+
+ @Override
+ void removeChild(WindowContainer child) {
+ if (child instanceof ActivityStack) {
+ ((ActivityStack) child).setTile(null);
+ }
+ mChildren.remove(child);
+ mAtmService.mTaskOrganizerController.dispatchTaskInfoChanged(
+ this, false /* force */);
+ }
+
+ void removeAllChildren() {
+ for (int i = mChildren.size() - 1; i >= 0; --i) {
+ final WindowContainer child = mChildren.get(i);
+ if (child instanceof ActivityStack) {
+ ((ActivityStack) child).setTile(null);
+ }
+ }
+ mChildren.clear();
+ mAtmService.mTaskOrganizerController.dispatchTaskInfoChanged(
+ this, false /* force */);
+ }
+
+ @Override
+ protected int getChildCount() {
+ // Currently 0 as this isn't a proper hierarchy member yet.
+ return 0;
+ }
+
+ @Override
+ public void setWindowingMode(/*@WindowConfiguration.WindowingMode*/ int windowingMode) {
+ Configuration c = new Configuration(getRequestedOverrideConfiguration());
+ c.windowConfiguration.setWindowingMode(windowingMode);
+ onRequestedOverrideConfigurationChanged(c);
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newParentConfig) {
+ super.onConfigurationChanged(newParentConfig);
+ for (int i = mChildren.size() - 1; i >= 0; --i) {
+ final WindowContainer child = mChildren.get(i);
+ child.onConfigurationChanged(child.getParent().getConfiguration());
+ }
+ }
+
+ /**
+ * Until this can be part of the hierarchy, the Stack level can use this utility during
+ * resolveOverrideConfig to simulate inheritance.
+ */
+ void updateResolvedConfig(Configuration inOutResolvedConfig) {
+ Rect resolveBounds = inOutResolvedConfig.windowConfiguration.getBounds();
+ if (resolveBounds == null || resolveBounds.isEmpty()) {
+ resolveBounds.set(getRequestedOverrideBounds());
+ }
+ int stackMode = inOutResolvedConfig.windowConfiguration.getWindowingMode();
+ if (stackMode == WindowConfiguration.WINDOWING_MODE_UNDEFINED
+ || stackMode == WindowConfiguration.WINDOWING_MODE_FULLSCREEN) {
+ // Also replace FULLSCREEN because we interpret FULLSCREEN as "fill parent"
+ inOutResolvedConfig.windowConfiguration.setWindowingMode(
+ getRequestedOverrideWindowingMode());
+ }
+ if (inOutResolvedConfig.smallestScreenWidthDp
+ == Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) {
+ inOutResolvedConfig.smallestScreenWidthDp =
+ getRequestedOverrideConfiguration().smallestScreenWidthDp;
+ }
+ }
+
+ @Override
+ void fillTaskInfo(TaskInfo info) {
+ super.fillTaskInfo(info);
+ WindowContainer top = null;
+ // Check mChildren.isEmpty directly because hasChild() -> getChildCount() always returns 0
+ if (!mChildren.isEmpty()) {
+ // Find the top-most root task which is a virtual child of this Tile. Because this is a
+ // virtual parent, the mChildren order here isn't changed during hierarchy operations.
+ WindowContainer parent = mChildren.get(0).getParent();
+ for (int i = parent.getChildCount() - 1; i >= 0; --i) {
+ if (mChildren.contains(parent.getChildAt(i))) {
+ top = parent.getChildAt(i);
+ break;
+ }
+ }
+ }
+ final Task topTask = top == null ? null : top.getTopMostTask();
+ boolean isResizable = topTask == null || topTask.isResizeable();
+ info.resizeMode = isResizable ? RESIZE_MODE_RESIZEABLE : RESIZE_MODE_UNRESIZEABLE;
+ info.topActivityType = top == null ? ACTIVITY_TYPE_UNDEFINED : top.getActivityType();
+ info.configuration.setTo(getRequestedOverrideConfiguration());
+ }
+
+ @Override
+ void removeImmediately() {
+ removeAllChildren();
+ super.removeImmediately();
+ }
+
+ static TaskTile forToken(IBinder token) {
+ try {
+ return (TaskTile) ((TaskToken) token).getContainer();
+ } catch (ClassCastException e) {
+ Slog.w(TAG, "Bad tile token: " + token, e);
+ return null;
+ }
+ }
+}
diff --git a/services/core/jni/com_android_server_SystemServer.cpp b/services/core/jni/com_android_server_SystemServer.cpp
index 78b64ca..67254b8 100644
--- a/services/core/jni/com_android_server_SystemServer.cpp
+++ b/services/core/jni/com_android_server_SystemServer.cpp
@@ -14,6 +14,12 @@
* limitations under the License.
*/
+#include <dlfcn.h>
+#include <pthread.h>
+
+#include <chrono>
+#include <thread>
+
#include <jni.h>
#include <nativehelper/JNIHelp.h>
@@ -25,12 +31,17 @@
#include <sensorservicehidl/SensorManager.h>
#include <bionic/malloc.h>
+#include <bionic/reserved_signals.h>
+#include <android-base/properties.h>
#include <cutils/properties.h>
#include <utils/Log.h>
#include <utils/misc.h>
#include <utils/AndroidThreads.h>
+using android::base::GetIntProperty;
+using namespace std::chrono_literals;
+
namespace android {
static void android_server_SystemServer_startSensorService(JNIEnv* /* env */, jobject /* clazz */) {
@@ -68,7 +79,50 @@
static void android_server_SystemServer_initZygoteChildHeapProfiling(JNIEnv* /* env */,
jobject /* clazz */) {
- android_mallopt(M_INIT_ZYGOTE_CHILD_PROFILING, nullptr, 0);
+ android_mallopt(M_INIT_ZYGOTE_CHILD_PROFILING, nullptr, 0);
+}
+
+static int get_current_max_fd() {
+ // Not actually guaranteed to be the max, but close enough for our purposes.
+ int fd = open("/dev/null", O_RDONLY | O_CLOEXEC);
+ LOG_ALWAYS_FATAL_IF(fd == -1, "failed to open /dev/null: %s", strerror(errno));
+ close(fd);
+ return fd;
+}
+
+static const char kFdLeakEnableThresholdProperty[] = "persist.sys.debug.fdtrack_enable_threshold";
+static const char kFdLeakAbortThresholdProperty[] = "persist.sys.debug.fdtrack_abort_threshold";
+static const char kFdLeakCheckIntervalProperty[] = "persist.sys.debug.fdtrack_interval";
+
+static void android_server_SystemServer_spawnFdLeakCheckThread(JNIEnv*, jobject) {
+ std::thread([]() {
+ pthread_setname_np(pthread_self(), "FdLeakCheckThread");
+ bool loaded = false;
+ while (true) {
+ const int enable_threshold = GetIntProperty(kFdLeakEnableThresholdProperty, 1024);
+ const int abort_threshold = GetIntProperty(kFdLeakAbortThresholdProperty, 2048);
+ const int check_interval = GetIntProperty(kFdLeakCheckIntervalProperty, 120);
+ int max_fd = get_current_max_fd();
+ if (max_fd > enable_threshold && !loaded) {
+ loaded = true;
+ ALOGE("fd count above threshold of %d, starting fd backtraces", enable_threshold);
+ if (dlopen("libfdtrack.so", RTLD_GLOBAL) == nullptr) {
+ ALOGE("failed to load libfdtrack.so: %s", dlerror());
+ }
+ } else if (max_fd > abort_threshold) {
+ raise(BIONIC_SIGNAL_FDTRACK);
+
+ // Wait for a bit to allow fdtrack to dump backtraces to logcat.
+ std::this_thread::sleep_for(5s);
+
+ LOG_ALWAYS_FATAL(
+ "b/140703823: aborting due to fd leak: check logs for fd "
+ "backtraces");
+ }
+
+ std::this_thread::sleep_for(std::chrono::seconds(check_interval));
+ }
+ }).detach();
}
/*
@@ -80,6 +134,9 @@
{ "startHidlServices", "()V", (void*) android_server_SystemServer_startHidlServices },
{ "initZygoteChildHeapProfiling", "()V",
(void*) android_server_SystemServer_initZygoteChildHeapProfiling },
+ { "spawnFdLeakCheckThread", "()V",
+ (void*) android_server_SystemServer_spawnFdLeakCheckThread },
+
};
int register_android_server_SystemServer(JNIEnv* env)
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index b7162f9..2a6b029 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -365,6 +365,12 @@
*/
private static native void initZygoteChildHeapProfiling();
+
+ /**
+ * Spawn a thread that monitors for fd leaks.
+ */
+ private static native void spawnFdLeakCheckThread();
+
/**
* The main entry point from zygote.
*/
@@ -499,6 +505,11 @@
initZygoteChildHeapProfiling();
}
+ // Debug builds - spawn a thread to monitor for fd leaks.
+ if (Build.IS_DEBUGGABLE) {
+ spawnFdLeakCheckThread();
+ }
+
// Check whether we failed to shut down last time we tried.
// This call may not return.
performPendingShutdown();
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index b7c9001..d2ddff3 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -66,8 +66,6 @@
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.SUSPEND_APPS"/>
<uses-permission android:name="android.permission.CONTROL_KEYGUARD"/>
- <uses-permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG"/>
- <uses-permission android:name="android.permission.LOG_COMPAT_CHANGE"/>
<uses-permission android:name="android.permission.MANAGE_BIND_INSTANT_SERVICE"/>
<uses-permission android:name="android.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS" />
<uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
index d22502d..4532400 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
@@ -16,9 +16,6 @@
package com.android.server.wm;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
-
import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
@@ -27,17 +24,14 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.when;
import android.app.Activity;
-import android.app.ActivityManager;
import android.app.PictureInPictureParams;
import android.app.servertransaction.ClientTransaction;
import android.app.servertransaction.EnterPipRequestedItem;
@@ -46,7 +40,6 @@
import android.os.IBinder;
import android.os.RemoteException;
import android.view.IDisplayWindowListener;
-import android.view.WindowContainerTransaction;
import androidx.test.filters.MediumTest;
@@ -126,47 +119,6 @@
}
@Test
- public void testTaskTransaction() {
- removeGlobalMinSizeRestriction();
- final ActivityStack stack = new StackBuilder(mRootWindowContainer)
- .setWindowingMode(WINDOWING_MODE_FREEFORM).build();
- final Task task = stack.getTopMostTask();
- WindowContainerTransaction t = new WindowContainerTransaction();
- Rect newBounds = new Rect(10, 10, 100, 100);
- t.setBounds(task.mRemoteToken, new Rect(10, 10, 100, 100));
- mService.applyContainerTransaction(t);
- assertEquals(newBounds, task.getBounds());
- }
-
- @Test
- public void testStackTransaction() {
- removeGlobalMinSizeRestriction();
- final ActivityStack stack = new StackBuilder(mRootWindowContainer)
- .setWindowingMode(WINDOWING_MODE_FREEFORM).build();
- ActivityManager.StackInfo info =
- mService.getStackInfo(WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD);
- WindowContainerTransaction t = new WindowContainerTransaction();
- assertEquals(stack.mRemoteToken, info.stackToken);
- Rect newBounds = new Rect(10, 10, 100, 100);
- t.setBounds(info.stackToken, new Rect(10, 10, 100, 100));
- mService.applyContainerTransaction(t);
- assertEquals(newBounds, stack.getBounds());
- }
-
- @Test
- public void testContainerChanges() {
- removeGlobalMinSizeRestriction();
- final ActivityStack stack = new StackBuilder(mRootWindowContainer)
- .setWindowingMode(WINDOWING_MODE_FREEFORM).build();
- final Task task = stack.getTopMostTask();
- WindowContainerTransaction t = new WindowContainerTransaction();
- assertTrue(task.isFocusable());
- t.setFocusable(stack.mRemoteToken, false);
- mService.applyContainerTransaction(t);
- assertFalse(task.isFocusable());
- }
-
- @Test
public void testDisplayWindowListener() {
final ArrayList<Integer> added = new ArrayList<>();
final ArrayList<Integer> changed = new ArrayList<>();
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
index 9e80cf2..078347e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2020 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.
@@ -16,45 +16,50 @@
package com.android.server.wm;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.assertFalse;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
-import android.graphics.Point;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+
+import android.app.ActivityManager.RunningTaskInfo;
+import android.app.ActivityManager.StackInfo;
+import android.content.res.Configuration;
import android.graphics.Rect;
-import android.platform.test.annotations.Presubmit;
import android.os.Binder;
import android.os.RemoteException;
+import android.platform.test.annotations.Presubmit;
+import android.view.Display;
import android.view.ITaskOrganizer;
+import android.view.IWindowContainer;
import android.view.SurfaceControl;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
+import android.view.WindowContainerTransaction;
import androidx.test.filters.SmallTest;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.ArrayList;
+import java.util.List;
+
/**
- * Test class for {@link TaskOrganizer}.
+ * Test class for {@link ITaskOrganizer} and {@link android.app.ITaskOrganizerController}.
*
* Build/Install/Run:
* atest WmTests:TaskOrganizerTests
@@ -67,7 +72,8 @@
final ITaskOrganizer organizer = mock(ITaskOrganizer.class);
when(organizer.asBinder()).thenReturn(new Binder());
- mWm.mAtmService.registerTaskOrganizer(organizer, windowingMode);
+ mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(
+ organizer, windowingMode);
return organizer;
}
@@ -83,7 +89,7 @@
final ITaskOrganizer organizer = registerMockOrganizer();
task.setTaskOrganizer(organizer);
- verify(organizer).taskAppeared(any(), any());
+ verify(organizer).taskAppeared(any());
task.removeImmediately();
verify(organizer).taskVanished(any());
@@ -97,10 +103,10 @@
final ITaskOrganizer organizer2 = registerMockOrganizer(WINDOWING_MODE_PINNED);
task.setTaskOrganizer(organizer);
- verify(organizer).taskAppeared(any(), any());
+ verify(organizer).taskAppeared(any());
task.setTaskOrganizer(organizer2);
verify(organizer).taskVanished(any());
- verify(organizer2).taskAppeared(any(), any());
+ verify(organizer2).taskAppeared(any());
}
@Test
@@ -111,10 +117,10 @@
final ITaskOrganizer organizer2 = registerMockOrganizer(WINDOWING_MODE_PINNED);
stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
- verify(organizer).taskAppeared(any(), any());
+ verify(organizer).taskAppeared(any());
stack.setWindowingMode(WINDOWING_MODE_PINNED);
verify(organizer).taskVanished(any());
- verify(organizer2).taskAppeared(any(), any());
+ verify(organizer2).taskAppeared(any());
}
@Test
@@ -124,7 +130,7 @@
final ITaskOrganizer organizer = registerMockOrganizer();
stack.setTaskOrganizer(organizer);
- verify(organizer).taskAppeared(any(), any());
+ verify(organizer).taskAppeared(any());
assertTrue(stack.isControlledByTaskOrganizer());
stack.setTaskOrganizer(null);
@@ -140,9 +146,176 @@
final Task task = createTaskInStack(stack, 0 /* userId */);
final Task task2 = createTaskInStack(stack, 0 /* userId */);
stack.setWindowingMode(WINDOWING_MODE_PINNED);
- verify(organizer, times(1)).taskAppeared(any(), any());
+ verify(organizer, times(1)).taskAppeared(any());
stack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
verify(organizer, times(1)).taskVanished(any());
}
+
+ @Test
+ public void testTaskTransaction() {
+ removeGlobalMinSizeRestriction();
+ final ActivityStack stack = new ActivityTestsBase.StackBuilder(mWm.mRoot)
+ .setWindowingMode(WINDOWING_MODE_FREEFORM).build();
+ final Task task = stack.getTopMostTask();
+ WindowContainerTransaction t = new WindowContainerTransaction();
+ Rect newBounds = new Rect(10, 10, 100, 100);
+ t.setBounds(task.mRemoteToken, new Rect(10, 10, 100, 100));
+ mWm.mAtmService.mTaskOrganizerController.applyContainerTransaction(t);
+ assertEquals(newBounds, task.getBounds());
+ }
+
+ @Test
+ public void testStackTransaction() {
+ removeGlobalMinSizeRestriction();
+ final ActivityStack stack = new ActivityTestsBase.StackBuilder(mWm.mRoot)
+ .setWindowingMode(WINDOWING_MODE_FREEFORM).build();
+ StackInfo info =
+ mWm.mAtmService.getStackInfo(WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD);
+ WindowContainerTransaction t = new WindowContainerTransaction();
+ assertEquals(stack.mRemoteToken, info.stackToken);
+ Rect newBounds = new Rect(10, 10, 100, 100);
+ t.setBounds(info.stackToken, new Rect(10, 10, 100, 100));
+ mWm.mAtmService.mTaskOrganizerController.applyContainerTransaction(t);
+ assertEquals(newBounds, stack.getBounds());
+ }
+
+ @Test
+ public void testContainerChanges() {
+ removeGlobalMinSizeRestriction();
+ final ActivityStack stack = new ActivityTestsBase.StackBuilder(mWm.mRoot)
+ .setWindowingMode(WINDOWING_MODE_FREEFORM).build();
+ final Task task = stack.getTopMostTask();
+ WindowContainerTransaction t = new WindowContainerTransaction();
+ assertTrue(task.isFocusable());
+ t.setFocusable(stack.mRemoteToken, false);
+ mWm.mAtmService.mTaskOrganizerController.applyContainerTransaction(t);
+ assertFalse(task.isFocusable());
+ }
+
+ @Test
+ public void testCreateDeleteRootTasks() {
+ RunningTaskInfo info1 = mWm.mAtmService.mTaskOrganizerController.createRootTask(
+ Display.DEFAULT_DISPLAY,
+ WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
+ assertEquals(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY,
+ info1.configuration.windowConfiguration.getWindowingMode());
+ assertEquals(ACTIVITY_TYPE_UNDEFINED, info1.topActivityType);
+
+ RunningTaskInfo info2 = mWm.mAtmService.mTaskOrganizerController.createRootTask(
+ Display.DEFAULT_DISPLAY,
+ WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+ assertEquals(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY,
+ info2.configuration.windowConfiguration.getWindowingMode());
+ assertEquals(ACTIVITY_TYPE_UNDEFINED, info2.topActivityType);
+
+ DisplayContent dc = mWm.mRoot.getDisplayContent(Display.DEFAULT_DISPLAY);
+ List<TaskTile> infos = getTaskTiles(dc);
+ assertEquals(2, infos.size());
+
+ assertTrue(mWm.mAtmService.mTaskOrganizerController.deleteRootTask(info1.token));
+ infos = getTaskTiles(dc);
+ assertEquals(1, infos.size());
+ assertEquals(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, infos.get(0).getWindowingMode());
+ }
+
+ @Test
+ public void testTileAddRemoveChild() {
+ RunningTaskInfo info1 = mWm.mAtmService.mTaskOrganizerController.createRootTask(
+ mDisplayContent.mDisplayId, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+
+ final ActivityStack stack = createTaskStackOnDisplay(
+ WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, mDisplayContent);
+ assertEquals(mDisplayContent.getWindowingMode(), stack.getWindowingMode());
+ TaskTile tile1 = TaskTile.forToken(info1.token.asBinder());
+ tile1.addChild(stack, 0 /* index */);
+ assertEquals(info1.configuration.windowConfiguration.getWindowingMode(),
+ stack.getWindowingMode());
+
+ // Info should reflect new membership
+ List<TaskTile> tiles = getTaskTiles(mDisplayContent);
+ info1 = new RunningTaskInfo();
+ tiles.get(0).fillTaskInfo(info1);
+ assertEquals(ACTIVITY_TYPE_STANDARD, info1.topActivityType);
+
+ // Children inherit configuration
+ Rect newSize = new Rect(10, 10, 300, 300);
+ Configuration c = new Configuration(tile1.getRequestedOverrideConfiguration());
+ c.windowConfiguration.setBounds(newSize);
+ tile1.onRequestedOverrideConfigurationChanged(c);
+ assertEquals(newSize, stack.getBounds());
+
+ tile1.removeChild(stack);
+ assertEquals(mDisplayContent.getWindowingMode(), stack.getWindowingMode());
+ info1 = new RunningTaskInfo();
+ tiles = getTaskTiles(mDisplayContent);
+ tiles.get(0).fillTaskInfo(info1);
+ assertEquals(ACTIVITY_TYPE_UNDEFINED, info1.topActivityType);
+ }
+
+ @Test
+ public void testTaskInfoCallback() {
+ final ArrayList<RunningTaskInfo> lastReportedTiles = new ArrayList<>();
+ final boolean[] called = {false};
+ ITaskOrganizer listener = new ITaskOrganizer.Stub() {
+ @Override
+ public void taskAppeared(RunningTaskInfo taskInfo) { }
+
+ @Override
+ public void taskVanished(IWindowContainer container) { }
+
+ @Override
+ public void transactionReady(int id, SurfaceControl.Transaction t) { }
+
+ @Override
+ public void onTaskInfoChanged(RunningTaskInfo info) throws RemoteException {
+ lastReportedTiles.add(info);
+ called[0] = true;
+ }
+ };
+ mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(listener,
+ WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+ RunningTaskInfo info1 = mWm.mAtmService.mTaskOrganizerController.createRootTask(
+ mDisplayContent.mDisplayId, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+ lastReportedTiles.clear();
+ called[0] = false;
+
+ final ActivityStack stack = createTaskStackOnDisplay(
+ WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, mDisplayContent);
+ TaskTile tile1 = TaskTile.forToken(info1.token.asBinder());
+ tile1.addChild(stack, 0 /* index */);
+ assertTrue(called[0]);
+ assertEquals(ACTIVITY_TYPE_STANDARD, lastReportedTiles.get(0).topActivityType);
+
+ lastReportedTiles.clear();
+ called[0] = false;
+ final ActivityStack stack2 = createTaskStackOnDisplay(
+ WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_HOME, mDisplayContent);
+ tile1.addChild(stack2, 0 /* index */);
+ assertTrue(called[0]);
+ assertEquals(ACTIVITY_TYPE_HOME, lastReportedTiles.get(0).topActivityType);
+
+ lastReportedTiles.clear();
+ called[0] = false;
+ mDisplayContent.positionStackAtTop(stack, false /* includingParents */);
+ assertTrue(called[0]);
+ assertEquals(ACTIVITY_TYPE_STANDARD, lastReportedTiles.get(0).topActivityType);
+
+ lastReportedTiles.clear();
+ called[0] = false;
+ tile1.removeAllChildren();
+ assertTrue(called[0]);
+ assertEquals(ACTIVITY_TYPE_UNDEFINED, lastReportedTiles.get(0).topActivityType);
+ }
+
+ private List<TaskTile> getTaskTiles(DisplayContent dc) {
+ ArrayList<TaskTile> out = new ArrayList<>();
+ for (int i = dc.getStackCount() - 1; i >= 0; --i) {
+ final Task t = dc.getStackAt(i);
+ if (t instanceof TaskTile) {
+ out.add((TaskTile) t);
+ }
+ }
+ return out;
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 8e362ae..1ca2e318 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -40,6 +40,7 @@
import static org.mockito.Mockito.mock;
import android.content.Context;
+import android.content.Intent;
import android.util.Log;
import android.view.Display;
import android.view.DisplayInfo;
@@ -340,6 +341,7 @@
.setWindowingMode(windowingMode)
.setActivityType(activityType)
.setCreateActivity(false)
+ .setIntent(new Intent())
.build();
}
}
diff --git a/telephony/java/android/telephony/BarringInfo.java b/telephony/java/android/telephony/BarringInfo.java
index 5419c3c..9baa66f 100644
--- a/telephony/java/android/telephony/BarringInfo.java
+++ b/telephony/java/android/telephony/BarringInfo.java
@@ -238,6 +238,12 @@
}
}
+ private static final BarringServiceInfo BARRING_SERVICE_INFO_UNKNOWN =
+ new BarringServiceInfo(BarringServiceInfo.BARRING_TYPE_UNKNOWN);
+
+ private static final BarringServiceInfo BARRING_SERVICE_INFO_UNBARRED =
+ new BarringServiceInfo(BarringServiceInfo.BARRING_TYPE_NONE);
+
private CellIdentity mCellIdentity;
// A SparseArray potentially mapping each BarringService type to a BarringServiceInfo config
@@ -298,17 +304,6 @@
}
/**
- * Return whether a service is currently barred based on the BarringInfo
- *
- * @param service the service to be checked.
- * @return true if the service is currently being barred, otherwise false
- */
- public boolean isServiceBarred(@BarringServiceType int service) {
- BarringServiceInfo bsi = mBarringServiceInfos.get(service);
- return bsi != null && (bsi.isBarred());
- }
-
- /**
* Get the BarringServiceInfo for a specified service.
*
* @return a BarringServiceInfo struct describing the current barring status for a service
@@ -319,9 +314,8 @@
// type as UNKNOWN; if the modem reports barring info but doesn't report for a particular
// service then we can safely assume that the service isn't barred (for instance because
// that particular service isn't applicable to the current RAN).
- return (bsi != null) ? bsi : new BarringServiceInfo(
- mBarringServiceInfos.size() > 0 ? BarringServiceInfo.BARRING_TYPE_NONE :
- BarringServiceInfo.BARRING_TYPE_UNKNOWN);
+ return (bsi != null) ? bsi : mBarringServiceInfos.size() > 0
+ ? BARRING_SERVICE_INFO_UNBARRED : BARRING_SERVICE_INFO_UNKNOWN;
}
/** @hide */
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 5b09cd9..a5a1ebc 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -1925,6 +1925,8 @@
/**
* Get the network registration state for the transport type and network domain.
+ * If multiple domains are in the input bitmask, only the first one from
+ * networkRegistrationInfo.getDomain() will be returned.
*
* @param domain The network {@link NetworkRegistrationInfo.Domain domain}
* @param transportType The transport type
@@ -2072,11 +2074,18 @@
public boolean isIwlanPreferred() {
return mIsIwlanPreferred;
}
- /**
- * @return {@code true}Returns True whenever the modem is searching for service.
- * To check both CS and PS domain
- */
+ /**
+ * This indicates whether the device is searching for service.
+ *
+ * This API reports the modem searching status for
+ * {@link AccessNetworkConstants#TRANSPORT_TYPE_WWAN} (cellular) service in either
+ * {@link NetworkRegistrationInfo#DOMAIN_CS} or {@link NetworkRegistrationInfo#DOMAIN_PS}.
+ * This API will not report searching status for
+ * {@link AccessNetworkConstants#TRANSPORT_TYPE_WLAN}.
+ *
+ * @return {@code true} whenever the modem is searching for service.
+ */
public boolean isSearching() {
NetworkRegistrationInfo psRegState = getNetworkRegistrationInfo(
NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
diff --git a/tests/PlatformCompatGating/Android.bp b/tests/PlatformCompatGating/Android.bp
index 609896e..5e9ef8e 100644
--- a/tests/PlatformCompatGating/Android.bp
+++ b/tests/PlatformCompatGating/Android.bp
@@ -18,6 +18,7 @@
name: "PlatformCompatGating",
// Only compile source java files in this apk.
srcs: ["src/**/*.java"],
+ certificate: "platform",
libs: [
"android.test.runner",
"android.test.base",
diff --git a/tests/PlatformCompatGating/test-rules/src/android/compat/testing/PlatformCompatChangeRule.java b/tests/PlatformCompatGating/test-rules/src/android/compat/testing/PlatformCompatChangeRule.java
index c00aa2a..932ec64 100644
--- a/tests/PlatformCompatGating/test-rules/src/android/compat/testing/PlatformCompatChangeRule.java
+++ b/tests/PlatformCompatGating/test-rules/src/android/compat/testing/PlatformCompatChangeRule.java
@@ -16,9 +16,7 @@
package android.compat.testing;
-import android.Manifest;
import android.app.Instrumentation;
-import android.app.UiAutomation;
import android.compat.Compatibility;
import android.compat.Compatibility.ChangeConfig;
import android.content.Context;
@@ -85,16 +83,12 @@
@Override
public void evaluate() throws Throwable {
Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
- UiAutomation uiAutomation = instrumentation.getUiAutomation();
String packageName = instrumentation.getTargetContext().getPackageName();
IPlatformCompat platformCompat = IPlatformCompat.Stub
.asInterface(ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
if (platformCompat == null) {
throw new IllegalStateException("Could not get IPlatformCompat service!");
}
- uiAutomation.adoptShellPermissionIdentity(
- Manifest.permission.READ_COMPAT_CHANGE_CONFIG,
- Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG);
Compatibility.setOverrides(mConfig);
try {
platformCompat.setOverridesForTest(new CompatibilityChangeConfig(mConfig),
@@ -107,7 +101,6 @@
} catch (RemoteException e) {
throw new RuntimeException("Could not call IPlatformCompat binder method!", e);
} finally {
- uiAutomation.dropShellPermissionIdentity();
Compatibility.clearOverrides();
}
}
diff --git a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java
index bc8d3c3..3fb0050 100644
--- a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java
+++ b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java
@@ -25,6 +25,7 @@
import android.content.Intent;
import android.graphics.Rect;
import android.os.Bundle;
+import android.os.RemoteException;
import android.view.ITaskOrganizer;
import android.view.IWindowContainer;
import android.view.SurfaceControl;
@@ -47,13 +48,16 @@
class Organizer extends ITaskOrganizer.Stub {
@Override
- public void taskAppeared(IWindowContainer wc, ActivityManager.RunningTaskInfo ti) {
- mView.reparentTask(wc);
+ public void taskAppeared(ActivityManager.RunningTaskInfo ti) {
+ mView.reparentTask(ti.token);
}
public void taskVanished(IWindowContainer wc) {
}
public void transactionReady(int id, SurfaceControl.Transaction t) {
}
+ @Override
+ public void onTaskInfoChanged(ActivityManager.RunningTaskInfo info) {
+ }
}
Organizer mOrganizer = new Organizer();
diff --git a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java
index fc1be28..8f3cb34 100644
--- a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java
+++ b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java
@@ -21,18 +21,14 @@
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.app.Service;
-import android.app.WindowConfiguration;
-import android.content.Context;
import android.content.Intent;
import android.graphics.Rect;
import android.os.IBinder;
import android.view.ITaskOrganizer;
import android.view.IWindowContainer;
-import android.view.WindowContainerTransaction;
import android.view.SurfaceControl;
-import android.view.SurfaceHolder;
-import android.view.SurfaceView;
import android.view.ViewGroup;
+import android.view.WindowContainerTransaction;
import android.view.WindowManager;
import android.widget.FrameLayout;
@@ -43,13 +39,13 @@
TaskView mTaskView;
class Organizer extends ITaskOrganizer.Stub {
- public void taskAppeared(IWindowContainer wc, ActivityManager.RunningTaskInfo ti) {
- mTaskView.reparentTask(wc);
+ public void taskAppeared(ActivityManager.RunningTaskInfo ti) {
+ mTaskView.reparentTask(ti.token);
final WindowContainerTransaction wct = new WindowContainerTransaction();
- wct.scheduleFinishEnterPip(wc, new Rect(0, 0, PIP_WIDTH, PIP_HEIGHT));
+ wct.scheduleFinishEnterPip(ti.token, new Rect(0, 0, PIP_WIDTH, PIP_HEIGHT));
try {
- ActivityTaskManager.getService().applyContainerTransaction(wct);
+ ActivityTaskManager.getTaskOrganizerController().applyContainerTransaction(wct);
} catch (Exception e) {
}
}
@@ -57,6 +53,8 @@
}
public void transactionReady(int id, SurfaceControl.Transaction t) {
}
+ public void onTaskInfoChanged(ActivityManager.RunningTaskInfo info) {
+ }
}
Organizer mOrganizer = new Organizer();
diff --git a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskView.java b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskView.java
index ff73340..9f32bb8 100644
--- a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskView.java
+++ b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskView.java
@@ -44,7 +44,7 @@
@Override
public void surfaceCreated(SurfaceHolder holder) {
try {
- ActivityTaskManager.getService().registerTaskOrganizer(mTaskOrganizer,
+ ActivityTaskManager.getTaskOrganizerController().registerTaskOrganizer(mTaskOrganizer,
mWindowingMode);
} catch (Exception e) {
}
diff --git a/tests/net/TEST_MAPPING b/tests/net/TEST_MAPPING
index a7853b6..005cbe9 100644
--- a/tests/net/TEST_MAPPING
+++ b/tests/net/TEST_MAPPING
@@ -1,7 +1,12 @@
{
- "postsubmit": [
+ "presubmit": [
{
"name": "FrameworksNetIntegrationTests"
}
+ ],
+ "postsubmit": [
+ {
+ "name": "FrameworksNetDeflakeTest"
+ }
]
}
\ No newline at end of file
diff --git a/tests/net/common/java/android/net/NetworkScoreTest.kt b/tests/net/common/java/android/net/NetworkScoreTest.kt
index 30836b7..a63d58d 100644
--- a/tests/net/common/java/android/net/NetworkScoreTest.kt
+++ b/tests/net/common/java/android/net/NetworkScoreTest.kt
@@ -16,7 +16,7 @@
package android.net
-import android.os.Parcelable
+import android.net.NetworkScore.Metrics.BANDWIDTH_UNKNOWN
import androidx.test.filters.SmallTest
import androidx.test.runner.AndroidJUnit4
import com.android.testutils.assertParcelSane
@@ -28,77 +28,49 @@
import org.junit.runner.RunWith
private const val TEST_SCORE = 80
-private const val KEY_DEFAULT_CAPABILITIES = "DEFAULT_CAPABILITIES"
@RunWith(AndroidJUnit4::class)
@SmallTest
class NetworkScoreTest {
@Test
fun testParcelNetworkScore() {
- val networkScore = NetworkScore()
val defaultCap = NetworkCapabilities()
- networkScore.putExtension(KEY_DEFAULT_CAPABILITIES, defaultCap)
- assertEquals(defaultCap, networkScore.getExtension(KEY_DEFAULT_CAPABILITIES))
- networkScore.putIntExtension(NetworkScore.LEGACY_SCORE, TEST_SCORE)
- assertEquals(TEST_SCORE, networkScore.getIntExtension(NetworkScore.LEGACY_SCORE))
- assertParcelSane(networkScore, 1)
- }
+ val builder = NetworkScore.Builder().setLegacyScore(TEST_SCORE)
+ assertEquals(TEST_SCORE, builder.build().getLegacyScore())
+ assertParcelSane(builder.build(), 7)
- @Test
- fun testNullKeyAndValue() {
- val networkScore = NetworkScore()
- val defaultCap = NetworkCapabilities()
- networkScore.putIntExtension(null, TEST_SCORE)
- assertEquals(TEST_SCORE, networkScore.getIntExtension(null))
- networkScore.putExtension(null, defaultCap)
- assertEquals(defaultCap, networkScore.getExtension(null))
- networkScore.putExtension(null, null)
- val result: Parcelable? = networkScore.getExtension(null)
- assertEquals(null, result)
- }
+ builder.addPolicy(NetworkScore.POLICY_IGNORE_ON_WIFI)
+ .addPolicy(NetworkScore.POLICY_DEFAULT_SUBSCRIPTION)
+ .setLinkLayerMetrics(NetworkScore.Metrics(44 /* latency */,
+ 380 /* downlinkBandwidth */, BANDWIDTH_UNKNOWN /* uplinkBandwidth */))
+ .setEndToEndMetrics(NetworkScore.Metrics(11 /* latency */,
+ BANDWIDTH_UNKNOWN /* downlinkBandwidth */, 100_000 /* uplinkBandwidth */))
+ .setRange(NetworkScore.RANGE_MEDIUM)
+ assertParcelSane(builder.build(), 7)
+ builder.clearPolicy(NetworkScore.POLICY_IGNORE_ON_WIFI)
+ val ns = builder.build()
+ assertParcelSane(ns, 7)
+ assertFalse(ns.hasPolicy(NetworkScore.POLICY_IGNORE_ON_WIFI))
+ assertTrue(ns.hasPolicy(NetworkScore.POLICY_DEFAULT_SUBSCRIPTION))
- @Test
- fun testRemoveExtension() {
- val networkScore = NetworkScore()
- val defaultCap = NetworkCapabilities()
- networkScore.putExtension(KEY_DEFAULT_CAPABILITIES, defaultCap)
- networkScore.putIntExtension(NetworkScore.LEGACY_SCORE, TEST_SCORE)
- assertEquals(defaultCap, networkScore.getExtension(KEY_DEFAULT_CAPABILITIES))
- assertEquals(TEST_SCORE, networkScore.getIntExtension(NetworkScore.LEGACY_SCORE))
- networkScore.removeExtension(KEY_DEFAULT_CAPABILITIES)
- networkScore.removeExtension(NetworkScore.LEGACY_SCORE)
- val result: Parcelable? = networkScore.getExtension(KEY_DEFAULT_CAPABILITIES)
- assertEquals(null, result)
- assertEquals(0, networkScore.getIntExtension(NetworkScore.LEGACY_SCORE))
+ val exitingNs = ns.withExiting(true)
+ assertNotEquals(ns.isExiting, exitingNs.isExiting)
+ assertNotEquals(ns, exitingNs)
+ assertParcelSane(exitingNs, 7)
}
@Test
fun testEqualsNetworkScore() {
- val ns1 = NetworkScore()
- val ns2 = NetworkScore()
- assertTrue(ns1.equals(ns2))
- assertEquals(ns1.hashCode(), ns2.hashCode())
+ val builder1 = NetworkScore.Builder()
+ val builder2 = NetworkScore.Builder()
+ assertTrue(builder1.build().equals(builder2.build()))
+ assertEquals(builder1.build().hashCode(), builder2.build().hashCode())
- ns1.putIntExtension(NetworkScore.LEGACY_SCORE, TEST_SCORE)
- assertFalse(ns1.equals(ns2))
- assertNotEquals(ns1.hashCode(), ns2.hashCode())
- ns2.putIntExtension(NetworkScore.LEGACY_SCORE, TEST_SCORE)
- assertTrue(ns1.equals(ns2))
- assertEquals(ns1.hashCode(), ns2.hashCode())
-
- val defaultCap = NetworkCapabilities()
- ns1.putExtension(KEY_DEFAULT_CAPABILITIES, defaultCap)
- assertFalse(ns1.equals(ns2))
- assertNotEquals(ns1.hashCode(), ns2.hashCode())
- ns2.putExtension(KEY_DEFAULT_CAPABILITIES, defaultCap)
- assertTrue(ns1.equals(ns2))
- assertEquals(ns1.hashCode(), ns2.hashCode())
-
- ns1.putIntExtension(null, 10)
- assertFalse(ns1.equals(ns2))
- assertNotEquals(ns1.hashCode(), ns2.hashCode())
- ns2.putIntExtension(null, 10)
- assertTrue(ns1.equals(ns2))
- assertEquals(ns1.hashCode(), ns2.hashCode())
+ builder1.setLegacyScore(TEST_SCORE)
+ assertFalse(builder1.build().equals(builder2.build()))
+ assertNotEquals(builder1.hashCode(), builder2.hashCode())
+ builder2.setLegacyScore(TEST_SCORE)
+ assertTrue(builder1.build().equals(builder2.build()))
+ assertEquals(builder1.build().hashCode(), builder2.build().hashCode())
}
}
diff --git a/tests/net/deflake/Android.bp b/tests/net/deflake/Android.bp
index 1c48c74..b1b0171 100644
--- a/tests/net/deflake/Android.bp
+++ b/tests/net/deflake/Android.bp
@@ -26,4 +26,5 @@
"net-host-tests-utils",
],
data: [":FrameworksNetTests"],
-}
\ No newline at end of file
+ test_suites: ["device-tests"],
+}
diff --git a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
index a35fb40..7ae9e95 100644
--- a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
+++ b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
@@ -40,6 +40,7 @@
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.NetworkProvider;
+import android.net.NetworkScore;
import android.net.NetworkSpecifier;
import android.net.SocketKeepalive;
import android.net.UidRange;
@@ -155,9 +156,13 @@
}
}
+ private NetworkScore makeNetworkScore(final int legacyScore) {
+ return new NetworkScore.Builder().setLegacyScore(legacyScore).build();
+ }
+
public void adjustScore(int change) {
mScore += change;
- mNetworkAgent.sendNetworkScore(mScore);
+ mNetworkAgent.sendNetworkScore(makeNetworkScore(mScore));
}
public int getScore() {
diff --git a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
index e863266..25e9057 100644
--- a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
@@ -353,8 +353,7 @@
NetworkCapabilities caps = new NetworkCapabilities();
caps.addCapability(0);
caps.addTransportType(transport);
- NetworkScore ns = new NetworkScore();
- ns.putIntExtension(NetworkScore.LEGACY_SCORE, 50);
+ NetworkScore ns = new NetworkScore.Builder().setLegacyScore(50).build();
NetworkAgentInfo nai = new NetworkAgentInfo(null, null, new Network(netId), info, null,
caps, ns, mCtx, null, null /* config */, mConnService, mNetd, mDnsResolver, mNMS,
NetworkProvider.ID_NONE);
diff --git a/tools/hiddenapi/Android.bp b/tools/hiddenapi/Android.bp
new file mode 100644
index 0000000..e0eb06cb
--- /dev/null
+++ b/tools/hiddenapi/Android.bp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+python_binary_host {
+ name: "merge_csv",
+ main: "merge_csv.py",
+ srcs: ["merge_csv.py"],
+ version: {
+ py2: {
+ enabled: false,
+ },
+ py3: {
+ enabled: true,
+ embedded_launcher: true
+ },
+ },
+}
diff --git a/tools/hiddenapi/merge_csv.py b/tools/hiddenapi/merge_csv.py
index 48c0755..9661927 100755
--- a/tools/hiddenapi/merge_csv.py
+++ b/tools/hiddenapi/merge_csv.py
@@ -21,20 +21,19 @@
import sys
csv_readers = [
- csv.DictReader(open(csv_file, 'rb'), delimiter=',', quotechar='|')
+ csv.DictReader(open(csv_file, 'r'), delimiter=',', quotechar='|')
for csv_file in sys.argv[1:]
]
# Build union of all columns from source files:
headers = set()
for reader in csv_readers:
- headers = headers.union(reader.fieldnames)
+ headers = headers.union(reader.fieldnames)
# Concatenate all files to output:
-out = csv.DictWriter(sys.stdout, delimiter=',', quotechar='|', fieldnames = sorted(headers))
+out = csv.DictWriter(sys.stdout, delimiter=',', quotechar='|', quoting=csv.QUOTE_MINIMAL,
+ dialect='unix', fieldnames=sorted(headers))
out.writeheader()
for reader in csv_readers:
- for row in reader:
- out.writerow(row)
-
-
+ for row in reader:
+ out.writerow(row)
diff --git a/tools/stats_log_api_gen/java_writer_q.cpp b/tools/stats_log_api_gen/java_writer_q.cpp
index 1259a68..a68c3a2 100644
--- a/tools/stats_log_api_gen/java_writer_q.cpp
+++ b/tools/stats_log_api_gen/java_writer_q.cpp
@@ -577,6 +577,50 @@
}
}
+// This method is called in main.cpp to generate StatsLog for modules that's compatible with
+// Q at compile-time.
+int write_stats_log_java_q_for_module(FILE* out, const Atoms& atoms,
+ const AtomDecl &attributionDecl, const string& moduleName,
+ const string& javaClass, const string& javaPackage,
+ const bool supportWorkSource) {
+ // Print prelude
+ fprintf(out, "// This file is autogenerated\n");
+ fprintf(out, "\n");
+ fprintf(out, "package %s;\n", javaPackage.c_str());
+ fprintf(out, "\n");
+ fprintf(out, "import static java.nio.charset.StandardCharsets.UTF_8;\n");
+ fprintf(out, "\n");
+ fprintf(out, "import android.util.StatsLog;\n");
+ fprintf(out, "import android.os.SystemClock;\n");
+ fprintf(out, "\n");
+ fprintf(out, "\n");
+ fprintf(out, "/**\n");
+ fprintf(out, " * Utility class for logging statistics events.\n");
+ fprintf(out, " */\n");
+ fprintf(out, "public class %s {\n", javaClass.c_str());
+
+ write_java_q_logging_constants(out, " ");
+
+ write_java_atom_codes(out, atoms, moduleName);
+
+ write_java_enum_values(out, atoms, moduleName);
+
+ int errors = 0;
+ // Print write methods
+ fprintf(out, " // Write methods\n");
+ errors += write_java_methods_q_schema(out, atoms.signatures_to_modules, attributionDecl,
+ moduleName, " ");
+ errors += write_java_non_chained_methods(out, atoms.non_chained_signatures_to_modules,
+ moduleName);
+ if (supportWorkSource) {
+ errors += write_java_work_source_methods(out, atoms.signatures_to_modules, moduleName);
+ }
+
+ fprintf(out, "}\n");
+
+ return errors;
+}
+
#if defined(STATS_SCHEMA_LEGACY)
static void write_java_method(
FILE* out,
@@ -639,48 +683,6 @@
return 0;
}
-
-int write_stats_log_java_q_for_module(FILE* out, const Atoms& atoms,
- const AtomDecl &attributionDecl, const string& moduleName,
- const string& javaClass, const string& javaPackage,
- const bool supportWorkSource) {
- // Print prelude
- fprintf(out, "// This file is autogenerated\n");
- fprintf(out, "\n");
- fprintf(out, "package %s;\n", javaPackage.c_str());
- fprintf(out, "\n");
- fprintf(out, "import static java.nio.charset.StandardCharsets.UTF_8;\n");
- fprintf(out, "\n");
- fprintf(out, "import android.util.StatsLog;\n");
- fprintf(out, "import android.os.SystemClock;\n");
- fprintf(out, "\n");
- fprintf(out, "\n");
- fprintf(out, "/**\n");
- fprintf(out, " * Utility class for logging statistics events.\n");
- fprintf(out, " */\n");
- fprintf(out, "public class %s {\n", javaClass.c_str());
-
- write_java_q_logging_constants(out, " ");
-
- write_java_atom_codes(out, atoms, moduleName);
-
- write_java_enum_values(out, atoms, moduleName);
-
- int errors = 0;
- // Print write methods
- fprintf(out, " // Write methods\n");
- errors += write_java_methods_q_schema(out, atoms.signatures_to_modules, attributionDecl,
- moduleName, " ");
- errors += write_java_non_chained_methods(out, atoms.non_chained_signatures_to_modules,
- moduleName);
- if (supportWorkSource) {
- errors += write_java_work_source_methods(out, atoms.signatures_to_modules, moduleName);
- }
-
- fprintf(out, "}\n");
-
- return errors;
-}
#endif
} // namespace stats_log_api_gen
diff --git a/tools/stats_log_api_gen/java_writer_q.h b/tools/stats_log_api_gen/java_writer_q.h
index 36df1d8..7d734df 100644
--- a/tools/stats_log_api_gen/java_writer_q.h
+++ b/tools/stats_log_api_gen/java_writer_q.h
@@ -45,13 +45,13 @@
const int requiredHelpers,
const string& indent);
-#if defined(STATS_SCHEMA_LEGACY)
-int write_stats_log_java_q(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl,
- const bool supportWorkSource);
-
int write_stats_log_java_q_for_module(FILE* out, const Atoms& atoms,
const AtomDecl &attributionDecl, const string& moduleName, const string& javaClass,
const string& javaPackage, const bool supportWorkSource);
+
+#if defined(STATS_SCHEMA_LEGACY)
+int write_stats_log_java_q(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl,
+ const bool supportWorkSource);
#endif
} // namespace stats_log_api_gen
} // namespace android
diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp
index 6089532..ddbf22c 100644
--- a/tools/stats_log_api_gen/main.cpp
+++ b/tools/stats_log_api_gen/main.cpp
@@ -511,8 +511,10 @@
fprintf(stderr, " --javaClass CLASS the class name of the java class.\n");
fprintf(stderr, " Optional for Java with module.\n");
fprintf(stderr, " Default is \"StatsLogInternal\"\n");
- fprintf(stderr, " --supportQ Include support for Android Q.\n");
+ fprintf(stderr, " --supportQ Include runtime support for Android Q.\n");
fprintf(stderr, " --worksource Include support for logging WorkSource objects.\n");
+ fprintf(stderr, " --compileQ Include compile-time support for Android Q "
+ "(Java only).\n");
}
/**
@@ -536,6 +538,7 @@
string javaClass = DEFAULT_JAVA_CLASS;
bool supportQ = false;
bool supportWorkSource = false;
+ bool compileQ = false;
int index = 1;
while (index < argc) {
@@ -630,6 +633,8 @@
supportQ = true;
} else if (0 == strcmp("--worksource", argv[index])) {
supportWorkSource = true;
+ } else if (0 == strcmp("--compileQ", argv[index])) {
+ compileQ = true;
}
index++;
@@ -645,12 +650,18 @@
return 1;
}
- if (DEFAULT_MODULE_NAME == moduleName && supportQ) {
+ if (DEFAULT_MODULE_NAME == moduleName && (supportQ || compileQ)) {
// Support for Q schema is not needed for default module.
fprintf(stderr, "%s cannot support Q schema\n", moduleName.c_str());
return 1;
}
+ if (supportQ && compileQ) {
+ // Runtime Q support is redundant if compile-time Q support is required.
+ fprintf(stderr, "Cannot specify compileQ and supportQ simultaneously.\n");
+ return 1;
+ }
+
// Collate the parameters
Atoms atoms;
int errorCount = collate_atoms(Atom::descriptor(), &atoms);
@@ -748,9 +759,15 @@
javaClass = "StatsLogInternal";
javaPackage = "android.util";
}
- errorCount = android::stats_log_api_gen::write_stats_log_java(
- out, atoms, attributionDecl, moduleName, javaClass, javaPackage, supportQ,
- supportWorkSource);
+ if (compileQ) {
+ errorCount = android::stats_log_api_gen::write_stats_log_java_q_for_module(
+ out, atoms, attributionDecl, moduleName, javaClass, javaPackage,
+ supportWorkSource);
+ } else {
+ errorCount = android::stats_log_api_gen::write_stats_log_java(
+ out, atoms, attributionDecl, moduleName, javaClass, javaPackage, supportQ,
+ supportWorkSource);
+ }
#endif
fclose(out);
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 0ef224a..8d95cb0 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -373,6 +373,7 @@
* ECDHE_ECDSA
* ECDHE_RSA
* </pre>
+ * @hide
*/
public static class SuiteBCipher {
private SuiteBCipher() { }
@@ -715,8 +716,8 @@
public BitSet allowedGroupManagementCiphers;
/**
* The set of SuiteB ciphers supported by this configuration.
- * To be used for WPA3-Enterprise mode.
- * See {@link SuiteBCipher} for descriptions of the values.
+ * To be used for WPA3-Enterprise mode. Set automatically by the framework based on the
+ * certificate type that is used in this configuration.
*/
@NonNull
public BitSet allowedSuiteBCiphers;
@@ -1929,54 +1930,38 @@
private NetworkSelectionStatus mNetworkSelectionStatus = new NetworkSelectionStatus();
/**
- * @hide
* This class is intended to store extra failure reason information for the most recent
* connection attempt, so that it may be surfaced to the settings UI
+ * @hide
*/
- @SystemApi
+ // TODO(b/148626966): called by SUW via reflection, remove once SUW is updated
public static class RecentFailure {
private RecentFailure() {}
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(value = {NONE, STATUS_AP_UNABLE_TO_HANDLE_NEW_STA})
- public @interface AssociationStatus {}
-
- /**
- * No recent failure, or no specific reason given for the recent connection failure
- */
- public static final int NONE = 0;
- /**
- * Connection to this network recently failed due to Association Rejection Status 17
- * (AP is full)
- */
- public static final int STATUS_AP_UNABLE_TO_HANDLE_NEW_STA = 17;
/**
* Association Rejection Status code (NONE for success/non-association-rejection-fail)
*/
- @AssociationStatus
- private int mAssociationStatus = NONE;
+ @RecentFailureReason
+ private int mAssociationStatus = RECENT_FAILURE_NONE;
/**
* @param status the association status code for the recent failure
- * @hide
*/
- public void setAssociationStatus(@AssociationStatus int status) {
+ public void setAssociationStatus(@RecentFailureReason int status) {
mAssociationStatus = status;
}
/**
* Sets the RecentFailure to NONE
- * @hide
*/
public void clear() {
- mAssociationStatus = NONE;
+ mAssociationStatus = RECENT_FAILURE_NONE;
}
/**
- * Get the recent failure code. One of {@link #NONE} or
- * {@link #STATUS_AP_UNABLE_TO_HANDLE_NEW_STA}.
+ * Get the recent failure code. One of {@link #RECENT_FAILURE_NONE} or
+ * {@link #RECENT_FAILURE_AP_UNABLE_TO_HANDLE_NEW_STA}.
*/
- @AssociationStatus
+ @RecentFailureReason
public int getAssociationStatus() {
return mAssociationStatus;
}
@@ -1986,10 +1971,47 @@
* RecentFailure member
* @hide
*/
+ // TODO(b/148626966): called by SUW via reflection, once SUW is updated, make private and
+ // rename to mRecentFailure
@NonNull
- @SystemApi
public final RecentFailure recentFailure = new RecentFailure();
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = "RECENT_FAILURE_", value = {
+ RECENT_FAILURE_NONE,
+ RECENT_FAILURE_AP_UNABLE_TO_HANDLE_NEW_STA})
+ public @interface RecentFailureReason {}
+
+ /**
+ * No recent failure, or no specific reason given for the recent connection failure
+ * @hide
+ */
+ @SystemApi
+ public static final int RECENT_FAILURE_NONE = 0;
+ /**
+ * Connection to this network recently failed due to Association Rejection Status 17
+ * (AP is full)
+ * @hide
+ */
+ @SystemApi
+ public static final int RECENT_FAILURE_AP_UNABLE_TO_HANDLE_NEW_STA = 17;
+
+ /**
+ * Get the failure reason for the most recent connection attempt, or
+ * {@link #RECENT_FAILURE_NONE} if there was no failure.
+ *
+ * Failure reasons include:
+ * {@link #RECENT_FAILURE_AP_UNABLE_TO_HANDLE_NEW_STA}
+ *
+ * @hide
+ */
+ @RecentFailureReason
+ @SystemApi
+ public int getRecentFailureReason() {
+ return recentFailure.getAssociationStatus();
+ }
+
/**
* Get the network selection status.
* @hide
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index 6f01350..8250a95 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -836,6 +836,8 @@
* Enable/Disable wifi scanning.
*
* @param enable set to true to enable scanning, set to false to disable all types of scanning.
+ *
+ * @see WifiManager#ACTION_WIFI_SCAN_AVAILABLE
* {@hide}
*/
@SystemApi
diff --git a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
index 3a0d080..756d679 100644
--- a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
+++ b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
@@ -19,6 +19,7 @@
import static android.net.wifi.WifiConfiguration.METERED_OVERRIDE_NONE;
import static android.net.wifi.WifiConfiguration.MeteredOverride;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.net.wifi.hotspot2.pps.Credential;
@@ -895,4 +896,18 @@
public boolean isOsuProvisioned() {
return getUpdateIdentifier() != Integer.MIN_VALUE;
}
+
+ /**
+ * Get a unique identifier for a PasspointConfiguration object.
+ *
+ * @return A unique identifier
+ * @throws IllegalStateException if Credential or HomeSP nodes are not initialized
+ */
+ public @NonNull String getUniqueId() throws IllegalStateException {
+ if (mCredential == null || mHomeSp == null || TextUtils.isEmpty(mHomeSp.getFqdn())) {
+ throw new IllegalStateException("Credential or HomeSP are not initialized");
+ }
+
+ return mHomeSp.getFqdn();
+ }
}
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java b/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java
index 9562f95..36c7213 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java
@@ -137,12 +137,12 @@
/** @hide */
@UnsupportedAppUsage
- public int netId = WifiP2pGroup.PERSISTENT_NET_ID;
+ public int netId = WifiP2pGroup.NETWORK_ID_PERSISTENT;
/**
* Get the network ID of this P2P configuration.
- * @return either a non-negative network ID, or one of {@link WifiP2pGroup#PERSISTENT_NET_ID} or
- * {@link WifiP2pGroup#TEMPORARY_NET_ID}.
+ * @return either a non-negative network ID, or one of
+ * {@link WifiP2pGroup#NETWORK_ID_PERSISTENT} or {@link WifiP2pGroup#NETWORK_ID_TEMPORARY}.
*/
public int getNetworkId() {
return netId;
@@ -280,7 +280,7 @@
private String mPassphrase = "";
private int mGroupOperatingBand = GROUP_OWNER_BAND_AUTO;
private int mGroupOperatingFrequency = GROUP_OWNER_BAND_AUTO;
- private int mNetId = WifiP2pGroup.TEMPORARY_NET_ID;
+ private int mNetId = WifiP2pGroup.NETWORK_ID_TEMPORARY;
/**
* Specify the peer's MAC address. If not set, the device will
@@ -460,9 +460,9 @@
*/
public @NonNull Builder enablePersistentMode(boolean persistent) {
if (persistent) {
- mNetId = WifiP2pGroup.PERSISTENT_NET_ID;
+ mNetId = WifiP2pGroup.NETWORK_ID_PERSISTENT;
} else {
- mNetId = WifiP2pGroup.TEMPORARY_NET_ID;
+ mNetId = WifiP2pGroup.NETWORK_ID_TEMPORARY;
}
return this;
}
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java b/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java
index 21f6704..e497b22 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java
@@ -41,7 +41,15 @@
* The temporary network id.
* @see #getNetworkId()
*/
- public static final int TEMPORARY_NET_ID = -1;
+ public static final int NETWORK_ID_TEMPORARY = -1;
+
+ /**
+ * The temporary network id.
+ *
+ * @hide
+ */
+ @UnsupportedAppUsage
+ public static final int TEMPORARY_NET_ID = NETWORK_ID_TEMPORARY;
/**
* The persistent network id.
@@ -49,7 +57,7 @@
* Otherwise, create a new persistent profile.
* @see #getNetworkId()
*/
- public static final int PERSISTENT_NET_ID = -2;
+ public static final int NETWORK_ID_PERSISTENT = -2;
/** The network name */
private String mNetworkName;
@@ -130,13 +138,13 @@
mPassphrase = match.group(4);
mOwner = new WifiP2pDevice(match.group(5));
if (match.group(6) != null) {
- mNetId = PERSISTENT_NET_ID;
+ mNetId = NETWORK_ID_PERSISTENT;
} else {
- mNetId = TEMPORARY_NET_ID;
+ mNetId = NETWORK_ID_TEMPORARY;
}
} else if (tokens[0].equals("P2P-INVITATION-RECEIVED")) {
String sa = null;
- mNetId = PERSISTENT_NET_ID;
+ mNetId = NETWORK_ID_PERSISTENT;
for (String token : tokens) {
String[] nameValue = token.split("=");
if (nameValue.length != 2) continue;
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
index 3459c94..0fe0675 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
@@ -1293,7 +1293,7 @@
@RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
public void createGroup(Channel c, ActionListener listener) {
checkChannel(c);
- c.mAsyncChannel.sendMessage(CREATE_GROUP, WifiP2pGroup.PERSISTENT_NET_ID,
+ c.mAsyncChannel.sendMessage(CREATE_GROUP, WifiP2pGroup.NETWORK_ID_PERSISTENT,
c.putListener(listener));
}
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java b/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
index 654154d..e78c5bf 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
@@ -18,6 +18,7 @@
import static android.net.wifi.WifiConfiguration.METERED_OVERRIDE_NONE;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -364,4 +365,54 @@
assertTrue(config.validateForR2());
assertTrue(config.isOsuProvisioned());
}
+
+ /**
+ * Verify that the unique identifier generated is correct.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateUniqueId() throws Exception {
+ PasspointConfiguration config = PasspointTestUtils.createConfig();
+ String uniqueId;
+ uniqueId = config.getUniqueId();
+ assertEquals(uniqueId, config.getHomeSp().getFqdn());
+ }
+
+ /**
+ * Verify that the unique identifier API generates an exception if HomeSP is not initialized.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateUniqueIdExceptionWithEmptyHomeSp() throws Exception {
+ PasspointConfiguration config = PasspointTestUtils.createConfig();
+ config.setHomeSp(null);
+ boolean exceptionCaught = false;
+ try {
+ String uniqueId = config.getUniqueId();
+ } catch (IllegalStateException e) {
+ exceptionCaught = true;
+ }
+ assertTrue(exceptionCaught);
+ }
+
+ /**
+ * Verify that the unique identifier API generates an exception if Credential is not
+ * initialized.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateUniqueIdExceptionWithEmptyCredential() throws Exception {
+ PasspointConfiguration config = PasspointTestUtils.createConfig();
+ config.setCredential(null);
+ boolean exceptionCaught = false;
+ try {
+ String uniqueId = config.getUniqueId();
+ } catch (IllegalStateException e) {
+ exceptionCaught = true;
+ }
+ assertTrue(exceptionCaught);
+ }
}