Merge "Set min_sdk_version to 29 in SampleRollbackApp."
diff --git a/Android.bp b/Android.bp
index c22dafb..55d9c4b 100644
--- a/Android.bp
+++ b/Android.bp
@@ -150,6 +150,9 @@
visibility: [
// DO NOT ADD ANY MORE ENTRIES TO THIS LIST
"//external/robolectric-shadows:__subpackages__",
+ //This will eventually replace the item above, and serves the
+ //same purpose.
+ "//external/robolectric:__subpackages__",
"//frameworks/layoutlib:__subpackages__",
],
}
diff --git a/core/api/current.txt b/core/api/current.txt
index 93cb7e4..ffecc09 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -32238,6 +32238,7 @@
field public static final String DISALLOW_BLUETOOTH = "no_bluetooth";
field public static final String DISALLOW_BLUETOOTH_SHARING = "no_bluetooth_sharing";
field public static final String DISALLOW_CAMERA_TOGGLE = "disallow_camera_toggle";
+ field public static final String DISALLOW_CELLULAR_2G = "no_cellular_2g";
field public static final String DISALLOW_CHANGE_WIFI_STATE = "no_change_wifi_state";
field public static final String DISALLOW_CONFIG_BLUETOOTH = "no_config_bluetooth";
field public static final String DISALLOW_CONFIG_BRIGHTNESS = "no_config_brightness";
@@ -41226,7 +41227,7 @@
field public static final String KEY_CARRIER_CONFIG_APPLIED_BOOL = "carrier_config_applied_bool";
field public static final String KEY_CARRIER_CONFIG_VERSION_STRING = "carrier_config_version_string";
field public static final String KEY_CARRIER_CROSS_SIM_IMS_AVAILABLE_BOOL = "carrier_cross_sim_ims_available_bool";
- field public static final String KEY_CARRIER_DATA_CALL_PERMANENT_FAILURE_STRINGS = "carrier_data_call_permanent_failure_strings";
+ field @Deprecated public static final String KEY_CARRIER_DATA_CALL_PERMANENT_FAILURE_STRINGS = "carrier_data_call_permanent_failure_strings";
field public static final String KEY_CARRIER_DEFAULT_ACTIONS_ON_DCFAILURE_STRING_ARRAY = "carrier_default_actions_on_dcfailure_string_array";
field public static final String KEY_CARRIER_DEFAULT_ACTIONS_ON_DEFAULT_NETWORK_AVAILABLE = "carrier_default_actions_on_default_network_available_string_array";
field public static final String KEY_CARRIER_DEFAULT_ACTIONS_ON_REDIRECTION_STRING_ARRAY = "carrier_default_actions_on_redirection_string_array";
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index d3fc379..068b40a 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -300,10 +300,6 @@
method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public void reportNetworkInterfaceForTransports(@NonNull String, @NonNull int[]) throws java.lang.RuntimeException;
}
- public class Binder implements android.os.IBinder {
- method public final void markVintfStability();
- }
-
public class BluetoothServiceManager {
method @NonNull public android.os.BluetoothServiceManager.ServiceRegisterer getBluetoothManagerServiceRegisterer();
}
@@ -343,10 +339,6 @@
method public boolean shouldBypassCache(@NonNull Q);
}
- public interface Parcelable {
- method public default int getStability();
- }
-
public class Process {
method public static final int getAppUidForSdkSandboxUid(int);
method public static final boolean isSdkSandboxUid(int);
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index bb14dc0..4a0d771 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -9239,6 +9239,7 @@
public class Binder implements android.os.IBinder {
method public int handleShellCommand(@NonNull android.os.ParcelFileDescriptor, @NonNull android.os.ParcelFileDescriptor, @NonNull android.os.ParcelFileDescriptor, @NonNull String[]);
+ method public final void markVintfStability();
method public static void setProxyTransactListener(@Nullable android.os.Binder.ProxyTransactListener);
}
@@ -9553,6 +9554,7 @@
}
public interface Parcelable {
+ method public default int getStability();
field public static final int PARCELABLE_STABILITY_LOCAL = 0; // 0x0
field public static final int PARCELABLE_STABILITY_VINTF = 1; // 0x1
}
@@ -9561,7 +9563,6 @@
ctor public ParcelableHolder(int);
method public int describeContents();
method @Nullable public <T extends android.os.Parcelable> T getParcelable(@NonNull Class<T>);
- method public int getStability();
method public void readFromParcel(@NonNull android.os.Parcel);
method public void setParcelable(@Nullable android.os.Parcelable);
method public void writeToParcel(@NonNull android.os.Parcel, int);
@@ -13552,6 +13553,7 @@
field public static final String ACTION_SIM_SLOT_STATUS_CHANGED = "android.telephony.action.SIM_SLOT_STATUS_CHANGED";
field public static final int ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G = 3; // 0x3
field public static final int ALLOWED_NETWORK_TYPES_REASON_POWER = 1; // 0x1
+ field public static final int ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS = 4; // 0x4
field public static final int CALL_WAITING_STATUS_DISABLED = 2; // 0x2
field public static final int CALL_WAITING_STATUS_ENABLED = 1; // 0x1
field public static final int CALL_WAITING_STATUS_FDN_CHECK_FAILURE = 5; // 0x5
diff --git a/core/java/android/content/ComponentName.java b/core/java/android/content/ComponentName.java
index 5f85984..f12e971 100644
--- a/core/java/android/content/ComponentName.java
+++ b/core/java/android/content/ComponentName.java
@@ -314,17 +314,14 @@
*/
@Override
public boolean equals(@Nullable Object obj) {
- try {
- if (obj != null) {
- ComponentName other = (ComponentName)obj;
- // Note: no null checks, because mPackage and mClass can
- // never be null.
- return mPackage.equals(other.mPackage)
- && mClass.equals(other.mClass);
- }
- } catch (ClassCastException e) {
+ if (obj instanceof ComponentName) {
+ ComponentName other = (ComponentName) obj;
+ // mPackage and mClass can never be null.
+ return mPackage.equals(other.mPackage)
+ && mClass.equals(other.mClass);
+ } else {
+ return false;
}
- return false;
}
@Override
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index 2f4b2c4..6d5c741 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -562,7 +562,7 @@
*
* @hide
*/
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @SystemApi(client = SystemApi.Client.PRIVILEGED_APPS)
public final native void markVintfStability();
/**
@@ -1219,25 +1219,40 @@
@UnsupportedAppUsage
private boolean execTransact(int code, long dataObj, long replyObj,
int flags) {
+
+ Parcel data = Parcel.obtain(dataObj);
+ Parcel reply = Parcel.obtain(replyObj);
+
// At that point, the parcel request headers haven't been parsed so we do not know what
// {@link WorkSource} the caller has set. Use calling UID as the default.
- final int callingUid = Binder.getCallingUid();
- final long origWorkSource = ThreadLocalWorkSource.setUid(callingUid);
+ //
+ // TODO: this is wrong - we should attribute along the entire call route
+ // also this attribution logic should move to native code - it only works
+ // for Java now
+ //
+ // This attribution support is not generic and therefore not support in RPC mode
+ final int callingUid = data.isForRpc() ? -1 : Binder.getCallingUid();
+ final long origWorkSource = callingUid == -1
+ ? -1 : ThreadLocalWorkSource.setUid(callingUid);
+
try {
- return execTransactInternal(code, dataObj, replyObj, flags, callingUid);
+ return execTransactInternal(code, data, reply, flags, callingUid);
} finally {
- ThreadLocalWorkSource.restore(origWorkSource);
+ reply.recycle();
+ data.recycle();
+
+ if (callingUid != -1) {
+ ThreadLocalWorkSource.restore(origWorkSource);
+ }
}
}
- private boolean execTransactInternal(int code, long dataObj, long replyObj, int flags,
+ private boolean execTransactInternal(int code, Parcel data, Parcel reply, int flags,
int callingUid) {
// Make sure the observer won't change while processing a transaction.
final BinderInternal.Observer observer = sObserver;
final CallSession callSession =
observer != null ? observer.callStarted(this, code, UNSET_WORKSOURCE) : null;
- Parcel data = Parcel.obtain(dataObj);
- Parcel reply = Parcel.obtain(replyObj);
// Theoretically, we should call transact, which will call onTransact,
// but all that does is rewind it, and we just got these from an IPC,
// so we'll just call it directly.
@@ -1268,8 +1283,10 @@
final boolean tracingEnabled = tagEnabled && transactionTraceName != null;
try {
+ // TODO - this logic should not be in Java - it should be in native
+ // code in libbinder so that it works for all binder users.
final BinderCallHeavyHitterWatcher heavyHitterWatcher = sHeavyHitterWatcher;
- if (heavyHitterWatcher != null) {
+ if (heavyHitterWatcher != null && callingUid != -1) {
// Notify the heavy hitter watcher, if it's enabled.
heavyHitterWatcher.onTransaction(callingUid, getClass(), code);
}
@@ -1277,7 +1294,10 @@
Trace.traceBegin(Trace.TRACE_TAG_AIDL, transactionTraceName);
}
- if ((flags & FLAG_COLLECT_NOTED_APP_OPS) != 0) {
+ // TODO - this logic should not be in Java - it should be in native
+ // code in libbinder so that it works for all binder users. Further,
+ // this should not re-use flags.
+ if ((flags & FLAG_COLLECT_NOTED_APP_OPS) != 0 && callingUid != -1) {
AppOpsManager.startNotedAppOpsCollection(callingUid);
try {
res = onTransact(code, data, reply, flags);
@@ -1320,8 +1340,6 @@
}
checkParcel(this, code, reply, "Unreasonably large binder reply buffer");
- reply.recycle();
- data.recycle();
}
// Just in case -- we are done with the IPC, so there should be no more strict
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index cb7e6f7..20602ce 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -107,20 +107,42 @@
private static final int UPDATABLE_DRIVER_GLOBAL_OPT_IN_PRERELEASE_DRIVER = 2;
private static final int UPDATABLE_DRIVER_GLOBAL_OPT_IN_OFF = 3;
+ // System properties related to ANGLE and legacy GLES graphics drivers.
+ private static final String PROPERTY_EGL_SYSTEM_DRIVER = "ro.hardware.egl";
+ // TODO (b/224558229): Properly add this to the list of system properties for a device:
+ private static final String PROPERTY_EGL_LEGACY_DRIVER = "ro.hardware.egl_legacy";
+
// Values for ANGLE_GL_DRIVER_ALL_ANGLE
private static final int ANGLE_GL_DRIVER_ALL_ANGLE_ON = 1;
private static final int ANGLE_GL_DRIVER_ALL_ANGLE_OFF = 0;
+ private static final int ANGLE_GL_DRIVER_ALL_LEGACY = -1;
// Values for ANGLE_GL_DRIVER_SELECTION_VALUES
private static final String ANGLE_GL_DRIVER_CHOICE_DEFAULT = "default";
private static final String ANGLE_GL_DRIVER_CHOICE_ANGLE = "angle";
+ private static final String ANGLE_GL_DRIVER_CHOICE_LEGACY = "legacy";
+ // The following value is a deprecated choice for "legacy"
private static final String ANGLE_GL_DRIVER_CHOICE_NATIVE = "native";
+ // Values returned by getDriverForPackage() and getDefaultDriverToUse() (avoid returning
+ // strings for performance reasons)
+ private static final int ANGLE_GL_DRIVER_TO_USE_LEGACY = 0;
+ private static final int ANGLE_GL_DRIVER_TO_USE_ANGLE = 1;
+
private ClassLoader mClassLoader;
private String mLibrarySearchPaths;
private String mLibraryPermittedPaths;
private GameManager mGameManager;
+ private boolean mAngleIsSystemDriver = false;
+ private boolean mNoLegacyDriver = false;
+ // When ANGLE is the system driver, this is the name of the legacy driver.
+ //
+ // IMPORTANT: When ANGLE is the system driver, and if there is a fallback "legacy" GLES driver
+ // (e.g. from the GPU provider), the name of that driver must be set here, unles and until
+ // PROPERTY_EGL_LEGACY_DRIVER has been properly plumbed and this becomes broadly available.
+ private String mEglLegacyDriver = "";
+
private int mAngleOptInIndex = -1;
/**
@@ -138,6 +160,23 @@
setupGpuLayers(context, coreSettings, pm, packageName, appInfoWithMetaData);
Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS);
+ // Determine if ANGLE is the system driver, as this will determine other logic
+ final String eglSystemDriver = SystemProperties.get(PROPERTY_EGL_SYSTEM_DRIVER);
+ Log.v(TAG, "GLES system driver is '" + eglSystemDriver + "'");
+ mAngleIsSystemDriver = eglSystemDriver.equals(ANGLE_DRIVER_NAME);
+ if (mAngleIsSystemDriver) {
+ // Lookup the legacy driver, to send down to the EGL loader
+ final String eglLegacyDriver = SystemProperties.get(PROPERTY_EGL_LEGACY_DRIVER);
+ if (eglLegacyDriver.isEmpty()) {
+ mNoLegacyDriver = true;
+ mEglLegacyDriver = eglSystemDriver;
+ }
+ } else {
+ mEglLegacyDriver = eglSystemDriver;
+ }
+ Log.v(TAG, "Legacy GLES driver is '" + mEglLegacyDriver + "'");
+
+ // Setup ANGLE and pass down ANGLE details to the C++ code
Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "setupAngle");
boolean useAngle = false;
if (setupAngle(context, coreSettings, pm, packageName)) {
@@ -145,6 +184,9 @@
useAngle = true;
setGpuStats(ANGLE_DRIVER_NAME, ANGLE_DRIVER_VERSION_NAME, ANGLE_DRIVER_VERSION_CODE,
0, packageName, getVulkanVersion(pm));
+ } else if (mNoLegacyDriver) {
+ Log.e(TAG, "Unexpected problem with the ANGLE for use with: '" + packageName + "'");
+ useAngle = true;
}
}
Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS);
@@ -188,28 +230,15 @@
/**
* Query to determine if ANGLE should be used
*/
- private boolean shouldUseAngle(Context context, Bundle coreSettings,
- String packageName) {
+ private boolean shouldUseAngle(Context context, Bundle coreSettings, String packageName) {
if (TextUtils.isEmpty(packageName)) {
- Log.v(TAG, "No package name specified, ANGLE should not be used");
- return false;
+ Log.v(TAG, "No package name specified; use the system driver");
+ return mAngleIsSystemDriver ? true : false;
}
- final String devOptIn = getDriverForPackage(context, coreSettings, packageName);
- Log.v(TAG, "ANGLE Developer option for '" + packageName + "' "
- + "set to: '" + devOptIn + "'");
-
- // We only want to use ANGLE if the developer has explicitly chosen something other than
- // default driver.
- final boolean forceAngle = devOptIn.equals(ANGLE_GL_DRIVER_CHOICE_ANGLE);
- final boolean forceNative = devOptIn.equals(ANGLE_GL_DRIVER_CHOICE_NATIVE);
- if (forceAngle || forceNative) {
- Log.v(TAG, "ANGLE developer option for " + packageName + ": " + devOptIn);
- }
-
- final boolean gameModeEnabledAngle = isAngleEnabledByGameMode(context, packageName);
-
- return !forceNative && (forceAngle || gameModeEnabledAngle);
+ final int driverToUse = getDriverForPackage(context, coreSettings, packageName);
+ boolean yesOrNo = driverToUse == ANGLE_GL_DRIVER_TO_USE_ANGLE;
+ return yesOrNo;
}
private int getVulkanVersion(PackageManager pm) {
@@ -417,34 +446,69 @@
return ai;
}
- private String getDriverForPackage(Context context, Bundle bundle, String packageName) {
+ /**
+ * Return the appropriate "default" driver, unless overridden by isAngleEnabledByGameMode().
+ */
+ private int getDefaultDriverToUse(Context context, String packageName) {
+ if (mAngleIsSystemDriver || isAngleEnabledByGameMode(context, packageName)) {
+ return ANGLE_GL_DRIVER_TO_USE_ANGLE;
+ } else {
+ return ANGLE_GL_DRIVER_TO_USE_LEGACY;
+ }
+ }
+
+ /*
+ * Determine which GLES "driver" should be used for the package, taking into account the
+ * following factors (in priority order):
+ *
+ * 1) The semi-global switch (i.e. Settings.Global.ANGLE_GL_DRIVER_ALL_ANGLE; which is set by
+ * the "angle_gl_driver_all_angle" setting; which forces a driver for all processes that
+ * start after the Java run time is up), if it forces a choice; otherwise ...
+ * 2) The per-application switch (i.e. Settings.Global.ANGLE_GL_DRIVER_SELECTION_PKGS and
+ * Settings.Global.ANGLE_GL_DRIVER_SELECTION_VALUES; which corresponds to the
+ * “angle_gl_driver_selection_pkgs” and “angle_gl_driver_selection_values” settings); if it
+ * forces a choice; otherwise ...
+ * 3) Use ANGLE if isAngleEnabledByGameMode() returns true; otherwise ...
+ * 4) The global switch (i.e. use the system driver, whether ANGLE or legacy;
+ * a.k.a. mAngleIsSystemDriver, which is set by the device’s “ro.hardware.egl” property)
+ *
+ * Factors 1 and 2 are decided by this method. Factors 3 and 4 are decided by
+ * getDefaultDriverToUse().
+ */
+ private int getDriverForPackage(Context context, Bundle bundle, String packageName) {
+ // Check the semi-global switch (i.e. once system has booted enough) for whether ANGLE
+ // should be forced on or off for "all appplications"
final int allUseAngle;
if (bundle != null) {
- allUseAngle =
- bundle.getInt(Settings.Global.ANGLE_GL_DRIVER_ALL_ANGLE);
+ allUseAngle = bundle.getInt(Settings.Global.ANGLE_GL_DRIVER_ALL_ANGLE);
} else {
ContentResolver contentResolver = context.getContentResolver();
allUseAngle = Settings.Global.getInt(contentResolver,
- Settings.Global.ANGLE_GL_DRIVER_ALL_ANGLE,
- ANGLE_GL_DRIVER_ALL_ANGLE_OFF);
+ Settings.Global.ANGLE_GL_DRIVER_ALL_ANGLE, ANGLE_GL_DRIVER_ALL_ANGLE_OFF);
}
if (allUseAngle == ANGLE_GL_DRIVER_ALL_ANGLE_ON) {
Log.v(TAG, "Turn on ANGLE for all applications.");
- return ANGLE_GL_DRIVER_CHOICE_ANGLE;
+ return ANGLE_GL_DRIVER_TO_USE_ANGLE;
+ }
+ if (allUseAngle == ANGLE_GL_DRIVER_ALL_LEGACY) {
+ Log.v(TAG, "Disable ANGLE for all applications.");
+ return ANGLE_GL_DRIVER_TO_USE_LEGACY;
}
// Make sure we have a good package name
if (TextUtils.isEmpty(packageName)) {
- return ANGLE_GL_DRIVER_CHOICE_DEFAULT;
+ return getDefaultDriverToUse(context, packageName);
}
+ // Get the per-application settings lists
final ContentResolver contentResolver = context.getContentResolver();
- final List<String> optInPackages =
- getGlobalSettingsString(contentResolver, bundle,
- Settings.Global.ANGLE_GL_DRIVER_SELECTION_PKGS);
- final List<String> optInValues =
- getGlobalSettingsString(contentResolver, bundle,
- Settings.Global.ANGLE_GL_DRIVER_SELECTION_VALUES);
+ final List<String> optInPackages = getGlobalSettingsString(
+ contentResolver, bundle, Settings.Global.ANGLE_GL_DRIVER_SELECTION_PKGS);
+ final List<String> optInValues = getGlobalSettingsString(
+ contentResolver, bundle, Settings.Global.ANGLE_GL_DRIVER_SELECTION_VALUES);
+ Log.v(TAG, "Currently set values for:");
+ Log.v(TAG, " angle_gl_driver_selection_pkgs = " + optInPackages);
+ Log.v(TAG, " angle_gl_driver_selection_values =" + optInValues);
// Make sure we have good settings to use
if (optInPackages.size() != optInValues.size()) {
@@ -454,17 +518,40 @@
+ optInPackages.size() + ", "
+ "number of values: "
+ optInValues.size());
- return ANGLE_GL_DRIVER_CHOICE_DEFAULT;
+ return getDefaultDriverToUse(context, packageName);
}
+ // See if this application is listed in the per-application settings lists
final int pkgIndex = getPackageIndex(packageName, optInPackages);
if (pkgIndex < 0) {
- return ANGLE_GL_DRIVER_CHOICE_DEFAULT;
+ // The application is NOT listed in the per-application settings lists; and so use the
+ // system driver (i.e. either ANGLE or the Legacy driver)
+ Log.v(TAG, "getDriverForPackage(): No per-application setting");
+ return getDefaultDriverToUse(context, packageName);
}
mAngleOptInIndex = pkgIndex;
- return optInValues.get(pkgIndex);
+ Log.v(TAG,
+ "getDriverForPackage(): using per-application switch: "
+ + optInValues.get(pkgIndex));
+ // The application IS listed in the per-application settings lists; and so use the
+ // setting--choosing the current system driver if the setting is "default" (i.e. either
+ // ANGLE or the Legacy driver)
+ String rtnValue = optInValues.get(pkgIndex);
+ Log.v(TAG,
+ "ANGLE Developer option for '" + packageName + "' "
+ + "set to: '" + rtnValue + "'");
+ if (rtnValue.equals(ANGLE_GL_DRIVER_CHOICE_ANGLE)) {
+ return ANGLE_GL_DRIVER_TO_USE_ANGLE;
+ } else if (rtnValue.equals(ANGLE_GL_DRIVER_CHOICE_NATIVE)
+ || rtnValue.equals(ANGLE_GL_DRIVER_CHOICE_LEGACY)) {
+ return ANGLE_GL_DRIVER_TO_USE_LEGACY;
+ } else {
+ // The user either chose default or an invalid value; go with the default driver or what
+ // the game dashboard indicates
+ return getDefaultDriverToUse(context, packageName);
+ }
}
/**
@@ -514,7 +601,13 @@
}
/**
- * Pass ANGLE details down to trigger enable logic
+ * Determine whether ANGLE should be used, set it up if so, and pass ANGLE details down to
+ * the C++ GraphicsEnv class.
+ *
+ * If ANGLE will be used, GraphicsEnv::setAngleInfo() will be called to enable ANGLE to be
+ * properly used. Otherwise, GraphicsEnv::setLegacyDriverInfo() will be called to
+ * enable the legacy GLES driver (e.g. when ANGLE is the system driver) to be identified and
+ * used.
*
* @param context
* @param bundle
@@ -527,6 +620,7 @@
String packageName) {
if (!shouldUseAngle(context, bundle, packageName)) {
+ setLegacyDriverInfo(packageName, mAngleIsSystemDriver, mEglLegacyDriver);
return false;
}
@@ -541,6 +635,7 @@
angleInfo = pm.getApplicationInfo(anglePkgName, 0);
} catch (PackageManager.NameNotFoundException e) {
Log.w(TAG, "ANGLE debug package '" + anglePkgName + "' not installed");
+ setLegacyDriverInfo(packageName, mAngleIsSystemDriver, mEglLegacyDriver);
return false;
}
}
@@ -550,16 +645,18 @@
anglePkgName = getAnglePackageName(pm);
if (TextUtils.isEmpty(anglePkgName)) {
Log.w(TAG, "Failed to find ANGLE package.");
+ setLegacyDriverInfo(packageName, mAngleIsSystemDriver, mEglLegacyDriver);
return false;
}
- Log.i(TAG, "ANGLE package enabled: " + anglePkgName);
+ Log.v(TAG, "ANGLE package enabled: " + anglePkgName);
try {
// Production ANGLE libraries must be pre-installed as a system app
angleInfo = pm.getApplicationInfo(anglePkgName,
PackageManager.MATCH_SYSTEM_ONLY);
} catch (PackageManager.NameNotFoundException e) {
Log.w(TAG, "ANGLE package '" + anglePkgName + "' not installed");
+ setLegacyDriverInfo(packageName, mAngleIsSystemDriver, mEglLegacyDriver);
return false;
}
}
@@ -573,21 +670,15 @@
+ "!/lib/"
+ abi;
- if (DEBUG) Log.v(TAG, "ANGLE package libs: " + paths);
-
- // We need to call setAngleInfo() with the package name and the developer option value
- //(native/angle/other). Then later when we are actually trying to load a driver,
- //GraphicsEnv::getShouldUseAngle() has seen the package name before and can confidently
- //answer yes/no based on the previously set developer option value.
- final String devOptIn;
- final String[] features = getAngleEglFeatures(context, bundle);
- final boolean gameModeEnabledAngle = isAngleEnabledByGameMode(context, packageName);
- if (gameModeEnabledAngle) {
- devOptIn = ANGLE_GL_DRIVER_CHOICE_ANGLE;
- } else {
- devOptIn = getDriverForPackage(context, bundle, packageName);
+ if (DEBUG) {
+ Log.v(TAG, "ANGLE package libs: " + paths);
}
- setAngleInfo(paths, packageName, devOptIn, features);
+
+ // If we make it to here, ANGLE will be used. Call setAngleInfo() with the package name,
+ // and features to use.
+ final String[] features = getAngleEglFeatures(context, bundle);
+ setAngleInfo(
+ paths, packageName, mAngleIsSystemDriver, ANGLE_GL_DRIVER_CHOICE_ANGLE, features);
return true;
}
@@ -876,8 +967,10 @@
private static native void setDriverPathAndSphalLibraries(String path, String sphalLibraries);
private static native void setGpuStats(String driverPackageName, String driverVersionName,
long driverVersionCode, long driverBuildTime, String appPackageName, int vulkanVersion);
- private static native void setAngleInfo(String path, String appPackage, String devOptIn,
- String[] features);
+ private static native void setAngleInfo(String path, String appPackage,
+ boolean angleIsSystemDriver, String devOptIn, String[] features);
+ private static native void setLegacyDriverInfo(
+ String appPackage, boolean angleIsSystemDriver, String legacyDriverName);
private static native boolean getShouldUseAngle(String packageName);
private static native boolean setInjectLayersPrSetDumpable();
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index a6ae663..7e15f07 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -368,6 +368,8 @@
@FastNative
private static native void nativeMarkForBinder(long nativePtr, IBinder binder);
@CriticalNative
+ private static native boolean nativeIsForRpc(long nativePtr);
+ @CriticalNative
private static native int nativeDataSize(long nativePtr);
@CriticalNative
private static native int nativeDataAvail(long nativePtr);
@@ -560,9 +562,11 @@
*/
public final void recycle() {
if (mRecycled) {
- Log.w(TAG, "Recycle called on unowned Parcel. (recycle twice?) Here: "
+ Log.wtf(TAG, "Recycle called on unowned Parcel. (recycle twice?) Here: "
+ Log.getStackTraceString(new Throwable())
+ " Original recycle call (if DEBUG_RECYCLE): ", mStack);
+
+ return;
}
mRecycled = true;
@@ -645,6 +649,15 @@
nativeMarkForBinder(mNativePtr, binder);
}
+ /**
+ * Whether this Parcel is written for an RPC transaction.
+ *
+ * @hide
+ */
+ public final boolean isForRpc() {
+ return nativeIsForRpc(mNativePtr);
+ }
+
/** @hide */
@ParcelFlags
@TestApi
diff --git a/core/java/android/os/Parcelable.java b/core/java/android/os/Parcelable.java
index 8a80457..a2b0486 100644
--- a/core/java/android/os/Parcelable.java
+++ b/core/java/android/os/Parcelable.java
@@ -188,7 +188,7 @@
* @return true if this parcelable is stable.
* @hide
*/
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @SystemApi(client = SystemApi.Client.PRIVILEGED_APPS)
default @Stability int getStability() {
return PARCELABLE_STABILITY_LOCAL;
}
diff --git a/core/java/android/os/ServiceManagerNative.java b/core/java/android/os/ServiceManagerNative.java
index 2dcf674..f2143f6 100644
--- a/core/java/android/os/ServiceManagerNative.java
+++ b/core/java/android/os/ServiceManagerNative.java
@@ -98,6 +98,10 @@
return mServiceManager.updatableViaApex(name);
}
+ public String[] getUpdatableNames(String apexName) throws RemoteException {
+ return mServiceManager.getUpdatableNames(apexName);
+ }
+
public ConnectionInfo getConnectionInfo(String name) throws RemoteException {
return mServiceManager.getConnectionInfo(name);
}
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 0ffdfc6..4b9f892 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1485,6 +1485,22 @@
public static final String KEY_RESTRICTIONS_PENDING = "restrictions_pending";
/**
+ * Specifies if a user is not allowed to use 2g networks.
+ *
+ * <p>This restriction can only be set by a device owner or a profile owner of an
+ * organization-owned managed profile on the parent profile.
+ * In all cases, the setting applies globally on the device and will prevent the device from
+ * scanning for or connecting to 2g networks, except in the case of an emergency.
+ *
+ * <p>The default value is <code>false</code>.
+ *
+ * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+ * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
+ * @see #getUserRestrictions()
+ */
+ public static final String DISALLOW_CELLULAR_2G = "no_cellular_2g";
+
+ /**
* List of key values that can be passed into the various user restriction related methods
* in {@link UserManager} & {@link DevicePolicyManager}.
* Note: This is slightly different from the real set of user restrictions listed in {@link
@@ -1565,6 +1581,7 @@
DISALLOW_SHARING_ADMIN_CONFIGURED_WIFI,
DISALLOW_WIFI_DIRECT,
DISALLOW_ADD_WIFI_CONFIG,
+ DISALLOW_CELLULAR_2G,
})
@Retention(RetentionPolicy.SOURCE)
public @interface UserRestrictionKey {}
diff --git a/core/java/android/os/storage/OWNERS b/core/java/android/os/storage/OWNERS
index 1f686e5..c80c57c 100644
--- a/core/java/android/os/storage/OWNERS
+++ b/core/java/android/os/storage/OWNERS
@@ -1,11 +1,15 @@
# Bug component: 95221
-corinac@google.com
-nandana@google.com
-zezeozue@google.com
-maco@google.com
-sahanas@google.com
+# Android Storage Team
abkaur@google.com
-chiangi@google.com
-narayan@google.com
+corinac@google.com
dipankarb@google.com
+krishang@google.com
+sahanas@google.com
+sergeynv@google.com
+shubhisaxena@google.com
+tylersaunders@google.com
+
+maco@google.com
+nandana@google.com
+narayan@google.com
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index df6b827..ba7df25 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -14410,6 +14410,18 @@
public static final String ANGLE_EGL_FEATURES = "angle_egl_features";
/**
+ * Comma-separated list of package names that ANGLE may have issues with
+ * @hide
+ */
+ public static final String ANGLE_DEFERLIST = "angle_deferlist";
+
+ /**
+ * Integer mode of the logic for applying `angle_deferlist`
+ * @hide
+ */
+ public static final String ANGLE_DEFERLIST_MODE = "angle_deferlist_mode";
+
+ /**
* Show the "ANGLE In Use" dialog box to the user when ANGLE is the OpenGL driver.
* The value is a boolean (1 or 0).
* @hide
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 12331bc..acf06e9 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -4858,7 +4858,7 @@
}
void reportKeepClearAreasChanged() {
- if (!mHasPendingKeepClearAreaChange) {
+ if (!mHasPendingKeepClearAreaChange || mView == null) {
return;
}
mHasPendingKeepClearAreaChange = false;
diff --git a/core/java/com/android/internal/security/TEST_MAPPING b/core/java/com/android/internal/security/TEST_MAPPING
index 9a5e90e..803760c 100644
--- a/core/java/com/android/internal/security/TEST_MAPPING
+++ b/core/java/com/android/internal/security/TEST_MAPPING
@@ -1,6 +1,17 @@
{
"presubmit": [
{
+ "name": "FrameworksCoreTests",
+ "options": [
+ {
+ "include-filter": "com.android.internal.security."
+ },
+ {
+ "include-annotation": "android.platform.test.annotations.Presubmit"
+ }
+ ]
+ },
+ {
"name": "ApkVerityTest",
"file_patterns": ["VerityUtils\\.java"]
}
diff --git a/core/java/com/android/internal/security/VerityUtils.java b/core/java/com/android/internal/security/VerityUtils.java
index 76f7b21..7f45c09 100644
--- a/core/java/com/android/internal/security/VerityUtils.java
+++ b/core/java/com/android/internal/security/VerityUtils.java
@@ -23,10 +23,28 @@
import android.system.OsConstants;
import android.util.Slog;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import com.android.internal.org.bouncycastle.cms.CMSException;
+import com.android.internal.org.bouncycastle.cms.CMSProcessableByteArray;
+import com.android.internal.org.bouncycastle.cms.CMSSignedData;
+import com.android.internal.org.bouncycastle.cms.SignerInformation;
+import com.android.internal.org.bouncycastle.cms.SignerInformationVerifier;
+import com.android.internal.org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder;
+import com.android.internal.org.bouncycastle.operator.OperatorCreationException;
+
import java.io.File;
import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
/** Provides fsverity related operations. */
public abstract class VerityUtils {
@@ -90,8 +108,100 @@
return (retval == 1);
}
- /** Returns hash of a root node for the fs-verity enabled file. */
- public static byte[] getFsverityRootHash(@NonNull String filePath) {
+ /**
+ * Verifies the signature over the fs-verity digest using the provided certificate.
+ *
+ * This method should only be used by any existing fs-verity use cases that require
+ * PKCS#7 signature verification, if backward compatibility is necessary.
+ *
+ * Since PKCS#7 is too flexible, for the current specific need, only specific configuration
+ * will be accepted:
+ * <ul>
+ * <li>Must use SHA256 as the digest algorithm
+ * <li>Must use rsaEncryption as signature algorithm
+ * <li>Must be detached / without content
+ * <li>Must not include any signed or unsigned attributes
+ * </ul>
+ *
+ * It is up to the caller to provide an appropriate/trusted certificate.
+ *
+ * @param signatureBlock byte array of a PKCS#7 detached signature
+ * @param digest fs-verity digest with the common configuration using sha256
+ * @param derCertInputStream an input stream of a X.509 certificate in DER
+ * @return whether the verification succeeds
+ */
+ public static boolean verifyPkcs7DetachedSignature(@NonNull byte[] signatureBlock,
+ @NonNull byte[] digest, @NonNull InputStream derCertInputStream) {
+ if (digest.length != 32) {
+ Slog.w(TAG, "Only sha256 is currently supported");
+ return false;
+ }
+
+ try {
+ CMSSignedData signedData = new CMSSignedData(
+ new CMSProcessableByteArray(toFormattedDigest(digest)),
+ signatureBlock);
+
+ if (!signedData.isDetachedSignature()) {
+ Slog.w(TAG, "Expect only detached siganture");
+ return false;
+ }
+ if (!signedData.getCertificates().getMatches(null).isEmpty()) {
+ Slog.w(TAG, "Expect no certificate in signature");
+ return false;
+ }
+ if (!signedData.getCRLs().getMatches(null).isEmpty()) {
+ Slog.w(TAG, "Expect no CRL in signature");
+ return false;
+ }
+
+ X509Certificate trustedCert = (X509Certificate) CertificateFactory.getInstance("X.509")
+ .generateCertificate(derCertInputStream);
+ SignerInformationVerifier verifier = new JcaSimpleSignerInfoVerifierBuilder()
+ .build(trustedCert);
+
+ // Verify any signature with the trusted certificate.
+ for (SignerInformation si : signedData.getSignerInfos().getSigners()) {
+ // To be the most strict while dealing with the complicated PKCS#7 signature, reject
+ // everything we don't need.
+ if (si.getSignedAttributes() != null && si.getSignedAttributes().size() > 0) {
+ Slog.w(TAG, "Unexpected signed attributes");
+ return false;
+ }
+ if (si.getUnsignedAttributes() != null && si.getUnsignedAttributes().size() > 0) {
+ Slog.w(TAG, "Unexpected unsigned attributes");
+ return false;
+ }
+ if (!NISTObjectIdentifiers.id_sha256.getId().equals(si.getDigestAlgOID())) {
+ Slog.w(TAG, "Unsupported digest algorithm OID: " + si.getDigestAlgOID());
+ return false;
+ }
+ if (!PKCSObjectIdentifiers.rsaEncryption.getId().equals(si.getEncryptionAlgOID())) {
+ Slog.w(TAG, "Unsupported encryption algorithm OID: "
+ + si.getEncryptionAlgOID());
+ return false;
+ }
+
+ if (si.verify(verifier)) {
+ return true;
+ }
+ }
+ return false;
+ } catch (CertificateException | CMSException | OperatorCreationException e) {
+ Slog.w(TAG, "Error occurred during the PKCS#7 signature verification", e);
+ }
+ return false;
+ }
+
+ /**
+ * Returns fs-verity digest for the file if enabled, otherwise returns null. The digest is a
+ * hash of root hash of fs-verity's Merkle tree with extra metadata.
+ *
+ * @see <a href="https://www.kernel.org/doc/html/latest/filesystems/fsverity.html#file-digest-computation">
+ * File digest computation in Linux kernel documentation</a>
+ * @return Bytes of fs-verity digest
+ */
+ public static byte[] getFsverityDigest(@NonNull String filePath) {
byte[] result = new byte[HASH_SIZE_BYTES];
int retval = measureFsverityNative(filePath, result);
if (retval < 0) {
@@ -103,6 +213,19 @@
return result;
}
+ /** @hide */
+ @VisibleForTesting
+ public static byte[] toFormattedDigest(byte[] digest) {
+ // Construct fsverity_formatted_digest used in fs-verity's built-in signature verification.
+ ByteBuffer buffer = ByteBuffer.allocate(12 + digest.length); // struct size + sha256 size
+ buffer.order(ByteOrder.LITTLE_ENDIAN);
+ buffer.put("FSVerity".getBytes(StandardCharsets.US_ASCII));
+ buffer.putShort((short) 1); // FS_VERITY_HASH_ALG_SHA256
+ buffer.putShort((short) digest.length);
+ buffer.put(digest);
+ return buffer.array();
+ }
+
private static native int enableFsverityNative(@NonNull String filePath,
@NonNull byte[] pkcs7Signature);
private static native int measureFsverityNative(@NonNull String filePath,
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 5498769..e032fa2 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -326,7 +326,6 @@
header_libs: [
"bionic_libc_platform_headers",
"dnsproxyd_protocol_headers",
- "libandroid_runtime_vm_headers",
],
},
host: {
@@ -415,24 +414,3 @@
never: true,
},
}
-
-cc_library_headers {
- name: "libandroid_runtime_vm_headers",
- host_supported: true,
- vendor_available: true,
- // TODO(b/153609531): remove when libbinder is not native_bridge_supported
- native_bridge_supported: true,
- // Allow only modules from the following list to create threads that can be
- // attached to the JVM. This list should be a subset of the dependencies of
- // libandroid_runtime.
- visibility: [
- "//frameworks/native/libs/binder",
- ],
- export_include_dirs: ["include_vm"],
- header_libs: [
- "jni_headers",
- ],
- export_header_lib_headers: [
- "jni_headers",
- ],
-}
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index eba6cca..6a051c3 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -22,7 +22,6 @@
#include <android-base/properties.h>
#include <android/graphics/jni_runtime.h>
#include <android_runtime/AndroidRuntime.h>
-#include <android_runtime/vm.h>
#include <assert.h>
#include <binder/IBinder.h>
#include <binder/IPCThreadState.h>
diff --git a/core/jni/android_os_GraphicsEnvironment.cpp b/core/jni/android_os_GraphicsEnvironment.cpp
index f44e829..78e2d31 100644
--- a/core/jni/android_os_GraphicsEnvironment.cpp
+++ b/core/jni/android_os_GraphicsEnvironment.cpp
@@ -50,7 +50,7 @@
}
void setAngleInfo_native(JNIEnv* env, jobject clazz, jstring path, jstring appName,
- jstring devOptIn, jobjectArray featuresObj) {
+ jboolean angleIsSystemDriver, jstring devOptIn, jobjectArray featuresObj) {
ScopedUtfChars pathChars(env, path);
ScopedUtfChars appNameChars(env, appName);
ScopedUtfChars devOptInChars(env, devOptIn);
@@ -74,7 +74,18 @@
}
android::GraphicsEnv::getInstance().setAngleInfo(pathChars.c_str(), appNameChars.c_str(),
- devOptInChars.c_str(), features);
+ angleIsSystemDriver, devOptInChars.c_str(),
+ features);
+}
+
+void setLegacyDriverInfo_native(JNIEnv* env, jobject clazz, jstring appName,
+ jboolean angleIsSystemDriver, jstring legacyDriverName) {
+ ScopedUtfChars appNameChars(env, appName);
+ ScopedUtfChars legacyDriverNameChars(env, legacyDriverName);
+
+ android::GraphicsEnv::getInstance().setLegacyDriverInfo(appNameChars.c_str(),
+ angleIsSystemDriver,
+ legacyDriverNameChars.c_str());
}
bool shouldUseAngle_native(JNIEnv* env, jobject clazz, jstring appName) {
@@ -120,8 +131,10 @@
{"setInjectLayersPrSetDumpable", "()Z",
reinterpret_cast<void*>(setInjectLayersPrSetDumpable_native)},
{"setAngleInfo",
- "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;)V",
+ "(Ljava/lang/String;Ljava/lang/String;ZLjava/lang/String;[Ljava/lang/String;)V",
reinterpret_cast<void*>(setAngleInfo_native)},
+ {"setLegacyDriverInfo", "(Ljava/lang/String;ZLjava/lang/String;)V",
+ reinterpret_cast<void*>(setLegacyDriverInfo_native)},
{"getShouldUseAngle", "(Ljava/lang/String;)Z",
reinterpret_cast<void*>(shouldUseAngle_native)},
{"setLayerPaths", "(Ljava/lang/ClassLoader;Ljava/lang/String;)V",
diff --git a/core/jni/android_os_Parcel.cpp b/core/jni/android_os_Parcel.cpp
index 1f64df4..4d8dac1 100644
--- a/core/jni/android_os_Parcel.cpp
+++ b/core/jni/android_os_Parcel.cpp
@@ -116,6 +116,11 @@
}
}
+static jboolean android_os_Parcel_isForRpc(jlong nativePtr) {
+ Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
+ return parcel ? parcel->isForRpc() : false;
+}
+
static jint android_os_Parcel_dataSize(jlong nativePtr)
{
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
@@ -808,6 +813,8 @@
// @FastNative
{"nativeMarkForBinder", "(JLandroid/os/IBinder;)V", (void*)android_os_Parcel_markForBinder},
// @CriticalNative
+ {"nativeIsForRpc", "(J)Z", (void*)android_os_Parcel_isForRpc},
+ // @CriticalNative
{"nativeDataSize", "(J)I", (void*)android_os_Parcel_dataSize},
// @CriticalNative
{"nativeDataAvail", "(J)I", (void*)android_os_Parcel_dataAvail},
diff --git a/core/jni/include_vm/android_runtime/vm.h b/core/jni/include_vm/android_runtime/vm.h
deleted file mode 100644
index a6e7c16..0000000
--- a/core/jni/include_vm/android_runtime/vm.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <jni.h>
-
-// Get the Java VM. If the symbol doesn't exist at runtime, it means libandroid_runtime
-// is not loaded in the current process. If the symbol exists but it returns nullptr, it
-// means JavaVM is not yet started.
-extern "C" JavaVM* AndroidRuntimeGetJavaVM();
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index 3c2a48a..e165b07 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -468,6 +468,10 @@
optional SettingProto updatable_driver_prerelease_opt_in_apps = 18;
optional SettingProto angle_egl_features = 19;
+ // ANGLE - List of Apps that ANGLE may have issues with
+ optional SettingProto angle_deferlist = 20;
+ // ANGLE - Integer mode of the logic for applying `angle_deferlist`
+ optional SettingProto angle_deferlist_mode = 21;
}
optional Gpu gpu = 59;
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 689620c..cf10504 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4320,13 +4320,13 @@
<string name="config_mediaProjectionPermissionDialogComponent" translatable="false">com.android.systemui/com.android.systemui.media.MediaProjectionPermissionActivity</string>
<!-- Corner radius of system dialogs -->
- <dimen name="config_dialogCornerRadius">2dp</dimen>
+ <dimen name="config_dialogCornerRadius">28dp</dimen>
<!-- Corner radius of system buttons -->
- <dimen name="config_buttonCornerRadius">@dimen/control_corner_material</dimen>
+ <dimen name="config_buttonCornerRadius">4dp</dimen>
<!-- Corner radius for bottom sheet system dialogs -->
- <dimen name="config_bottomDialogCornerRadius">@dimen/config_dialogCornerRadius</dimen>
+ <dimen name="config_bottomDialogCornerRadius">16dp</dimen>
<!-- Corner radius of system progress bars -->
- <dimen name="config_progressBarCornerRadius">@dimen/progress_bar_corner_material</dimen>
+ <dimen name="config_progressBarCornerRadius">1000dp</dimen>
<!-- Controls whether system buttons use all caps for text -->
<bool name="config_buttonTextAllCaps">true</bool>
<!-- Name of the font family used for system surfaces where the font should use medium weight -->
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index b754100..8697acd 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -979,9 +979,9 @@
<dimen name="controls_thumbnail_image_max_width">280dp</dimen>
<!-- System-provided radius for the background view of app widgets. The resolved value of this resource may change at runtime. -->
- <dimen name="system_app_widget_background_radius">16dp</dimen>
+ <dimen name="system_app_widget_background_radius">28dp</dimen>
<!-- System-provided radius for inner views on app widgets. The resolved value of this resource may change at runtime. -->
- <dimen name="system_app_widget_inner_radius">8dp</dimen>
+ <dimen name="system_app_widget_inner_radius">20dp</dimen>
<!-- System-provided padding for inner views on app widgets. The resolved value of this resource may change at runtime. @removed -->
<dimen name="__removed_system_app_widget_internal_padding">16dp</dimen>
diff --git a/core/tests/coretests/OWNERS b/core/tests/coretests/OWNERS
index 0fb0c30..e8c9fe7 100644
--- a/core/tests/coretests/OWNERS
+++ b/core/tests/coretests/OWNERS
@@ -1 +1,4 @@
include platform/frameworks/base:/services/core/java/com/android/server/am/OWNERS
+
+per-file BinderTest.java = file:platform/frameworks/native:/libs/binder/OWNERS
+per-file ParcelTest.java = file:platform/frameworks/native:/libs/binder/OWNERS
diff --git a/core/tests/coretests/src/android/app/activity/OWNERS b/core/tests/coretests/src/android/app/activity/OWNERS
index 0862c05..7e24aef 100644
--- a/core/tests/coretests/src/android/app/activity/OWNERS
+++ b/core/tests/coretests/src/android/app/activity/OWNERS
@@ -1 +1,2 @@
include /services/core/java/com/android/server/wm/OWNERS
+include /services/core/java/com/android/server/am/OWNERS
diff --git a/core/tests/coretests/src/android/app/backup/OWNERS b/core/tests/coretests/src/android/app/backup/OWNERS
new file mode 100644
index 0000000..53b6c78
--- /dev/null
+++ b/core/tests/coretests/src/android/app/backup/OWNERS
@@ -0,0 +1 @@
+include /services/backup/OWNERS
\ No newline at end of file
diff --git a/core/tests/coretests/src/android/os/ParcelTest.java b/core/tests/coretests/src/android/os/ParcelTest.java
index fdd278b..e2fe87b4 100644
--- a/core/tests/coretests/src/android/os/ParcelTest.java
+++ b/core/tests/coretests/src/android/os/ParcelTest.java
@@ -37,6 +37,13 @@
private static final String INTERFACE_TOKEN_2 = "Another IBinder interface token";
@Test
+ public void testIsForRpc() {
+ Parcel p = Parcel.obtain();
+ assertEquals(false, p.isForRpc());
+ p.recycle();
+ }
+
+ @Test
public void testCallingWorkSourceUidAfterWrite() {
Parcel p = Parcel.obtain();
// Method does not throw if replaceCallingWorkSourceUid is called before requests headers
diff --git a/core/tests/coretests/src/com/android/internal/security/ContentSignerWrapper.java b/core/tests/coretests/src/com/android/internal/security/ContentSignerWrapper.java
new file mode 100644
index 0000000..0254afe
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/security/ContentSignerWrapper.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.security;
+
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.operator.ContentSigner;
+
+import java.io.OutputStream;
+
+/** A wrapper class of ContentSigner */
+class ContentSignerWrapper implements ContentSigner {
+ private final ContentSigner mSigner;
+
+ ContentSignerWrapper(ContentSigner wrapped) {
+ mSigner = wrapped;
+ }
+
+ @Override
+ public AlgorithmIdentifier getAlgorithmIdentifier() {
+ return mSigner.getAlgorithmIdentifier();
+ }
+
+ @Override
+ public OutputStream getOutputStream() {
+ return mSigner.getOutputStream();
+ }
+
+ @Override
+ public byte[] getSignature() {
+ return mSigner.getSignature();
+ }
+}
diff --git a/core/tests/coretests/src/com/android/internal/security/OWNERS b/core/tests/coretests/src/com/android/internal/security/OWNERS
new file mode 100644
index 0000000..4f4d8d7
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/security/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 36824
+
+per-file VerityUtilsTest.java = file:platform/system/security:/fsverity/OWNERS
diff --git a/core/tests/coretests/src/com/android/internal/security/VerityUtilsTest.java b/core/tests/coretests/src/com/android/internal/security/VerityUtilsTest.java
new file mode 100644
index 0000000..d1d8018
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/security/VerityUtilsTest.java
@@ -0,0 +1,334 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.security;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.bouncycastle.asn1.ASN1Encoding;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.x500.X500Name;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.cert.X509CertificateHolder;
+import org.bouncycastle.cert.X509v3CertificateBuilder;
+import org.bouncycastle.cms.CMSException;
+import org.bouncycastle.cms.CMSProcessableByteArray;
+import org.bouncycastle.cms.CMSSignedData;
+import org.bouncycastle.cms.CMSSignedDataGenerator;
+import org.bouncycastle.cms.SignerInfoGenerator;
+import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder;
+import org.bouncycastle.operator.ContentSigner;
+import org.bouncycastle.operator.DigestCalculator;
+import org.bouncycastle.operator.OperatorCreationException;
+import org.bouncycastle.operator.bc.BcDigestCalculatorProvider;
+import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.time.Duration;
+import java.time.Instant;
+import java.util.Arrays;
+import java.util.Date;
+
+@Presubmit
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class VerityUtilsTest {
+ private static final byte[] SAMPLE_DIGEST = "12345678901234567890123456789012".getBytes();
+ private static final byte[] FORMATTED_SAMPLE_DIGEST = toFormattedDigest(SAMPLE_DIGEST);
+
+ KeyPair mKeyPair;
+ ContentSigner mContentSigner;
+ X509CertificateHolder mCertificateHolder;
+ byte[] mCertificateDerEncoded;
+
+ @Before
+ public void setUp() throws Exception {
+ mKeyPair = KeyPairGenerator.getInstance("RSA").generateKeyPair();
+ mContentSigner = newFsverityContentSigner(mKeyPair.getPrivate());
+ mCertificateHolder =
+ newX509CertificateHolder(mContentSigner, mKeyPair.getPublic(), "Someone");
+ mCertificateDerEncoded = mCertificateHolder.getEncoded();
+ }
+
+ @Test
+ public void testOnlyAcceptCorrectDigest() throws Exception {
+ byte[] pkcs7Signature =
+ generatePkcs7Signature(mContentSigner, mCertificateHolder, FORMATTED_SAMPLE_DIGEST);
+
+ byte[] anotherDigest = Arrays.copyOf(SAMPLE_DIGEST, SAMPLE_DIGEST.length);
+ anotherDigest[0] ^= (byte) 1;
+
+ assertTrue(verifySignature(pkcs7Signature, SAMPLE_DIGEST, mCertificateDerEncoded));
+ assertFalse(verifySignature(pkcs7Signature, anotherDigest, mCertificateDerEncoded));
+ }
+
+ @Test
+ public void testDigestWithWrongSize() throws Exception {
+ byte[] pkcs7Signature =
+ generatePkcs7Signature(mContentSigner, mCertificateHolder, FORMATTED_SAMPLE_DIGEST);
+ assertTrue(verifySignature(pkcs7Signature, SAMPLE_DIGEST, mCertificateDerEncoded));
+
+ byte[] digestTooShort = Arrays.copyOfRange(SAMPLE_DIGEST, 0, SAMPLE_DIGEST.length - 1);
+ assertFalse(verifySignature(pkcs7Signature, digestTooShort, mCertificateDerEncoded));
+
+ byte[] digestTooLong = Arrays.copyOfRange(SAMPLE_DIGEST, 0, SAMPLE_DIGEST.length + 1);
+ assertFalse(verifySignature(pkcs7Signature, digestTooLong, mCertificateDerEncoded));
+ }
+
+ @Test
+ public void testOnlyAcceptGoodSignature() throws Exception {
+ byte[] pkcs7Signature =
+ generatePkcs7Signature(mContentSigner, mCertificateHolder, FORMATTED_SAMPLE_DIGEST);
+
+ byte[] anotherDigest = Arrays.copyOf(SAMPLE_DIGEST, SAMPLE_DIGEST.length);
+ anotherDigest[0] ^= (byte) 1;
+ byte[] anotherPkcs7Signature =
+ generatePkcs7Signature(
+ mContentSigner, mCertificateHolder, toFormattedDigest(anotherDigest));
+
+ assertTrue(verifySignature(pkcs7Signature, SAMPLE_DIGEST, mCertificateDerEncoded));
+ assertFalse(verifySignature(anotherPkcs7Signature, SAMPLE_DIGEST, mCertificateDerEncoded));
+ }
+
+ @Test
+ public void testOnlyValidCertCanVerify() throws Exception {
+ byte[] pkcs7Signature =
+ generatePkcs7Signature(mContentSigner, mCertificateHolder, FORMATTED_SAMPLE_DIGEST);
+
+ var wrongKeyPair = KeyPairGenerator.getInstance("RSA").generateKeyPair();
+ var wrongContentSigner = newFsverityContentSigner(wrongKeyPair.getPrivate());
+ var wrongCertificateHolder =
+ newX509CertificateHolder(wrongContentSigner, wrongKeyPair.getPublic(), "Not Me");
+ byte[] wrongCertificateDerEncoded = wrongCertificateHolder.getEncoded();
+
+ assertFalse(verifySignature(pkcs7Signature, SAMPLE_DIGEST, wrongCertificateDerEncoded));
+ }
+
+ @Test
+ public void testRejectSignatureWithContent() throws Exception {
+ CMSSignedDataGenerator generator =
+ newFsveritySignedDataGenerator(mContentSigner, mCertificateHolder);
+ byte[] pkcs7SignatureNonDetached =
+ generatePkcs7SignatureInternal(
+ generator, FORMATTED_SAMPLE_DIGEST, /* encapsulate */ true);
+
+ assertFalse(
+ verifySignature(pkcs7SignatureNonDetached, SAMPLE_DIGEST, mCertificateDerEncoded));
+ }
+
+ @Test
+ public void testRejectSignatureWithCertificate() throws Exception {
+ CMSSignedDataGenerator generator =
+ newFsveritySignedDataGenerator(mContentSigner, mCertificateHolder);
+ generator.addCertificate(mCertificateHolder);
+ byte[] pkcs7Signature =
+ generatePkcs7SignatureInternal(
+ generator, FORMATTED_SAMPLE_DIGEST, /* encapsulate */ false);
+
+ assertFalse(
+ verifySignature(pkcs7Signature, SAMPLE_DIGEST, mCertificateDerEncoded));
+ }
+
+ @Ignore("No easy way to construct test data")
+ @Test
+ public void testRejectSignatureWithCRL() throws Exception {
+ CMSSignedDataGenerator generator =
+ newFsveritySignedDataGenerator(mContentSigner, mCertificateHolder);
+
+ // The current bouncycastle version does not have an easy way to generate a CRL.
+ // TODO: enable the test once this is doable, e.g. with X509v2CRLBuilder.
+ // generator.addCRL(new X509CRLHolder(CertificateList.getInstance(new DERSequence(...))));
+ byte[] pkcs7Signature =
+ generatePkcs7SignatureInternal(
+ generator, FORMATTED_SAMPLE_DIGEST, /* encapsulate */ false);
+
+ assertFalse(
+ verifySignature(pkcs7Signature, SAMPLE_DIGEST, mCertificateDerEncoded));
+ }
+
+ @Test
+ public void testRejectUnsupportedSignatureAlgorithms() throws Exception {
+ var contentSigner = newFsverityContentSigner(mKeyPair.getPrivate(), "MD5withRSA", null);
+ var certificateHolder =
+ newX509CertificateHolder(contentSigner, mKeyPair.getPublic(), "Someone");
+ byte[] pkcs7Signature =
+ generatePkcs7Signature(contentSigner, certificateHolder, FORMATTED_SAMPLE_DIGEST);
+
+ assertFalse(verifySignature(pkcs7Signature, SAMPLE_DIGEST, certificateHolder.getEncoded()));
+ }
+
+ @Test
+ public void testRejectUnsupportedDigestAlgorithm() throws Exception {
+ CMSSignedDataGenerator generator = new CMSSignedDataGenerator();
+ generator.addSignerInfoGenerator(
+ newSignerInfoGenerator(
+ mContentSigner,
+ mCertificateHolder,
+ OIWObjectIdentifiers.idSHA1,
+ true)); // directSignature
+ byte[] pkcs7Signature =
+ generatePkcs7SignatureInternal(
+ generator, FORMATTED_SAMPLE_DIGEST, /* encapsulate */ false);
+
+ assertFalse(verifySignature(pkcs7Signature, SAMPLE_DIGEST, mCertificateDerEncoded));
+ }
+
+ @Test
+ public void testRejectAnySignerInfoAttributes() throws Exception {
+ var generator = new CMSSignedDataGenerator();
+ generator.addSignerInfoGenerator(
+ newSignerInfoGenerator(
+ mContentSigner,
+ mCertificateHolder,
+ NISTObjectIdentifiers.id_sha256,
+ false)); // directSignature
+ byte[] pkcs7Signature =
+ generatePkcs7SignatureInternal(
+ generator, FORMATTED_SAMPLE_DIGEST, /* encapsulate */ false);
+
+ assertFalse(verifySignature(pkcs7Signature, SAMPLE_DIGEST, mCertificateDerEncoded));
+ }
+
+ private static boolean verifySignature(
+ byte[] pkcs7Signature, byte[] fsverityDigest, byte[] certificateDerEncoded) {
+ return VerityUtils.verifyPkcs7DetachedSignature(
+ pkcs7Signature, fsverityDigest, new ByteArrayInputStream(certificateDerEncoded));
+ }
+
+ private static byte[] toFormattedDigest(byte[] digest) {
+ return VerityUtils.toFormattedDigest(digest);
+ }
+
+ private static byte[] generatePkcs7Signature(
+ ContentSigner contentSigner, X509CertificateHolder certificateHolder, byte[] signedData)
+ throws IOException, CMSException, OperatorCreationException {
+ CMSSignedDataGenerator generator =
+ newFsveritySignedDataGenerator(contentSigner, certificateHolder);
+ return generatePkcs7SignatureInternal(generator, signedData, /* encapsulate */ false);
+ }
+
+ private static byte[] generatePkcs7SignatureInternal(
+ CMSSignedDataGenerator generator, byte[] signedData, boolean encapsulate)
+ throws IOException, CMSException, OperatorCreationException {
+ CMSSignedData cmsSignedData =
+ generator.generate(new CMSProcessableByteArray(signedData), encapsulate);
+ return cmsSignedData.toASN1Structure().getEncoded(ASN1Encoding.DL);
+ }
+
+ private static CMSSignedDataGenerator newFsveritySignedDataGenerator(
+ ContentSigner contentSigner, X509CertificateHolder certificateHolder)
+ throws IOException, CMSException, OperatorCreationException {
+ var generator = new CMSSignedDataGenerator();
+ generator.addSignerInfoGenerator(
+ newSignerInfoGenerator(
+ contentSigner,
+ certificateHolder,
+ NISTObjectIdentifiers.id_sha256,
+ true)); // directSignature
+ return generator;
+ }
+
+ private static SignerInfoGenerator newSignerInfoGenerator(
+ ContentSigner contentSigner,
+ X509CertificateHolder certificateHolder,
+ ASN1ObjectIdentifier digestAlgorithmId,
+ boolean directSignature)
+ throws IOException, CMSException, OperatorCreationException {
+ var provider =
+ new BcDigestCalculatorProvider() {
+ /**
+ * Allow the caller to override the digest algorithm, especially when the
+ * default does not work (i.e. BcDigestCalculatorProvider could return null).
+ *
+ * <p>For example, the current fs-verity signature has to use rsaEncryption for
+ * the signature algorithm, but BcDigestCalculatorProvider will return null,
+ * thus we need a way to override.
+ *
+ * <p>TODO: After bouncycastle 1.70, we can remove this override and just use
+ * {@code JcaSignerInfoGeneratorBuilder#setContentDigest}.
+ */
+ @Override
+ public DigestCalculator get(AlgorithmIdentifier algorithm)
+ throws OperatorCreationException {
+ return super.get(new AlgorithmIdentifier(digestAlgorithmId));
+ }
+ };
+ var builder =
+ new JcaSignerInfoGeneratorBuilder(provider).setDirectSignature(directSignature);
+ return builder.build(contentSigner, certificateHolder);
+ }
+
+ private static ContentSigner newFsverityContentSigner(PrivateKey privateKey)
+ throws OperatorCreationException {
+ // fs-verity expects the signature to have rsaEncryption as the exact algorithm, so
+ // override the default.
+ return newFsverityContentSigner(
+ privateKey, "SHA256withRSA", PKCSObjectIdentifiers.rsaEncryption);
+ }
+
+ private static ContentSigner newFsverityContentSigner(
+ PrivateKey privateKey,
+ String signatureAlgorithm,
+ ASN1ObjectIdentifier signatureAlgorithmIdOverride)
+ throws OperatorCreationException {
+ if (signatureAlgorithmIdOverride != null) {
+ return new ContentSignerWrapper(
+ new JcaContentSignerBuilder(signatureAlgorithm).build(privateKey)) {
+ @Override
+ public AlgorithmIdentifier getAlgorithmIdentifier() {
+ return new AlgorithmIdentifier(signatureAlgorithmIdOverride);
+ }
+ };
+ } else {
+ return new JcaContentSignerBuilder(signatureAlgorithm).build(privateKey);
+ }
+ }
+
+ private static X509CertificateHolder newX509CertificateHolder(
+ ContentSigner contentSigner, PublicKey publicKey, String name) {
+ // Time doesn't really matter, as we only care about the key.
+ Instant now = Instant.now();
+
+ return new X509v3CertificateBuilder(
+ new X500Name("CN=Issuer " + name),
+ /* serial= */ BigInteger.valueOf(now.getEpochSecond()),
+ new Date(now.minus(Duration.ofDays(1)).toEpochMilli()),
+ new Date(now.plus(Duration.ofDays(1)).toEpochMilli()),
+ new X500Name("CN=Subject " + name),
+ SubjectPublicKeyInfo.getInstance(publicKey.getEncoded()))
+ .build(contentSigner);
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/OWNERS
new file mode 100644
index 0000000..7237d2b
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/OWNERS
@@ -0,0 +1,2 @@
+# WM shell sub-modules splitscreen owner
+chenghsiuchang@google.com
diff --git a/libs/WindowManager/Shell/tests/OWNERS b/libs/WindowManager/Shell/tests/OWNERS
index f4efc37..1c28c3d 100644
--- a/libs/WindowManager/Shell/tests/OWNERS
+++ b/libs/WindowManager/Shell/tests/OWNERS
@@ -6,3 +6,4 @@
lbill@google.com
madym@google.com
hwwang@google.com
+chenghsiuchang@google.com
diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
index 507d3dc..9e17b9e 100644
--- a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
+++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
@@ -224,10 +224,10 @@
// TODO should we let the bound of the drawable do this for us?
const SkRect bounds = SkRect::MakeWH(properties.getWidth(), properties.getHeight());
bool quickRejected = properties.getClipToBounds() && canvas->quickReject(bounds);
- auto clipBounds = canvas->getLocalClipBounds();
- SkIRect srcBounds = SkIRect::MakeWH(bounds.width(), bounds.height());
- SkIPoint offset = SkIPoint::Make(0.0f, 0.0f);
if (!quickRejected) {
+ auto clipBounds = canvas->getLocalClipBounds();
+ SkIRect srcBounds = SkIRect::MakeWH(bounds.width(), bounds.height());
+ SkIPoint offset = SkIPoint::Make(0.0f, 0.0f);
SkiaDisplayList* displayList = renderNode->getDisplayList().asSkiaDl();
const LayerProperties& layerProperties = properties.layerProperties();
// composing a hardware layer
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index e7eda3e..30fae1d 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -6600,8 +6600,8 @@
}
}
if (k == ports.size()) {
- // this hould never happen
- Log.e(TAG, "updatePortConfig port not found for handle: "+port.handle().id());
+ // This can happen in case of stale audio patch referring to a removed device and is
+ // handled by the caller.
return null;
}
AudioGainConfig gainCfg = portCfg.gain();
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 95599bd..1183ca3 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -174,6 +174,12 @@
jfieldID typeId;
} gDescriptorInfo;
+static struct {
+ jclass clazz;
+ jmethodID ctorId;
+ jmethodID setId;
+} gBufferInfo;
+
struct fields_t {
jmethodID postEventFromNativeID;
jmethodID lockAndGetContextID;
@@ -460,11 +466,7 @@
return err;
}
- ScopedLocalRef<jclass> clazz(
- env, env->FindClass("android/media/MediaCodec$BufferInfo"));
-
- jmethodID method = env->GetMethodID(clazz.get(), "set", "(IIJI)V");
- env->CallVoidMethod(bufferInfo, method, (jint)offset, (jint)size, timeUs, flags);
+ env->CallVoidMethod(bufferInfo, gBufferInfo.setId, (jint)offset, (jint)size, timeUs, flags);
return OK;
}
@@ -1091,13 +1093,7 @@
CHECK(msg->findInt64("timeUs", &timeUs));
CHECK(msg->findInt32("flags", (int32_t *)&flags));
- ScopedLocalRef<jclass> clazz(
- env, env->FindClass("android/media/MediaCodec$BufferInfo"));
- jmethodID ctor = env->GetMethodID(clazz.get(), "<init>", "()V");
- jmethodID method = env->GetMethodID(clazz.get(), "set", "(IIJI)V");
-
- obj = env->NewObject(clazz.get(), ctor);
-
+ obj = env->NewObject(gBufferInfo.clazz, gBufferInfo.ctorId);
if (obj == NULL) {
if (env->ExceptionCheck()) {
ALOGE("Could not create MediaCodec.BufferInfo.");
@@ -1107,7 +1103,7 @@
return;
}
- env->CallVoidMethod(obj, method, (jint)offset, (jint)size, timeUs, flags);
+ env->CallVoidMethod(obj, gBufferInfo.setId, (jint)offset, (jint)size, timeUs, flags);
break;
}
@@ -3235,6 +3231,16 @@
gDescriptorInfo.typeId = env->GetFieldID(clazz.get(), "mType", "I");
CHECK(gDescriptorInfo.typeId != NULL);
+
+ clazz.reset(env->FindClass("android/media/MediaCodec$BufferInfo"));
+ CHECK(clazz.get() != NULL);
+ gBufferInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
+
+ gBufferInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
+ CHECK(gBufferInfo.ctorId != NULL);
+
+ gBufferInfo.setId = env->GetMethodID(clazz.get(), "set", "(IIJI)V");
+ CHECK(gBufferInfo.setId != NULL);
}
static void android_media_MediaCodec_native_setup(
diff --git a/opengl/java/android/opengl/GLSurfaceView.java b/opengl/java/android/opengl/GLSurfaceView.java
index 75131b0..4738318 100644
--- a/opengl/java/android/opengl/GLSurfaceView.java
+++ b/opengl/java/android/opengl/GLSurfaceView.java
@@ -1667,7 +1667,15 @@
mWantRenderNotification = true;
mRequestRender = true;
mRenderComplete = false;
- mFinishDrawingRunnable = finishDrawing;
+ final Runnable oldCallback = mFinishDrawingRunnable;
+ mFinishDrawingRunnable = () -> {
+ if (oldCallback != null) {
+ oldCallback.run();
+ }
+ if (finishDrawing != null) {
+ finishDrawing.run();
+ }
+ };
sGLThreadManager.notifyAll();
}
diff --git a/packages/EasterEgg/Android.bp b/packages/EasterEgg/Android.bp
index f8785f2..e88410c 100644
--- a/packages/EasterEgg/Android.bp
+++ b/packages/EasterEgg/Android.bp
@@ -36,7 +36,7 @@
certificate: "platform",
optimize: {
- enabled: false,
+ proguard_flags_files: ["proguard.flags"],
},
static_libs: [
diff --git a/packages/EasterEgg/proguard.flags b/packages/EasterEgg/proguard.flags
new file mode 100644
index 0000000..b333ab0
--- /dev/null
+++ b/packages/EasterEgg/proguard.flags
@@ -0,0 +1,4 @@
+# Note: This is a very conservative keep rule, but as the amount of app
+# code is small, this minimizes any maintenance risks while providing
+# most of the shrinking benefits for referenced libraries.
+-keep class com.android.egg.** { *; }
diff --git a/packages/SettingsLib/src/com/android/settingslib/qrcode/OWNERS b/packages/SettingsLib/src/com/android/settingslib/qrcode/OWNERS
new file mode 100644
index 0000000..61c73fb
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/qrcode/OWNERS
@@ -0,0 +1,8 @@
+# Default reviewers for this and subdirectories.
+bonianchen@google.com
+changbetty@google.com
+goldmanj@google.com
+wengsu@google.com
+zoeychen@google.com
+
+# Emergency approvers in case the above are not available
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index ccfeae4..8683eac 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -771,6 +771,12 @@
Settings.Global.ANGLE_EGL_FEATURES,
GlobalSettingsProto.Gpu.ANGLE_EGL_FEATURES);
dumpSetting(s, p,
+ Settings.Global.ANGLE_DEFERLIST,
+ GlobalSettingsProto.Gpu.ANGLE_DEFERLIST);
+ dumpSetting(s, p,
+ Settings.Global.ANGLE_DEFERLIST_MODE,
+ GlobalSettingsProto.Gpu.ANGLE_DEFERLIST_MODE);
+ dumpSetting(s, p,
Settings.Global.SHOW_ANGLE_IN_USE_DIALOG_BOX,
GlobalSettingsProto.Gpu.SHOW_ANGLE_IN_USE_DIALOG);
dumpSetting(s, p,
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 19bbcff0..ded7e785 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -5514,13 +5514,17 @@
}
if (currentVersion == 210) {
final SettingsState secureSettings = getSecureSettingsLocked(userId);
- final int defaultValueVibrateIconEnabled = getContext().getResources()
- .getInteger(R.integer.def_statusBarVibrateIconEnabled);
- secureSettings.insertSettingOverrideableByRestoreLocked(
- Secure.STATUS_BAR_SHOW_VIBRATE_ICON,
- String.valueOf(defaultValueVibrateIconEnabled),
- null /* tag */, true /* makeDefault */,
- SettingsState.SYSTEM_PACKAGE_NAME);
+ final Setting currentSetting = secureSettings.getSettingLocked(
+ Secure.STATUS_BAR_SHOW_VIBRATE_ICON);
+ if (currentSetting.isNull()) {
+ final int defaultValueVibrateIconEnabled = getContext().getResources()
+ .getInteger(R.integer.def_statusBarVibrateIconEnabled);
+ secureSettings.insertSettingOverrideableByRestoreLocked(
+ Secure.STATUS_BAR_SHOW_VIBRATE_ICON,
+ String.valueOf(defaultValueVibrateIconEnabled),
+ null /* tag */, true /* makeDefault */,
+ SettingsState.SYSTEM_PACKAGE_NAME);
+ }
currentVersion = 211;
}
// vXXX: Add new settings above this point.
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index cce5154..1dc0887 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -512,6 +512,8 @@
Settings.Global.ANGLE_GL_DRIVER_SELECTION_PKGS,
Settings.Global.ANGLE_GL_DRIVER_SELECTION_VALUES,
Settings.Global.ANGLE_EGL_FEATURES,
+ Settings.Global.ANGLE_DEFERLIST,
+ Settings.Global.ANGLE_DEFERLIST_MODE,
Settings.Global.UPDATABLE_DRIVER_ALL_APPS,
Settings.Global.UPDATABLE_DRIVER_PRODUCTION_OPT_IN_APPS,
Settings.Global.UPDATABLE_DRIVER_PRERELEASE_OPT_IN_APPS,
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index c69eae3..be1e6fe 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -3841,7 +3841,7 @@
}
}
- private void setLeAudioVolumeOnModeUpdate(int mode, int streamType, int device) {
+ private void setLeAudioVolumeOnModeUpdate(int mode, int device) {
switch (mode) {
case AudioSystem.MODE_IN_COMMUNICATION:
case AudioSystem.MODE_IN_CALL:
@@ -3857,10 +3857,16 @@
return;
}
- // Currently, DEVICE_OUT_BLE_HEADSET is the only output type for LE_AUDIO profile.
- // (See AudioDeviceBroker#createBtDeviceInfo())
- int index = mStreamStates[streamType].getIndex(AudioSystem.DEVICE_OUT_BLE_HEADSET);
- int maxIndex = mStreamStates[streamType].getMaxIndex();
+ // Forcefully set LE audio volume as a workaround, since in some cases
+ // (like the outgoing call) the value of 'device' is not DEVICE_OUT_BLE_*
+ // even when BLE is connected.
+ if (!AudioSystem.isLeAudioDeviceType(device)) {
+ device = AudioSystem.DEVICE_OUT_BLE_HEADSET;
+ }
+
+ final int streamType = getBluetoothContextualVolumeStream(mode);
+ final int index = mStreamStates[streamType].getIndex(device);
+ final int maxIndex = mStreamStates[streamType].getMaxIndex();
if (DEBUG_VOL) {
Log.d(TAG, "setLeAudioVolumeOnModeUpdate postSetLeAudioVolumeIndex index="
@@ -5242,9 +5248,7 @@
// change of mode may require volume to be re-applied on some devices
updateAbsVolumeMultiModeDevices(previousMode, mode);
- // Forcefully set LE audio volume as a workaround, since the value of 'device'
- // is not DEVICE_OUT_BLE_* even when BLE is connected.
- setLeAudioVolumeOnModeUpdate(mode, streamType, device);
+ setLeAudioVolumeOnModeUpdate(mode, device);
// when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all SCO
// connections not started by the application changing the mode when pid changes
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 6795b6b..c671a2c 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -28,6 +28,7 @@
import static android.os.PowerWhitelistManager.REASON_VPN;
import static android.os.UserHandle.PER_USER_RANGE;
+import static com.android.net.module.util.NetworkStackConstants.IPV6_MIN_MTU;
import static com.android.server.vcn.util.PersistableBundleUtils.STRING_DESERIALIZER;
import static java.util.Objects.requireNonNull;
@@ -79,10 +80,12 @@
import android.net.RouteInfo;
import android.net.UidRangeParcel;
import android.net.UnderlyingNetworkInfo;
+import android.net.Uri;
import android.net.VpnManager;
import android.net.VpnProfileState;
import android.net.VpnService;
import android.net.VpnTransportInfo;
+import android.net.ipsec.ike.ChildSaProposal;
import android.net.ipsec.ike.ChildSessionCallback;
import android.net.ipsec.ike.ChildSessionConfiguration;
import android.net.ipsec.ike.ChildSessionParams;
@@ -92,6 +95,7 @@
import android.net.ipsec.ike.IkeSessionConnectionInfo;
import android.net.ipsec.ike.IkeSessionParams;
import android.net.ipsec.ike.IkeTunnelConnectionParams;
+import android.net.ipsec.ike.exceptions.IkeIOException;
import android.net.ipsec.ike.exceptions.IkeNetworkLostException;
import android.net.ipsec.ike.exceptions.IkeNonProtocolException;
import android.net.ipsec.ike.exceptions.IkeProtocolException;
@@ -139,6 +143,7 @@
import com.android.server.DeviceIdleInternal;
import com.android.server.LocalServices;
import com.android.server.net.BaseNetworkObserver;
+import com.android.server.vcn.util.MtuUtils;
import com.android.server.vcn.util.PersistableBundleUtils;
import libcore.io.IoUtils;
@@ -151,6 +156,8 @@
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.SocketException;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
@@ -164,6 +171,7 @@
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
@@ -226,6 +234,16 @@
private static final int VPN_DEFAULT_SCORE = 101;
/**
+ * The reset session timer for data stall. If a session has not successfully revalidated after
+ * the delay, the session will be torn down and restarted in an attempt to recover. Delay
+ * counter is reset on successful validation only.
+ *
+ * <p>If retries have exceeded the length of this array, the last entry in the array will be
+ * used as a repeating interval.
+ */
+ private static final long[] DATA_STALL_RESET_DELAYS_SEC = {30L, 60L, 120L, 240L, 480L, 960L};
+
+ /**
* The initial token value of IKE session.
*/
private static final int STARTING_TOKEN = -1;
@@ -271,6 +289,7 @@
private final UserManager mUserManager;
private final VpnProfileStore mVpnProfileStore;
+ protected boolean mDataStallSuspected = false;
@VisibleForTesting
VpnProfileStore getVpnProfileStore() {
@@ -522,10 +541,46 @@
@NonNull LinkProperties lp,
@NonNull NetworkScore score,
@NonNull NetworkAgentConfig config,
- @Nullable NetworkProvider provider) {
+ @Nullable NetworkProvider provider,
+ @Nullable ValidationStatusCallback callback) {
return new VpnNetworkAgentWrapper(
- context, looper, logTag, nc, lp, score, config, provider);
+ context, looper, logTag, nc, lp, score, config, provider, callback);
}
+
+ /**
+ * Get the length of time to wait before resetting the ike session when a data stall is
+ * suspected.
+ */
+ public long getDataStallResetSessionSeconds(int count) {
+ if (count >= DATA_STALL_RESET_DELAYS_SEC.length) {
+ return DATA_STALL_RESET_DELAYS_SEC[DATA_STALL_RESET_DELAYS_SEC.length - 1];
+ } else {
+ return DATA_STALL_RESET_DELAYS_SEC[count];
+ }
+ }
+
+ /** Gets the MTU of an interface using Java NetworkInterface primitives */
+ public int getJavaNetworkInterfaceMtu(@Nullable String iface, int defaultValue)
+ throws SocketException {
+ if (iface == null) return defaultValue;
+
+ final NetworkInterface networkInterface = NetworkInterface.getByName(iface);
+ return networkInterface == null ? defaultValue : networkInterface.getMTU();
+ }
+
+ /** Calculates the VPN Network's max MTU based on underlying network and configuration */
+ public int calculateVpnMtu(
+ @NonNull List<ChildSaProposal> childProposals,
+ int maxMtu,
+ int underlyingMtu,
+ boolean isIpv4) {
+ return MtuUtils.getMtu(childProposals, maxMtu, underlyingMtu, isIpv4);
+ }
+ }
+
+ @VisibleForTesting
+ interface ValidationStatusCallback {
+ void onValidationStatus(int status);
}
public Vpn(Looper looper, Context context, INetworkManagementService netService, INetd netd,
@@ -1367,6 +1422,11 @@
}
private LinkProperties makeLinkProperties() {
+ // The design of disabling IPv6 is only enabled for IKEv2 VPN because it needs additional
+ // logic to handle IPv6 only VPN, and the IPv6 only VPN may be restarted when its MTU
+ // is lower than 1280. The logic is controlled by IKEv2VpnRunner, so the design is only
+ // enabled for IKEv2 VPN.
+ final boolean disableIPV6 = (isIkev2VpnRunner() && mConfig.mtu < IPV6_MIN_MTU);
boolean allowIPv4 = mConfig.allowIPv4;
boolean allowIPv6 = mConfig.allowIPv6;
@@ -1376,6 +1436,7 @@
if (mConfig.addresses != null) {
for (LinkAddress address : mConfig.addresses) {
+ if (disableIPV6 && address.isIpv6()) continue;
lp.addLinkAddress(address);
allowIPv4 |= address.getAddress() instanceof Inet4Address;
allowIPv6 |= address.getAddress() instanceof Inet6Address;
@@ -1384,8 +1445,9 @@
if (mConfig.routes != null) {
for (RouteInfo route : mConfig.routes) {
+ final InetAddress address = route.getDestination().getAddress();
+ if (disableIPV6 && address instanceof Inet6Address) continue;
lp.addRoute(route);
- InetAddress address = route.getDestination().getAddress();
if (route.getType() == RouteInfo.RTN_UNICAST) {
allowIPv4 |= address instanceof Inet4Address;
@@ -1396,7 +1458,8 @@
if (mConfig.dnsServers != null) {
for (String dnsServer : mConfig.dnsServers) {
- InetAddress address = InetAddresses.parseNumericAddress(dnsServer);
+ final InetAddress address = InetAddresses.parseNumericAddress(dnsServer);
+ if (disableIPV6 && address instanceof Inet6Address) continue;
lp.addDnsServer(address);
allowIPv4 |= address instanceof Inet4Address;
allowIPv6 |= address instanceof Inet6Address;
@@ -1410,7 +1473,7 @@
NetworkStackConstants.IPV4_ADDR_ANY, 0), null /*gateway*/,
null /*iface*/, RTN_UNREACHABLE));
}
- if (!allowIPv6) {
+ if (!allowIPv6 || disableIPV6) {
lp.addRoute(new RouteInfo(new IpPrefix(
NetworkStackConstants.IPV6_ADDR_ANY, 0), null /*gateway*/,
null /*iface*/, RTN_UNREACHABLE));
@@ -1460,6 +1523,11 @@
@GuardedBy("this")
private void agentConnect() {
+ agentConnect(null /* validationCallback */);
+ }
+
+ @GuardedBy("this")
+ private void agentConnect(@Nullable ValidationStatusCallback validationCallback) {
LinkProperties lp = makeLinkProperties();
// VPN either provide a default route (IPv4 or IPv6 or both), or they are a split tunnel
@@ -1507,7 +1575,7 @@
mNetworkAgent = mDeps.newNetworkAgent(mContext, mLooper, NETWORKTYPE /* logtag */,
mNetworkCapabilities, lp,
new NetworkScore.Builder().setLegacyInt(VPN_DEFAULT_SCORE).build(),
- networkAgentConfig, mNetworkProvider);
+ networkAgentConfig, mNetworkProvider, validationCallback);
final long token = Binder.clearCallingIdentity();
try {
mNetworkAgent.register();
@@ -1541,6 +1609,18 @@
updateState(DetailedState.DISCONNECTED, "agentDisconnect");
}
+ @GuardedBy("this")
+ private void startNewNetworkAgent(NetworkAgent oldNetworkAgent, String reason) {
+ // Initialize the state for a new agent, while keeping the old one connected
+ // in case this new connection fails.
+ mNetworkAgent = null;
+ updateState(DetailedState.CONNECTING, reason);
+ // Bringing up a new NetworkAgent to prevent the data leakage before tearing down the old
+ // NetworkAgent.
+ agentConnect();
+ agentDisconnect(oldNetworkAgent);
+ }
+
/**
* Establish a VPN network and return the file descriptor of the VPN interface. This methods
* returns {@code null} if the application is revoked or not prepared.
@@ -1630,16 +1710,7 @@
setUnderlyingNetworks(config.underlyingNetworks);
}
} else {
- // Initialize the state for a new agent, while keeping the old one connected
- // in case this new connection fails.
- mNetworkAgent = null;
- updateState(DetailedState.CONNECTING, "establish");
- // Set up forwarding and DNS rules.
- agentConnect();
- // Remove the old tun's user forwarding rules
- // The new tun's user rules have already been added above so they will take over
- // as rules are deleted. This prevents data leakage as the rules are moved over.
- agentDisconnect(oldNetworkAgent);
+ startNewNetworkAgent(oldNetworkAgent, "establish");
}
if (oldConnection != null) {
@@ -2676,6 +2747,17 @@
void onSessionLost(int token, @Nullable Exception exception);
}
+ private static boolean isIPv6Only(List<LinkAddress> linkAddresses) {
+ boolean hasIPV6 = false;
+ boolean hasIPV4 = false;
+ for (final LinkAddress address : linkAddresses) {
+ hasIPV6 |= address.isIpv6();
+ hasIPV4 |= address.isIpv4();
+ }
+
+ return hasIPV6 && !hasIPV4;
+ }
+
/**
* Internal class managing IKEv2/IPsec VPN connectivity
*
@@ -2723,7 +2805,7 @@
@Nullable private ScheduledFuture<?> mScheduledHandleNetworkLostFuture;
@Nullable private ScheduledFuture<?> mScheduledHandleRetryIkeSessionFuture;
-
+ @Nullable private ScheduledFuture<?> mScheduledHandleDataStallFuture;
/** Signal to ensure shutdown is honored even if a new Network is connected. */
private boolean mIsRunning = true;
@@ -2750,6 +2832,14 @@
private boolean mMobikeEnabled = false;
/**
+ * The number of attempts to reset the IKE session since the last successful connection.
+ *
+ * <p>This variable controls the retry delay, and is reset when the VPN pass network
+ * validation.
+ */
+ private int mDataStallRetryCount = 0;
+
+ /**
* The number of attempts since the last successful connection.
*
* <p>This variable controls the retry delay, and is reset when a new IKE session is
@@ -2881,15 +2971,27 @@
try {
final String interfaceName = mTunnelIface.getInterfaceName();
- final int maxMtu = mProfile.getMaxMtu();
final List<LinkAddress> internalAddresses = childConfig.getInternalAddresses();
final List<String> dnsAddrStrings = new ArrayList<>();
+ int vpnMtu;
+ vpnMtu = calculateVpnMtu();
+
+ // If the VPN is IPv6 only and its MTU is lower than 1280, mark the network as lost
+ // and send the VpnManager event to the VPN app.
+ if (isIPv6Only(internalAddresses) && vpnMtu < IPV6_MIN_MTU) {
+ onSessionLost(
+ token,
+ new IkeIOException(
+ new IOException("No valid addresses for MTU < 1280")));
+ return;
+ }
final Collection<RouteInfo> newRoutes = VpnIkev2Utils.getRoutesFromTrafficSelectors(
childConfig.getOutboundTrafficSelectors());
for (final LinkAddress address : internalAddresses) {
mTunnelIface.addAddress(address.getAddress(), address.getPrefixLength());
}
+
for (InetAddress addr : childConfig.getInternalDnsServers()) {
dnsAddrStrings.add(addr.getHostAddress());
}
@@ -2907,7 +3009,7 @@
if (mVpnRunner != this) return;
mInterface = interfaceName;
- mConfig.mtu = maxMtu;
+ mConfig.mtu = vpnMtu;
mConfig.interfaze = mInterface;
mConfig.addresses.clear();
@@ -2931,7 +3033,7 @@
if (isSettingsVpnLocked()) {
prepareStatusIntent();
}
- agentConnect();
+ agentConnect(this::onValidationStatus);
return; // Link properties are already sent.
} else {
// Underlying networks also set in agentConnect()
@@ -3010,12 +3112,54 @@
// Ignore stale runner.
if (mVpnRunner != this) return;
+ final LinkProperties oldLp = makeLinkProperties();
+
+ final boolean underlyingNetworkHasChanged =
+ !Arrays.equals(mConfig.underlyingNetworks, new Network[]{network});
mConfig.underlyingNetworks = new Network[] {network};
- mNetworkCapabilities =
- new NetworkCapabilities.Builder(mNetworkCapabilities)
- .setUnderlyingNetworks(Collections.singletonList(network))
- .build();
- doSetUnderlyingNetworks(mNetworkAgent, Collections.singletonList(network));
+ mConfig.mtu = calculateVpnMtu();
+
+ final LinkProperties newLp = makeLinkProperties();
+
+ // If MTU is < 1280, IPv6 addresses will be removed. If there are no addresses
+ // left (e.g. IPv6-only VPN network), mark VPN as having lost the session.
+ if (newLp.getLinkAddresses().isEmpty()) {
+ onSessionLost(
+ token,
+ new IkeIOException(
+ new IOException("No valid addresses for MTU < 1280")));
+ return;
+ }
+
+ final Set<LinkAddress> removedAddrs = new HashSet<>(oldLp.getLinkAddresses());
+ removedAddrs.removeAll(newLp.getLinkAddresses());
+
+ // If addresses were removed despite no IKE config change, IPv6 addresses must
+ // have been removed due to MTU size. Restart the VPN to ensure all IPv6
+ // unconnected sockets on the new VPN network are closed and retried on the new
+ // VPN network.
+ if (!removedAddrs.isEmpty()) {
+ startNewNetworkAgent(
+ mNetworkAgent, "MTU too low for IPv6; restarting network agent");
+
+ for (LinkAddress removed : removedAddrs) {
+ mTunnelIface.removeAddress(
+ removed.getAddress(), removed.getPrefixLength());
+ }
+ } else {
+ // Put below 3 updates into else block is because agentConnect() will do
+ // those things, so there is no need to do the redundant work.
+ if (!newLp.equals(oldLp)) doSendLinkProperties(mNetworkAgent, newLp);
+ if (underlyingNetworkHasChanged) {
+ mNetworkCapabilities =
+ new NetworkCapabilities.Builder(mNetworkCapabilities)
+ .setUnderlyingNetworks(
+ Collections.singletonList(network))
+ .build();
+ doSetUnderlyingNetworks(mNetworkAgent,
+ Collections.singletonList(network));
+ }
+ }
}
mTunnelIface.setUnderlyingNetwork(network);
@@ -3065,6 +3209,60 @@
startOrMigrateIkeSession(network);
}
+ @NonNull
+ private IkeSessionParams getIkeSessionParams(@NonNull Network underlyingNetwork) {
+ final IkeTunnelConnectionParams ikeTunConnParams =
+ mProfile.getIkeTunnelConnectionParams();
+ if (ikeTunConnParams != null) {
+ final IkeSessionParams.Builder builder =
+ new IkeSessionParams.Builder(ikeTunConnParams.getIkeSessionParams())
+ .setNetwork(underlyingNetwork);
+ return builder.build();
+ } else {
+ return VpnIkev2Utils.buildIkeSessionParams(mContext, mProfile, underlyingNetwork);
+ }
+ }
+
+ @NonNull
+ private ChildSessionParams getChildSessionParams() {
+ final IkeTunnelConnectionParams ikeTunConnParams =
+ mProfile.getIkeTunnelConnectionParams();
+ if (ikeTunConnParams != null) {
+ return ikeTunConnParams.getTunnelModeChildSessionParams();
+ } else {
+ return VpnIkev2Utils.buildChildSessionParams(mProfile.getAllowedAlgorithms());
+ }
+ }
+
+ private int calculateVpnMtu() {
+ final Network underlyingNetwork = mIkeConnectionInfo.getNetwork();
+ final LinkProperties lp = mConnectivityManager.getLinkProperties(underlyingNetwork);
+ if (underlyingNetwork == null || lp == null) {
+ // Return the max MTU defined in VpnProfile as the fallback option when there is no
+ // underlying network or LinkProperties is null.
+ return mProfile.getMaxMtu();
+ }
+
+ int underlyingMtu = lp.getMtu();
+
+ // Try to get MTU from kernel if MTU is not set in LinkProperties.
+ if (underlyingMtu == 0) {
+ try {
+ underlyingMtu = mDeps.getJavaNetworkInterfaceMtu(lp.getInterfaceName(),
+ mProfile.getMaxMtu());
+ } catch (SocketException e) {
+ Log.d(TAG, "Got a SocketException when getting MTU from kernel: " + e);
+ return mProfile.getMaxMtu();
+ }
+ }
+
+ return mDeps.calculateVpnMtu(
+ getChildSessionParams().getSaProposals(),
+ mProfile.getMaxMtu(),
+ underlyingMtu,
+ mIkeConnectionInfo.getLocalAddress() instanceof Inet4Address);
+ }
+
/**
* Start a new IKE session.
*
@@ -3115,24 +3313,6 @@
// (non-default) network, and start the new one.
resetIkeState();
- // Get Ike options from IkeTunnelConnectionParams if it's available in the
- // profile.
- final IkeTunnelConnectionParams ikeTunConnParams =
- mProfile.getIkeTunnelConnectionParams();
- final IkeSessionParams ikeSessionParams;
- final ChildSessionParams childSessionParams;
- if (ikeTunConnParams != null) {
- final IkeSessionParams.Builder builder = new IkeSessionParams.Builder(
- ikeTunConnParams.getIkeSessionParams()).setNetwork(underlyingNetwork);
- ikeSessionParams = builder.build();
- childSessionParams = ikeTunConnParams.getTunnelModeChildSessionParams();
- } else {
- ikeSessionParams = VpnIkev2Utils.buildIkeSessionParams(
- mContext, mProfile, underlyingNetwork);
- childSessionParams = VpnIkev2Utils.buildChildSessionParams(
- mProfile.getAllowedAlgorithms());
- }
-
// TODO: Remove the need for adding two unused addresses with
// IPsec tunnels.
final InetAddress address = InetAddress.getLocalHost();
@@ -3150,8 +3330,8 @@
mSession =
mIkev2SessionCreator.createIkeSession(
mContext,
- ikeSessionParams,
- childSessionParams,
+ getIkeSessionParams(underlyingNetwork),
+ getChildSessionParams(),
mExecutor,
new VpnIkev2Utils.IkeSessionCallbackImpl(
TAG, IkeV2VpnRunner.this, token),
@@ -3200,18 +3380,52 @@
// Ignore stale runner.
if (mVpnRunner != Vpn.IkeV2VpnRunner.this) return;
- // Handle the report only for current VPN network.
+ // Handle the report only for current VPN network. If data stall is already
+ // reported, ignoring the other reports. It means that the stall is not
+ // recovered by MOBIKE and should be on the way to reset the ike session.
if (mNetworkAgent != null
- && mNetworkAgent.getNetwork().equals(report.getNetwork())) {
+ && mNetworkAgent.getNetwork().equals(report.getNetwork())
+ && !mDataStallSuspected) {
Log.d(TAG, "Data stall suspected");
// Trigger MOBIKE.
maybeMigrateIkeSession(mActiveNetwork);
+ mDataStallSuspected = true;
}
}
}
}
+ public void onValidationStatus(int status) {
+ if (status == NetworkAgent.VALIDATION_STATUS_VALID) {
+ // No data stall now. Reset it.
+ mExecutor.execute(() -> {
+ mDataStallSuspected = false;
+ mDataStallRetryCount = 0;
+ if (mScheduledHandleDataStallFuture != null) {
+ Log.d(TAG, "Recovered from stall. Cancel pending reset action.");
+ mScheduledHandleDataStallFuture.cancel(false /* mayInterruptIfRunning */);
+ mScheduledHandleDataStallFuture = null;
+ }
+ });
+ } else {
+ // Skip other invalid status if the scheduled recovery exists.
+ if (mScheduledHandleDataStallFuture != null) return;
+
+ mScheduledHandleDataStallFuture = mExecutor.schedule(() -> {
+ if (mDataStallSuspected) {
+ Log.d(TAG, "Reset session to recover stalled network");
+ // This will reset old state if it exists.
+ startIkeSession(mActiveNetwork);
+ }
+
+ // Reset mScheduledHandleDataStallFuture since it's already run on executor
+ // thread.
+ mScheduledHandleDataStallFuture = null;
+ }, mDeps.getDataStallResetSessionSeconds(mDataStallRetryCount++), TimeUnit.SECONDS);
+ }
+ }
+
/**
* Handles loss of the default underlying network
*
@@ -4339,6 +4553,7 @@
// un-finalized.
@VisibleForTesting
public static class VpnNetworkAgentWrapper extends NetworkAgent {
+ private final ValidationStatusCallback mCallback;
/** Create an VpnNetworkAgentWrapper */
public VpnNetworkAgentWrapper(
@NonNull Context context,
@@ -4348,8 +4563,10 @@
@NonNull LinkProperties lp,
@NonNull NetworkScore score,
@NonNull NetworkAgentConfig config,
- @Nullable NetworkProvider provider) {
+ @Nullable NetworkProvider provider,
+ @Nullable ValidationStatusCallback callback) {
super(context, looper, logTag, nc, lp, score, config, provider);
+ mCallback = callback;
}
/** Update the LinkProperties */
@@ -4371,6 +4588,13 @@
public void onNetworkUnwanted() {
// We are user controlled, not driven by NetworkRequest.
}
+
+ @Override
+ public void onValidationStatus(int status, Uri redirectUri) {
+ if (mCallback != null) {
+ mCallback.onValidationStatus(status);
+ }
+ }
}
/**
diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index a25ac21..c725441 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -458,7 +458,6 @@
*/
public float getNitsFromBacklight(float backlight) {
if (mBacklightToNitsSpline == null) {
- Slog.wtf(TAG, "requesting nits when no mapping exists.");
return NITS_INVALID;
}
backlight = Math.max(backlight, mBacklightMinimum);
diff --git a/services/core/java/com/android/server/pm/ApkChecksums.java b/services/core/java/com/android/server/pm/ApkChecksums.java
index c2f2b0a..ffe0ca0 100644
--- a/services/core/java/com/android/server/pm/ApkChecksums.java
+++ b/services/core/java/com/android/server/pm/ApkChecksums.java
@@ -650,7 +650,7 @@
// Skip /product folder.
// TODO(b/231354111): remove this hack once we are allowed to change SELinux rules.
if (!containsFile(Environment.getProductDirectory(), filePath)) {
- byte[] verityHash = VerityUtils.getFsverityRootHash(filePath);
+ byte[] verityHash = VerityUtils.getFsverityDigest(filePath);
if (verityHash != null) {
return new ApkChecksum(split, TYPE_WHOLE_MERKLE_ROOT_4K_SHA256, verityHash);
}
diff --git a/services/core/java/com/android/server/pm/OWNERS b/services/core/java/com/android/server/pm/OWNERS
index 8534fab..84324f2 100644
--- a/services/core/java/com/android/server/pm/OWNERS
+++ b/services/core/java/com/android/server/pm/OWNERS
@@ -3,8 +3,6 @@
jsharkey@android.com
jsharkey@google.com
narayan@google.com
-svetoslavganov@android.com
-svetoslavganov@google.com
include /PACKAGE_MANAGER_OWNERS
# apex support
@@ -26,16 +24,10 @@
per-file PackageUsage.java = file:dex/OWNERS
# multi user / cross profile
-per-file CrossProfileAppsServiceImpl.java = omakoto@google.com, yamasani@google.com
-per-file CrossProfileAppsService.java = omakoto@google.com, yamasani@google.com
-per-file CrossProfileIntentFilter.java = omakoto@google.com, yamasani@google.com
-per-file CrossProfileIntentResolver.java = omakoto@google.com, yamasani@google.com
+per-file CrossProfile* = file:MULTIUSER_AND_ENTERPRISE_OWNERS
per-file RestrictionsSet.java = file:MULTIUSER_AND_ENTERPRISE_OWNERS
-per-file UserManager* = file:/MULTIUSER_OWNERS
per-file UserRestriction* = file:MULTIUSER_AND_ENTERPRISE_OWNERS
-per-file UserSystemPackageInstaller* = file:/MULTIUSER_OWNERS
-per-file UserTypeDetails.java = file:/MULTIUSER_OWNERS
-per-file UserTypeFactory.java = file:/MULTIUSER_OWNERS
+per-file User* = file:/MULTIUSER_OWNERS
# security
per-file KeySetHandle.java = cbrubaker@google.com, nnk@google.com
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index 016c1cb..fe797d2 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -147,7 +147,8 @@
UserManager.DISALLOW_WIFI_TETHERING,
UserManager.DISALLOW_SHARING_ADMIN_CONFIGURED_WIFI,
UserManager.DISALLOW_WIFI_DIRECT,
- UserManager.DISALLOW_ADD_WIFI_CONFIG
+ UserManager.DISALLOW_ADD_WIFI_CONFIG,
+ UserManager.DISALLOW_CELLULAR_2G
});
public static final Set<String> DEPRECATED_USER_RESTRICTIONS = Sets.newArraySet(
@@ -195,7 +196,8 @@
UserManager.DISALLOW_CHANGE_WIFI_STATE,
UserManager.DISALLOW_WIFI_TETHERING,
UserManager.DISALLOW_WIFI_DIRECT,
- UserManager.DISALLOW_ADD_WIFI_CONFIG
+ UserManager.DISALLOW_ADD_WIFI_CONFIG,
+ UserManager.DISALLOW_CELLULAR_2G
);
/**
@@ -234,7 +236,8 @@
UserManager.DISALLOW_CHANGE_WIFI_STATE,
UserManager.DISALLOW_WIFI_TETHERING,
UserManager.DISALLOW_WIFI_DIRECT,
- UserManager.DISALLOW_ADD_WIFI_CONFIG
+ UserManager.DISALLOW_ADD_WIFI_CONFIG,
+ UserManager.DISALLOW_CELLULAR_2G
);
/**
diff --git a/services/core/java/com/android/server/pm/VerificationParams.java b/services/core/java/com/android/server/pm/VerificationParams.java
index 7423bf6..d3112c5 100644
--- a/services/core/java/com/android/server/pm/VerificationParams.java
+++ b/services/core/java/com/android/server/pm/VerificationParams.java
@@ -643,7 +643,7 @@
private List<ComponentName> matchVerifiers(PackageInfoLite pkgInfo,
List<ResolveInfo> receivers, final PackageVerificationState verificationState) {
- if (pkgInfo.verifiers.length == 0) {
+ if (pkgInfo.verifiers == null || pkgInfo.verifiers.length == 0) {
return null;
}
diff --git a/services/core/java/com/android/server/pm/dex/ArtManagerService.java b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
index 9ebef3b..af507cd 100644
--- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java
+++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
@@ -52,6 +52,7 @@
import com.android.server.LocalServices;
import com.android.server.pm.Installer;
import com.android.server.pm.Installer.InstallerException;
+import com.android.server.pm.PackageManagerService;
import com.android.server.pm.PackageManagerServiceCompilerMapping;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.pkg.parsing.PackageInfoWithoutStateUtils;
@@ -724,6 +725,13 @@
@Override
public PackageOptimizationInfo getPackageOptimizationInfo(
ApplicationInfo info, String abi, String activityName) {
+ if (info.packageName.equals(PackageManagerService.PLATFORM_PACKAGE_NAME)) {
+ // PackageManagerService.PLATFORM_PACKAGE_NAME in this context means that the
+ // activity is defined in bootclasspath. Currently, we don't have an API to get the
+ // correct optimization info.
+ return PackageOptimizationInfo.createWithNoInfo();
+ }
+
String compilationReason;
String compilationFilter;
try {
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 8d831d7..91dcc8e 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -1441,7 +1441,7 @@
a.colorMode = ActivityInfo.COLOR_MODE_DEFAULT;
a.flags |= ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
a.resizeMode = RESIZE_MODE_UNRESIZEABLE;
- a.configChanges = ActivityInfo.CONFIG_ORIENTATION;
+ a.configChanges = 0xffffffff;
final ActivityOptions options = ActivityOptions.makeBasic();
options.setLaunchActivityType(ACTIVITY_TYPE_DREAM);
diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java
index 35cc5e3..ddfdff6 100644
--- a/services/core/java/com/android/server/wm/RemoteAnimationController.java
+++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java
@@ -308,11 +308,11 @@
mService.closeSurfaceTransaction("RemoteAnimationController#finished");
mIsFinishing = false;
}
+ // Reset input for all activities when the remote animation is finished.
+ final Consumer<ActivityRecord> updateActivities =
+ activity -> activity.setDropInputForAnimation(false);
+ mDisplayContent.forAllActivities(updateActivities);
}
- // Reset input for all activities when the remote animation is finished.
- final Consumer<ActivityRecord> updateActivities =
- activity -> activity.setDropInputForAnimation(false);
- mDisplayContent.forAllActivities(updateActivities);
setRunningRemoteAnimation(false);
ProtoLog.i(WM_DEBUG_REMOTE_ANIMATIONS, "Finishing remote animation");
}
diff --git a/services/tests/mockingservicestests/OWNERS b/services/tests/mockingservicestests/OWNERS
index 2bb1649..4dda51f 100644
--- a/services/tests/mockingservicestests/OWNERS
+++ b/services/tests/mockingservicestests/OWNERS
@@ -1,5 +1,8 @@
include platform/frameworks/base:/services/core/java/com/android/server/am/OWNERS
+
+# Game Platform
per-file FakeGameClassifier.java = file:/GAME_MANAGER_OWNERS
per-file FakeGameServiceProviderInstance = file:/GAME_MANAGER_OWNERS
per-file FakeServiceConnector.java = file:/GAME_MANAGER_OWNERS
per-file Game* = file:/GAME_MANAGER_OWNERS
+per-file res/xml/game_manager* = file:/GAME_MANAGER_OWNERS
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 8e6d6a8..bb0522c 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1180,8 +1180,12 @@
"carrier_data_call_retry_network_requested_max_count_int";
/**
- * Data call setup permanent failure causes by the carrier
+ * Data call setup permanent failure causes by the carrier.
+ *
+ * @deprecated This API key was added in mistake and is not used anymore by the telephony data
+ * frameworks.
*/
+ @Deprecated
public static final String KEY_CARRIER_DATA_CALL_PERMANENT_FAILURE_STRINGS =
"carrier_data_call_permanent_failure_strings";
@@ -8308,7 +8312,8 @@
*
* The syntax of the retry rule:
* 1. Retry based on {@link NetworkCapabilities}. Note that only APN-type network capabilities
- * are supported.
+ * are supported. If the capabilities are not specified, then the retry rule only applies
+ * to the current failed APN used in setup data call request.
* "capabilities=[netCaps1|netCaps2|...], [retry_interval=n1|n2|n3|n4...], [maximum_retries=n]"
*
* 2. Retry based on {@link DataFailCause}
@@ -8319,15 +8324,16 @@
* "capabilities=[netCaps1|netCaps2|...], fail_causes=[cause1|cause2|cause3|...],
* [retry_interval=n1|n2|n3|n4...], [maximum_retries=n]"
*
+ * 4. Permanent fail causes (no timer-based retry) on the current failed APN. Retry interval
+ * is specified for retrying the next available APN.
+ * "permanent_fail_causes=8|27|28|29|30|32|33|35|50|51|111|-5|-6|65537|65538|-3|65543|65547|
+ * 2252|2253|2254, retry_interval=2500"
+ *
* For example,
* "capabilities=eims, retry_interval=1000, maximum_retries=20" means if the attached
* network request is emergency, then retry data network setup every 1 second for up to 20
* times.
*
- * "fail_causes=8|27|28|29|30|32|33|35|50|51|111|-5|-6|65537|65538|-3|2253|2254
- * , maximum_retries=0" means for those fail causes, never retry with timers. Note that
- * when environment changes, retry can still happen.
- *
* "capabilities=internet|enterprise|dun|ims|fota, retry_interval=2500|3000|"
* "5000|10000|15000|20000|40000|60000|120000|240000|600000|1200000|1800000"
* "1800000, maximum_retries=20" means for those capabilities, retry happens in 2.5s, 3s, 5s,
@@ -9205,8 +9211,13 @@
sDefaults.putStringArray(
KEY_TELEPHONY_DATA_SETUP_RETRY_RULES_STRING_ARRAY, new String[] {
"capabilities=eims, retry_interval=1000, maximum_retries=20",
- "fail_causes=8|27|28|29|30|32|33|35|50|51|111|-5|-6|65537|65538|-3|2252|"
- + "2253|2254, maximum_retries=0", // No retry for those causes
+ // Permanent fail causes. When setup data call fails with the following
+ // fail causes, telephony data frameworks will stop timer-based retry on
+ // the failed APN until power cycle, APM, or some special events. Note that
+ // even timer-based retry is not performed, condition-based (RAT changes,
+ // registration state changes) retry can still happen.
+ "permanent_fail_causes=8|27|28|29|30|32|33|35|50|51|111|-5|-6|65537|65538|"
+ + "-3|65543|65547|2252|2253|2254, retry_interval=2500",
"capabilities=mms|supl|cbs, retry_interval=2000",
"capabilities=internet|enterprise|dun|ims|fota, retry_interval=2500|3000|"
+ "5000|10000|15000|20000|40000|60000|120000|240000|"
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 5ed6cb9..291524a 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -3952,6 +3952,10 @@
* may provide one. Or, a carrier may decide to provide the phone number via source
* {@link #PHONE_NUMBER_SOURCE_CARRIER carrier} if neither source UICC nor IMS is available.
*
+ * <p>The availability and correctness of the phone number depends on the underlying source
+ * and the network etc. Additional verification is needed to use this number for
+ * security-related or other sensitive scenarios.
+ *
* @param subscriptionId the subscription ID, or {@link #DEFAULT_SUBSCRIPTION_ID}
* for the default one.
* @param source the source of the phone number, one of the PHONE_NUMBER_SOURCE_* constants.
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 70d8270..a081bc3 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -9358,7 +9358,8 @@
ALLOWED_NETWORK_TYPES_REASON_USER,
ALLOWED_NETWORK_TYPES_REASON_POWER,
ALLOWED_NETWORK_TYPES_REASON_CARRIER,
- ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G
+ ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G,
+ ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS,
})
@Retention(RetentionPolicy.SOURCE)
public @interface AllowedNetworkTypesReason {
@@ -9397,6 +9398,15 @@
public static final int ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G = 3;
/**
+ * To indicate allowed network type change is requested by an update to the
+ * {@link android.os.UserManager.DISALLOW_CELLULAR_2G} user restriction.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS = 4;
+
+ /**
* Set the allowed network types of the device and provide the reason triggering the allowed
* network change.
* <p>Requires permission: android.Manifest.MODIFY_PHONE_STATE or
@@ -9488,6 +9498,7 @@
case TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_POWER:
case TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_CARRIER:
case TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G:
+ case ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS:
return true;
}
return false;