Merge "Add more fields in the light greylist."
diff --git a/Android.mk b/Android.mk
index 470714b..c4fffc89 100644
--- a/Android.mk
+++ b/Android.mk
@@ -664,6 +664,7 @@
-toroot / \
-hdf android.whichdoc online \
-devsite \
+ -yamlV2 \
$(sample_groups) \
-hdf android.hasSamples true \
-samplesdir $(samples_dir)
diff --git a/api/current.txt b/api/current.txt
index fbf1c22..e9902b1 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -23443,6 +23443,11 @@
method protected void finalize();
method public boolean requiresSecureDecoderComponent(java.lang.String);
method public void setMediaCasSession(android.media.MediaCas.Session);
+ field public static final byte SCRAMBLE_CONTROL_EVEN_KEY = 2; // 0x2
+ field public static final byte SCRAMBLE_CONTROL_ODD_KEY = 3; // 0x3
+ field public static final byte SCRAMBLE_CONTROL_RESERVED = 1; // 0x1
+ field public static final byte SCRAMBLE_CONTROL_UNSCRAMBLED = 0; // 0x0
+ field public static final byte SCRAMBLE_FLAG_PES_HEADER = 1; // 0x1
}
public class MediaDescription implements android.os.Parcelable {
diff --git a/api/system-current.txt b/api/system-current.txt
index f9640ba..0555263 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1592,7 +1592,7 @@
method public abstract void onMessageReceipt(int, int, android.hardware.location.ContextHubMessage);
}
- public deprecated class ContextHubMessage {
+ public deprecated class ContextHubMessage implements android.os.Parcelable {
ctor public ContextHubMessage(int, int, byte[]);
method public int describeContents();
method public byte[] getData();
@@ -1723,7 +1723,7 @@
field public static final android.os.Parcelable.Creator<android.hardware.location.MemoryRegion> CREATOR;
}
- public deprecated class NanoApp {
+ public deprecated class NanoApp implements android.os.Parcelable {
ctor public NanoApp();
ctor public deprecated NanoApp(int, byte[]);
ctor public NanoApp(long, byte[]);
@@ -1771,7 +1771,7 @@
field public static final android.os.Parcelable.Creator<android.hardware.location.NanoAppBinary> CREATOR;
}
- public deprecated class NanoAppFilter {
+ public deprecated class NanoAppFilter implements android.os.Parcelable {
ctor public NanoAppFilter(long, int, int, long);
method public int describeContents();
method public boolean testMatch(android.hardware.location.NanoAppInstanceInfo);
@@ -1786,7 +1786,7 @@
field public static final int VENDOR_ANY = -1; // 0xffffffff
}
- public deprecated class NanoAppInstanceInfo {
+ public deprecated class NanoAppInstanceInfo implements android.os.Parcelable {
ctor public NanoAppInstanceInfo();
method public int describeContents();
method public long getAppId();
@@ -4312,7 +4312,8 @@
method public int[] getRecoverySecretTypes() throws android.security.keystore.recovery.InternalRecoveryServiceException;
method public deprecated int getRecoveryStatus(java.lang.String, java.lang.String) throws android.security.keystore.recovery.InternalRecoveryServiceException;
method public int getRecoveryStatus(java.lang.String) throws android.security.keystore.recovery.InternalRecoveryServiceException;
- method public void initRecoveryService(java.lang.String, byte[]) throws java.security.cert.CertificateException, android.security.keystore.recovery.InternalRecoveryServiceException;
+ method public deprecated void initRecoveryService(java.lang.String, byte[]) throws java.security.cert.CertificateException, android.security.keystore.recovery.InternalRecoveryServiceException;
+ method public void initRecoveryService(java.lang.String, byte[], byte[]) throws java.security.cert.CertificateException, android.security.keystore.recovery.InternalRecoveryServiceException;
method public void recoverySecretAvailable(android.security.keystore.recovery.KeyChainProtectionParams) throws android.security.keystore.recovery.InternalRecoveryServiceException;
method public void removeKey(java.lang.String) throws android.security.keystore.recovery.InternalRecoveryServiceException;
method public void setRecoverySecretTypes(int[]) throws android.security.keystore.recovery.InternalRecoveryServiceException;
@@ -5397,6 +5398,7 @@
field public static final int RESET_OPTION_DELETE_FIELD_LOADED_TEST_PROFILES = 2; // 0x2
field public static final int RESET_OPTION_DELETE_OPERATIONAL_PROFILES = 1; // 0x1
field public static final int RESET_OPTION_RESET_DEFAULT_SMDP_ADDRESS = 4; // 0x4
+ field public static final int RESULT_EUICC_NOT_FOUND = -2; // 0xfffffffe
field public static final int RESULT_OK = 0; // 0x0
field public static final int RESULT_UNKNOWN_ERROR = -1; // 0xffffffff
}
diff --git a/api/test-current.txt b/api/test-current.txt
index bc43692..2559d24 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -561,6 +561,7 @@
public static final class Settings.Global extends android.provider.Settings.NameValueTable {
field public static final java.lang.String AUTOFILL_COMPAT_ALLOWED_PACKAGES = "autofill_compat_allowed_packages";
+ field public static final java.lang.String HIDDEN_API_BLACKLIST_EXEMPTIONS = "hidden_api_blacklist_exemptions";
field public static final java.lang.String LOCATION_GLOBAL_KILL_SWITCH = "location_global_kill_switch";
field public static final java.lang.String LOW_POWER_MODE = "low_power";
field public static final java.lang.String USE_OPEN_WIFI_PACKAGE = "use_open_wifi_package";
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 42ae022..8e06504 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -104,6 +104,7 @@
KeyguardStateChanged keyguard_state_changed = 62;
KeyguardBouncerStateChanged keyguard_bouncer_state_changed = 63;
KeyguardBouncerPasswordEntered keyguard_bouncer_password_entered = 64;
+ AppDied app_died=65;
// TODO: Reorder the numbering so that the most frequent occur events occur in the first 15.
}
@@ -1235,6 +1236,17 @@
optional int64 swap_in_bytes = 8;
}
+/*
+ * Logs when the ActivityManagerService detects that an app died.
+ *
+ * Logged from:
+ * frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
+ */
+message AppDied {
+ // timestamp(elapsedRealtime) of record creation
+ optional uint64 timestamp_millis = 1;
+}
+
//////////////////////////////////////////////////////////////////////
// Pulled atoms below this line //
//////////////////////////////////////////////////////////////////////
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index de4d178..2d73ce0 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -44,7 +44,6 @@
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.Rect;
-import android.net.Uri;
import android.os.BatteryStats;
import android.os.Binder;
import android.os.Build;
@@ -2763,30 +2762,6 @@
}
/**
- * Updates (grants or revokes) a persitable URI permission.
- *
- * @param uri URI to be granted or revoked.
- * @param prefix if {@code false}, permission apply to this specific URI; if {@code true}, it
- * applies to all URIs that are prefixed by this URI.
- * @param packageName target package.
- * @param grant if {@code true} a new permission will be granted, otherwise an existing
- * permission will be revoked.
- *
- * @return whether or not the requested succeeded.
- *
- * @hide
- */
- public boolean updatePersistableUriPermission(Uri uri, boolean prefix, String packageName,
- boolean grant) {
- try {
- return getService().updatePersistableUriPermission(uri, prefix, packageName, grant,
- UserHandle.myUserId());
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
* Information you can retrieve about any processes that are in an error condition.
*/
public static class ProcessErrorStateInfo implements Parcelable {
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index eaa23c6..0d45dfa 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -423,10 +423,8 @@
void reportActivityFullyDrawn(in IBinder token, boolean restoredFromBundle);
void restart();
void performIdleMaintenance();
- void takePersistableUriPermission(in Uri uri, int modeFlags, int userId);
- boolean updatePersistableUriPermission(in Uri uri, boolean prefix, String packageName,
- boolean grant, int userId);
- void releasePersistableUriPermission(in Uri uri, int modeFlags, int userId);
+ void takePersistableUriPermission(in Uri uri, int modeFlags, String toPackage, int userId);
+ void releasePersistableUriPermission(in Uri uri, int modeFlags, String toPackage, int userId);
ParceledListSlice getPersistedUriPermissions(in String packageName, boolean incoming);
void appNotRespondingViaProvider(in IBinder connection);
Rect getTaskBounds(int taskId);
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index 4e2cb64..49faf40 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -33,7 +33,6 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceManager.ServiceNotFoundException;
-import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Log;
import android.view.KeyEvent;
@@ -752,6 +751,8 @@
*
* <p>This function can be safely called at any time (even if no search is active.)
*
+ * <p>{@link Configuration#UI_MODE_TYPE_TELEVISION} does not support this method.
+ *
* @see #startSearch
*/
public void stopSearch() {
@@ -802,6 +803,8 @@
/**
* Set or clear the callback that will be invoked whenever the search UI is dismissed.
*
+ * <p>{@link Configuration#UI_MODE_TYPE_TELEVISION} does not support this method.
+ *
* @param listener The {@link OnDismissListener} to use, or null.
*/
public void setOnDismissListener(final OnDismissListener listener) {
@@ -811,6 +814,8 @@
/**
* Set or clear the callback that will be invoked whenever the search UI is canceled.
*
+ * <p>{@link Configuration#UI_MODE_TYPE_TELEVISION} does not support this method.
+ *
* @param listener The {@link OnCancelListener} to use, or null.
*/
public void setOnCancelListener(OnCancelListener listener) {
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index 1312a2e..ef41b10 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -1309,6 +1309,11 @@
if (domain == null) return;
final Uri uri = Uri.parse(domain);
+ if (uri == null) {
+ // Cannot log domain because it could contain PII;
+ Log.w(TAG, "Failed to parse web domain");
+ return;
+ }
mWebScheme = uri.getScheme();
mWebDomain = uri.getHost();
}
diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java
index a2e714e..94fd138 100644
--- a/core/java/android/bluetooth/BluetoothA2dp.java
+++ b/core/java/android/bluetooth/BluetoothA2dp.java
@@ -25,7 +25,6 @@
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
-import android.media.AudioManager;
import android.os.Binder;
import android.os.IBinder;
import android.os.ParcelUuid;
@@ -599,34 +598,6 @@
}
/**
- * Tells remote device to adjust volume. Only if absolute volume is
- * supported. Uses the following values:
- * <ul>
- * <li>{@link AudioManager#ADJUST_LOWER}</li>
- * <li>{@link AudioManager#ADJUST_RAISE}</li>
- * <li>{@link AudioManager#ADJUST_MUTE}</li>
- * <li>{@link AudioManager#ADJUST_UNMUTE}</li>
- * </ul>
- *
- * @param direction One of the supported adjust values.
- * @hide
- */
- public void adjustAvrcpAbsoluteVolume(int direction) {
- if (DBG) Log.d(TAG, "adjustAvrcpAbsoluteVolume");
- try {
- mServiceLock.readLock().lock();
- if (mService != null && isEnabled()) {
- mService.adjustAvrcpAbsoluteVolume(direction);
- }
- if (mService == null) Log.w(TAG, "Proxy not attached to service");
- } catch (RemoteException e) {
- Log.e(TAG, "Error talking to BT service in adjustAvrcpAbsoluteVolume()", e);
- } finally {
- mServiceLock.readLock().unlock();
- }
- }
-
- /**
* Tells remote device to set an absolute volume. Only if absolute volume is supported
*
* @param volume Absolute volume to be set on AVRCP side
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 22496a4..10331d4 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -2102,7 +2102,23 @@
Preconditions.checkNotNull(uri, "uri");
try {
ActivityManager.getService().takePersistableUriPermission(
- ContentProvider.getUriWithoutUserId(uri), modeFlags, resolveUserId(uri));
+ ContentProvider.getUriWithoutUserId(uri), modeFlags, /* toPackage= */ null,
+ resolveUserId(uri));
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public void takePersistableUriPermission(@NonNull String toPackage, @NonNull Uri uri,
+ @Intent.AccessUriMode int modeFlags) {
+ Preconditions.checkNotNull(toPackage, "toPackage");
+ Preconditions.checkNotNull(uri, "uri");
+ try {
+ ActivityManager.getService().takePersistableUriPermission(
+ ContentProvider.getUriWithoutUserId(uri), modeFlags, toPackage,
+ resolveUserId(uri));
} catch (RemoteException e) {
}
}
@@ -2120,7 +2136,23 @@
Preconditions.checkNotNull(uri, "uri");
try {
ActivityManager.getService().releasePersistableUriPermission(
- ContentProvider.getUriWithoutUserId(uri), modeFlags, resolveUserId(uri));
+ ContentProvider.getUriWithoutUserId(uri), modeFlags, /* toPackage= */ null,
+ resolveUserId(uri));
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public void releasePersistableUriPermission(@NonNull String toPackage, @NonNull Uri uri,
+ @Intent.AccessUriMode int modeFlags) {
+ Preconditions.checkNotNull(toPackage, "toPackage");
+ Preconditions.checkNotNull(uri, "uri");
+ try {
+ ActivityManager.getService().releasePersistableUriPermission(
+ ContentProvider.getUriWithoutUserId(uri), modeFlags, toPackage,
+ resolveUserId(uri));
} catch (RemoteException e) {
}
}
diff --git a/core/java/android/content/pm/PackageItemInfo.java b/core/java/android/content/pm/PackageItemInfo.java
index 2c0c6ad0..53ffd55 100644
--- a/core/java/android/content/pm/PackageItemInfo.java
+++ b/core/java/android/content/pm/PackageItemInfo.java
@@ -43,6 +43,14 @@
*/
public class PackageItemInfo {
private static final float MAX_LABEL_SIZE_PX = 500f;
+
+ private static volatile boolean sForceSafeLabels = false;
+
+ /** {@hide} */
+ public static void setForceSafeLabels(boolean forceSafeLabels) {
+ sForceSafeLabels = forceSafeLabels;
+ }
+
/**
* Public name of this item. From the "android:name" attribute.
*/
@@ -128,7 +136,16 @@
* @return Returns a CharSequence containing the item's label. If the
* item does not have a label, its name is returned.
*/
- public CharSequence loadLabel(PackageManager pm) {
+ public @NonNull CharSequence loadLabel(@NonNull PackageManager pm) {
+ if (sForceSafeLabels) {
+ return loadSafeLabel(pm);
+ } else {
+ return loadUnsafeLabel(pm);
+ }
+ }
+
+ /** {@hide} */
+ public CharSequence loadUnsafeLabel(PackageManager pm) {
if (nonLocalizedLabel != null) {
return nonLocalizedLabel;
}
@@ -163,7 +180,7 @@
@SystemApi
public @NonNull CharSequence loadSafeLabel(@NonNull PackageManager pm) {
// loadLabel() always returns non-null
- String label = loadLabel(pm).toString();
+ String label = loadUnsafeLabel(pm).toString();
// strip HTML tags to avoid <br> and other tags overwriting original message
String labelStr = Html.fromHtml(label).toString();
diff --git a/core/java/android/hardware/location/ContextHubMessage.java b/core/java/android/hardware/location/ContextHubMessage.java
index f85ce3e..e1c69d7 100644
--- a/core/java/android/hardware/location/ContextHubMessage.java
+++ b/core/java/android/hardware/location/ContextHubMessage.java
@@ -33,7 +33,7 @@
*/
@SystemApi
@Deprecated
-public class ContextHubMessage {
+public class ContextHubMessage implements Parcelable {
private static final int DEBUG_LOG_NUM_BYTES = 16;
private int mType;
private int mVersion;
diff --git a/core/java/android/hardware/location/NanoApp.java b/core/java/android/hardware/location/NanoApp.java
index b5c01ec..ded1bb8c 100644
--- a/core/java/android/hardware/location/NanoApp.java
+++ b/core/java/android/hardware/location/NanoApp.java
@@ -36,7 +36,7 @@
*/
@SystemApi
@Deprecated
-public class NanoApp {
+public class NanoApp implements Parcelable {
private final String TAG = "NanoApp";
private final String UNKNOWN = "Unknown";
diff --git a/core/java/android/hardware/location/NanoAppFilter.java b/core/java/android/hardware/location/NanoAppFilter.java
index 75a96ee..4d8e734 100644
--- a/core/java/android/hardware/location/NanoAppFilter.java
+++ b/core/java/android/hardware/location/NanoAppFilter.java
@@ -28,7 +28,7 @@
*/
@SystemApi
@Deprecated
-public class NanoAppFilter {
+public class NanoAppFilter implements Parcelable {
private static final String TAG = "NanoAppFilter";
diff --git a/core/java/android/hardware/location/NanoAppInstanceInfo.java b/core/java/android/hardware/location/NanoAppInstanceInfo.java
index f1926eaa..75fb915 100644
--- a/core/java/android/hardware/location/NanoAppInstanceInfo.java
+++ b/core/java/android/hardware/location/NanoAppInstanceInfo.java
@@ -34,7 +34,7 @@
*/
@SystemApi
@Deprecated
-public class NanoAppInstanceInfo {
+public class NanoAppInstanceInfo implements Parcelable {
private String mPublisher = "Unknown";
private String mName = "Unknown";
diff --git a/core/java/android/net/IpPrefix.java b/core/java/android/net/IpPrefix.java
index 6e2654e..4631c56 100644
--- a/core/java/android/net/IpPrefix.java
+++ b/core/java/android/net/IpPrefix.java
@@ -25,6 +25,7 @@
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
+import java.util.Comparator;
/**
* This class represents an IP prefix, i.e., a contiguous block of IP addresses aligned on a
@@ -187,6 +188,20 @@
}
/**
+ * Returns whether the specified prefix is entirely contained in this prefix.
+ *
+ * Note this is mathematical inclusion, so a prefix is always contained within itself.
+ * @param otherPrefix the prefix to test
+ * @hide
+ */
+ public boolean containsPrefix(IpPrefix otherPrefix) {
+ if (otherPrefix.getPrefixLength() < prefixLength) return false;
+ final byte[] otherAddress = otherPrefix.getRawAddress();
+ NetworkUtils.maskRawAddress(otherAddress, prefixLength);
+ return Arrays.equals(otherAddress, address);
+ }
+
+ /**
* @hide
*/
public boolean isIPv6() {
@@ -230,6 +245,38 @@
}
/**
+ * Returns a comparator ordering IpPrefixes by length, shorter to longer.
+ * Contents of the address will break ties.
+ * @hide
+ */
+ public static Comparator<IpPrefix> lengthComparator() {
+ return new Comparator<IpPrefix>() {
+ @Override
+ public int compare(IpPrefix prefix1, IpPrefix prefix2) {
+ if (prefix1.isIPv4()) {
+ if (prefix2.isIPv6()) return -1;
+ } else {
+ if (prefix2.isIPv4()) return 1;
+ }
+ final int p1len = prefix1.getPrefixLength();
+ final int p2len = prefix2.getPrefixLength();
+ if (p1len < p2len) return -1;
+ if (p2len < p1len) return 1;
+ final byte[] a1 = prefix1.address;
+ final byte[] a2 = prefix2.address;
+ final int len = a1.length < a2.length ? a1.length : a2.length;
+ for (int i = 0; i < len; ++i) {
+ if (a1[i] < a2[i]) return -1;
+ if (a1[i] > a2[i]) return 1;
+ }
+ if (a2.length < len) return 1;
+ if (a1.length < len) return -1;
+ return 0;
+ }
+ };
+ }
+
+ /**
* Implement the Parcelable interface.
*/
public static final Creator<IpPrefix> CREATOR =
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 74b52c9..17b46c6 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -891,7 +891,16 @@
/**
* List of UIDs this network applies to. No restriction if null.
* <p>
- * This is typically (and at this time, only) used by VPN. This network is only available to
+ * For networks, mUids represent the list of network this applies to, and null means this
+ * network applies to all UIDs.
+ * For requests, mUids is the list of UIDs this network MUST apply to to match ; ALL UIDs
+ * must be included in a network so that they match. As an exception to the general rule,
+ * a null mUids field for requests mean "no requirements" rather than what the general rule
+ * would suggest ("must apply to all UIDs") : this is because this has shown to be what users
+ * of this API expect in practice. A network that must match all UIDs can still be
+ * expressed with a set ranging the entire set of possible UIDs.
+ * <p>
+ * mUids is typically (and at this time, only) used by VPN. This network is only available to
* the UIDs in this list, and it is their default network. Apps in this list that wish to
* bypass the VPN can do so iff the VPN app allows them to or if they are privileged. If this
* member is null, then the network is not restricted by app UID. If it's an empty list, then
@@ -1013,8 +1022,7 @@
* @hide
*/
public boolean satisfiedByUids(NetworkCapabilities nc) {
- if (null == nc.mUids) return true; // The network satisfies everything.
- if (null == mUids) return false; // Not everything allowed but requires everything
+ if (null == nc.mUids || null == mUids) return true; // The network satisfies everything.
for (UidRange requiredRange : mUids) {
if (requiredRange.contains(nc.mEstablishingVpnAppUid)) return true;
if (!nc.appliesToUidRange(requiredRange)) {
diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java
index a072409..61199f9 100644
--- a/core/java/android/net/NetworkRequest.java
+++ b/core/java/android/net/NetworkRequest.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.Process;
import android.text.TextUtils;
import android.util.proto.ProtoOutputStream;
@@ -132,12 +133,18 @@
* needed in terms of {@link NetworkCapabilities} features
*/
public static class Builder {
- private final NetworkCapabilities mNetworkCapabilities = new NetworkCapabilities();
+ private final NetworkCapabilities mNetworkCapabilities;
/**
* Default constructor for Builder.
*/
- public Builder() {}
+ public Builder() {
+ // By default, restrict this request to networks available to this app.
+ // Apps can rescind this restriction, but ConnectivityService will enforce
+ // it for apps that do not have the NETWORK_SETTINGS permission.
+ mNetworkCapabilities = new NetworkCapabilities();
+ mNetworkCapabilities.setSingleUid(Process.myUid());
+ }
/**
* Build {@link NetworkRequest} give the current set of capabilities.
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index fe9563d..9a5d502 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -16,19 +16,20 @@
package android.net;
-import java.io.FileDescriptor;
-import java.net.InetAddress;
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.net.SocketException;
-import java.net.UnknownHostException;
-import java.util.Collection;
-import java.util.Locale;
-
import android.os.Parcel;
import android.util.Log;
import android.util.Pair;
+import java.io.FileDescriptor;
+import java.math.BigInteger;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.SocketException;
+import java.net.UnknownHostException;
+import java.util.Collection;
+import java.util.Locale;
+import java.util.TreeSet;
/**
* Native methods for managing network interfaces.
@@ -385,4 +386,72 @@
result = builder.toString();
return result;
}
+
+ /**
+ * Returns a prefix set without overlaps.
+ *
+ * This expects the src set to be sorted from shorter to longer. Results are undefined
+ * failing this condition. The returned prefix set is sorted in the same order as the
+ * passed set, with the same comparator.
+ */
+ private static TreeSet<IpPrefix> deduplicatePrefixSet(final TreeSet<IpPrefix> src) {
+ final TreeSet<IpPrefix> dst = new TreeSet<>(src.comparator());
+ // Prefixes match addresses that share their upper part up to their length, therefore
+ // the only kind of possible overlap in two prefixes is strict inclusion of the longer
+ // (more restrictive) in the shorter (including equivalence if they have the same
+ // length).
+ // Because prefixes in the src set are sorted from shorter to longer, deduplicating
+ // is done by simply iterating in order, and not adding any longer prefix that is
+ // already covered by a shorter one.
+ newPrefixes:
+ for (IpPrefix newPrefix : src) {
+ for (IpPrefix existingPrefix : dst) {
+ if (existingPrefix.containsPrefix(newPrefix)) {
+ continue newPrefixes;
+ }
+ }
+ dst.add(newPrefix);
+ }
+ return dst;
+ }
+
+ /**
+ * Returns how many IPv4 addresses match any of the prefixes in the passed ordered set.
+ *
+ * Obviously this returns an integral value between 0 and 2**32.
+ * The behavior is undefined if any of the prefixes is not an IPv4 prefix or if the
+ * set is not ordered smallest prefix to longer prefix.
+ *
+ * @param prefixes the set of prefixes, ordered by length
+ */
+ public static long routedIPv4AddressCount(final TreeSet<IpPrefix> prefixes) {
+ long routedIPCount = 0;
+ for (final IpPrefix prefix : deduplicatePrefixSet(prefixes)) {
+ if (!prefix.isIPv4()) {
+ Log.wtf(TAG, "Non-IPv4 prefix in routedIPv4AddressCount");
+ }
+ int rank = 32 - prefix.getPrefixLength();
+ routedIPCount += 1L << rank;
+ }
+ return routedIPCount;
+ }
+
+ /**
+ * Returns how many IPv6 addresses match any of the prefixes in the passed ordered set.
+ *
+ * This returns a BigInteger between 0 and 2**128.
+ * The behavior is undefined if any of the prefixes is not an IPv6 prefix or if the
+ * set is not ordered smallest prefix to longer prefix.
+ */
+ public static BigInteger routedIPv6AddressCount(final TreeSet<IpPrefix> prefixes) {
+ BigInteger routedIPCount = BigInteger.ZERO;
+ for (final IpPrefix prefix : deduplicatePrefixSet(prefixes)) {
+ if (!prefix.isIPv6()) {
+ Log.wtf(TAG, "Non-IPv6 prefix in routedIPv6AddressCount");
+ }
+ int rank = 128 - prefix.getPrefixLength();
+ routedIPCount = routedIPCount.add(BigInteger.ONE.shiftLeft(rank));
+ }
+ return routedIPCount;
+ }
}
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index 76c13be..a93e25a 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -479,6 +479,8 @@
/** Initialize a Builder from an existing ThreadPolicy. */
public Builder(ThreadPolicy policy) {
mMask = policy.mask;
+ mListener = policy.mListener;
+ mExecutor = policy.mCallbackExecutor;
}
/**
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index bc3e740..8fc6901 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -11468,6 +11468,7 @@
*
* @hide
*/
+ @TestApi
public static final String HIDDEN_API_BLACKLIST_EXEMPTIONS =
"hidden_api_blacklist_exemptions";
diff --git a/core/java/android/security/keystore/recovery/RecoveryController.java b/core/java/android/security/keystore/recovery/RecoveryController.java
index 6c882e1..4881375 100644
--- a/core/java/android/security/keystore/recovery/RecoveryController.java
+++ b/core/java/android/security/keystore/recovery/RecoveryController.java
@@ -99,7 +99,11 @@
public static final int ERROR_SESSION_EXPIRED = 24;
/**
- * Failed because the provided certificate was not a valid X509 certificate.
+ * Failed because the format of the provided certificate is incorrect, e.g., cannot be decoded
+ * properly or misses necessary fields.
+ *
+ * <p>Note that this is different from {@link #ERROR_INVALID_CERTIFICATE}, which implies the
+ * certificate has a correct format but cannot be validated.
*
* @hide
*/
@@ -121,6 +125,16 @@
*/
public static final int ERROR_INVALID_KEY_FORMAT = 27;
+ /**
+ * Failed because the provided certificate cannot be validated, e.g., is expired or has invalid
+ * signatures.
+ *
+ * <p>Note that this is different from {@link #ERROR_BAD_CERTIFICATE_FORMAT}, which denotes
+ * incorrect certificate formats, e.g., due to wrong encoding or structure.
+ *
+ * @hide
+ */
+ public static final int ERROR_INVALID_CERTIFICATE = 28;
private final ILockSettings mBinder;
private final KeyStore mKeyStore;
@@ -149,23 +163,9 @@
}
/**
- * Initializes key recovery service for the calling application. RecoveryController
- * randomly chooses one of the keys from the list and keeps it to use for future key export
- * operations. Collection of all keys in the list must be signed by the provided {@code
- * rootCertificateAlias}, which must also be present in the list of root certificates
- * preinstalled on the device. The random selection allows RecoveryController to select
- * which of a set of remote recovery service devices will be used.
- *
- * <p>In addition, RecoveryController enforces a delay of three months between
- * consecutive initialization attempts, to limit the ability of an attacker to often switch
- * remote recovery devices and significantly increase number of recovery attempts.
- *
- * @param rootCertificateAlias alias of a root certificate preinstalled on the device
- * @param signedPublicKeyList binary blob a list of X509 certificates and signature
- * @throws CertificateException if the {@code signedPublicKeyList} is in a bad format.
- * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
- * service.
+ * @deprecated Use {@link #initRecoveryService(String, byte[], byte[])} instead.
*/
+ @Deprecated
@RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
public void initRecoveryService(
@NonNull String rootCertificateAlias, @NonNull byte[] signedPublicKeyList)
@@ -175,7 +175,54 @@
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
} catch (ServiceSpecificException e) {
- if (e.errorCode == ERROR_BAD_CERTIFICATE_FORMAT) {
+ if (e.errorCode == ERROR_BAD_CERTIFICATE_FORMAT
+ || e.errorCode == ERROR_INVALID_CERTIFICATE) {
+ throw new CertificateException(e.getMessage());
+ }
+ throw wrapUnexpectedServiceSpecificException(e);
+ }
+ }
+
+ /**
+ * Initializes the recovery service for the calling application. The detailed steps should be:
+ * <ol>
+ * <li>Parse {@code signatureFile} to get relevant information.
+ * <li>Validate the signer's X509 certificate, contained in {@code signatureFile}, against
+ * the root certificate pre-installed in the OS and chosen by {@code
+ * rootCertificateAlias}.
+ * <li>Verify the public-key signature, contained in {@code signatureFile}, and verify it
+ * against the entire {@code certificateFile}.
+ * <li>Parse {@code certificateFile} to get relevant information.
+ * <li>Check the serial number, contained in {@code certificateFile}, and skip the following
+ * steps if the serial number is not larger than the one previously stored.
+ * <li>Randomly choose a X509 certificate from the endpoint X509 certificates, contained in
+ * {@code certificateFile}, and validate it against the root certificate pre-installed
+ * in the OS and chosen by {@code rootCertificateAlias}.
+ * <li>Store the chosen X509 certificate and the serial in local database for later use.
+ * </ol>
+ *
+ * @param rootCertificateAlias the alias of a root certificate pre-installed in the OS
+ * @param certificateFile the binary content of the XML file containing a list of recovery
+ * service X509 certificates, and other metadata including the serial number
+ * @param signatureFile the binary content of the XML file containing the public-key signature
+ * of the entire certificate file, and a signer's X509 certificate
+ * @throws CertificateException if the given certificate files cannot be parsed or validated
+ * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
+ * service.
+ */
+ @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
+ public void initRecoveryService(
+ @NonNull String rootCertificateAlias, @NonNull byte[] certificateFile,
+ @NonNull byte[] signatureFile)
+ throws CertificateException, InternalRecoveryServiceException {
+ try {
+ mBinder.initRecoveryServiceWithSigFile(
+ rootCertificateAlias, certificateFile, signatureFile);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ } catch (ServiceSpecificException e) {
+ if (e.errorCode == ERROR_BAD_CERTIFICATE_FORMAT
+ || e.errorCode == ERROR_INVALID_CERTIFICATE) {
throw new CertificateException(e.getMessage());
}
throw wrapUnexpectedServiceSpecificException(e);
diff --git a/core/java/android/security/keystore/recovery/RecoverySession.java b/core/java/android/security/keystore/recovery/RecoverySession.java
index 2b627b4..137dd89 100644
--- a/core/java/android/security/keystore/recovery/RecoverySession.java
+++ b/core/java/android/security/keystore/recovery/RecoverySession.java
@@ -94,7 +94,8 @@
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
} catch (ServiceSpecificException e) {
- if (e.errorCode == RecoveryController.ERROR_BAD_CERTIFICATE_FORMAT) {
+ if (e.errorCode == RecoveryController.ERROR_BAD_CERTIFICATE_FORMAT
+ || e.errorCode == RecoveryController.ERROR_INVALID_CERTIFICATE) {
throw new CertificateException(e.getMessage());
}
throw mRecoveryController.wrapUnexpectedServiceSpecificException(e);
@@ -143,7 +144,8 @@
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
} catch (ServiceSpecificException e) {
- if (e.errorCode == RecoveryController.ERROR_BAD_CERTIFICATE_FORMAT) {
+ if (e.errorCode == RecoveryController.ERROR_BAD_CERTIFICATE_FORMAT
+ || e.errorCode == RecoveryController.ERROR_INVALID_CERTIFICATE) {
throw new CertificateException(e.getMessage());
}
throw mRecoveryController.wrapUnexpectedServiceSpecificException(e);
diff --git a/core/java/android/text/format/DateFormat.java b/core/java/android/text/format/DateFormat.java
index eba9129..94025ef 100755
--- a/core/java/android/text/format/DateFormat.java
+++ b/core/java/android/text/format/DateFormat.java
@@ -159,9 +159,9 @@
private static Locale sIs24HourLocale;
private static boolean sIs24Hour;
-
/**
- * Returns true if user preference is set to 24-hour format.
+ * Returns true if times should be formatted as 24 hour times, false if times should be
+ * formatted as 12 hour (AM/PM) times. Based on the user's chosen locale and other preferences.
* @param context the context to use for the content resolver
* @return true if 24 hour time format is selected, false otherwise.
*/
@@ -170,7 +170,8 @@
}
/**
- * Returns true if user preference with the given user handle is set to 24-hour format.
+ * Returns true if times should be formatted as 24 hour times, false if times should be
+ * formatted as 12 hour (AM/PM) times. Based on the user's chosen locale and other preferences.
* @param context the context to use for the content resolver
* @param userHandle the user handle of the user to query.
* @return true if 24 hour time format is selected, false otherwise.
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index cc9b8a8..b7524fb 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -152,6 +152,7 @@
private static native void nativeSeverChildren(long transactionObj, long nativeObject);
private static native void nativeSetOverrideScalingMode(long transactionObj, long nativeObject,
int scalingMode);
+ private static native void nativeDestroy(long transactionObj, long nativeObject);
private static native IBinder nativeGetHandle(long nativeObject);
private static native boolean nativeGetTransformToDisplayInverse(long nativeObject);
@@ -1572,6 +1573,16 @@
return this;
}
+ /**
+ * Same as {@link #destroy()} except this is invoked in a transaction instead of
+ * immediately.
+ */
+ public Transaction destroy(SurfaceControl sc) {
+ sc.checkNotReleased();
+ nativeDestroy(mNativeObject, sc.mNativeObject);
+ return this;
+ }
+
public Transaction setDisplaySurface(IBinder displayToken, Surface surface) {
if (displayToken == null) {
throw new IllegalArgumentException("displayToken must not be null");
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index a8f6b03..fadc3dc 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -1683,7 +1683,7 @@
* @param callback will be called on the UI thread with {@code true} if initialization is
* successful, {@code false} otherwise.
*/
- public static void startSafeBrowsing(Context context,
+ public static void startSafeBrowsing(@NonNull Context context,
@Nullable ValueCallback<Boolean> callback) {
getFactory().getStatics().initSafeBrowsing(context, callback);
}
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index 7c9cf7a..5a06f7f 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -65,6 +65,8 @@
// {@code ServiceSpecificException} may be thrown to signal an error, which caller can
// convert to {@code RecoveryManagerException}.
void initRecoveryService(in String rootCertificateAlias, in byte[] signedPublicKeyList);
+ void initRecoveryServiceWithSigFile(in String rootCertificateAlias,
+ in byte[] recoveryServiceCertFile, in byte[] recoveryServiceSigFile);
KeyChainSnapshot getKeyChainSnapshot();
byte[] generateAndStoreKey(String alias);
String generateKey(String alias);
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 0ef5445..8ca5062 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -846,6 +846,14 @@
transaction->setOverrideScalingMode(ctrl, scalingMode);
}
+static void nativeDestroyInTransaction(JNIEnv* env, jclass clazz,
+ jlong transactionObj,
+ jlong nativeObject) {
+ auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+ auto ctrl = reinterpret_cast<SurfaceControl*>(nativeObject);
+ transaction->destroySurface(ctrl);
+}
+
static jobject nativeGetHandle(JNIEnv* env, jclass clazz, jlong nativeObject) {
auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
return javaObjectForIBinder(env, ctrl->getHandle());
@@ -997,6 +1005,8 @@
(void*)nativeSeverChildren } ,
{"nativeSetOverrideScalingMode", "(JJI)V",
(void*)nativeSetOverrideScalingMode },
+ {"nativeDestroy", "(JJ)V",
+ (void*)nativeDestroyInTransaction },
{"nativeGetHandle", "(J)Landroid/os/IBinder;",
(void*)nativeGetHandle },
{"nativeScreenshotToBuffer",
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index a7178a0..5e12e7e 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2978,7 +2978,18 @@
settings app. This permission cannot be granted to third-party apps.
<p>Protection level: signature
-->
- <permission android:name="android.permission.MANAGE_SCOPED_ACCESS_DIRECTORY_PERMISSIONS"
+ <permission
+ android:name="android.permission.MANAGE_SCOPED_ACCESS_DIRECTORY_PERMISSIONS"
+ android:protectionLevel="signature" />
+
+ <!-- @hide
+ Allows an application to change the status of a persistable URI permission granted
+ to another application.
+ <p>This permission should <em>only</em> be requested by the platform
+ settings app. This permission cannot be granted to third-party apps.
+ <p>Protection level: signature
+ -->
+ <permission android:name="android.permission.FORCE_PERSISTABLE_URI_PERMISSIONS"
android:protectionLevel="signature" />
<!-- @SystemApi Old permission for deleting an app's cache files, no longer used,
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index c3ae5fa..f38dcea 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3320,8 +3320,7 @@
[CHAR LIMIT=NONE] -->
<string name="alert_windows_notification_message">If you don’t want <xliff:g id="name" example="Google Maps">%s</xliff:g> to use this feature, tap to open settings and turn it off.</string>
<!-- Notification action to turn-off app displaying on-top of other apps. [CHAR LIMIT=20] -->
- <string name="alert_windows_notification_turn_off_action">TURN OFF</string>
-
+ <string name="alert_windows_notification_turn_off_action">Turn off</string>
<!-- External media notification strings -->
<skip />
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
index e74dc6d..54358e3 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -201,10 +201,10 @@
* android:drawable="@drawable/vectordrawable" >
* <target
* android:name="rotationGroup"
- * android:animation="@anim/rotation" />
+ * android:animation="@animator/rotation" />
* <target
* android:name="v"
- * android:animation="@anim/path_morph" />
+ * android:animation="@animator/path_morph" />
* </animated-vector>
* </pre>
* </li>
diff --git a/media/java/android/media/MediaDescrambler.java b/media/java/android/media/MediaDescrambler.java
index 40c837b..99bd254 100644
--- a/media/java/android/media/MediaDescrambler.java
+++ b/media/java/android/media/MediaDescrambler.java
@@ -125,6 +125,38 @@
}
/**
+ * Scramble control value indicating that the samples are not scrambled.
+ * @see #descramble(ByteBuffer, ByteBuffer, android.media.MediaCodec.CryptoInfo)
+ */
+ public static final byte SCRAMBLE_CONTROL_UNSCRAMBLED = 0;
+
+ /**
+ * Scramble control value reserved and shouldn't be used currently.
+ * @see #descramble(ByteBuffer, ByteBuffer, android.media.MediaCodec.CryptoInfo)
+ */
+ public static final byte SCRAMBLE_CONTROL_RESERVED = 1;
+
+ /**
+ * Scramble control value indicating that the even key is used.
+ * @see #descramble(ByteBuffer, ByteBuffer, android.media.MediaCodec.CryptoInfo)
+ */
+ public static final byte SCRAMBLE_CONTROL_EVEN_KEY = 2;
+
+ /**
+ * Scramble control value indicating that the odd key is used.
+ * @see #descramble(ByteBuffer, ByteBuffer, android.media.MediaCodec.CryptoInfo)
+ */
+ public static final byte SCRAMBLE_CONTROL_ODD_KEY = 3;
+
+ /**
+ * Scramble flag for a hint indicating that the descrambling request is for
+ * retrieving the PES header info only.
+ *
+ * @see #descramble(ByteBuffer, ByteBuffer, android.media.MediaCodec.CryptoInfo)
+ */
+ public static final byte SCRAMBLE_FLAG_PES_HEADER = (1 << 0);
+
+ /**
* Descramble a ByteBuffer of data described by a
* {@link android.media.MediaCodec.CryptoInfo} structure.
*
@@ -133,7 +165,15 @@
* @param dstBuf ByteBuffer to hold the descrambled data, which starts at
* dstBuf.position().
* @param cryptoInfo a {@link android.media.MediaCodec.CryptoInfo} structure
- * describing the subsamples contained in src.
+ * describing the subsamples contained in srcBuf. The iv and mode fields in
+ * CryptoInfo are not used. key[0] contains the MPEG2TS scrambling control bits
+ * (as defined in ETSI TS 100 289 (2011): "Digital Video Broadcasting (DVB);
+ * Support for use of the DVB Scrambling Algorithm version 3 within digital
+ * broadcasting systems"), and the value must be one of {@link #SCRAMBLE_CONTROL_UNSCRAMBLED},
+ * {@link #SCRAMBLE_CONTROL_RESERVED}, {@link #SCRAMBLE_CONTROL_EVEN_KEY} or
+ * {@link #SCRAMBLE_CONTROL_ODD_KEY}. key[1] is a set of bit flags, with the
+ * only possible bit being {@link #SCRAMBLE_FLAG_PES_HEADER} currently.
+ * key[2~15] are not used.
*
* @return number of bytes that have been successfully descrambled, with negative
* values indicating errors.
@@ -169,6 +209,7 @@
try {
return native_descramble(
cryptoInfo.key[0],
+ cryptoInfo.key[1],
cryptoInfo.numSubSamples,
cryptoInfo.numBytesOfClearData,
cryptoInfo.numBytesOfEncryptedData,
@@ -204,7 +245,8 @@
private native final void native_setup(@NonNull IHwBinder decramblerBinder);
private native final void native_release();
private native final int native_descramble(
- byte key, int numSubSamples, int[] numBytesOfClearData, int[] numBytesOfEncryptedData,
+ byte key, byte flags, int numSubSamples,
+ int[] numBytesOfClearData, int[] numBytesOfEncryptedData,
@NonNull ByteBuffer srcBuf, int srcOffset, int srcLimit,
ByteBuffer dstBuf, int dstOffset, int dstLimit) throws RemoteException;
diff --git a/media/java/android/media/MediaItem2.java b/media/java/android/media/MediaItem2.java
index b7b75e4..f9eceab 100644
--- a/media/java/android/media/MediaItem2.java
+++ b/media/java/android/media/MediaItem2.java
@@ -57,22 +57,6 @@
private final MediaItem2Provider mProvider;
/**
- * Create a new media item.
- *
- * @param mediaId id of this item. It must be unique whithin this app
- * @param metadata metadata with the media id.
- * @param flags The flags for this item.
- * @hide
- */
- // TODO(jaewan): Remove this
- public MediaItem2(@NonNull Context context, @NonNull String mediaId,
- @NonNull DataSourceDesc dsd, @Nullable MediaMetadata2 metadata,
- @Flags int flags) {
- mProvider = ApiLoader.getProvider(context).createMediaItem2(
- context, this, mediaId, dsd, metadata, flags);
- }
-
- /**
* Create a new media item
* @hide
*/
@@ -159,13 +143,8 @@
/**
* Build {@link MediaItem2}
*/
- // TODO(jaewan): Move it to updatable
public static final class Builder {
- private Context mContext;
- private @Flags int mFlags;
- private String mMediaId;
- private MediaMetadata2 mMetadata;
- private DataSourceDesc mDataSourceDesc;
+ private final MediaItem2Provider.BuilderProvider mProvider;
/**
* Constructor for {@link Builder}
@@ -174,8 +153,8 @@
* @param flags
*/
public Builder(@NonNull Context context, @Flags int flags) {
- mContext = context;
- mFlags = flags;
+ mProvider = ApiLoader.getProvider(context).createMediaItem2Builder(
+ context, this, flags);
}
/**
@@ -192,8 +171,7 @@
* @return this instance for chaining
*/
public Builder setMediaId(@Nullable String mediaId) {
- mMediaId = mediaId;
- return this;
+ return mProvider.setMediaId_impl(mediaId);
}
/**
@@ -208,19 +186,17 @@
* @return this instance for chaining
*/
public Builder setMetadata(@Nullable MediaMetadata2 metadata) {
- mMetadata = metadata;
- return this;
+ return mProvider.setMetadata_impl(metadata);
}
/**
- * Set the data source descriptor for this instance. {@code null} for unset.
+ * Set the data source descriptor for this instance. Should not be {@code null}.
*
* @param dataSourceDesc data source descriptor
* @return this instance for chaining
*/
- public Builder setDataSourceDesc(@Nullable DataSourceDesc dataSourceDesc) {
- mDataSourceDesc = dataSourceDesc;
- return this;
+ public Builder setDataSourceDesc(@NonNull DataSourceDesc dataSourceDesc) {
+ return mProvider.setDataSourceDesc_impl(dataSourceDesc);
}
/**
@@ -229,13 +205,7 @@
* @return a new {@link MediaItem2}.
*/
public MediaItem2 build() {
- String id = (mMetadata != null)
- ? mMetadata.getString(MediaMetadata2.METADATA_KEY_MEDIA_ID) : null;
- if (id == null) {
- // TODO(jaewan): Double check if its sufficient (e.g. Use UUID instead?)
- id = (mMediaId != null) ? mMediaId : toString();
- }
- return new MediaItem2(mContext, id, mDataSourceDesc, mMetadata, mFlags);
+ return mProvider.build_impl();
}
}
}
diff --git a/media/java/android/media/MediaMetadata2.java b/media/java/android/media/MediaMetadata2.java
index b363831..f3425e8 100644
--- a/media/java/android/media/MediaMetadata2.java
+++ b/media/java/android/media/MediaMetadata2.java
@@ -41,78 +41,143 @@
public final class MediaMetadata2 {
/**
* The title of the media.
+ *
+ * @see Builder#putText(String, CharSequence)
+ * @see Builder#putString(String, String)
+ * @see #getText(String)
+ * @see #getString(String)
*/
public static final String METADATA_KEY_TITLE = "android.media.metadata.TITLE";
/**
* The artist of the media.
+ *
+ * @see Builder#putText(String, CharSequence)
+ * @see Builder#putString(String, String)
+ * @see #getText(String)
+ * @see #getString(String)
*/
public static final String METADATA_KEY_ARTIST = "android.media.metadata.ARTIST";
/**
* The duration of the media in ms. A negative duration indicates that the
* duration is unknown (or infinite).
+ *
+ * @see Builder#putLong(String, long)
+ * @see #getLong(String)
*/
public static final String METADATA_KEY_DURATION = "android.media.metadata.DURATION";
/**
* The album title for the media.
+ *
+ * @see Builder#putText(String, CharSequence)
+ * @see Builder#putString(String, String)
+ * @see #getText(String)
+ * @see #getString(String)
*/
public static final String METADATA_KEY_ALBUM = "android.media.metadata.ALBUM";
/**
* The author of the media.
+ *
+ * @see Builder#putText(String, CharSequence)
+ * @see Builder#putString(String, String)
+ * @see #getText(String)
+ * @see #getString(String)
*/
public static final String METADATA_KEY_AUTHOR = "android.media.metadata.AUTHOR";
/**
* The writer of the media.
+ *
+ * @see Builder#putText(String, CharSequence)
+ * @see Builder#putString(String, String)
+ * @see #getText(String)
+ * @see #getString(String)
*/
public static final String METADATA_KEY_WRITER = "android.media.metadata.WRITER";
/**
* The composer of the media.
+ *
+ * @see Builder#putText(String, CharSequence)
+ * @see Builder#putString(String, String)
+ * @see #getText(String)
+ * @see #getString(String)
*/
public static final String METADATA_KEY_COMPOSER = "android.media.metadata.COMPOSER";
/**
* The compilation status of the media.
+ *
+ * @see Builder#putText(String, CharSequence)
+ * @see Builder#putString(String, String)
+ * @see #getText(String)
+ * @see #getString(String)
*/
public static final String METADATA_KEY_COMPILATION = "android.media.metadata.COMPILATION";
/**
* The date the media was created or published. The format is unspecified
* but RFC 3339 is recommended.
+ *
+ * @see Builder#putText(String, CharSequence)
+ * @see Builder#putString(String, String)
+ * @see #getText(String)
+ * @see #getString(String)
*/
public static final String METADATA_KEY_DATE = "android.media.metadata.DATE";
/**
* The year the media was created or published as a long.
+ *
+ * @see Builder#putLong(String, long)
+ * @see #getLong(String)
*/
public static final String METADATA_KEY_YEAR = "android.media.metadata.YEAR";
/**
* The genre of the media.
+ *
+ * @see Builder#putText(String, CharSequence)
+ * @see Builder#putString(String, String)
+ * @see #getText(String)
+ * @see #getString(String)
*/
public static final String METADATA_KEY_GENRE = "android.media.metadata.GENRE";
/**
* The track number for the media.
+ *
+ * @see Builder#putLong(String, long)
+ * @see #getLong(String)
*/
public static final String METADATA_KEY_TRACK_NUMBER = "android.media.metadata.TRACK_NUMBER";
/**
* The number of tracks in the media's original source.
+ *
+ * @see Builder#putLong(String, long)
+ * @see #getLong(String)
*/
public static final String METADATA_KEY_NUM_TRACKS = "android.media.metadata.NUM_TRACKS";
/**
* The disc number for the media's original source.
+ *
+ * @see Builder#putLong(String, long)
+ * @see #getLong(String)
*/
public static final String METADATA_KEY_DISC_NUMBER = "android.media.metadata.DISC_NUMBER";
/**
* The artist for the album of the media's original source.
+ *
+ * @see Builder#putText(String, CharSequence)
+ * @see Builder#putString(String, String)
+ * @see #getText(String)
+ * @see #getString(String)
*/
public static final String METADATA_KEY_ALBUM_ARTIST = "android.media.metadata.ALBUM_ARTIST";
@@ -122,11 +187,19 @@
* The artwork should be relatively small and may be scaled down
* if it is too large. For higher resolution artwork
* {@link #METADATA_KEY_ART_URI} should be used instead.
+ *
+ * @see Builder#putBitmap(String, Bitmap)
+ * @see #getBitmap(String)
*/
public static final String METADATA_KEY_ART = "android.media.metadata.ART";
/**
* The artwork for the media as a Uri style String.
+ *
+ * @see Builder#putText(String, CharSequence)
+ * @see Builder#putString(String, String)
+ * @see #getText(String)
+ * @see #getString(String)
*/
public static final String METADATA_KEY_ART_URI = "android.media.metadata.ART_URI";
@@ -136,26 +209,36 @@
* The artwork should be relatively small and may be scaled down
* if it is too large. For higher resolution artwork
* {@link #METADATA_KEY_ALBUM_ART_URI} should be used instead.
+ *
+ * @see Builder#putBitmap(String, Bitmap)
+ * @see #getBitmap(String)
*/
public static final String METADATA_KEY_ALBUM_ART = "android.media.metadata.ALBUM_ART";
/**
* The artwork for the album of the media's original source as a Uri style
* String.
+ *
+ * @see Builder#putText(String, CharSequence)
+ * @see Builder#putString(String, String)
+ * @see #getText(String)
+ * @see #getString(String)
*/
public static final String METADATA_KEY_ALBUM_ART_URI = "android.media.metadata.ALBUM_ART_URI";
/**
* The user's rating for the media.
*
- * @see Rating
+ * @see Builder#putRating(String, Rating2)
+ * @see #getRating(String)
*/
public static final String METADATA_KEY_USER_RATING = "android.media.metadata.USER_RATING";
/**
* The overall rating for the media.
*
- * @see Rating
+ * @see Builder#putRating(String, Rating2)
+ * @see #getRating(String)
*/
public static final String METADATA_KEY_RATING = "android.media.metadata.RATING";
@@ -164,6 +247,11 @@
* the same as {@link #METADATA_KEY_TITLE} but may differ for some formats.
* When displaying media described by this metadata this should be preferred
* if present.
+ *
+ * @see Builder#putText(String, CharSequence)
+ * @see Builder#putString(String, String)
+ * @see #getText(String)
+ * @see #getString(String)
*/
public static final String METADATA_KEY_DISPLAY_TITLE = "android.media.metadata.DISPLAY_TITLE";
@@ -171,6 +259,11 @@
* A subtitle that is suitable for display to the user. When displaying a
* second line for media described by this metadata this should be preferred
* to other fields if present.
+ *
+ * @see Builder#putText(String, CharSequence)
+ * @see Builder#putString(String, String)
+ * @see #getText(String)
+ * @see #getString(String)
*/
public static final String METADATA_KEY_DISPLAY_SUBTITLE
= "android.media.metadata.DISPLAY_SUBTITLE";
@@ -179,6 +272,11 @@
* A description that is suitable for display to the user. When displaying
* more information for media described by this metadata this should be
* preferred to other fields if present.
+ *
+ * @see Builder#putText(String, CharSequence)
+ * @see Builder#putString(String, String)
+ * @see #getText(String)
+ * @see #getString(String)
*/
public static final String METADATA_KEY_DISPLAY_DESCRIPTION
= "android.media.metadata.DISPLAY_DESCRIPTION";
@@ -191,6 +289,9 @@
* The icon should be relatively small and may be scaled down
* if it is too large. For higher resolution artwork
* {@link #METADATA_KEY_DISPLAY_ICON_URI} should be used instead.
+ *
+ * @see Builder#putBitmap(String, Bitmap)
+ * @see #getBitmap(String)
*/
public static final String METADATA_KEY_DISPLAY_ICON
= "android.media.metadata.DISPLAY_ICON";
@@ -200,6 +301,11 @@
* displaying more information for media described by this metadata the
* display description should be preferred to other fields when present.
* This must be a Uri style String.
+ *
+ * @see Builder#putText(String, CharSequence)
+ * @see Builder#putString(String, String)
+ * @see #getText(String)
+ * @see #getString(String)
*/
public static final String METADATA_KEY_DISPLAY_ICON_URI
= "android.media.metadata.DISPLAY_ICON_URI";
@@ -211,6 +317,11 @@
* {@link MediaController2#playFromMediaId(String, Bundle)}
* to initiate playback when provided by a {@link MediaBrowser2} connected to
* the same app.
+ *
+ * @see Builder#putText(String, CharSequence)
+ * @see Builder#putString(String, String)
+ * @see #getText(String)
+ * @see #getString(String)
*/
public static final String METADATA_KEY_MEDIA_ID = "android.media.metadata.MEDIA_ID";
@@ -220,17 +331,30 @@
* {@link MediaController2#playFromUri(Uri, Bundle)}
* to initiate playback when provided by a {@link MediaBrowser2} connected to
* the same app.
+ *
+ * @see Builder#putText(String, CharSequence)
+ * @see Builder#putString(String, String)
+ * @see #getText(String)
+ * @see #getString(String)
*/
public static final String METADATA_KEY_MEDIA_URI = "android.media.metadata.MEDIA_URI";
/**
* The radio frequency in Float format if this metdata representing radio content.
+ *
+ * @see Builder#putFloat(String, float)
+ * @see #getFloat(String)
*/
public static final String METADATA_KEY_RADIO_FREQUENCY =
"android.media.metadata.RADIO_FREQUENCY";
/**
* The radio callsign in String format if this metdata representing radio content.
+ *
+ * @see Builder#putText(String, CharSequence)
+ * @see Builder#putString(String, String)
+ * @see #getText(String)
+ * @see #getString(String)
*/
public static final String METADATA_KEY_RADIO_CALLSIGN =
"android.media.metadata.RADIO_CALLSIGN";
@@ -247,6 +371,9 @@
* <li>{@link #BT_FOLDER_TYPE_PLAYLISTS}</li>
* <li>{@link #BT_FOLDER_TYPE_YEARS}</li>
* </ul>
+ *
+ * @see Builder#putLong(String, long)
+ * @see #getLong(String)
*/
public static final String METADATA_KEY_BT_FOLDER_TYPE
= "android.media.metadata.BT_FOLDER_TYPE";
@@ -297,6 +424,9 @@
* Whether the media is an advertisement. A value of 0 indicates it is not an advertisement. A
* value of 1 or non-zero indicates it is an advertisement. If not specified, this value is set
* to 0 by default.
+ *
+ * @see Builder#putLong(String, long)
+ * @see #getLong(String)
*/
public static final String METADATA_KEY_ADVERTISEMENT = "android.media.metadata.ADVERTISEMENT";
@@ -309,6 +439,9 @@
* <li>{@link #STATUS_DOWNLOADING}</li>
* <li>{@link #STATUS_DOWNLOADED}</li>
* </ul>
+ *
+ * @see Builder#putLong(String, long)
+ * @see #getLong(String)
*/
public static final String METADATA_KEY_DOWNLOAD_STATUS =
"android.media.metadata.DOWNLOAD_STATUS";
diff --git a/media/java/android/media/update/MediaItem2Provider.java b/media/java/android/media/update/MediaItem2Provider.java
index 1d5b414..b494f9e 100644
--- a/media/java/android/media/update/MediaItem2Provider.java
+++ b/media/java/android/media/update/MediaItem2Provider.java
@@ -17,6 +17,8 @@
package android.media.update;
import android.media.DataSourceDesc;
+import android.media.MediaItem2;
+import android.media.MediaItem2.Builder;
import android.media.MediaMetadata2;
import android.os.Bundle;
@@ -33,4 +35,11 @@
MediaMetadata2 getMetadata_impl();
String getMediaId_impl();
DataSourceDesc getDataSourceDesc_impl();
+
+ interface BuilderProvider {
+ Builder setMediaId_impl(String mediaId);
+ Builder setMetadata_impl(MediaMetadata2 metadata);
+ Builder setDataSourceDesc_impl(DataSourceDesc dataSourceDesc);
+ MediaItem2 build_impl();
+ }
}
diff --git a/media/java/android/media/update/StaticProvider.java b/media/java/android/media/update/StaticProvider.java
index 47f5ed3..843fa71 100644
--- a/media/java/android/media/update/StaticProvider.java
+++ b/media/java/android/media/update/StaticProvider.java
@@ -85,7 +85,7 @@
MediaMetadata2 playlistMetadata);
PlaylistParams fromBundle_PlaylistParams(Context context, Bundle bundle);
CommandButtonProvider.BuilderProvider createMediaSession2CommandButtonBuilder(Context context,
- MediaSession2.CommandButton.Builder builder);
+ MediaSession2.CommandButton.Builder instance);
BuilderBaseProvider<MediaSession2, SessionCallback> createMediaSession2Builder(
Context context, MediaSession2.Builder instance);
@@ -111,8 +111,8 @@
String packageName, String serviceName, int uid);
SessionToken2 fromBundle_SessionToken2(Context context, Bundle bundle);
- MediaItem2Provider createMediaItem2(Context context, MediaItem2 mediaItem2,
- String mediaId, DataSourceDesc dsd, MediaMetadata2 metadata, int flags);
+ MediaItem2Provider.BuilderProvider createMediaItem2Builder(
+ Context context, MediaItem2.Builder instance, int flags);
MediaItem2 fromBundle_MediaItem2(Context context, Bundle bundle);
VolumeProvider2Provider createVolumeProvider2(Context context, VolumeProvider2 instance,
@@ -120,9 +120,9 @@
MediaMetadata2 fromBundle_MediaMetadata2(Context context, Bundle bundle);
MediaMetadata2Provider.BuilderProvider createMediaMetadata2Builder(
- Context context, MediaMetadata2.Builder builder);
+ Context context, MediaMetadata2.Builder instance);
MediaMetadata2Provider.BuilderProvider createMediaMetadata2Builder(
- Context context, MediaMetadata2.Builder builder, MediaMetadata2 source);
+ Context context, MediaMetadata2.Builder instance, MediaMetadata2 source);
Rating2 newUnratedRating_Rating2(Context context, int ratingStyle);
Rating2 fromBundle_Rating2(Context context, Bundle bundle);
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 62030bb..a1022c0 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -1011,7 +1011,7 @@
sp<IDescrambler> descrambler;
if (descramblerBinderObj != NULL) {
- descrambler = JDescrambler::GetDescrambler(env, descramblerBinderObj);
+ descrambler = GetDescrambler(env, descramblerBinderObj);
}
err = codec->configure(format, bufferProducer, crypto, descrambler, flags);
diff --git a/media/jni/android_media_MediaDescrambler.cpp b/media/jni/android_media_MediaDescrambler.cpp
index add47463..aa79ce0 100644
--- a/media/jni/android_media_MediaDescrambler.cpp
+++ b/media/jni/android_media_MediaDescrambler.cpp
@@ -25,18 +25,64 @@
#include <android/hardware/cas/native/1.0/BpHwDescrambler.h>
#include <android/hardware/cas/native/1.0/BnHwDescrambler.h>
+#include <android/hardware/cas/native/1.0/IDescrambler.h>
#include <binder/MemoryDealer.h>
#include <hidl/HidlSupport.h>
#include <hidlmemory/FrameworkUtils.h>
#include <media/stagefright/foundation/ADebug.h>
+#include <media/cas/DescramblerAPI.h>
#include <nativehelper/ScopedLocalRef.h>
namespace android {
+class IMemory;
+class MemoryDealer;
+namespace hardware {
+class HidlMemory;
+};
using hardware::fromHeap;
+using hardware::HidlMemory;
+using hardware::hidl_string;
+using hardware::hidl_vec;
+using namespace hardware::cas::V1_0;
+using namespace hardware::cas::native::V1_0;
+
+struct JDescrambler : public RefBase {
+ JDescrambler(JNIEnv *env, jobject descramberBinderObj);
+
+ status_t descramble(
+ uint32_t key,
+ ssize_t totalLength,
+ const hidl_vec<SubSample>& subSamples,
+ const void *srcPtr,
+ jint srcOffset,
+ void *dstPtr,
+ jint dstOffset,
+ Status *status,
+ uint32_t *bytesWritten,
+ hidl_string *detailedError);
+
+
+protected:
+ virtual ~JDescrambler();
+
+private:
+ sp<IDescrambler> mDescrambler;
+ sp<IMemory> mMem;
+ sp<MemoryDealer> mDealer;
+ sp<HidlMemory> mHidlMemory;
+ SharedBuffer mDescramblerSrcBuffer;
+
+ Mutex mSharedMemLock;
+
+ bool ensureBufferCapacity(size_t neededSize);
+
+ DISALLOW_EVIL_CONSTRUCTORS(JDescrambler);
+};
struct fields_t {
jfieldID context;
+ jbyte flagPesHeader;
};
static fields_t gFields;
@@ -111,8 +157,7 @@
mDealer.clear();
}
-// static
-sp<IDescrambler> JDescrambler::GetDescrambler(JNIEnv *env, jobject obj) {
+sp<IDescrambler> GetDescrambler(JNIEnv *env, jobject obj) {
if (obj != NULL) {
sp<hardware::IBinder> hwBinder =
JHwRemoteBinder::GetNativeContext(env, obj)->getBinder();
@@ -155,7 +200,7 @@
}
status_t JDescrambler::descramble(
- jbyte key,
+ uint32_t key,
ssize_t totalLength,
const hidl_vec<SubSample>& subSamples,
const void *srcPtr,
@@ -228,6 +273,12 @@
gFields.context = env->GetFieldID(clazz.get(), "mNativeContext", "J");
CHECK(gFields.context != NULL);
+
+ jfieldID fieldPesHeader = env->GetStaticFieldID(
+ clazz.get(), "SCRAMBLE_FLAG_PES_HEADER", "B");
+ CHECK(fieldPesHeader != NULL);
+
+ gFields.flagPesHeader = env->GetStaticByteField(clazz.get(), fieldPesHeader);
}
static void android_media_MediaDescrambler_native_setup(
@@ -323,7 +374,7 @@
}
static jint android_media_MediaDescrambler_native_descramble(
- JNIEnv *env, jobject thiz, jbyte key, jint numSubSamples,
+ JNIEnv *env, jobject thiz, jbyte key, jbyte flags, jint numSubSamples,
jintArray numBytesOfClearDataObj, jintArray numBytesOfEncryptedDataObj,
jobject srcBuf, jint srcOffset, jint srcLimit,
jobject dstBuf, jint dstOffset, jint dstLimit) {
@@ -364,12 +415,18 @@
return -1;
}
+ uint32_t scramblingControl = (uint32_t)key;
+
+ if (flags & gFields.flagPesHeader) {
+ scramblingControl |= DescramblerPlugin::kScrambling_Flag_PesHeader;
+ }
+
Status status;
uint32_t bytesWritten;
hidl_string detailedError;
err = descrambler->descramble(
- key, totalLength, subSamples,
+ scramblingControl, totalLength, subSamples,
srcPtr, srcOffset, dstPtr, dstOffset,
&status, &bytesWritten, &detailedError);
@@ -401,7 +458,7 @@
(void *)android_media_MediaDescrambler_native_init },
{ "native_setup", "(Landroid/os/IHwBinder;)V",
(void *)android_media_MediaDescrambler_native_setup },
- { "native_descramble", "(BI[I[ILjava/nio/ByteBuffer;IILjava/nio/ByteBuffer;II)I",
+ { "native_descramble", "(BBI[I[ILjava/nio/ByteBuffer;IILjava/nio/ByteBuffer;II)I",
(void *)android_media_MediaDescrambler_native_descramble },
};
diff --git a/media/jni/android_media_MediaDescrambler.h b/media/jni/android_media_MediaDescrambler.h
index 2354dc2..0ae4187 100644
--- a/media/jni/android_media_MediaDescrambler.h
+++ b/media/jni/android_media_MediaDescrambler.h
@@ -19,57 +19,19 @@
#include "jni.h"
-#include <android/hardware/cas/native/1.0/IDescrambler.h>
-
-#include <media/stagefright/foundation/ABase.h>
-#include <utils/Mutex.h>
+#include <utils/RefBase.h>
namespace android {
-class IMemory;
-class MemoryDealer;
namespace hardware {
-class HidlMemory;
-};
-using hardware::HidlMemory;
-using hardware::hidl_string;
-using hardware::hidl_vec;
-using namespace hardware::cas::V1_0;
-using namespace hardware::cas::native::V1_0;
+namespace cas {
+namespace native {
+namespace V1_0 {
+struct IDescrambler;
+}}}}
+using hardware::cas::native::V1_0::IDescrambler;
-struct JDescrambler : public RefBase {
- JDescrambler(JNIEnv *env, jobject descramberBinderObj);
-
- status_t descramble(
- jbyte key,
- ssize_t totalLength,
- const hidl_vec<SubSample>& subSamples,
- const void *srcPtr,
- jint srcOffset,
- void *dstPtr,
- jint dstOffset,
- Status *status,
- uint32_t *bytesWritten,
- hidl_string *detailedError);
-
- static sp<IDescrambler> GetDescrambler(JNIEnv *env, jobject obj);
-
-protected:
- virtual ~JDescrambler();
-
-private:
- sp<IDescrambler> mDescrambler;
- sp<IMemory> mMem;
- sp<MemoryDealer> mDealer;
- sp<HidlMemory> mHidlMemory;
- SharedBuffer mDescramblerSrcBuffer;
-
- Mutex mSharedMemLock;
-
- bool ensureBufferCapacity(size_t neededSize);
-
- DISALLOW_EVIL_CONSTRUCTORS(JDescrambler);
-};
+sp<IDescrambler> GetDescrambler(JNIEnv *env, jobject obj);
} // namespace android
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index ca4ea9e..7b1a9e1 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -353,8 +353,6 @@
<dimen name="qs_footer_padding_start">16dp</dimen>
<dimen name="qs_footer_padding_end">24dp</dimen>
<dimen name="qs_footer_icon_size">16dp</dimen>
- <!-- Difference between drag handle margin in QQS and expanded QS -->
- <dimen name="qs_footer_drag_handle_offset">10dp</dimen>
<dimen name="qs_notif_collapsed_space">64dp</dimen>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index a01f71a..d006af1 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -270,7 +270,7 @@
<style name="TextAppearance.QS.TileLabel">
<item name="android:textSize">@dimen/qs_tile_text_size</item>
- <item name="android:fontFamily">sans-serif-condensed</item>
+ <item name="android:fontFamily">sans-serif</item>
</style>
<style name="BaseBrightnessDialogContainer">
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
index 7b48e02..e9888df 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
@@ -86,14 +86,9 @@
private View mActionsContainer;
private View mDragHandle;
- private final int mDragHandleExpandOffset;
public QSFooterImpl(Context context, AttributeSet attrs) {
super(context, attrs);
-
- mDragHandleExpandOffset = getResources().
- getDimensionPixelSize(R.dimen.qs_footer_drag_handle_offset);
-
}
@Override
@@ -171,7 +166,6 @@
.addFloat(mDivider, "alpha", 0, 1)
.addFloat(mCarrierText, "alpha", 0, 0, 1)
.addFloat(mActionsContainer, "alpha", 0, 1)
- .addFloat(mDragHandle, "translationY", mDragHandleExpandOffset, 0)
.addFloat(mDragHandle, "alpha", 1, 0, 0)
.setStartDelay(0.15f)
.build();
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index f633003..79297aa 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -17,6 +17,7 @@
package com.android.server;
import static android.Manifest.permission.RECEIVE_DATA_ACTIVITY_CHANGE;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.NETID_UNSET;
import static android.net.ConnectivityManager.TYPE_ETHERNET;
@@ -1359,9 +1360,8 @@
if (nai != null) {
synchronized (nai) {
if (nai.networkCapabilities != null) {
- // TODO : don't remove the UIDs when communicating with processes
- // that have the NETWORK_SETTINGS permission.
- return networkCapabilitiesWithoutUids(nai.networkCapabilities);
+ return networkCapabilitiesWithoutUidsUnlessAllowed(nai.networkCapabilities,
+ Binder.getCallingPid(), Binder.getCallingUid());
}
}
}
@@ -1374,10 +1374,18 @@
return getNetworkCapabilitiesInternal(getNetworkAgentInfoForNetwork(network));
}
- private NetworkCapabilities networkCapabilitiesWithoutUids(NetworkCapabilities nc) {
+ private NetworkCapabilities networkCapabilitiesWithoutUidsUnlessAllowed(
+ NetworkCapabilities nc, int callerPid, int callerUid) {
+ if (checkSettingsPermission(callerPid, callerUid)) return new NetworkCapabilities(nc);
return new NetworkCapabilities(nc).setUids(null);
}
+ private void restrictRequestUidsForCaller(NetworkCapabilities nc) {
+ if (!checkSettingsPermission()) {
+ nc.setSingleUid(Binder.getCallingUid());
+ }
+ }
+
@Override
public NetworkState[] getAllNetworkState() {
// Require internal since we're handing out IMSI details
@@ -1577,6 +1585,16 @@
"ConnectivityService");
}
+ private boolean checkSettingsPermission() {
+ return PERMISSION_GRANTED == mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.NETWORK_SETTINGS);
+ }
+
+ private boolean checkSettingsPermission(int pid, int uid) {
+ return PERMISSION_GRANTED == mContext.checkPermission(
+ android.Manifest.permission.NETWORK_SETTINGS, pid, uid);
+ }
+
private void enforceTetherAccessPermission() {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.ACCESS_NETWORK_STATE,
@@ -4258,13 +4276,12 @@
enforceMeteredApnPolicy(networkCapabilities);
}
ensureRequestableCapabilities(networkCapabilities);
- // Set the UID range for this request to the single UID of the requester.
+ // Set the UID range for this request to the single UID of the requester, or to an empty
+ // set of UIDs if the caller has the appropriate permission and UIDs have not been set.
// This will overwrite any allowed UIDs in the requested capabilities. Though there
// are no visible methods to set the UIDs, an app could use reflection to try and get
// networks for other apps so it's essential that the UIDs are overwritten.
- // TODO : don't forcefully set the UID when communicating with processes
- // that have the NETWORK_SETTINGS permission.
- networkCapabilities.setSingleUid(Binder.getCallingUid());
+ restrictRequestUidsForCaller(networkCapabilities);
if (timeoutMs < 0) {
throw new IllegalArgumentException("Bad timeout specified");
@@ -4338,9 +4355,7 @@
enforceMeteredApnPolicy(networkCapabilities);
ensureRequestableCapabilities(networkCapabilities);
ensureValidNetworkSpecifier(networkCapabilities);
- // TODO : don't forcefully set the UID when communicating with processes
- // that have the NETWORK_SETTINGS permission.
- networkCapabilities.setSingleUid(Binder.getCallingUid());
+ restrictRequestUidsForCaller(networkCapabilities);
NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, TYPE_NONE,
nextNetworkRequestId(), NetworkRequest.Type.REQUEST);
@@ -4394,9 +4409,7 @@
}
NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities);
- // TODO : don't forcefully set the UIDs when communicating with processes
- // that have the NETWORK_SETTINGS permission.
- nc.setSingleUid(Binder.getCallingUid());
+ restrictRequestUidsForCaller(nc);
if (!ConnectivityManager.checkChangePermission(mContext)) {
// Apps without the CHANGE_NETWORK_STATE permission can't use background networks, so
// make all their listens include NET_CAPABILITY_FOREGROUND. That way, they will get
@@ -4426,9 +4439,7 @@
ensureValidNetworkSpecifier(networkCapabilities);
final NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities);
- // TODO : don't forcefully set the UIDs when communicating with processes
- // that have the NETWORK_SETTINGS permission.
- nc.setSingleUid(Binder.getCallingUid());
+ restrictRequestUidsForCaller(nc);
NetworkRequest networkRequest = new NetworkRequest(nc, TYPE_NONE, nextNetworkRequestId(),
NetworkRequest.Type.LISTEN);
@@ -4992,8 +5003,8 @@
}
case ConnectivityManager.CALLBACK_CAP_CHANGED: {
// networkAgent can't be null as it has been accessed a few lines above.
- final NetworkCapabilities nc =
- networkCapabilitiesWithoutUids(networkAgent.networkCapabilities);
+ final NetworkCapabilities nc = networkCapabilitiesWithoutUidsUnlessAllowed(
+ networkAgent.networkCapabilities, nri.mPid, nri.mUid);
putParcelable(bundle, nc);
break;
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 28a79bd..6726b6e 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -10149,92 +10149,33 @@
}
/**
- * Updates (grants or revokes) a persitable URI permission.
- *
- * @param uri URI to be granted or revoked.
- * @param prefix if {@code false}, permission apply to this specific URI; if {@code true}, it
- * applies to all URIs that are prefixed by this URI.
- * @param packageName target package.
- * @param grant if {@code true} a new permission will be granted, otherwise an existing
- * permission will be revoked.
- * @param userId user handle
- *
- * @return whether or not the requested succeeded.
- *
- * @deprecated TODO(b/72055774): caller should use takePersistableUriPermission() or
- * releasePersistableUriPermission() instead, but such change will be made in a separate CL
- * so it can be easily reverted if it breaks existing functionality.
- */
- @Deprecated // STOPSHIP if not removed
- @Override
- public boolean updatePersistableUriPermission(Uri uri, boolean prefix, String packageName,
- boolean grant, int userId) {
- enforceCallingPermission(android.Manifest.permission.GET_APP_GRANTED_URI_PERMISSIONS,
- "updatePersistableUriPermission");
- final int uid = mPackageManagerInt.getPackageUid(packageName, 0, userId);
-
- final GrantUri grantUri = new GrantUri(userId, uri, prefix);
-
- boolean persistChanged = false;
- synchronized (this) {
- if (grant) { // Grant
- final String authority = uri.getAuthority();
- final ProviderInfo pi = getProviderInfoLocked(authority, userId, 0);
- if (pi == null) {
- Slog.w(TAG, "No content provider found for authority " + authority);
- return false;
- }
- final UriPermission permission = findOrCreateUriPermissionLocked(pi.packageName,
- packageName, uid, grantUri);
- if (permission.isNew()) {
- final int modeFlags = Intent.FLAG_GRANT_READ_URI_PERMISSION
- | Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
- permission.initPersistedModes(modeFlags, System.currentTimeMillis());
- persistChanged = true;
- } else {
- // Caller should not try to grant permission that is already granted.
- Slog.w(TAG_URI_PERMISSION,
- "permission already granted for " + grantUri.toSafeString());
- return false;
- }
- persistChanged |= maybePrunePersistedUriGrantsLocked(uid);
- } else { // Revoke
- final UriPermission permission = findUriPermissionLocked(uid, grantUri);
- if (permission == null) {
- // Caller should not try to revoke permission that is not granted.
- Slog.v(TAG_URI_PERMISSION, "no permission for " + grantUri.toSafeString());
- return false;
- } else {
- permission.modeFlags = 0;
- removeUriPermissionIfNeededLocked(permission);
- persistChanged = true;
- }
- }
- if (persistChanged) {
- schedulePersistUriGrants();
- }
- }
- return true;
- }
-
- /**
* @param uri This uri must NOT contain an embedded userId.
+ * @param toPackage Name of package whose uri is being granted to (if {@code null}, uses
+ * calling uid)
* @param userId The userId in which the uri is to be resolved.
*/
@Override
- public void takePersistableUriPermission(Uri uri, final int modeFlags, int userId) {
- enforceNotIsolatedCaller("takePersistableUriPermission");
+ public void takePersistableUriPermission(Uri uri, final int modeFlags,
+ @Nullable String toPackage, int userId) {
+ final int uid;
+ if (toPackage != null) {
+ enforceCallingPermission(android.Manifest.permission.FORCE_PERSISTABLE_URI_PERMISSIONS,
+ "takePersistableUriPermission");
+ uid = mPackageManagerInt.getPackageUid(toPackage, 0, userId);
+ } else {
+ enforceNotIsolatedCaller("takePersistableUriPermission");
+ uid = Binder.getCallingUid();
+ }
Preconditions.checkFlagsArgument(modeFlags,
Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
synchronized (this) {
- final int callingUid = Binder.getCallingUid();
boolean persistChanged = false;
GrantUri grantUri = new GrantUri(userId, uri, false);
- UriPermission exactPerm = findUriPermissionLocked(callingUid, grantUri);
- UriPermission prefixPerm = findUriPermissionLocked(callingUid,
+ UriPermission exactPerm = findUriPermissionLocked(uid, grantUri);
+ UriPermission prefixPerm = findUriPermissionLocked(uid,
new GrantUri(userId, uri, true));
final boolean exactValid = (exactPerm != null)
@@ -10244,7 +10185,7 @@
if (!(exactValid || prefixValid)) {
throw new SecurityException("No persistable permission grants found for UID "
- + callingUid + " and Uri " + grantUri.toSafeString());
+ + uid + " and Uri " + grantUri.toSafeString());
}
if (exactValid) {
@@ -10254,7 +10195,7 @@
persistChanged |= prefixPerm.takePersistableModes(modeFlags);
}
- persistChanged |= maybePrunePersistedUriGrantsLocked(callingUid);
+ persistChanged |= maybePrunePersistedUriGrantsLocked(uid);
if (persistChanged) {
schedulePersistUriGrants();
@@ -10264,25 +10205,36 @@
/**
* @param uri This uri must NOT contain an embedded userId.
+ * @param toPackage Name of the target package whose uri is being released (if {@code null},
+ * uses calling uid)
* @param userId The userId in which the uri is to be resolved.
*/
@Override
- public void releasePersistableUriPermission(Uri uri, final int modeFlags, int userId) {
- enforceNotIsolatedCaller("releasePersistableUriPermission");
+ public void releasePersistableUriPermission(Uri uri, final int modeFlags,
+ @Nullable String toPackage, int userId) {
+
+ final int uid;
+ if (toPackage != null) {
+ enforceCallingPermission(android.Manifest.permission.FORCE_PERSISTABLE_URI_PERMISSIONS,
+ "releasePersistableUriPermission");
+ uid = mPackageManagerInt.getPackageUid(toPackage, 0, userId);
+ } else {
+ enforceNotIsolatedCaller("releasePersistableUriPermission");
+ uid = Binder.getCallingUid();
+ }
Preconditions.checkFlagsArgument(modeFlags,
Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
synchronized (this) {
- final int callingUid = Binder.getCallingUid();
boolean persistChanged = false;
- UriPermission exactPerm = findUriPermissionLocked(callingUid,
+ UriPermission exactPerm = findUriPermissionLocked(uid,
new GrantUri(userId, uri, false));
- UriPermission prefixPerm = findUriPermissionLocked(callingUid,
+ UriPermission prefixPerm = findUriPermissionLocked(uid,
new GrantUri(userId, uri, true));
- if (exactPerm == null && prefixPerm == null) {
- throw new SecurityException("No permission grants found for UID " + callingUid
+ if (exactPerm == null && prefixPerm == null && toPackage == null) {
+ throw new SecurityException("No permission grants found for UID " + uid
+ " and Uri " + uri.toSafeString());
}
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 274a4b0..ae98ca0 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -230,6 +230,8 @@
private static final String ATTR_COMPONENTSPECIFIED = "component_specified";
static final String ACTIVITY_ICON_SUFFIX = "_activity_icon_";
+ private static final int MAX_STORED_STATE_TRANSITIONS = 5;
+
final ActivityManagerService service; // owner
final IApplicationToken.Stub appToken; // window manager token
AppWindowContainerController mWindowContainerController;
@@ -366,6 +368,28 @@
private final Configuration mTmpConfig = new Configuration();
private final Rect mTmpBounds = new Rect();
+ private final ArrayList<StateTransition> mRecentTransitions = new ArrayList<>();
+
+ // TODO(b/71506345): Remove once issue has been resolved.
+ private static class StateTransition {
+ final long time;
+ final ActivityState prev;
+ final ActivityState state;
+ final String reason;
+
+ StateTransition(ActivityState prev, ActivityState state, String reason) {
+ time = System.currentTimeMillis();
+ this.prev = prev;
+ this.state = state;
+ this.reason = reason;
+ }
+
+ @Override
+ public String toString() {
+ return "[" + prev + "->" + state + ":" + reason + "@" + time + "]";
+ }
+ }
+
private static String startingWindowStateToString(int state) {
switch (state) {
case STARTING_WINDOW_NOT_SHOWN:
@@ -380,9 +404,18 @@
}
String getLifecycleDescription(String reason) {
+ StringBuilder transitionBuilder = new StringBuilder();
+
+ for (int i = 0, size = mRecentTransitions.size(); i < size; ++i) {
+ transitionBuilder.append(mRecentTransitions.get(i));
+ if (i + 1 < size) {
+ transitionBuilder.append(",");
+ }
+ }
+
return "name= " + this + ", component=" + intent.getComponent().flattenToShortString()
+ ", package=" + packageName + ", state=" + mState + ", reason=" + reason
- + ", time=" + System.currentTimeMillis();
+ + ", time=" + System.currentTimeMillis() + " transitions=" + transitionBuilder;
}
void dump(PrintWriter pw, String prefix) {
@@ -1581,7 +1614,16 @@
void setState(ActivityState state, String reason) {
if (DEBUG_STATES) Slog.v(TAG_STATES, "State movement: " + this + " from:" + getState()
+ " to:" + state + " reason:" + reason);
+ final ActivityState prev = mState;
mState = state;
+
+ if (mState != prev) {
+ if (mRecentTransitions.size() == MAX_STORED_STATE_TRANSITIONS) {
+ mRecentTransitions.remove(0);
+ }
+
+ mRecentTransitions.add(new StateTransition(prev, state, reason));
+ }
}
ActivityState getState() {
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index dd2358c..4541acd 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -1041,7 +1041,9 @@
return;
}
- mStats.updateBluetoothStateLocked(info);
+ synchronized (mStats) {
+ mStats.updateBluetoothStateLocked(info);
+ }
}
@Override
diff --git a/services/core/java/com/android/server/am/UriPermission.java b/services/core/java/com/android/server/am/UriPermission.java
index 3bf1cf4..1e071aa 100644
--- a/services/core/java/com/android/server/am/UriPermission.java
+++ b/services/core/java/com/android/server/am/UriPermission.java
@@ -124,10 +124,6 @@
updateModeFlags();
}
- boolean isNew() {
- return persistedCreateTime == INVALID_TIME;
- }
-
void grantModes(int modeFlags, UriPermissionOwner owner) {
final boolean persistable = (modeFlags & Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) != 0;
modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index bb46d5e..c9bdcf1 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -57,6 +57,7 @@
import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
import android.net.NetworkMisc;
+import android.net.NetworkUtils;
import android.net.RouteInfo;
import android.net.UidRange;
import android.net.Uri;
@@ -105,6 +106,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.math.BigInteger;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
@@ -113,6 +115,7 @@
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
+import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.SortedSet;
@@ -131,6 +134,24 @@
// the device idle whitelist during service launch and VPN bootstrap.
private static final long VPN_LAUNCH_IDLE_WHITELIST_DURATION_MS = 60 * 1000;
+ // Settings for how much of the address space should be routed so that Vpn considers
+ // "most" of the address space is routed. This is used to determine whether this Vpn
+ // should be marked with the INTERNET capability.
+ private static final long MOST_IPV4_ADDRESSES_COUNT;
+ private static final BigInteger MOST_IPV6_ADDRESSES_COUNT;
+ static {
+ // 85% of the address space must be routed for Vpn to consider this VPN to provide
+ // INTERNET access.
+ final int howManyPercentIsMost = 85;
+
+ final long twoPower32 = 1L << 32;
+ MOST_IPV4_ADDRESSES_COUNT = twoPower32 * howManyPercentIsMost / 100;
+ final BigInteger twoPower128 = BigInteger.ONE.shiftLeft(128);
+ MOST_IPV6_ADDRESSES_COUNT = twoPower128
+ .multiply(BigInteger.valueOf(howManyPercentIsMost))
+ .divide(BigInteger.valueOf(100));
+ }
+
// TODO: create separate trackers for each unique VPN to support
// automated reconnection
@@ -830,10 +851,39 @@
return lp;
}
+ /**
+ * Analyzes the passed LinkedProperties to figure out whether it routes to most of the IP space.
+ *
+ * This returns true if the passed LinkedProperties contains routes to either most of the IPv4
+ * space or to most of the IPv6 address space, where "most" is defined by the value of the
+ * MOST_IPV{4,6}_ADDRESSES_COUNT constants : if more than this number of addresses are matched
+ * by any of the routes, then it's decided that most of the space is routed.
+ * @hide
+ */
+ @VisibleForTesting
+ static boolean providesRoutesToMostDestinations(LinkProperties lp) {
+ final Comparator<IpPrefix> prefixLengthComparator = IpPrefix.lengthComparator();
+ TreeSet<IpPrefix> ipv4Prefixes = new TreeSet<>(prefixLengthComparator);
+ TreeSet<IpPrefix> ipv6Prefixes = new TreeSet<>(prefixLengthComparator);
+ for (final RouteInfo route : lp.getAllRoutes()) {
+ IpPrefix destination = route.getDestination();
+ if (destination.isIPv4()) {
+ ipv4Prefixes.add(destination);
+ } else {
+ ipv6Prefixes.add(destination);
+ }
+ }
+ if (NetworkUtils.routedIPv4AddressCount(ipv4Prefixes) > MOST_IPV4_ADDRESSES_COUNT) {
+ return true;
+ }
+ return NetworkUtils.routedIPv6AddressCount(ipv6Prefixes)
+ .compareTo(MOST_IPV6_ADDRESSES_COUNT) >= 0;
+ }
+
private void agentConnect() {
LinkProperties lp = makeLinkProperties();
- if (lp.hasIPv4DefaultRoute() || lp.hasIPv6DefaultRoute()) {
+ if (providesRoutesToMostDestinations(lp)) {
mNetworkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
} else {
mNetworkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 752ab8f..a572cdf 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -1983,6 +1983,14 @@
}
@Override
+ public void initRecoveryServiceWithSigFile(@NonNull String rootCertificateAlias,
+ @NonNull byte[] recoveryServiceCertFile, @NonNull byte[] recoveryServiceSigFile)
+ throws RemoteException {
+ mRecoverableKeyStoreManager.initRecoveryServiceWithSigFile(rootCertificateAlias,
+ recoveryServiceCertFile, recoveryServiceSigFile);
+ }
+
+ @Override
public KeyChainSnapshot getKeyChainSnapshot() throws RemoteException {
return mRecoverableKeyStoreManager.getKeyChainSnapshot();
}
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
index 1e0703a..20f3403 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
@@ -20,6 +20,7 @@
import static android.security.keystore.recovery.RecoveryController.ERROR_DECRYPTION_FAILED;
import static android.security.keystore.recovery.RecoveryController.ERROR_INSECURE_USER;
import static android.security.keystore.recovery.RecoveryController.ERROR_INVALID_KEY_FORMAT;
+import static android.security.keystore.recovery.RecoveryController.ERROR_INVALID_CERTIFICATE;
import static android.security.keystore.recovery.RecoveryController.ERROR_NO_SNAPSHOT_PENDING;
import static android.security.keystore.recovery.RecoveryController.ERROR_SERVICE_INTERNAL_ERROR;
import static android.security.keystore.recovery.RecoveryController.ERROR_SESSION_EXPIRED;
@@ -44,6 +45,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.HexDump;
import com.android.server.locksettings.recoverablekeystore.certificate.CertUtils;
+import com.android.server.locksettings.recoverablekeystore.certificate.SigXml;
import com.android.server.locksettings.recoverablekeystore.storage.ApplicationKeyStorage;
import com.android.server.locksettings.recoverablekeystore.certificate.CertParsingException;
import com.android.server.locksettings.recoverablekeystore.certificate.CertValidationException;
@@ -160,6 +162,9 @@
}
}
+ /**
+ * @deprecated Use {@link #initRecoveryServiceWithSigFile(String, byte[], byte[])} instead.
+ */
public void initRecoveryService(
@NonNull String rootCertificateAlias, @NonNull byte[] recoveryServiceCertFile)
throws RemoteException {
@@ -167,8 +172,6 @@
int userId = UserHandle.getCallingUserId();
int uid = Binder.getCallingUid();
- // TODO: Check the public-key signature on the whole file before parsing it
-
CertXml certXml;
try {
certXml = CertXml.parse(recoveryServiceCertFile);
@@ -204,7 +207,7 @@
} catch (CertValidationException e) {
Log.e(TAG, "Invalid endpoint cert", e);
throw new ServiceSpecificException(
- ERROR_BAD_CERTIFICATE_FORMAT, "Failed to validate certificate.");
+ ERROR_INVALID_CERTIFICATE, "Failed to validate certificate.");
}
try {
Log.d(TAG, "Saving the randomly chosen endpoint certificate to database");
@@ -219,6 +222,50 @@
}
}
+ /**
+ * Initializes the recovery service with the two files {@code recoveryServiceCertFile} and
+ * {@code recoveryServiceSigFile}.
+ *
+ * @param rootCertificateAlias the alias for the root certificate that is used for validating
+ * the recovery service certificates.
+ * @param recoveryServiceCertFile the content of the XML file containing a list of certificates
+ * for the recovery service.
+ * @param recoveryServiceSigFile the content of the XML file containing the public-key signature
+ * over the entire content of {@code recoveryServiceCertFile}.
+ */
+ public void initRecoveryServiceWithSigFile(
+ @NonNull String rootCertificateAlias, @NonNull byte[] recoveryServiceCertFile,
+ @NonNull byte[] recoveryServiceSigFile)
+ throws RemoteException {
+ if (recoveryServiceCertFile == null || recoveryServiceSigFile == null) {
+ Log.d(TAG, "The given cert or sig file is null");
+ throw new ServiceSpecificException(
+ ERROR_BAD_CERTIFICATE_FORMAT, "The given cert or sig file is null.");
+ }
+
+ SigXml sigXml;
+ try {
+ sigXml = SigXml.parse(recoveryServiceSigFile);
+ } catch (CertParsingException e) {
+ Log.d(TAG, "Failed to parse the sig file: " + HexDump.toHexString(
+ recoveryServiceSigFile));
+ throw new ServiceSpecificException(
+ ERROR_BAD_CERTIFICATE_FORMAT, "Failed to parse the sig file.");
+ }
+
+ try {
+ sigXml.verifyFileSignature(TrustedRootCert.TRUSTED_ROOT_CERT, recoveryServiceCertFile);
+ } catch (CertValidationException e) {
+ Log.d(TAG, "The signature over the cert file is invalid."
+ + " Cert: " + HexDump.toHexString(recoveryServiceCertFile)
+ + " Sig: " + HexDump.toHexString(recoveryServiceSigFile));
+ throw new ServiceSpecificException(
+ ERROR_INVALID_CERTIFICATE, "The signature over the cert file is invalid.");
+ }
+
+ initRecoveryService(rootCertificateAlias, recoveryServiceCertFile);
+ }
+
private PublicKey parseEcPublicKey(@NonNull byte[] bytes) throws ServiceSpecificException {
try {
KeyFactory kf = KeyFactory.getInstance("EC");
@@ -392,7 +439,7 @@
// verifierPublicKey; otherwise, the user secret may be decrypted by a key that is not owned
// by the original recovery service.
if (!publicKeysMatch(publicKey, vaultParams)) {
- throw new ServiceSpecificException(ERROR_BAD_CERTIFICATE_FORMAT,
+ throw new ServiceSpecificException(ERROR_INVALID_CERTIFICATE,
"The public keys given in verifierPublicKey and vaultParams do not match.");
}
diff --git a/services/core/java/com/android/server/pm/InstantAppResolverConnection.java b/services/core/java/com/android/server/pm/InstantAppResolverConnection.java
index 98f421e..16b4368 100644
--- a/services/core/java/com/android/server/pm/InstantAppResolverConnection.java
+++ b/services/core/java/com/android/server/pm/InstantAppResolverConnection.java
@@ -16,6 +16,8 @@
package com.android.server.pm;
+import android.annotation.AnyThread;
+import android.annotation.WorkerThread;
import android.app.IInstantAppResolver;
import android.app.InstantAppResolverService;
import android.content.ComponentName;
@@ -37,6 +39,7 @@
import android.util.TimedRemoteCaller;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.os.BackgroundThread;
import java.util.ArrayList;
import java.util.List;
@@ -68,6 +71,7 @@
private static final int STATE_IDLE = 0; // no bind operation is ongoing
private static final int STATE_BINDING = 1; // someone is binding and waiting
private static final int STATE_PENDING = 2; // a bind is pending, but the caller is not waiting
+ private final Handler mBgHandler;
@GuardedBy("mLock")
private int mBindState = STATE_IDLE;
@@ -78,6 +82,7 @@
Context context, ComponentName componentName, String action) {
mContext = context;
mIntent = new Intent(action).setComponent(componentName);
+ mBgHandler = BackgroundThread.getHandler();
}
public final List<InstantAppResolveInfo> getInstantAppResolveInfoList(Intent sanitizedIntent,
@@ -131,6 +136,7 @@
}
}
+ @WorkerThread
private IInstantAppResolver getRemoteInstanceLazy(String token)
throws ConnectionException, TimeoutException, InterruptedException {
long binderToken = Binder.clearCallingIdentity();
@@ -157,6 +163,7 @@
}
}
+ @WorkerThread
private IInstantAppResolver bind(String token)
throws ConnectionException, TimeoutException, InterruptedException {
boolean doUnbind = false;
@@ -241,6 +248,19 @@
}
}
+ @AnyThread
+ void optimisticBind() {
+ mBgHandler.post(() -> {
+ try {
+ if (bind("Optimistic Bind") != null && DEBUG_INSTANT) {
+ Slog.i(TAG, "Optimistic bind succeeded.");
+ }
+ } catch (ConnectionException | TimeoutException | InterruptedException e) {
+ Slog.e(TAG, "Optimistic bind failed.", e);
+ }
+ });
+ }
+
@Override
public void binderDied() {
if (DEBUG_INSTANT) {
@@ -249,6 +269,7 @@
synchronized (mLock) {
handleBinderDiedLocked();
}
+ optimisticBind();
}
@GuardedBy("mLock")
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 5cf7903..98fb18a 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -20873,6 +20873,16 @@
reconcileApps(StorageManager.UUID_PRIVATE_INTERNAL);
mPermissionManager.systemReady();
+
+ if (mInstantAppResolverConnection != null) {
+ mContext.registerReceiver(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ mInstantAppResolverConnection.optimisticBind();
+ mContext.unregisterReceiver(this);
+ }
+ }, new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
+ }
}
public void waitForAppDataPrepared() {
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
index 32f38b7..a9a1456 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
@@ -347,7 +347,7 @@
Intent intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGING)
.putExtra(PowerManager.EXTRA_POWER_SAVE_MODE, enabled)
.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
- mContext.sendBroadcast(intent);
+ mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
diff --git a/services/core/java/com/android/server/wm/AppWindowThumbnail.java b/services/core/java/com/android/server/wm/AppWindowThumbnail.java
index db95634..3cd3e8b 100644
--- a/services/core/java/com/android/server/wm/AppWindowThumbnail.java
+++ b/services/core/java/com/android/server/wm/AppWindowThumbnail.java
@@ -53,8 +53,7 @@
AppWindowThumbnail(Transaction t, AppWindowToken appToken, GraphicBuffer thumbnailHeader) {
mAppToken = appToken;
- mSurfaceAnimator = new SurfaceAnimator(this, this::onAnimationFinished,
- appToken.mService.mAnimator::addAfterPrepareSurfacesRunnable, appToken.mService);
+ mSurfaceAnimator = new SurfaceAnimator(this, this::onAnimationFinished, appToken.mService);
mWidth = thumbnailHeader.getWidth();
mHeight = thumbnailHeader.getHeight();
@@ -145,11 +144,6 @@
}
@Override
- public void destroyAfterPendingTransaction(SurfaceControl surface) {
- mAppToken.destroyAfterPendingTransaction(surface);
- }
-
- @Override
public void onAnimationLeashCreated(Transaction t, SurfaceControl leash) {
t.setLayer(leash, Integer.MAX_VALUE);
}
diff --git a/services/core/java/com/android/server/wm/Dimmer.java b/services/core/java/com/android/server/wm/Dimmer.java
index 4394a99..a180a3a 100644
--- a/services/core/java/com/android/server/wm/Dimmer.java
+++ b/services/core/java/com/android/server/wm/Dimmer.java
@@ -55,11 +55,6 @@
}
@Override
- public void destroyAfterPendingTransaction(SurfaceControl surface) {
- mHost.destroyAfterPendingTransaction(surface);
- }
-
- @Override
public SurfaceControl.Builder makeAnimationLeash() {
return mHost.makeAnimationLeash();
}
@@ -119,7 +114,7 @@
if (!mDimming) {
mDimLayer.destroy();
}
- }, mHost.mService.mAnimator::addAfterPrepareSurfacesRunnable, mHost.mService);
+ }, mHost.mService);
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 232e1c1..59bece0 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -382,11 +382,6 @@
*/
private int mSurfaceSize;
- /**
- * A list of surfaces to be destroyed after {@link #mPendingTransaction} is applied.
- */
- private final ArrayList<SurfaceControl> mPendingDestroyingSurfaces = new ArrayList<>();
-
/** Temporary float array to retrieve 3x3 matrix values. */
private final float[] mTmpFloats = new float[9];
@@ -1961,10 +1956,6 @@
}
}
mService.mAnimator.removeDisplayLocked(mDisplayId);
-
- // The pending transaction won't be applied so we should
- // just clean up any surfaces pending destruction.
- onPendingTransactionApplied();
} finally {
mRemovingDisplay = false;
}
@@ -3874,22 +3865,6 @@
}
@Override
- public void destroyAfterPendingTransaction(SurfaceControl surface) {
- mPendingDestroyingSurfaces.add(surface);
- }
-
- /**
- * Destroys any surfaces that have been put into the pending list with
- * {@link #destroyAfterPendingTransaction}.
- */
- void onPendingTransactionApplied() {
- for (int i = mPendingDestroyingSurfaces.size() - 1; i >= 0; i--) {
- mPendingDestroyingSurfaces.get(i).destroy();
- }
- mPendingDestroyingSurfaces.clear();
- }
-
- @Override
void prepareSurfaces() {
final ScreenRotationAnimation screenRotationAnimation =
mService.mAnimator.getScreenRotationAnimationLocked(mDisplayId);
@@ -3903,6 +3878,7 @@
mPendingTransaction.setAlpha(mWindowingLayer,
screenRotationAnimation.getEnterTransformation().getAlpha());
}
+
super.prepareSurfaces();
}
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 44ef247..f7344b2 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -219,7 +219,7 @@
private void addAnimation(Task task) {
if (DEBUG) Log.d(TAG, "addAnimation(" + task.getName() + ")");
final SurfaceAnimator anim = new SurfaceAnimator(task, null /* animationFinishedCallback */,
- mService.mAnimator::addAfterPrepareSurfacesRunnable, mService);
+ mService);
final TaskAnimationAdapter taskAdapter = new TaskAnimationAdapter(task);
anim.startAnimation(task.getPendingTransaction(), taskAdapter, false /* hidden */);
task.commitPendingTransaction();
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 8d36dac..f32c275 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -795,7 +795,6 @@
mService.enableScreenIfNeededLocked();
mService.scheduleAnimationLocked();
- mService.mWindowPlacerLocked.destroyPendingSurfaces();
if (DEBUG_WINDOW_TRACE) Slog.e(TAG,
"performSurfacePlacementInner exit: animating=" + mService.mAnimator.isAnimating());
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java
index 83baee1..76f5396 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimator.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java
@@ -33,7 +33,6 @@
import com.android.internal.annotations.VisibleForTesting;
import java.io.PrintWriter;
-import java.util.function.Consumer;
/**
* A class that can run animations on objects that have a set of child surfaces. We do this by
@@ -60,21 +59,17 @@
/**
* @param animatable The object to animate.
* @param animationFinishedCallback Callback to invoke when an animation has finished running.
- * @param addAfterPrepareSurfaces Consumer that takes a runnable and executes it after preparing
- * surfaces in WM. Can be implemented differently during testing.
*/
SurfaceAnimator(Animatable animatable, @Nullable Runnable animationFinishedCallback,
- Consumer<Runnable> addAfterPrepareSurfaces, WindowManagerService service) {
+ WindowManagerService service) {
mAnimatable = animatable;
mService = service;
mAnimationFinishedCallback = animationFinishedCallback;
- mInnerAnimationFinishedCallback = getFinishedCallback(animationFinishedCallback,
- addAfterPrepareSurfaces);
+ mInnerAnimationFinishedCallback = getFinishedCallback(animationFinishedCallback);
}
private OnAnimationFinishedCallback getFinishedCallback(
- @Nullable Runnable animationFinishedCallback,
- Consumer<Runnable> addAfterPrepareSurfaces) {
+ @Nullable Runnable animationFinishedCallback) {
return anim -> {
synchronized (mService.mWindowMap) {
final SurfaceAnimator target = mService.mAnimationTransferMap.remove(anim);
@@ -83,30 +78,13 @@
return;
}
- // TODO: This should use pendingTransaction eventually, but right now things
- // happening on the animation finished callback are happening on the global
- // transaction.
- // For now we need to run this after it's guaranteed that the transaction that
- // reparents the surface onto the leash is executed already. Otherwise this may be
- // executed first, leading to surface loss, as the reparent operations wouldn't
- // be in order.
- addAfterPrepareSurfaces.accept(() -> {
- if (anim != mAnimation) {
- // Callback was from another animation - ignore.
- return;
- }
- final Transaction t = new Transaction();
- SurfaceControl.openTransaction();
- try {
- reset(t, true /* destroyLeash */);
- if (animationFinishedCallback != null) {
- animationFinishedCallback.run();
- }
- } finally {
- SurfaceControl.mergeToGlobalTransaction(t);
- SurfaceControl.closeTransaction();
- }
- });
+ if (anim != mAnimation) {
+ return;
+ }
+ reset(mAnimatable.getPendingTransaction(), true /* destroyLeash */);
+ if (animationFinishedCallback != null) {
+ animationFinishedCallback.run();
+ }
}
};
}
@@ -282,15 +260,19 @@
final SurfaceControl surface = mAnimatable.getSurfaceControl();
final SurfaceControl parent = mAnimatable.getParentSurfaceControl();
+ boolean scheduleAnim = false;
+
// If the surface was destroyed, we don't care to reparent it back.
final boolean destroy = mLeash != null && surface != null && parent != null;
if (destroy) {
if (DEBUG_ANIM) Slog.i(TAG, "Reparenting to original parent");
t.reparent(surface, parent.getHandle());
+ scheduleAnim = true;
}
mService.mAnimationTransferMap.remove(mAnimation);
if (mLeash != null && destroyLeash) {
- mAnimatable.destroyAfterPendingTransaction(mLeash);
+ t.destroy(mLeash);
+ scheduleAnim = true;
}
mLeash = null;
mAnimation = null;
@@ -298,6 +280,11 @@
// Make sure to inform the animatable after the leash was destroyed.
if (destroy) {
mAnimatable.onAnimationLeashDestroyed(t);
+ scheduleAnim = true;
+ }
+
+ if (scheduleAnim) {
+ mService.scheduleAnimationLocked();
}
}
@@ -379,13 +366,6 @@
void onAnimationLeashDestroyed(Transaction t);
/**
- * Destroy a given surface after executing {@link #getPendingTransaction}.
- *
- * @see WindowContainer#destroyAfterPendingTransaction
- */
- void destroyAfterPendingTransaction(SurfaceControl surface);
-
- /**
* @return A new surface to be used for the animation leash, inserted at the correct
* position in the hierarchy.
*/
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 20349b9..ab10197 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -226,13 +226,6 @@
if (SHOW_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION animate");
}
- final int numDisplays = mDisplayContentsAnimators.size();
- for (int i = 0; i < numDisplays; i++) {
- final int displayId = mDisplayContentsAnimators.keyAt(i);
- final DisplayContent dc = mService.mRoot.getDisplayContent(displayId);
- dc.onPendingTransactionApplied();
- }
-
boolean hasPendingLayoutChanges = mService.mRoot.hasPendingLayoutChanges(this);
boolean doRequest = false;
if (mBulkUpdateParams != 0) {
@@ -266,7 +259,6 @@
}
mService.destroyPreservedSurfaceLocked();
- mService.mWindowPlacerLocked.destroyPendingSurfaces();
executeAfterPrepareSurfacesRunnables();
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 42f6065..b7525c0 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -109,8 +109,7 @@
WindowContainer(WindowManagerService service) {
mService = service;
mPendingTransaction = service.mTransactionFactory.make();
- mSurfaceAnimator = new SurfaceAnimator(this, this::onAnimationFinished,
- service.mAnimator::addAfterPrepareSurfacesRunnable, service);
+ mSurfaceAnimator = new SurfaceAnimator(this, this::onAnimationFinished, service);
}
@Override
@@ -286,8 +285,9 @@
}
if (mSurfaceControl != null) {
- destroyAfterPendingTransaction(mSurfaceControl);
+ getPendingTransaction().destroy(mSurfaceControl);
mSurfaceControl = null;
+ scheduleAnimation();
}
if (mParent != null) {
@@ -1079,19 +1079,6 @@
return mSurfaceControl;
}
- /**
- * Destroy a given surface after executing mPendingTransaction. This is
- * largely a workaround for destroy not being part of transactions
- * rather than an intentional design, so please take care when
- * expanding use.
- */
- @Override
- public void destroyAfterPendingTransaction(SurfaceControl surface) {
- if (mParent != null) {
- mParent.destroyAfterPendingTransaction(surface);
- }
- }
-
@Override
public Transaction getPendingTransaction() {
return mPendingTransaction;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 22028cb..c5b270e 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -4035,7 +4035,9 @@
final boolean hasSurface = mWinAnimator.hasSurface();
if (hasSurface) {
- mWinAnimator.hide("onExitAnimationDone");
+ // Use pendingTransaction here so hide is done the same transaction as the other
+ // animations when exiting
+ mWinAnimator.hide(getPendingTransaction(), "onExitAnimationDone");
}
// If we have an app token, we ask it to destroy the surface for us, so that it can take
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 247cab2..13f05e0 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -164,6 +164,8 @@
private boolean mAnimationStartDelayed;
+ private final SurfaceControl.Transaction mTmpTransaction = new SurfaceControl.Transaction();
+
/** The pixel format of the underlying SurfaceControl */
int mSurfaceFormat;
@@ -286,16 +288,21 @@
}
}
- void hide(String reason) {
+ void hide(SurfaceControl.Transaction transaction, String reason) {
if (!mLastHidden) {
//dump();
mLastHidden = true;
if (mSurfaceController != null) {
- mSurfaceController.hideInTransaction(reason);
+ mSurfaceController.hide(transaction, reason);
}
}
}
+ void hide(String reason) {
+ hide(mTmpTransaction, reason);
+ SurfaceControl.mergeToGlobalTransaction(mTmpTransaction);
+ }
+
boolean finishDrawingLocked() {
final boolean startingWindow =
mWin.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index 1b64d0a..9d6f8f7 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -86,6 +86,8 @@
private final int mWindowType;
private final Session mWindowSession;
+ private final SurfaceControl.Transaction mTmpTransaction = new SurfaceControl.Transaction();
+
public WindowSurfaceController(SurfaceSession s, String name, int w, int h, int format,
int flags, WindowStateAnimator animator, int windowType, int ownerUid) {
mAnimator = animator;
@@ -135,21 +137,23 @@
}
}
- void hideInTransaction(String reason) {
+ void hide(SurfaceControl.Transaction transaction, String reason) {
if (SHOW_TRANSACTIONS) logSurface("HIDE ( " + reason + " )", null);
mHiddenForOtherReasons = true;
mAnimator.destroyPreservedSurfaceLocked();
- updateVisibility();
+ if (mSurfaceShown) {
+ hideSurface(transaction);
+ }
}
- private void hideSurface() {
+ private void hideSurface(SurfaceControl.Transaction transaction) {
if (mSurfaceControl == null) {
return;
}
setShown(false);
try {
- mSurfaceControl.hide();
+ transaction.hide(mSurfaceControl);
} catch (RuntimeException e) {
Slog.w(TAG, "Exception hiding surface in " + this);
}
@@ -408,7 +412,8 @@
private boolean updateVisibility() {
if (mHiddenForCrop || mHiddenForOtherReasons) {
if (mSurfaceShown) {
- hideSurface();
+ hideSurface(mTmpTransaction);
+ SurfaceControl.mergeToGlobalTransaction(mTmpTransaction);
}
return false;
} else {
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 286cc49..4179590 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -103,7 +103,6 @@
}
private final LayerAndToken mTmpLayerAndToken = new LayerAndToken();
- private final ArrayList<SurfaceControl> mPendingDestroyingSurfaces = new ArrayList<>();
private final SparseIntArray mTempTransitionReasons = new SparseIntArray();
private final Runnable mPerformSurfacePlacement;
@@ -702,25 +701,6 @@
}
}
- /**
- * Puts the {@param surface} into a pending list to be destroyed after the current transaction
- * has been committed.
- */
- void destroyAfterTransaction(SurfaceControl surface) {
- mPendingDestroyingSurfaces.add(surface);
- }
-
- /**
- * Destroys any surfaces that have been put into the pending list with
- * {@link #destroyAfterTransaction}.
- */
- void destroyPendingSurfaces() {
- for (int i = mPendingDestroyingSurfaces.size() - 1; i >= 0; i--) {
- mPendingDestroyingSurfaces.get(i).destroy();
- }
- mPendingDestroyingSurfaces.clear();
- }
-
public void dump(PrintWriter pw, String prefix) {
pw.println(prefix + "mTraversalScheduled=" + mTraversalScheduled);
pw.println(prefix + "mHoldScreenWindow=" + mService.mRoot.mHoldScreenWindow);
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 5b5de0e..ccfadc0 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -23,6 +23,7 @@
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources.Theme;
@@ -331,6 +332,8 @@
// The system server should never make non-oneway calls
Binder.setWarnOnBlocking(true);
+ // The system server should always load safe labels
+ PackageItemInfo.setForceSafeLabels(true);
// Deactivate SQLiteCompatibilityWalFlags until settings provider is initialized
SQLiteCompatibilityWalFlags.init(null);
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
index e6a36c6..0ceb558 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
@@ -295,6 +295,18 @@
}
@Test
+ public void initRecoveryService_throwsIfInvalidCert() throws Exception {
+ byte[] modifiedCertXml = TestData.getCertXml();
+ modifiedCertXml[modifiedCertXml.length - 50] ^= 1; // Flip a bit in the certificate
+ try {
+ mRecoverableKeyStoreManager.initRecoveryService(ROOT_CERTIFICATE_ALIAS, modifiedCertXml);
+ fail("should have thrown");
+ } catch (ServiceSpecificException e) {
+ assertThat(e.getMessage()).contains("validate cert");
+ }
+ }
+
+ @Test
public void initRecoveryService_updatesWithLargerSerial() throws Exception {
int uid = Binder.getCallingUid();
int userId = UserHandle.getCallingUserId();
@@ -355,6 +367,70 @@
}
@Test
+ public void initRecoveryServiceWithSigFile_succeeds() throws Exception {
+ int uid = Binder.getCallingUid();
+ int userId = UserHandle.getCallingUserId();
+ mRecoverableKeyStoreDb.setShouldCreateSnapshot(userId, uid, false);
+
+ mRecoverableKeyStoreManager.initRecoveryServiceWithSigFile(
+ ROOT_CERTIFICATE_ALIAS, TestData.getCertXml(), TestData.getSigXml());
+
+ assertThat(mRecoverableKeyStoreDb.getShouldCreateSnapshot(userId, uid)).isTrue();
+ assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertPath(userId, uid)).isEqualTo(
+ TestData.CERT_PATH_1);
+ assertThat(mRecoverableKeyStoreDb.getRecoveryServicePublicKey(userId, uid)).isNull();
+ }
+
+ @Test
+ public void initRecoveryServiceWithSigFile_throwsIfNullCertFile() throws Exception {
+ try {
+ mRecoverableKeyStoreManager.initRecoveryServiceWithSigFile(
+ ROOT_CERTIFICATE_ALIAS, /*recoveryServiceCertFile=*/ null,
+ TestData.getSigXml());
+ fail("should have thrown");
+ } catch (ServiceSpecificException e) {
+ assertThat(e.getMessage()).contains("is null");
+ }
+ }
+
+ @Test
+ public void initRecoveryServiceWithSigFile_throwsIfNullSigFile() throws Exception {
+ try {
+ mRecoverableKeyStoreManager.initRecoveryServiceWithSigFile(
+ ROOT_CERTIFICATE_ALIAS, TestData.getCertXml(),
+ /*recoveryServiceSigFile=*/ null);
+ fail("should have thrown");
+ } catch (ServiceSpecificException e) {
+ assertThat(e.getMessage()).contains("is null");
+ }
+ }
+
+ @Test
+ public void initRecoveryServiceWithSigFile_throwsIfWrongSigFileFormat() throws Exception {
+ try {
+ mRecoverableKeyStoreManager.initRecoveryServiceWithSigFile(
+ ROOT_CERTIFICATE_ALIAS, TestData.getCertXml(),
+ getUtf8Bytes("wrong-sig-file-format"));
+ fail("should have thrown");
+ } catch (ServiceSpecificException e) {
+ assertThat(e.getMessage()).contains("parse the sig file");
+ }
+ }
+
+ @Test
+ public void initRecoveryServiceWithSigFile_throwsIfInvalidFileSignature() throws Exception {
+ byte[] modifiedCertXml = TestData.getCertXml();
+ modifiedCertXml[modifiedCertXml.length - 1] = 0; // Change the last new line char to a zero
+ try {
+ mRecoverableKeyStoreManager.initRecoveryServiceWithSigFile(
+ ROOT_CERTIFICATE_ALIAS, modifiedCertXml, TestData.getSigXml());
+ fail("should have thrown");
+ } catch (ServiceSpecificException e) {
+ assertThat(e.getMessage()).contains("is invalid");
+ }
+ }
+
+ @Test
public void startRecoverySession_checksPermissionFirst() throws Exception {
mRecoverableKeyStoreManager.startRecoverySession(
TEST_SESSION_ID,
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestData.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestData.java
index 0e4f91b..b5d6ce8 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestData.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestData.java
@@ -9,6 +9,7 @@
public final class TestData {
+ private static final long DEFAULT_SERIAL = 1000;
private static final String CERT_PATH_ENCODING = "PkiPath";
private static final String CERT_PATH_1_BASE64 = ""
@@ -89,10 +90,11 @@
private static final String THM_CERT_XML_BEFORE_SERIAL = ""
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
- + "<certificates>\n"
- + " <metadata>\n"
- + " <serial>\n";
- private static final String THM_CERT_XML_AFTER_SERIAL = ""
+ + "<certificates>\n"
+ + " <metadata>\n"
+ + " <serial>\n"
+ + " ";
+ private static final String THM_CERT_XML_AFTER_SERIAL = "\n"
+ " </serial>\n"
+ " <creation-time>\n"
+ " 1515697631\n"
@@ -163,6 +165,53 @@
+ " </cert>\n"
+ " </endpoints>\n"
+ "</certificates>\n";
+ private static final String THM_SIG_XML = ""
+ + "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ + "<signature>\n"
+ + " <intermediates>\n"
+ + " </intermediates>\n"
+ + " <certificate>\n"
+ + " MIIFLzCCAxegAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwIDEeMBwGA1UEAwwVR29v\n"
+ + " Z2xlIENyeXB0QXV0aFZhdWx0MB4XDTE4MDIwMzAwNDIwM1oXDTI4MDIwMTAwNDIw\n"
+ + " M1owLTErMCkGA1UEAwwiR29vZ2xlIENyeXB0QXV0aFZhdWx0IEludGVybWVkaWF0\n"
+ + " ZTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANyQeJvRfqtDIOqTjnX1\n"
+ + " vl27Q6sI+TfRdcrDP4fPnLhwZlpYoZwc4dZLZf1gClHM7TT8Ru8WRZVRNUbbvAnn\n"
+ + " hX4LccdI4BRYeESB8Va+8fB+f0dMPHUESTv1pConsO4nTpKf9Y6Iy0pUBPnoyLyZ\n"
+ + " 6QHGkw6t1mrCVwutRWxnEQezDn9x5m7hxJbNztLOWds0rVwKDJEMapZ/oaneEYTz\n"
+ + " qRQ60zWL3lGBQinD7D/PTDGkXqQjJBOMr4qOJgf9EE4kgRybqxJZmUyi0otKfaWF\n"
+ + " /5cvzJTETEgdOix95vTvtBZbjDYEHY1kzjA8A7fDhrDfcU2KANBzZJBiadQRiYhw\n"
+ + " PyTHvv4lYKALEElzbNMde0HFa5cBD6J6C3xE75AP3ul3pcoz3E+wA6RxYunv2j4A\n"
+ + " miXg/l/C+Bgzr2YziXAfXa/zpEjhqm09A5qDQoMgdfIpuNpDICC/fSXgqQOl/a5Y\n"
+ + " 4OE45PA1tU9hSbexhSWEFxvKFOTxio32w9ThABqjmwpMBhmAH+aWF5DKlNTDK+rP\n"
+ + " ptHMZ6FUHeW0/2ALIp0jThVcRS5QFaTdJPJXZERB6fn8soCezq/XULPbZmsR0K80\n"
+ + " uB62fJXsImw5r/AP8aJRYvZNrunOyGL1qEmqutw09FsDM4tw0pmQV7GHM+mie6j+\n"
+ + " k2txpF1rV+t6lfFWSZuyA5QvAgMBAAGjZjBkMB0GA1UdDgQWBBR3qZ3aEI+WZ/dW\n"
+ + " QRfkV8PEoEttoDAfBgNVHSMEGDAWgBSbZfrqOYH54EJpkdKMZjMcz/Hp+DASBgNV\n"
+ + " HRMBAf8ECDAGAQH/AgEBMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOC\n"
+ + " AgEAWBKGG5b5ZVOjA3TzQ8t/RNY+UcAIcdQ+CF/usUbGBSMnKkKWgTzgF6DdE6k/\n"
+ + " mXX0IOpn07I/MDXPpUDN4ZfIWFm9vLsba1kMFE/+/S7ymdIB0LkXyXxWHZgZ2ATe\n"
+ + " xkPbm+l0GLs/QR/othB604lefzo+qCaBbUXqXPEOMoKyL2Sl5TQBbAN05WDvjzCS\n"
+ + " 7nSjxQTOxXDHMV322gaWB7+efcUfknsS4bMCUXBOgeqnBNUR6BoB3SX2avn6tLtS\n"
+ + " t3dfzQEcOoIFxcTtSpu3PDlj6WajAwKdbSQU3TZ0L10u3Zz0jEL72w8gDl5OStkG\n"
+ + " SuRNVEYuPavb2PucL2blVopwGpwtkNbLylGdrzJpmmuA10Tx39ZNj2dWyJzT03zM\n"
+ + " 0XlDRuGFZrdCieUH1dblmoOC6JyW+f7lO1ETNIC1I7LEz6B8beXTCM7LAiTVoVrn\n"
+ + " ZFqoBY8vrso4zobe8o2kydbmGuYeuKO4rGJqsYihl+RkxHmKMrS4WC/f+no0cv9h\n"
+ + " AFockmGQp63lOGI/HBb37WT9lxdV5jbpeH7bYan/y2jtlbyC48+I3WF+kP7t/Uh1\n"
+ + " KYcOuxlBDtt/NXRummzI00Ht7YRzLD4ZCfLbufK0EskMZ1EG6tvBC/OmlA7pCaWT\n"
+ + " St8KzOHtsYKgJA3Fea4OxDkEL6lBSommVOp2zWybKLb3Gzc=\n"
+ + " </certificate>\n"
+ + " <value>\n"
+ + " uKJ4W8BPCdVaIBe2ZiMxxk5L5vGBV9QwaOEGU80LgtA/gEqkiO2IMUBlQJFqvvhh6RSph5lWpLuv\n"
+ + " /Xt7WBzDsZOcxXNffg2+pWNpbpwZdHohlwQEI1OqiVYVnfG4euAkzeWZZLsRUuAjHfcWVIzDoSoK\n"
+ + " wC+gqdUQHBV+pWyn6PXVslS0JIldeegbiwF076M1D7ybeCABXoQelSZRHkx1szO8UnxSR3X7Cemu\n"
+ + " p9De/7z9+WPPclqybINVIPy6Kvl8mHrGSlzawQRDKtoMrJa8bo93PookF8sbg5EoGapV0yNpMEiA\n"
+ + " spq3DEcdXB6mGDGPnLbS2WXq4zjKopASRKkZvOMdgfS6NdUMDtKS1TsOrv2KKTkLnGYfvdAeWiMg\n"
+ + " oFbuyYQ0mnDlLH1UW6anI8RxXn+wmdyZA+/ksapGvRmkvz0Mb997WzqNl7v7UTr0SU3Ws01hFsm6\n"
+ + " lW++MsotkyfpR9mWB8/dqVNVShLmIlt7U/YFVfziYSrVdjcAdIlgJ6Ihxb92liQHOU+Qr1YDOmm1\n"
+ + " JSnhlQVvFxWZG7hm5laNL6lqXz5VV6Gk5IeLtMb8kdHz3zj4ascdldapVPLJIa5741GNNgQNU0nH\n"
+ + " FhAyKk0zN7PbL1/XGWPU+s5lai4HE6JM2CKA7jE7cYrdaDZxbba+9iWzQ4YEBDr5Z3OoloK5dvs=\n"
+ + " </value>\n"
+ + "</signature>\n";
public static byte[] getCertPath1Bytes() {
try {
@@ -199,4 +248,12 @@
String xml = THM_CERT_XML_BEFORE_SERIAL + serial + THM_CERT_XML_AFTER_SERIAL;
return xml.getBytes(StandardCharsets.UTF_8);
}
+
+ public static byte[] getCertXml() {
+ return getCertXmlWithSerial(DEFAULT_SERIAL);
+ }
+
+ public static byte[] getSigXml() {
+ return THM_SIG_XML.getBytes(StandardCharsets.UTF_8);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
index b55c79b..76e4e89 100644
--- a/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import android.support.test.filters.FlakyTest;
import org.junit.Test;
import android.platform.test.annotations.Presubmit;
@@ -45,6 +46,7 @@
*/
@SmallTest
@Presubmit
+@FlakyTest(bugId = 74078662)
@org.junit.runner.RunWith(AndroidJUnit4.class)
public class AppWindowContainerControllerTests extends WindowTestsBase {
@@ -131,7 +133,6 @@
assertNoStartingWindow(controller.getAppWindowToken(mDisplayContent));
controller.getAppWindowToken(mDisplayContent).getParent().getParent().removeImmediately();
- mDisplayContent.onPendingTransactionApplied();
}
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java b/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java
index 64c3037..a120eba 100644
--- a/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java
@@ -23,11 +23,11 @@
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.FlakyTest;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.view.SurfaceControl;
@@ -39,7 +39,6 @@
import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -47,7 +46,6 @@
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
-import java.util.concurrent.CountDownLatch;
/**
* Test class for {@link SurfaceAnimatorTest}.
@@ -87,7 +85,7 @@
callbackCaptor.getValue().onAnimationFinished(mSpec);
assertNotAnimating(mAnimatable);
assertTrue(mAnimatable.mFinishedCallbackCalled);
- assertTrue(mAnimatable.mPendingDestroySurfaces.contains(mAnimatable.mLeash));
+ verify(mTransaction).destroy(eq(mAnimatable.mLeash));
// TODO: Verify reparenting once we use mPendingTransaction to reparent it back
}
@@ -97,7 +95,7 @@
final SurfaceControl firstLeash = mAnimatable.mLeash;
mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec2, true /* hidden */);
- assertTrue(mAnimatable.mPendingDestroySurfaces.contains(firstLeash));
+ verify(mTransaction).destroy(eq(firstLeash));
assertFalse(mAnimatable.mFinishedCallbackCalled);
final ArgumentCaptor<OnAnimationFinishedCallback> callbackCaptor = ArgumentCaptor.forClass(
@@ -124,7 +122,7 @@
assertNotAnimating(mAnimatable);
verify(mSpec).onAnimationCancelled(any());
assertTrue(mAnimatable.mFinishedCallbackCalled);
- assertTrue(mAnimatable.mPendingDestroySurfaces.contains(mAnimatable.mLeash));
+ verify(mTransaction).destroy(eq(mAnimatable.mLeash));
}
@Test
@@ -145,7 +143,7 @@
verifyZeroInteractions(mSpec);
assertNotAnimating(mAnimatable);
assertTrue(mAnimatable.mFinishedCallbackCalled);
- assertTrue(mAnimatable.mPendingDestroySurfaces.contains(mAnimatable.mLeash));
+ verify(mTransaction).destroy(eq(mAnimatable.mLeash));
}
@Test
@@ -161,11 +159,11 @@
assertNotAnimating(mAnimatable);
assertAnimating(mAnimatable2);
assertEquals(leash, mAnimatable2.mSurfaceAnimator.mLeash);
- assertFalse(mAnimatable.mPendingDestroySurfaces.contains(leash));
+ verify(mTransaction, never()).destroy(eq(leash));
callbackCaptor.getValue().onAnimationFinished(mSpec);
assertNotAnimating(mAnimatable2);
assertTrue(mAnimatable2.mFinishedCallbackCalled);
- assertTrue(mAnimatable2.mPendingDestroySurfaces.contains(leash));
+ verify(mTransaction).destroy(eq(leash));
}
private void assertAnimating(MyAnimatable animatable) {
@@ -182,7 +180,6 @@
final SurfaceControl mParent;
final SurfaceControl mSurface;
- final ArrayList<SurfaceControl> mPendingDestroySurfaces = new ArrayList<>();
final SurfaceAnimator mSurfaceAnimator;
SurfaceControl mLeash;
boolean mFinishedCallbackCalled;
@@ -198,7 +195,7 @@
.build();
mFinishedCallbackCalled = false;
mLeash = null;
- mSurfaceAnimator = new SurfaceAnimator(this, mFinishedCallback, Runnable::run, sWm);
+ mSurfaceAnimator = new SurfaceAnimator(this, mFinishedCallback, sWm);
}
@Override
@@ -219,11 +216,6 @@
}
@Override
- public void destroyAfterPendingTransaction(SurfaceControl surface) {
- mPendingDestroySurfaces.add(surface);
- }
-
- @Override
public Builder makeAnimationLeash() {
return new SurfaceControl.Builder(mSession) {
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowConfigurationTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowConfigurationTests.java
index e78224c..41e446b 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowConfigurationTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowConfigurationTests.java
@@ -22,6 +22,7 @@
import android.content.res.Configuration;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.FlakyTest;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.view.DisplayInfo;
@@ -44,6 +45,7 @@
* bit FrameworksServicesTests:com.android.server.wm.WindowConfigurationTests
*/
@SmallTest
+@FlakyTest(bugId = 74078662)
@Presubmit
@org.junit.runner.RunWith(AndroidJUnit4.class)
public class WindowConfigurationTests extends WindowTestsBase {
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowContainerControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowContainerControllerTests.java
index bab2170..502cb6e 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowContainerControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowContainerControllerTests.java
@@ -18,6 +18,7 @@
import android.app.WindowConfiguration;
import android.content.res.Configuration;
+import android.support.test.filters.FlakyTest;
import org.junit.Test;
import android.platform.test.annotations.Presubmit;
@@ -38,6 +39,7 @@
*/
@SmallTest
@Presubmit
+@FlakyTest(bugId = 74078662)
@org.junit.runner.RunWith(AndroidJUnit4.class)
public class WindowContainerControllerTests extends WindowTestsBase {
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java
index 1bd9a93..8446d25 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import android.support.test.filters.FlakyTest;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -55,6 +56,7 @@
*/
@SmallTest
@Presubmit
+@FlakyTest(bugId = 74078662)
@RunWith(AndroidJUnit4.class)
public class WindowContainerTests extends WindowTestsBase {
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
index 74c72bf..83868d6 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
@@ -21,6 +21,7 @@
import org.junit.runner.RunWith;
import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.FlakyTest;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -52,6 +53,7 @@
* atest FrameworksServicesTests:com.android.server.wm.WindowStateTests
*/
@SmallTest
+@FlakyTest(bugId = 74078662)
@Presubmit
@RunWith(AndroidJUnit4.class)
public class WindowStateTests extends WindowTestsBase {
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java
index 7219104..394e636 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java
@@ -20,6 +20,7 @@
import org.junit.runner.RunWith;
import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.FlakyTest;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -40,6 +41,7 @@
* bit FrameworksServicesTests:com.android.server.wm.WindowTokenTests
*/
@SmallTest
+@FlakyTest(bugId = 74078662)
@Presubmit
@RunWith(AndroidJUnit4.class)
public class WindowTokenTests extends WindowTestsBase {
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTracingTest.java b/services/tests/servicestests/src/com/android/server/wm/WindowTracingTest.java
index ad9aea7..a3ade1e 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTracingTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTracingTest.java
@@ -31,6 +31,7 @@
import android.platform.test.annotations.Presubmit;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
+import android.support.test.filters.FlakyTest;
import android.support.test.runner.AndroidJUnit4;
import android.util.proto.ProtoOutputStream;
@@ -56,6 +57,7 @@
* bit FrameworksServicesTests:com.android.server.wm.WindowTracingTest
*/
@SmallTest
+@FlakyTest(bugId = 74078662)
@Presubmit
@RunWith(AndroidJUnit4.class)
public class WindowTracingTest extends WindowTestsBase {
diff --git a/services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java b/services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java
index 5f44fb6..547be55 100644
--- a/services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java
@@ -35,6 +35,7 @@
import android.platform.test.annotations.Presubmit;
import android.support.test.filters.SmallTest;
+import android.support.test.filters.FlakyTest;
import android.support.test.runner.AndroidJUnit4;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
@@ -53,6 +54,7 @@
* bit FrameworksServicesTests:com.android.server.wm.ZOrderingTests
*/
@SmallTest
+@FlakyTest(bugId = 74078662)
@Presubmit
@RunWith(AndroidJUnit4.class)
public class ZOrderingTests extends WindowTestsBase {
diff --git a/services/tests/servicestests/src/com/android/server/wm/utils/RotationCacheTest.java b/services/tests/servicestests/src/com/android/server/wm/utils/RotationCacheTest.java
index d3cf978..6bbc7eb 100644
--- a/services/tests/servicestests/src/com/android/server/wm/utils/RotationCacheTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/utils/RotationCacheTest.java
@@ -24,6 +24,7 @@
import static org.junit.Assert.assertThat;
import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.FlakyTest;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.util.Pair;
@@ -37,6 +38,7 @@
@RunWith(AndroidJUnit4.class)
@SmallTest
+@FlakyTest(bugId = 74078662)
@Presubmit
public class RotationCacheTest {
@@ -100,4 +102,4 @@
assertThat(mCache.getOrCompute("hello", 1), equalTo(create("hello", 1)));
assertThat(mComputationCalled, is(true));
}
-}
\ No newline at end of file
+}
diff --git a/telephony/java/android/telephony/LocationAccessPolicy.java b/telephony/java/android/telephony/LocationAccessPolicy.java
index b362df9..26ffe32 100644
--- a/telephony/java/android/telephony/LocationAccessPolicy.java
+++ b/telephony/java/android/telephony/LocationAccessPolicy.java
@@ -82,8 +82,7 @@
.noteOpNoThrow(opCode, uid, pkgName) != AppOpsManager.MODE_ALLOWED) {
return false;
}
- if (!isLocationModeEnabled(context, UserHandle.getUserId(uid))
- && !isLegacyForeground(context, pkgName, uid)) {
+ if (!isLocationModeEnabled(context, UserHandle.getUserId(uid))) {
return false;
}
// If the user or profile is current, permission is granted.
@@ -101,35 +100,6 @@
&& locationMode != Settings.Secure.LOCATION_MODE_SENSORS_ONLY;
}
- private static boolean isLegacyForeground(@NonNull Context context, @NonNull String pkgName,
- int uid) {
- long token = Binder.clearCallingIdentity();
- try {
- return isLegacyVersion(context, pkgName) && isForegroundApp(context, uid);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- private static boolean isLegacyVersion(@NonNull Context context, @NonNull String pkgName) {
- try {
- if (context.getPackageManager().getApplicationInfo(pkgName, 0)
- .targetSdkVersion <= Build.VERSION_CODES.O) {
- return true;
- }
- } catch (PackageManager.NameNotFoundException e) {
- // In case of exception, assume known app (more strict checking)
- // Note: This case will never happen since checkPackage is
- // called to verify validity before checking app's version.
- }
- return false;
- }
-
- private static boolean isForegroundApp(@NonNull Context context, int uid) {
- final ActivityManager am = context.getSystemService(ActivityManager.class);
- return am.getUidImportance(uid) <= ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
- }
-
private static boolean checkInteractAcrossUsersFull(@NonNull Context context) {
return context.checkCallingOrSelfPermission(
android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
diff --git a/telephony/java/android/telephony/euicc/EuiccCardManager.java b/telephony/java/android/telephony/euicc/EuiccCardManager.java
index c3f4007..38f9745 100644
--- a/telephony/java/android/telephony/euicc/EuiccCardManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccCardManager.java
@@ -116,6 +116,9 @@
/** Result code of an unknown error. */
public static final int RESULT_UNKNOWN_ERROR = -1;
+ /** Result code when the eUICC card with the given card Id is not found. */
+ public static final int RESULT_EUICC_NOT_FOUND = -2;
+
/**
* Callback to receive the result of an eUICC card API.
*
diff --git a/tests/net/java/android/net/IpPrefixTest.java b/tests/net/java/android/net/IpPrefixTest.java
index b5b2c07..1f1ba2e 100644
--- a/tests/net/java/android/net/IpPrefixTest.java
+++ b/tests/net/java/android/net/IpPrefixTest.java
@@ -223,14 +223,14 @@
}
@Test
- public void testContains() {
+ public void testContainsInetAddress() {
IpPrefix p = new IpPrefix("2001:db8:f00::ace:d00d/127");
assertTrue(p.contains(Address("2001:db8:f00::ace:d00c")));
assertTrue(p.contains(Address("2001:db8:f00::ace:d00d")));
assertFalse(p.contains(Address("2001:db8:f00::ace:d00e")));
assertFalse(p.contains(Address("2001:db8:f00::bad:d00d")));
assertFalse(p.contains(Address("2001:4868:4860::8888")));
- assertFalse(p.contains(null));
+ assertFalse(p.contains((InetAddress)null));
assertFalse(p.contains(Address("8.8.8.8")));
p = new IpPrefix("192.0.2.0/23");
@@ -251,6 +251,53 @@
}
@Test
+ public void testContainsIpPrefix() {
+ assertTrue(new IpPrefix("0.0.0.0/0").containsPrefix(new IpPrefix("0.0.0.0/0")));
+ assertTrue(new IpPrefix("0.0.0.0/0").containsPrefix(new IpPrefix("1.2.3.4/0")));
+ assertTrue(new IpPrefix("0.0.0.0/0").containsPrefix(new IpPrefix("1.2.3.4/8")));
+ assertTrue(new IpPrefix("0.0.0.0/0").containsPrefix(new IpPrefix("1.2.3.4/24")));
+ assertTrue(new IpPrefix("0.0.0.0/0").containsPrefix(new IpPrefix("1.2.3.4/23")));
+
+ assertTrue(new IpPrefix("1.2.3.4/8").containsPrefix(new IpPrefix("1.2.3.4/8")));
+ assertTrue(new IpPrefix("1.2.3.4/8").containsPrefix(new IpPrefix("1.254.12.9/8")));
+ assertTrue(new IpPrefix("1.2.3.4/21").containsPrefix(new IpPrefix("1.2.3.4/21")));
+ assertTrue(new IpPrefix("1.2.3.4/32").containsPrefix(new IpPrefix("1.2.3.4/32")));
+
+ assertTrue(new IpPrefix("1.2.3.4/20").containsPrefix(new IpPrefix("1.2.3.0/24")));
+
+ assertFalse(new IpPrefix("1.2.3.4/32").containsPrefix(new IpPrefix("1.2.3.5/32")));
+ assertFalse(new IpPrefix("1.2.3.4/8").containsPrefix(new IpPrefix("2.2.3.4/8")));
+ assertFalse(new IpPrefix("0.0.0.0/16").containsPrefix(new IpPrefix("0.0.0.0/15")));
+ assertFalse(new IpPrefix("100.0.0.0/8").containsPrefix(new IpPrefix("99.0.0.0/8")));
+
+ assertTrue(new IpPrefix("::/0").containsPrefix(new IpPrefix("::/0")));
+ assertTrue(new IpPrefix("::/0").containsPrefix(new IpPrefix("2001:db8::f00/1")));
+ assertTrue(new IpPrefix("::/0").containsPrefix(new IpPrefix("3d8a:661:a0::770/8")));
+ assertTrue(new IpPrefix("::/0").containsPrefix(new IpPrefix("2001:db8::f00/8")));
+ assertTrue(new IpPrefix("::/0").containsPrefix(new IpPrefix("2001:db8::f00/64")));
+ assertTrue(new IpPrefix("::/0").containsPrefix(new IpPrefix("2001:db8::f00/113")));
+ assertTrue(new IpPrefix("::/0").containsPrefix(new IpPrefix("2001:db8::f00/128")));
+
+ assertTrue(new IpPrefix("2001:db8:f00::ace:d00d/64").containsPrefix(
+ new IpPrefix("2001:db8:f00::ace:d00d/64")));
+ assertTrue(new IpPrefix("2001:db8:f00::ace:d00d/64").containsPrefix(
+ new IpPrefix("2001:db8:f00::ace:d00d/120")));
+ assertFalse(new IpPrefix("2001:db8:f00::ace:d00d/64").containsPrefix(
+ new IpPrefix("2001:db8:f00::ace:d00d/32")));
+ assertFalse(new IpPrefix("2001:db8:f00::ace:d00d/64").containsPrefix(
+ new IpPrefix("2006:db8:f00::ace:d00d/96")));
+
+ assertTrue(new IpPrefix("2001:db8:f00::ace:d00d/128").containsPrefix(
+ new IpPrefix("2001:db8:f00::ace:d00d/128")));
+ assertTrue(new IpPrefix("2001:db8:f00::ace:d00d/100").containsPrefix(
+ new IpPrefix("2001:db8:f00::ace:ccaf/110")));
+
+ assertFalse(new IpPrefix("2001:db8:f00::ace:d00d/128").containsPrefix(
+ new IpPrefix("2001:db8:f00::ace:d00e/128")));
+ assertFalse(new IpPrefix("::/30").containsPrefix(new IpPrefix("::/29")));
+ }
+
+ @Test
public void testHashCode() {
IpPrefix p = new IpPrefix(new byte[4], 0);
Random random = new Random();
diff --git a/tests/net/java/android/net/NetworkCapabilitiesTest.java b/tests/net/java/android/net/NetworkCapabilitiesTest.java
index 4227da6..ec6a5ec 100644
--- a/tests/net/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/net/java/android/net/NetworkCapabilitiesTest.java
@@ -214,7 +214,9 @@
assertFalse(netCap.appliesToUidRange(new UidRange(60, 3400)));
NetworkCapabilities netCap2 = new NetworkCapabilities();
- assertFalse(netCap2.satisfiedByUids(netCap));
+ // A new netcap object has null UIDs, so anything will satisfy it.
+ assertTrue(netCap2.satisfiedByUids(netCap));
+ // Still not equal though.
assertFalse(netCap2.equalsUids(netCap));
netCap2.setUids(uids);
assertTrue(netCap2.satisfiedByUids(netCap));
@@ -231,7 +233,7 @@
assertTrue(netCap.appliesToUid(650));
assertFalse(netCap.appliesToUid(500));
- assertFalse(new NetworkCapabilities().satisfiedByUids(netCap));
+ assertTrue(new NetworkCapabilities().satisfiedByUids(netCap));
netCap.combineCapabilities(new NetworkCapabilities());
assertTrue(netCap.appliesToUid(500));
assertTrue(netCap.appliesToUidRange(new UidRange(1, 100000)));
diff --git a/tests/net/java/android/net/NetworkUtilsTest.java b/tests/net/java/android/net/NetworkUtilsTest.java
index 8d51c3b..a5ee8e3 100644
--- a/tests/net/java/android/net/NetworkUtilsTest.java
+++ b/tests/net/java/android/net/NetworkUtilsTest.java
@@ -19,8 +19,10 @@
import android.net.NetworkUtils;
import android.test.suitebuilder.annotation.SmallTest;
+import java.math.BigInteger;
import java.net.Inet4Address;
import java.net.InetAddress;
+import java.util.TreeSet;
import junit.framework.TestCase;
@@ -67,4 +69,101 @@
assertInvalidNetworkMask(IPv4Address("255.255.255.253"));
assertInvalidNetworkMask(IPv4Address("255.255.0.255"));
}
+
+ @SmallTest
+ public void testRoutedIPv4AddressCount() {
+ final TreeSet<IpPrefix> set = new TreeSet<>(IpPrefix.lengthComparator());
+ // No routes routes to no addresses.
+ assertEquals(0, NetworkUtils.routedIPv4AddressCount(set));
+
+ set.add(new IpPrefix("0.0.0.0/0"));
+ assertEquals(1l << 32, NetworkUtils.routedIPv4AddressCount(set));
+
+ set.add(new IpPrefix("20.18.0.0/16"));
+ set.add(new IpPrefix("20.18.0.0/24"));
+ set.add(new IpPrefix("20.18.0.0/8"));
+ // There is a default route, still covers everything
+ assertEquals(1l << 32, NetworkUtils.routedIPv4AddressCount(set));
+
+ set.clear();
+ set.add(new IpPrefix("20.18.0.0/24"));
+ set.add(new IpPrefix("20.18.0.0/8"));
+ // The 8-length includes the 24-length prefix
+ assertEquals(1l << 24, NetworkUtils.routedIPv4AddressCount(set));
+
+ set.add(new IpPrefix("10.10.10.126/25"));
+ // The 8-length does not include this 25-length prefix
+ assertEquals((1l << 24) + (1 << 7), NetworkUtils.routedIPv4AddressCount(set));
+
+ set.clear();
+ set.add(new IpPrefix("1.2.3.4/32"));
+ set.add(new IpPrefix("1.2.3.4/32"));
+ set.add(new IpPrefix("1.2.3.4/32"));
+ set.add(new IpPrefix("1.2.3.4/32"));
+ assertEquals(1l, NetworkUtils.routedIPv4AddressCount(set));
+
+ set.add(new IpPrefix("1.2.3.5/32"));
+ set.add(new IpPrefix("1.2.3.6/32"));
+
+ set.add(new IpPrefix("1.2.3.7/32"));
+ set.add(new IpPrefix("1.2.3.8/32"));
+ set.add(new IpPrefix("1.2.3.9/32"));
+ set.add(new IpPrefix("1.2.3.0/32"));
+ assertEquals(7l, NetworkUtils.routedIPv4AddressCount(set));
+
+ // 1.2.3.4/30 eats 1.2.3.{4-7}/32
+ set.add(new IpPrefix("1.2.3.4/30"));
+ set.add(new IpPrefix("6.2.3.4/28"));
+ set.add(new IpPrefix("120.2.3.4/16"));
+ assertEquals(7l - 4 + 4 + 16 + 65536, NetworkUtils.routedIPv4AddressCount(set));
+ }
+
+ @SmallTest
+ public void testRoutedIPv6AddressCount() {
+ final TreeSet<IpPrefix> set = new TreeSet<>(IpPrefix.lengthComparator());
+ // No routes routes to no addresses.
+ assertEquals(BigInteger.ZERO, NetworkUtils.routedIPv6AddressCount(set));
+
+ set.add(new IpPrefix("::/0"));
+ assertEquals(BigInteger.ONE.shiftLeft(128), NetworkUtils.routedIPv6AddressCount(set));
+
+ set.add(new IpPrefix("1234:622a::18/64"));
+ set.add(new IpPrefix("add4:f00:80:f7:1111::6adb/96"));
+ set.add(new IpPrefix("add4:f00:80:f7:1111::6adb/8"));
+ // There is a default route, still covers everything
+ assertEquals(BigInteger.ONE.shiftLeft(128), NetworkUtils.routedIPv6AddressCount(set));
+
+ set.clear();
+ set.add(new IpPrefix("add4:f00:80:f7:1111::6adb/96"));
+ set.add(new IpPrefix("add4:f00:80:f7:1111::6adb/8"));
+ // The 8-length includes the 96-length prefix
+ assertEquals(BigInteger.ONE.shiftLeft(120), NetworkUtils.routedIPv6AddressCount(set));
+
+ set.add(new IpPrefix("10::26/64"));
+ // The 8-length does not include this 64-length prefix
+ assertEquals(BigInteger.ONE.shiftLeft(120).add(BigInteger.ONE.shiftLeft(64)),
+ NetworkUtils.routedIPv6AddressCount(set));
+
+ set.clear();
+ set.add(new IpPrefix("add4:f00:80:f7:1111::6ad4/128"));
+ set.add(new IpPrefix("add4:f00:80:f7:1111::6ad4/128"));
+ set.add(new IpPrefix("add4:f00:80:f7:1111::6ad4/128"));
+ set.add(new IpPrefix("add4:f00:80:f7:1111::6ad4/128"));
+ assertEquals(BigInteger.ONE, NetworkUtils.routedIPv6AddressCount(set));
+
+ set.add(new IpPrefix("add4:f00:80:f7:1111::6ad5/128"));
+ set.add(new IpPrefix("add4:f00:80:f7:1111::6ad6/128"));
+ set.add(new IpPrefix("add4:f00:80:f7:1111::6ad7/128"));
+ set.add(new IpPrefix("add4:f00:80:f7:1111::6ad8/128"));
+ set.add(new IpPrefix("add4:f00:80:f7:1111::6ad9/128"));
+ set.add(new IpPrefix("add4:f00:80:f7:1111::6ad0/128"));
+ assertEquals(BigInteger.valueOf(7), NetworkUtils.routedIPv6AddressCount(set));
+
+ // add4:f00:80:f7:1111::6ad4/126 eats add4:f00:8[:f7:1111::6ad{4-7}/128
+ set.add(new IpPrefix("add4:f00:80:f7:1111::6ad4/126"));
+ set.add(new IpPrefix("d00d:f00:80:f7:1111::6ade/124"));
+ set.add(new IpPrefix("f00b:a33::/112"));
+ assertEquals(BigInteger.valueOf(7l - 4 + 4 + 16 + 65536),
+ NetworkUtils.routedIPv6AddressCount(set));
+ }
}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 2aea1d7..207e24a 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -387,6 +387,7 @@
mScore = 20;
break;
case TRANSPORT_VPN:
+ mNetworkCapabilities.removeCapability(NET_CAPABILITY_NOT_VPN);
mScore = ConnectivityConstants.VPN_DEFAULT_SCORE;
break;
default:
@@ -3748,14 +3749,19 @@
final int uid = Process.myUid();
final TestNetworkCallback genericNetworkCallback = new TestNetworkCallback();
+ final TestNetworkCallback genericNotVpnNetworkCallback = new TestNetworkCallback();
final TestNetworkCallback wifiNetworkCallback = new TestNetworkCallback();
final TestNetworkCallback vpnNetworkCallback = new TestNetworkCallback();
- final NetworkRequest genericRequest = new NetworkRequest.Builder().build();
+ final NetworkRequest genericNotVpnRequest = new NetworkRequest.Builder().build();
+ final NetworkRequest genericRequest = new NetworkRequest.Builder()
+ .removeCapability(NET_CAPABILITY_NOT_VPN).build();
final NetworkRequest wifiRequest = new NetworkRequest.Builder()
.addTransportType(TRANSPORT_WIFI).build();
final NetworkRequest vpnNetworkRequest = new NetworkRequest.Builder()
+ .removeCapability(NET_CAPABILITY_NOT_VPN)
.addTransportType(TRANSPORT_VPN).build();
mCm.registerNetworkCallback(genericRequest, genericNetworkCallback);
+ mCm.registerNetworkCallback(genericNotVpnRequest, genericNotVpnNetworkCallback);
mCm.registerNetworkCallback(wifiRequest, wifiNetworkCallback);
mCm.registerNetworkCallback(vpnNetworkRequest, vpnNetworkCallback);
@@ -3763,6 +3769,7 @@
mWiFiNetworkAgent.connect(false);
genericNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+ genericNotVpnNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
wifiNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
vpnNetworkCallback.assertNoCallback();
@@ -3777,16 +3784,19 @@
vpnNetworkAgent.connect(false);
genericNetworkCallback.expectAvailableCallbacksUnvalidated(vpnNetworkAgent);
+ genericNotVpnNetworkCallback.assertNoCallback();
wifiNetworkCallback.assertNoCallback();
vpnNetworkCallback.expectAvailableCallbacksUnvalidated(vpnNetworkAgent);
genericNetworkCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, vpnNetworkAgent);
+ genericNotVpnNetworkCallback.assertNoCallback();
vpnNetworkCallback.expectCapabilitiesLike(nc -> null == nc.getUids(), vpnNetworkAgent);
ranges.clear();
vpnNetworkAgent.setUids(ranges);
genericNetworkCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
+ genericNotVpnNetworkCallback.assertNoCallback();
wifiNetworkCallback.assertNoCallback();
vpnNetworkCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
@@ -3794,18 +3804,21 @@
vpnNetworkAgent.setUids(ranges);
genericNetworkCallback.expectAvailableCallbacksValidated(vpnNetworkAgent);
+ genericNotVpnNetworkCallback.assertNoCallback();
wifiNetworkCallback.assertNoCallback();
vpnNetworkCallback.expectAvailableCallbacksValidated(vpnNetworkAgent);
mWiFiNetworkAgent.disconnect();
genericNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ genericNotVpnNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
wifiNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
vpnNetworkCallback.assertNoCallback();
vpnNetworkAgent.disconnect();
genericNetworkCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
+ genericNotVpnNetworkCallback.assertNoCallback();
wifiNetworkCallback.assertNoCallback();
vpnNetworkCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
index 1dbf9b2..f59850d 100644
--- a/tests/net/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/net/java/com/android/server/connectivity/VpnTest.java
@@ -57,9 +57,13 @@
import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.net.ConnectivityManager;
+import android.net.IConnectivityManager;
+import android.net.IpPrefix;
+import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo.DetailedState;
+import android.net.RouteInfo;
import android.net.UidRange;
import android.net.VpnService;
import android.os.Build.VERSION_CODES;
@@ -90,7 +94,8 @@
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
-
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
/**
* Tests for {@link Vpn}.
@@ -563,4 +568,75 @@
return networks.get(network);
}).when(mConnectivityManager).getNetworkCapabilities(any());
}
+
+ // Need multiple copies of this, but Java's Stream objects can't be reused or
+ // duplicated.
+ private Stream<String> publicIpV4Routes() {
+ return Stream.of(
+ "0.0.0.0/5", "8.0.0.0/7", "11.0.0.0/8", "12.0.0.0/6", "16.0.0.0/4",
+ "32.0.0.0/3", "64.0.0.0/2", "128.0.0.0/3", "160.0.0.0/5", "168.0.0.0/6",
+ "172.0.0.0/12", "172.32.0.0/11", "172.64.0.0/10", "172.128.0.0/9",
+ "173.0.0.0/8", "174.0.0.0/7", "176.0.0.0/4", "192.0.0.0/9", "192.128.0.0/11",
+ "192.160.0.0/13", "192.169.0.0/16", "192.170.0.0/15", "192.172.0.0/14",
+ "192.176.0.0/12", "192.192.0.0/10", "193.0.0.0/8", "194.0.0.0/7",
+ "196.0.0.0/6", "200.0.0.0/5", "208.0.0.0/4");
+ }
+
+ private Stream<String> publicIpV6Routes() {
+ return Stream.of(
+ "::/1", "8000::/2", "c000::/3", "e000::/4", "f000::/5", "f800::/6",
+ "fe00::/8", "2605:ef80:e:af1d::/64");
+ }
+
+ @Test
+ public void testProvidesRoutesToMostDestinations() {
+ final LinkProperties lp = new LinkProperties();
+
+ // Default route provides routes to all IPv4 destinations.
+ lp.addRoute(new RouteInfo(new IpPrefix("0.0.0.0/0")));
+ assertTrue(Vpn.providesRoutesToMostDestinations(lp));
+
+ // Empty LP provides routes to no destination
+ lp.clear();
+ assertFalse(Vpn.providesRoutesToMostDestinations(lp));
+
+ // All IPv4 routes except for local networks. This is the case most relevant
+ // to this function. It provides routes to almost the entire space.
+ // (clone the stream so that we can reuse it later)
+ publicIpV4Routes().forEach(s -> lp.addRoute(new RouteInfo(new IpPrefix(s))));
+ assertTrue(Vpn.providesRoutesToMostDestinations(lp));
+
+ // Removing a 16-bit prefix, which is 65536 addresses. This is still enough to
+ // provide routes to "most" destinations.
+ lp.removeRoute(new RouteInfo(new IpPrefix("192.169.0.0/16")));
+ assertTrue(Vpn.providesRoutesToMostDestinations(lp));
+
+ // Remove the /2 route, which represent a quarter of the available routing space.
+ // This LP does not provides routes to "most" destinations any more.
+ lp.removeRoute(new RouteInfo(new IpPrefix("64.0.0.0/2")));
+ assertFalse(Vpn.providesRoutesToMostDestinations(lp));
+
+ lp.clear();
+ publicIpV6Routes().forEach(s -> lp.addRoute(new RouteInfo(new IpPrefix(s))));
+ assertTrue(Vpn.providesRoutesToMostDestinations(lp));
+
+ lp.removeRoute(new RouteInfo(new IpPrefix("::/1")));
+ assertFalse(Vpn.providesRoutesToMostDestinations(lp));
+
+ // V6 does not provide sufficient coverage but v4 does
+ publicIpV4Routes().forEach(s -> lp.addRoute(new RouteInfo(new IpPrefix(s))));
+ assertTrue(Vpn.providesRoutesToMostDestinations(lp));
+
+ // V4 still does
+ lp.removeRoute(new RouteInfo(new IpPrefix("192.169.0.0/16")));
+ assertTrue(Vpn.providesRoutesToMostDestinations(lp));
+
+ // V4 does not any more
+ lp.removeRoute(new RouteInfo(new IpPrefix("64.0.0.0/2")));
+ assertFalse(Vpn.providesRoutesToMostDestinations(lp));
+
+ // V4 does not, but V6 has sufficient coverage again
+ lp.addRoute(new RouteInfo(new IpPrefix("::/1")));
+ assertTrue(Vpn.providesRoutesToMostDestinations(lp));
+ }
}