Merge "Use asm built from source in framework tools."
diff --git a/ApiDocs.bp b/ApiDocs.bp
index bf3a6a3..a46ecce 100644
--- a/ApiDocs.bp
+++ b/ApiDocs.bp
@@ -183,6 +183,7 @@
/////////////////////////////////////////////////////////////////////
framework_docs_only_args = " -android -manifest $(location core/res/AndroidManifest.xml) " +
+ "-metalavaApiSince " +
"-werror -lerror -hide 111 -hide 113 -hide 125 -hide 126 -hide 127 -hide 128 " +
"-overview $(location core/java/overview.html) " +
// Federate Support Library references against local API file.
@@ -374,7 +375,7 @@
],
proofread_file: "ds-docs-proofread.txt",
args: framework_docs_only_args +
- " -toroot / -yamlV2 -metalavaApiSince -samplegroup Admin " +
+ " -toroot / -yamlV2 -samplegroup Admin " +
" -samplegroup Background " +
" -samplegroup Connectivity " +
" -samplegroup Content " +
diff --git a/api/Android.bp b/api/Android.bp
index 210b8f5..ef88790 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -109,6 +109,7 @@
"framework-sdksandbox",
"framework-tethering",
"framework-uwb",
+ "framework-virtualization",
"framework-wifi",
"i18n.module.public.api",
],
diff --git a/api/api.go b/api/api.go
index 6a6c493..ba0fdc1 100644
--- a/api/api.go
+++ b/api/api.go
@@ -27,8 +27,16 @@
const art = "art.module.public.api"
const conscrypt = "conscrypt.module.public.api"
const i18n = "i18n.module.public.api"
+const virtualization = "framework-virtualization"
var core_libraries_modules = []string{art, conscrypt, i18n}
+// List of modules that are not yet updatable, and hence they can still compile
+// against hidden APIs. These modules are filtered out when building the
+// updatable-framework-module-impl (because updatable-framework-module-impl is
+// built against module_current SDK). Instead they are directly statically
+// linked into the all-framework-module-lib, which is building against hidden
+// APIs.
+var non_updatable_modules = []string{virtualization}
// The intention behind this soong plugin is to generate a number of "merged"
// API-related modules that would otherwise require a large amount of very
@@ -249,12 +257,31 @@
func createMergedFrameworkImpl(ctx android.LoadHookContext, modules []string) {
// This module is for the "framework-all" module, which should not include the core libraries.
modules = removeAll(modules, core_libraries_modules)
- props := libraryProps{}
- props.Name = proptools.StringPtr("all-framework-module-impl")
- props.Static_libs = transformArray(modules, "", ".impl")
- props.Sdk_version = proptools.StringPtr("module_current")
- props.Visibility = []string{"//frameworks/base"}
- ctx.CreateModule(java.LibraryFactory, &props)
+ // Remove the modules that belong to non-updatable APEXes since those are allowed to compile
+ // against unstable APIs.
+ modules = removeAll(modules, non_updatable_modules)
+ // First create updatable-framework-module-impl, which contains all updatable modules.
+ // This module compiles against module_lib SDK.
+ {
+ props := libraryProps{}
+ props.Name = proptools.StringPtr("updatable-framework-module-impl")
+ props.Static_libs = transformArray(modules, "", ".impl")
+ props.Sdk_version = proptools.StringPtr("module_current")
+ props.Visibility = []string{"//frameworks/base"}
+ ctx.CreateModule(java.LibraryFactory, &props)
+ }
+
+ // Now create all-framework-module-impl, which contains updatable-framework-module-impl
+ // and all non-updatable modules. This module compiles against hidden APIs.
+ {
+ props := libraryProps{}
+ props.Name = proptools.StringPtr("all-framework-module-impl")
+ props.Static_libs = transformArray(non_updatable_modules, "", ".impl")
+ props.Static_libs = append(props.Static_libs, "updatable-framework-module-impl")
+ props.Sdk_version = proptools.StringPtr("core_platform")
+ props.Visibility = []string{"//frameworks/base"}
+ ctx.CreateModule(java.LibraryFactory, &props)
+ }
}
func createMergedFrameworkModuleLibStubs(ctx android.LoadHookContext, modules []string) {
diff --git a/core/api/current.txt b/core/api/current.txt
index 2f1845f..01bfecf 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -20016,7 +20016,10 @@
field public static final int ENCODING_DRA = 28; // 0x1c
field public static final int ENCODING_DTS = 7; // 0x7
field public static final int ENCODING_DTS_HD = 8; // 0x8
- field public static final int ENCODING_DTS_UHD = 27; // 0x1b
+ field public static final int ENCODING_DTS_HD_MA = 29; // 0x1d
+ field @Deprecated public static final int ENCODING_DTS_UHD = 27; // 0x1b
+ field public static final int ENCODING_DTS_UHD_P1 = 27; // 0x1b
+ field public static final int ENCODING_DTS_UHD_P2 = 30; // 0x1e
field public static final int ENCODING_E_AC3 = 6; // 0x6
field public static final int ENCODING_E_AC3_JOC = 18; // 0x12
field public static final int ENCODING_IEC61937 = 13; // 0xd
@@ -27354,6 +27357,15 @@
package android.nfc {
+ public final class AvailableNfcAntenna implements android.os.Parcelable {
+ ctor public AvailableNfcAntenna(int, int);
+ method public int describeContents();
+ method public int getLocationX();
+ method public int getLocationY();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.nfc.AvailableNfcAntenna> CREATOR;
+ }
+
public class FormatException extends java.lang.Exception {
ctor public FormatException();
ctor public FormatException(String);
@@ -27415,6 +27427,7 @@
method @Deprecated public void enableForegroundNdefPush(android.app.Activity, android.nfc.NdefMessage);
method public void enableReaderMode(android.app.Activity, android.nfc.NfcAdapter.ReaderCallback, int, android.os.Bundle);
method public static android.nfc.NfcAdapter getDefaultAdapter(android.content.Context);
+ method @Nullable public android.nfc.NfcAntennaInfo getNfcAntennaInfo();
method public boolean ignore(android.nfc.Tag, int, android.nfc.NfcAdapter.OnTagRemovedListener, android.os.Handler);
method @Deprecated public boolean invokeBeam(android.app.Activity);
method public boolean isEnabled();
@@ -27477,6 +27490,17 @@
method public void onTagDiscovered(android.nfc.Tag);
}
+ public final class NfcAntennaInfo implements android.os.Parcelable {
+ ctor public NfcAntennaInfo(int, int, boolean, @NonNull java.util.List<android.nfc.AvailableNfcAntenna>);
+ method public int describeContents();
+ method @NonNull public java.util.List<android.nfc.AvailableNfcAntenna> getAvailableNfcAntennas();
+ method public int getDeviceHeight();
+ method public int getDeviceWidth();
+ method public boolean isDeviceFoldable();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.nfc.NfcAntennaInfo> CREATOR;
+ }
+
public final class NfcEvent {
field public final android.nfc.NfcAdapter nfcAdapter;
field public final int peerLlcpMajorVersion;
diff --git a/core/java/Android.bp b/core/java/Android.bp
index cf30e31..eac8b9b 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -485,3 +485,9 @@
}
// protolog end
+
+// temporary placeholder until the real module is available
+java_library {
+ name: "framework-configinfrastructure",
+ sdk_version: "module_current",
+}
diff --git a/core/java/android/content/AttributionSource.java b/core/java/android/content/AttributionSource.java
index b0c6cbc..e981581 100644
--- a/core/java/android/content/AttributionSource.java
+++ b/core/java/android/content/AttributionSource.java
@@ -29,6 +29,7 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.os.Process;
+import android.os.UserHandle;
import android.permission.PermissionManager;
import android.util.ArraySet;
@@ -297,7 +298,7 @@
public boolean checkCallingUid() {
final int callingUid = Binder.getCallingUid();
if (callingUid != Process.ROOT_UID
- && callingUid != Process.SYSTEM_UID
+ && UserHandle.getAppId(callingUid) != Process.SYSTEM_UID
&& callingUid != mAttributionSourceState.uid) {
return false;
}
diff --git a/core/java/android/content/integrity/AppInstallMetadata.java b/core/java/android/content/integrity/AppInstallMetadata.java
index 9874890..91b0007 100644
--- a/core/java/android/content/integrity/AppInstallMetadata.java
+++ b/core/java/android/content/integrity/AppInstallMetadata.java
@@ -129,9 +129,18 @@
@Override
public String toString() {
return String.format(
- "AppInstallMetadata { PackageName = %s, AppCerts = %s, InstallerName = %s,"
- + " InstallerCerts = %s, VersionCode = %d, PreInstalled = %b, StampPresent ="
- + " %b, StampVerified = %b, StampTrusted = %b, StampCert = %s }",
+ "AppInstallMetadata {"
+ + " PackageName = %s,"
+ + " AppCerts = %s,"
+ + " AppCertsLineage = %s,"
+ + " InstallerName = %s,"
+ + " InstallerCerts = %s,"
+ + " VersionCode = %d,"
+ + " PreInstalled = %b,"
+ + " StampPresent = %b,"
+ + " StampVerified = %b,"
+ + " StampTrusted = %b,"
+ + " StampCert = %s }",
mPackageName,
mAppCertificates,
mAppCertificateLineage,
diff --git a/core/java/android/content/pm/OWNERS b/core/java/android/content/pm/OWNERS
index 25efdc6..a6674370 100644
--- a/core/java/android/content/pm/OWNERS
+++ b/core/java/android/content/pm/OWNERS
@@ -1,12 +1,10 @@
# Bug component: 36137
-patb@google.com
+file:/PACKAGE_MANAGER_OWNERS
-per-file Package* = file:/PACKAGE_MANAGER_OWNERS
per-file PackageParser.java = set noparent
per-file PackageParser.java = chiuwinson@google.com,patb@google.com
per-file *Capability* = file:/core/java/android/content/pm/SHORTCUT_OWNERS
per-file *Shortcut* = file:/core/java/android/content/pm/SHORTCUT_OWNERS
-per-file AppSearchPerson.java = file:/core/java/android/content/pm/SHORTCUT_OWNERS
per-file *Launcher* = file:/core/java/android/content/pm/LAUNCHER_OWNERS
per-file UserInfo* = file:/MULTIUSER_OWNERS
diff --git a/core/java/android/hardware/radio/Announcement.java b/core/java/android/hardware/radio/Announcement.java
index 8febed3..bab4153 100644
--- a/core/java/android/hardware/radio/Announcement.java
+++ b/core/java/android/hardware/radio/Announcement.java
@@ -86,7 +86,7 @@
public Announcement(@NonNull ProgramSelector selector, @Type int type,
@NonNull Map<String, String> vendorInfo) {
mSelector = Objects.requireNonNull(selector);
- mType = Objects.requireNonNull(type);
+ mType = type;
mVendorInfo = Objects.requireNonNull(vendorInfo);
}
diff --git a/core/java/android/hardware/radio/OWNERS b/core/java/android/hardware/radio/OWNERS
index d2bdd64..302fdd7 100644
--- a/core/java/android/hardware/radio/OWNERS
+++ b/core/java/android/hardware/radio/OWNERS
@@ -1,3 +1,4 @@
xuweilin@google.com
oscarazu@google.com
+ericjeong@google.com
keunyoung@google.com
diff --git a/core/java/android/net/vcn/VcnManager.java b/core/java/android/net/vcn/VcnManager.java
index 40e4083..3a7aea5 100644
--- a/core/java/android/net/vcn/VcnManager.java
+++ b/core/java/android/net/vcn/VcnManager.java
@@ -104,12 +104,23 @@
// TODO: Add separate signal strength thresholds for 2.4 GHz and 5GHz
+ /**
+ * Key for transports that need to be marked as restricted by the VCN
+ *
+ * <p>Defaults to TRANSPORT_WIFI if the config does not exist
+ *
+ * @hide
+ */
+ public static final String VCN_RESTRICTED_TRANSPORTS_INT_ARRAY_KEY =
+ "vcn_restricted_transports";
+
/** List of Carrier Config options to extract from Carrier Config bundles. @hide */
@NonNull
public static final String[] VCN_RELATED_CARRIER_CONFIG_KEYS =
new String[] {
VCN_NETWORK_SELECTION_WIFI_ENTRY_RSSI_THRESHOLD_KEY,
- VCN_NETWORK_SELECTION_WIFI_EXIT_RSSI_THRESHOLD_KEY
+ VCN_NETWORK_SELECTION_WIFI_EXIT_RSSI_THRESHOLD_KEY,
+ VCN_RESTRICTED_TRANSPORTS_INT_ARRAY_KEY
};
private static final Map<
diff --git a/core/java/android/nfc/AvailableNfcAntenna.aidl b/core/java/android/nfc/AvailableNfcAntenna.aidl
new file mode 100644
index 0000000..9d06e2d
--- /dev/null
+++ b/core/java/android/nfc/AvailableNfcAntenna.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.nfc;
+
+parcelable AvailableNfcAntenna;
diff --git a/core/java/android/nfc/AvailableNfcAntenna.java b/core/java/android/nfc/AvailableNfcAntenna.java
new file mode 100644
index 0000000..946ba67
--- /dev/null
+++ b/core/java/android/nfc/AvailableNfcAntenna.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.nfc;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Represents a single available Nfc antenna
+ * on an Android device.
+ */
+public final class AvailableNfcAntenna implements Parcelable {
+ /**
+ * Location on the antenna on the Y axis in millimeters.
+ * 0 is the bottom-left when the user is facing the screen.
+ */
+ private final int mLocationX;
+ /**
+ * Location on the antenna on the Y axis in millimeters.
+ * 0 is the bottom-left when the user is facing the screen.
+ */
+ private final int mLocationY;
+
+ public AvailableNfcAntenna(int locationX, int locationY) {
+ this.mLocationX = locationX;
+ this.mLocationY = locationY;
+ }
+
+ /**
+ * Location on the antenna on the X axis in millimeters.
+ * 0 is the bottom-left when the user is facing the screen.
+ */
+ public int getLocationX() {
+ return mLocationX;
+ }
+
+ /**
+ * Location on the antenna on the Y axis in millimeters.
+ * 0 is the bottom-left when the user is facing the screen.
+ */
+ public int getLocationY() {
+ return mLocationY;
+ }
+
+ private AvailableNfcAntenna(Parcel in) {
+ this.mLocationX = in.readInt();
+ this.mLocationY = in.readInt();
+ }
+
+ public static final @android.annotation.NonNull Parcelable.Creator<AvailableNfcAntenna>
+ CREATOR = new Parcelable.Creator<AvailableNfcAntenna>() {
+ @Override
+ public AvailableNfcAntenna createFromParcel(Parcel in) {
+ return new AvailableNfcAntenna(in);
+ }
+
+ @Override
+ public AvailableNfcAntenna[] newArray(int size) {
+ return new AvailableNfcAntenna[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mLocationX);
+ dest.writeInt(mLocationY);
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + mLocationX;
+ result = prime * result + mLocationY;
+ return result;
+ }
+
+ /**
+ * Returns true if the specified AvailableNfcAntenna contains
+ * identical specifications.
+ */
+ @Override
+ public boolean equals(@Nullable Object obj) {
+ if (this == obj) return true;
+ if (obj == null) return false;
+ if (getClass() != obj.getClass()) return false;
+ AvailableNfcAntenna other = (AvailableNfcAntenna) obj;
+ if (this.mLocationX != other.mLocationX) return false;
+ return this.mLocationY == other.mLocationY;
+ }
+
+ @Override
+ public String toString() {
+ return "AvailableNfcAntenna " + "x: " + mLocationX + " y: " + mLocationY;
+ }
+}
diff --git a/core/java/android/nfc/INfcAdapter.aidl b/core/java/android/nfc/INfcAdapter.aidl
index cb9a3e4..de107a2 100644
--- a/core/java/android/nfc/INfcAdapter.aidl
+++ b/core/java/android/nfc/INfcAdapter.aidl
@@ -31,6 +31,7 @@
import android.nfc.INfcUnlockHandler;
import android.nfc.ITagRemovedCallback;
import android.nfc.INfcDta;
+import android.nfc.NfcAntennaInfo;
import android.os.Bundle;
/**
@@ -72,6 +73,7 @@
boolean isNfcSecureEnabled();
boolean deviceSupportsNfcSecure();
boolean setNfcSecure(boolean enable);
+ NfcAntennaInfo getNfcAntennaInfo();
boolean setControllerAlwaysOn(boolean value);
boolean isControllerAlwaysOn();
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index 3282d56..f545c30 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -18,6 +18,7 @@
import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
@@ -1854,6 +1855,36 @@
}
/**
+ * Returns information regarding Nfc antennas on the device
+ * such as their relative positioning on the device.
+ *
+ * @return Information on the nfc antenna(s) on the device.
+ * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
+ */
+ @Nullable
+ public NfcAntennaInfo getNfcAntennaInfo() {
+ if (!sHasNfcFeature) {
+ throw new UnsupportedOperationException();
+ }
+ try {
+ return sService.getNfcAntennaInfo();
+ } catch (RemoteException e) {
+ attemptDeadServiceRecovery(e);
+ // Try one more time
+ if (sService == null) {
+ Log.e(TAG, "Failed to recover NFC Service.");
+ return null;
+ }
+ try {
+ return sService.getNfcAntennaInfo();
+ } catch (RemoteException ee) {
+ Log.e(TAG, "Failed to recover NFC Service.");
+ }
+ return null;
+ }
+ }
+
+ /**
* Checks Secure NFC feature is enabled.
*
* @return True if Secure NFC is enabled, false otherwise
diff --git a/core/java/android/nfc/NfcAntennaInfo.aidl b/core/java/android/nfc/NfcAntennaInfo.aidl
new file mode 100644
index 0000000..d5e79fc
--- /dev/null
+++ b/core/java/android/nfc/NfcAntennaInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.nfc;
+
+parcelable NfcAntennaInfo;
diff --git a/core/java/android/nfc/NfcAntennaInfo.java b/core/java/android/nfc/NfcAntennaInfo.java
new file mode 100644
index 0000000..d54fcd2
--- /dev/null
+++ b/core/java/android/nfc/NfcAntennaInfo.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.nfc;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+/**
+ * Contains information on all available Nfc
+ * antennas on an Android device as well as information
+ * on the device itself in relation positioning of the
+ * antennas.
+ */
+public final class NfcAntennaInfo implements Parcelable {
+ // Width of the device in millimeters.
+ private final int mDeviceWidth;
+ // Height of the device in millimeters.
+ private final int mDeviceHeight;
+ // Whether the device is foldable.
+ private final boolean mDeviceFoldable;
+ // All available Nfc Antennas on the device.
+ private final List<AvailableNfcAntenna> mAvailableNfcAntennas;
+
+ public NfcAntennaInfo(int deviceWidth, int deviceHeight, boolean deviceFoldable,
+ @NonNull List<AvailableNfcAntenna> availableNfcAntennas) {
+ this.mDeviceWidth = deviceWidth;
+ this.mDeviceHeight = deviceHeight;
+ this.mDeviceFoldable = deviceFoldable;
+ this.mAvailableNfcAntennas = availableNfcAntennas;
+ }
+
+ /**
+ * Width of the device in millimeters.
+ */
+ public int getDeviceWidth() {
+ return mDeviceWidth;
+ }
+
+ /**
+ * Height of the device in millimeters.
+ */
+ public int getDeviceHeight() {
+ return mDeviceHeight;
+ }
+
+ /**
+ * Whether the device is foldable. When the device is foldable,
+ * the 0, 0 is considered to be bottom-left when the device is unfolded and
+ * the screens are facing the user. For non-foldable devices 0, 0
+ * is bottom-left when the user is facing the screen.
+ */
+ public boolean isDeviceFoldable() {
+ return mDeviceFoldable;
+ }
+
+ /**
+ * Get all NFC antennas that exist on the device.
+ */
+ @NonNull
+ public List<AvailableNfcAntenna> getAvailableNfcAntennas() {
+ return mAvailableNfcAntennas;
+ }
+
+ private NfcAntennaInfo(Parcel in) {
+ this.mDeviceWidth = in.readInt();
+ this.mDeviceHeight = in.readInt();
+ this.mDeviceFoldable = in.readByte() != 0;
+ this.mAvailableNfcAntennas = new ArrayList<>();
+ in.readParcelableList(this.mAvailableNfcAntennas,
+ AvailableNfcAntenna.class.getClassLoader());
+ }
+
+ public static final @NonNull Parcelable.Creator<NfcAntennaInfo> CREATOR =
+ new Parcelable.Creator<NfcAntennaInfo>() {
+ @Override
+ public NfcAntennaInfo createFromParcel(Parcel in) {
+ return new NfcAntennaInfo(in);
+ }
+
+ @Override
+ public NfcAntennaInfo[] newArray(int size) {
+ return new NfcAntennaInfo[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mDeviceWidth);
+ dest.writeInt(mDeviceHeight);
+ dest.writeByte((byte) (mDeviceFoldable ? 1 : 0));
+ dest.writeTypedList(mAvailableNfcAntennas, 0);
+ }
+}
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index 3d10661..0f3ed19 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -328,16 +328,28 @@
public static final native boolean isDirectlyHandlingTransaction();
/**
+ * Returns {@code true} if the current thread has had its identity
+ * set explicitly via {@link #clearCallingIdentity()}
+ *
+ * @hide
+ */
+ @CriticalNative
+ private static native boolean hasExplicitIdentity();
+
+ /**
* Return the Linux UID assigned to the process that sent the transaction
* currently being processed.
*
* @throws IllegalStateException if the current thread is not currently
- * executing an incoming transaction.
+ * executing an incoming transaction and the calling identity has not been
+ * explicitly set with {@link #clearCallingIdentity()}
*/
public static final int getCallingUidOrThrow() {
- if (!isDirectlyHandlingTransaction()) {
+ if (!isDirectlyHandlingTransaction() && !hasExplicitIdentity()) {
throw new IllegalStateException(
- "Thread is not in a binder transcation");
+ "Thread is not in a binder transaction, "
+ + "and the calling identity has not been "
+ + "explicitly set with clearCallingIdentity");
}
return getCallingUid();
}
diff --git a/core/java/com/android/internal/expresslog/OWNERS b/core/java/com/android/internal/expresslog/OWNERS
new file mode 100644
index 0000000..ee865b1
--- /dev/null
+++ b/core/java/com/android/internal/expresslog/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/stats/OWNERS
diff --git a/core/jni/OWNERS b/core/jni/OWNERS
index a068008..53594e1 100644
--- a/core/jni/OWNERS
+++ b/core/jni/OWNERS
@@ -29,7 +29,7 @@
per-file android_util_AssetManager* = file:/core/java/android/content/res/OWNERS
per-file android_util_StringBlock* = file:/core/java/android/content/res/OWNERS
per-file android_util_XmlBlock* = file:/core/java/android/content/res/OWNERS
-per-file com_android_internal_content_om_OverlayConfig* = file:/core/java/android/content/res/OWNERS
+per-file com_android_internal_content_om_Overlay* = file:/core/java/android/content/res/OWNERS
# Binder related things
per-file android_os_Parcel* = file:platform/frameworks/native:/libs/binder/OWNERS
@@ -99,3 +99,5 @@
# PM
per-file com_android_internal_content_* = file:/PACKAGE_MANAGER_OWNERS
+# Stats/expresslog
+per-file *expresslog* = file:/services/core/java/com/android/server/stats/OWNERS
diff --git a/core/jni/android_media_AudioFormat.h b/core/jni/android_media_AudioFormat.h
index 0e6b587..962b501 100644
--- a/core/jni/android_media_AudioFormat.h
+++ b/core/jni/android_media_AudioFormat.h
@@ -45,8 +45,10 @@
#define ENCODING_MPEGH_BL_L4 24
#define ENCODING_MPEGH_LC_L3 25
#define ENCODING_MPEGH_LC_L4 26
-#define ENCODING_DTS_UHD 27
+#define ENCODING_DTS_UHD_P1 27
#define ENCODING_DRA 28
+#define ENCODING_DTS_HD_MA 29
+#define ENCODING_DTS_UHD_P2 30
#define ENCODING_INVALID 0
#define ENCODING_DEFAULT 1
@@ -112,10 +114,14 @@
return AUDIO_FORMAT_MPEGH_LC_L3;
case ENCODING_MPEGH_LC_L4:
return AUDIO_FORMAT_MPEGH_LC_L4;
- case ENCODING_DTS_UHD:
+ case ENCODING_DTS_UHD_P1:
return AUDIO_FORMAT_DTS_UHD;
case ENCODING_DRA:
return AUDIO_FORMAT_DRA;
+ case ENCODING_DTS_HD_MA:
+ return AUDIO_FORMAT_DTS_HD_MA;
+ case ENCODING_DTS_UHD_P2:
+ return AUDIO_FORMAT_DTS_UHD_P2;
default:
return AUDIO_FORMAT_INVALID;
}
@@ -186,9 +192,13 @@
case AUDIO_FORMAT_MPEGH_LC_L4:
return ENCODING_MPEGH_LC_L4;
case AUDIO_FORMAT_DTS_UHD:
- return ENCODING_DTS_UHD;
+ return ENCODING_DTS_UHD_P1;
case AUDIO_FORMAT_DRA:
return ENCODING_DRA;
+ case AUDIO_FORMAT_DTS_HD_MA:
+ return ENCODING_DTS_HD_MA;
+ case AUDIO_FORMAT_DTS_UHD_P2:
+ return ENCODING_DTS_UHD_P2;
case AUDIO_FORMAT_DEFAULT:
return ENCODING_DEFAULT;
default:
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 01837f4..a7c7d0b 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -983,6 +983,10 @@
IPCThreadState::self()->restoreCallingIdentity(token);
}
+static jboolean android_os_Binder_hasExplicitIdentity() {
+ return IPCThreadState::self()->hasExplicitIdentity();
+}
+
static void android_os_Binder_setThreadStrictModePolicy(jint policyMask)
{
IPCThreadState::self()->setStrictModePolicy(policyMask);
@@ -1079,6 +1083,8 @@
// @CriticalNative
{ "restoreCallingIdentity", "(J)V", (void*)android_os_Binder_restoreCallingIdentity },
// @CriticalNative
+ { "hasExplicitIdentity", "()Z", (void*)android_os_Binder_hasExplicitIdentity },
+ // @CriticalNative
{ "setThreadStrictModePolicy", "(I)V", (void*)android_os_Binder_setThreadStrictModePolicy },
// @CriticalNative
{ "getThreadStrictModePolicy", "()I", (void*)android_os_Binder_getThreadStrictModePolicy },
diff --git a/core/res/OWNERS b/core/res/OWNERS
index 22f40a1..6d05e07 100644
--- a/core/res/OWNERS
+++ b/core/res/OWNERS
@@ -1,5 +1,4 @@
adamp@google.com
-alanv@google.com
asc@google.com
cinek@google.com
dsandler@android.com
@@ -20,9 +19,6 @@
ogunwale@google.com
patb@google.com
shanh@google.com
-svetoslavganov@android.com
-svetoslavganov@google.com
-toddke@google.com
tsuji@google.com
yamasani@google.com
diff --git a/core/tests/coretests/src/android/os/BinderTest.java b/core/tests/coretests/src/android/os/BinderTest.java
index 99dbe64..02f8790 100644
--- a/core/tests/coretests/src/android/os/BinderTest.java
+++ b/core/tests/coretests/src/android/os/BinderTest.java
@@ -20,6 +20,8 @@
import junit.framework.TestCase;
+import static org.testng.Assert.assertThrows;
+
public class BinderTest extends TestCase {
private static final int UID = 100;
@@ -45,12 +47,8 @@
}
@SmallTest
- public void testGetCallingUidOrThrow() throws Exception {
- try {
- Binder.getCallingUidOrThrow();
- throw new AssertionError("IllegalStateException expected");
- } catch (IllegalStateException expected) {
- }
+ public void testGetCallingUidOrThrow_throws() throws Exception {
+ assertThrows(IllegalStateException.class, () -> Binder.getCallingUidOrThrow());
}
@SmallTest
diff --git a/data/keyboards/Generic.kl b/data/keyboards/Generic.kl
index c81473d..8e7c6a8 100644
--- a/data/keyboards/Generic.kl
+++ b/data/keyboards/Generic.kl
@@ -363,6 +363,7 @@
# key 413 "KEY_DIGITS"
# key 414 "KEY_TEEN"
# key 415 "KEY_TWEN"
+key 528 FOCUS
key 429 CONTACTS
diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java
index d06bbc6..b8090c4 100644
--- a/media/java/android/media/AudioFormat.java
+++ b/media/java/android/media/AudioFormat.java
@@ -350,10 +350,29 @@
public static final int ENCODING_MPEGH_LC_L3 = 25;
/** Audio data format: MPEG-H low complexity profile, level 4 */
public static final int ENCODING_MPEGH_LC_L4 = 26;
- /** Audio data format: DTS UHD compressed */
- public static final int ENCODING_DTS_UHD = 27;
+ /** Audio data format: DTS UHD Profile-1 compressed (aka DTS:X Profile 1)
+ * Has the same meaning and value as ENCODING_DTS_UHD_P1.
+ * @deprecated Use {@link #ENCODING_DTS_UHD_P1} instead. */
+ @Deprecated public static final int ENCODING_DTS_UHD = 27;
/** Audio data format: DRA compressed */
public static final int ENCODING_DRA = 28;
+ /** Audio data format: DTS HD Master Audio compressed
+ * DTS HD Master Audio stream is variable bit rate and contains lossless audio.
+ * Use {@link #ENCODING_DTS_HD_MA} for lossless audio content (DTS-HD MA Lossless)
+ * and use {@link #ENCODING_DTS_HD} for other DTS bitstreams with extension substream
+ * (DTS 8Ch Discrete, DTS Hi Res, DTS Express). */
+ public static final int ENCODING_DTS_HD_MA = 29;
+ /** Audio data format: DTS UHD Profile-1 compressed (aka DTS:X Profile 1)
+ * Has the same meaning and value as the deprecated {@link #ENCODING_DTS_UHD}.*/
+ public static final int ENCODING_DTS_UHD_P1 = 27;
+ /** Audio data format: DTS UHD Profile-2 compressed
+ * DTS-UHD Profile-2 supports delivery of Channel-Based Audio, Object-Based Audio
+ * and High Order Ambisonic presentations up to the fourth order.
+ * Use {@link #ENCODING_DTS_UHD_P1} to transmit DTS UHD Profile 1 (aka DTS:X Profile 1)
+ * bitstream.
+ * Use {@link #ENCODING_DTS_UHD_P2} to transmit DTS UHD Profile 2 (aka DTS:X Profile 2)
+ * bitstream. */
+ public static final int ENCODING_DTS_UHD_P2 = 30;
/** @hide */
public static String toLogFriendlyEncoding(int enc) {
@@ -410,10 +429,14 @@
return "ENCODING_MPEGH_LC_L3";
case ENCODING_MPEGH_LC_L4:
return "ENCODING_MPEGH_LC_L4";
- case ENCODING_DTS_UHD:
- return "ENCODING_DTS_UHD";
+ case ENCODING_DTS_UHD_P1:
+ return "ENCODING_DTS_UHD_P1";
case ENCODING_DRA:
return "ENCODING_DRA";
+ case ENCODING_DTS_HD_MA:
+ return "ENCODING_DTS_HD_MA";
+ case ENCODING_DTS_UHD_P2:
+ return "ENCODING_DTS_UHD_P2";
default :
return "invalid encoding " + enc;
}
@@ -768,8 +791,10 @@
case ENCODING_MPEGH_BL_L4:
case ENCODING_MPEGH_LC_L3:
case ENCODING_MPEGH_LC_L4:
- case ENCODING_DTS_UHD:
+ case ENCODING_DTS_UHD_P1:
case ENCODING_DRA:
+ case ENCODING_DTS_HD_MA:
+ case ENCODING_DTS_UHD_P2:
return true;
default:
return false;
@@ -805,8 +830,10 @@
case ENCODING_MPEGH_BL_L4:
case ENCODING_MPEGH_LC_L3:
case ENCODING_MPEGH_LC_L4:
- case ENCODING_DTS_UHD:
+ case ENCODING_DTS_UHD_P1:
case ENCODING_DRA:
+ case ENCODING_DTS_HD_MA:
+ case ENCODING_DTS_UHD_P2:
return true;
default:
return false;
@@ -845,8 +872,10 @@
case ENCODING_MPEGH_BL_L4:
case ENCODING_MPEGH_LC_L3:
case ENCODING_MPEGH_LC_L4:
- case ENCODING_DTS_UHD:
+ case ENCODING_DTS_UHD_P1:
case ENCODING_DRA:
+ case ENCODING_DTS_HD_MA:
+ case ENCODING_DTS_UHD_P2:
return false;
case ENCODING_INVALID:
default:
@@ -885,8 +914,10 @@
case ENCODING_MPEGH_BL_L4:
case ENCODING_MPEGH_LC_L3:
case ENCODING_MPEGH_LC_L4:
- case ENCODING_DTS_UHD:
+ case ENCODING_DTS_UHD_P1:
case ENCODING_DRA:
+ case ENCODING_DTS_HD_MA:
+ case ENCODING_DTS_UHD_P2:
return false;
case ENCODING_INVALID:
default:
@@ -1173,8 +1204,10 @@
case ENCODING_MPEGH_BL_L4:
case ENCODING_MPEGH_LC_L3:
case ENCODING_MPEGH_LC_L4:
- case ENCODING_DTS_UHD:
+ case ENCODING_DTS_UHD_P1:
case ENCODING_DRA:
+ case ENCODING_DTS_HD_MA:
+ case ENCODING_DTS_UHD_P2:
mEncoding = encoding;
break;
case ENCODING_INVALID:
@@ -1402,8 +1435,10 @@
ENCODING_MPEGH_BL_L4,
ENCODING_MPEGH_LC_L3,
ENCODING_MPEGH_LC_L4,
- ENCODING_DTS_UHD,
- ENCODING_DRA }
+ ENCODING_DTS_UHD_P1,
+ ENCODING_DRA,
+ ENCODING_DTS_HD_MA,
+ ENCODING_DTS_UHD_P2 }
)
@Retention(RetentionPolicy.SOURCE)
public @interface Encoding {}
@@ -1423,8 +1458,10 @@
ENCODING_MPEGH_BL_L4,
ENCODING_MPEGH_LC_L3,
ENCODING_MPEGH_LC_L4,
- ENCODING_DTS_UHD,
- ENCODING_DRA
+ ENCODING_DTS_UHD_P1,
+ ENCODING_DRA,
+ ENCODING_DTS_HD_MA,
+ ENCODING_DTS_UHD_P2
};
/** @hide */
@@ -1442,8 +1479,10 @@
ENCODING_MPEGH_BL_L4,
ENCODING_MPEGH_LC_L3,
ENCODING_MPEGH_LC_L4,
- ENCODING_DTS_UHD,
- ENCODING_DRA }
+ ENCODING_DTS_UHD_P1,
+ ENCODING_DRA,
+ ENCODING_DTS_HD_MA,
+ ENCODING_DTS_UHD_P2 }
)
@Retention(RetentionPolicy.SOURCE)
public @interface SurroundSoundEncoding {}
@@ -1485,10 +1524,14 @@
return "MPEG-H 3D Audio low complexity profile level 3";
case ENCODING_MPEGH_LC_L4:
return "MPEG-H 3D Audio low complexity profile level 4";
- case ENCODING_DTS_UHD:
- return "DTS UHD";
+ case ENCODING_DTS_UHD_P1:
+ return "DTS UHD Profile 1";
case ENCODING_DRA:
return "DRA";
+ case ENCODING_DTS_HD_MA:
+ return "DTS HD Master Audio";
+ case ENCODING_DTS_UHD_P2:
+ return "DTS UHD Profile 2";
default:
return "Unknown surround sound format";
}
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index b7282218..e6896bc 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -443,6 +443,10 @@
return "AUDIO_FORMAT_APTX_ADAPTIVE_QLEA";
case /* AUDIO_FORMAT_APTX_ADAPTIVE_R4 */ 0x31000000:
return "AUDIO_FORMAT_APTX_ADAPTIVE_R4";
+ case /* AUDIO_FORMAT_DTS_HD_MA */ 0x32000000:
+ return "AUDIO_FORMAT_DTS_HD_MA";
+ case /* AUDIO_FORMAT_DTS_UHD_P2 */ 0x33000000:
+ return "AUDIO_FORMAT_DTS_UHD_P2";
/* Aliases */
case /* AUDIO_FORMAT_PCM_16_BIT */ 0x1:
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index 62d14e1..659aafe 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -3751,6 +3751,11 @@
// Skip input stream to the end of the EXIF chunk
totalInputStream.skipBytes(WEBP_CHUNK_TYPE_BYTE_LENGTH);
int exifChunkLength = totalInputStream.readInt();
+ // RIFF chunks have a single padding byte at the end if the declared chunk size is
+ // odd.
+ if (exifChunkLength % 2 != 0) {
+ exifChunkLength++;
+ }
totalInputStream.skipBytes(exifChunkLength);
// Write new EXIF chunk to output stream
@@ -3821,7 +3826,7 @@
int widthAndHeight = 0;
int width = 0;
int height = 0;
- int alpha = 0;
+ boolean alpha = false;
// Save VP8 frame data for later
byte[] vp8Frame = new byte[3];
@@ -3856,7 +3861,7 @@
width = ((widthAndHeight << 18) >> 18) + 1;
height = ((widthAndHeight << 4) >> 18) + 1;
// Retrieve alpha bit
- alpha = widthAndHeight & (1 << 3);
+ alpha = (widthAndHeight & (1 << 28)) != 0;
bytesToRead -= (1 /* VP8L signature */ + 4);
}
@@ -3864,10 +3869,12 @@
nonHeaderOutputStream.write(WEBP_CHUNK_TYPE_VP8X);
nonHeaderOutputStream.writeInt(WEBP_CHUNK_TYPE_VP8X_DEFAULT_LENGTH);
byte[] data = new byte[WEBP_CHUNK_TYPE_VP8X_DEFAULT_LENGTH];
+ // ALPHA flag
+ if (alpha) {
+ data[0] = (byte) (data[0] | (1 << 4));
+ }
// EXIF flag
data[0] = (byte) (data[0] | (1 << 3));
- // ALPHA flag
- data[0] = (byte) (data[0] | (alpha << 4));
// VP8X stores Width - 1 and Height - 1 values
width -= 1;
height -= 1;
diff --git a/media/java/android/media/audio/common/AidlConversion.java b/media/java/android/media/audio/common/AidlConversion.java
index 491a8ec..6a5eae6 100644
--- a/media/java/android/media/audio/common/AidlConversion.java
+++ b/media/java/android/media/audio/common/AidlConversion.java
@@ -515,7 +515,7 @@
} else if (MediaFormat.MIMETYPE_AUDIO_MPEGH_LC_L4.equals(aidl.encoding)) {
return AudioFormat.ENCODING_MPEGH_LC_L4;
} else if (MediaFormat.MIMETYPE_AUDIO_DTS_UHD.equals(aidl.encoding)) {
- return AudioFormat.ENCODING_DTS_UHD;
+ return AudioFormat.ENCODING_DTS_UHD_P1;
} else if (MediaFormat.MIMETYPE_AUDIO_DRA.equals(aidl.encoding)) {
return AudioFormat.ENCODING_DRA;
} else {
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ExifInterfaceTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ExifInterfaceTest.java
index 195df78..006f4e9 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ExifInterfaceTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ExifInterfaceTest.java
@@ -23,6 +23,7 @@
import android.graphics.BitmapFactory;
import android.media.ExifInterface;
import android.os.Environment;
+import android.os.FileUtils;
import android.test.AndroidTestCase;
import android.util.Log;
import android.system.ErrnoException;
@@ -37,6 +38,8 @@
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Objects;
import libcore.io.IoUtils;
import libcore.io.Streams;
@@ -353,20 +356,23 @@
}
}
- private void testSaveAttributes_withFileName(File imageFile, ExpectedValue expectedValue)
+ private void testSaveAttributes_withFileName(File srcFile, ExpectedValue expectedValue)
throws IOException {
+ File imageFile = clone(srcFile);
String verboseTag = imageFile.getName();
ExifInterface exifInterface = new ExifInterface(imageFile.getAbsolutePath());
exifInterface.saveAttributes();
exifInterface = new ExifInterface(imageFile.getAbsolutePath());
compareWithExpectedValue(exifInterface, expectedValue, verboseTag);
+ assertBitmapsEquivalent(srcFile, imageFile);
+ assertSecondSaveProducesSameSizeFile(imageFile);
// Test for modifying one attribute.
+ exifInterface = new ExifInterface(imageFile.getAbsolutePath());
String backupValue = exifInterface.getAttribute(ExifInterface.TAG_MAKE);
exifInterface.setAttribute(ExifInterface.TAG_MAKE, "abc");
exifInterface.saveAttributes();
- exifInterface = new ExifInterface(imageFile.getAbsolutePath());
assertEquals("abc", exifInterface.getAttribute(ExifInterface.TAG_MAKE));
// Restore the backup value.
exifInterface.setAttribute(ExifInterface.TAG_MAKE, backupValue);
@@ -481,4 +487,56 @@
// Test if it is possible to parse the volantis generated JPEG smoothly.
testExifInterfaceForJpeg(VOLANTIS_JPEG, R.array.volantis_jpg);
}
+
+ /**
+ * Asserts that {@code expectedImageFile} and {@code actualImageFile} can be decoded by
+ * {@link BitmapFactory} and the results have the same width, height and MIME type.
+ *
+ * <p>This does not check the image itself for similarity/equality.
+ */
+ private void assertBitmapsEquivalent(File expectedImageFile, File actualImageFile) {
+ BitmapFactory.Options expectedOptions = new BitmapFactory.Options();
+ Bitmap expectedBitmap = Objects.requireNonNull(
+ BitmapFactory.decodeFile(expectedImageFile.getAbsolutePath(), expectedOptions));
+ BitmapFactory.Options actualOptions = new BitmapFactory.Options();
+ Bitmap actualBitmap = Objects.requireNonNull(
+ BitmapFactory.decodeFile(actualImageFile.getAbsolutePath(), actualOptions));
+
+ assertEquals(expectedOptions.outWidth, actualOptions.outWidth);
+ assertEquals(expectedOptions.outHeight, actualOptions.outHeight);
+ assertEquals(expectedOptions.outMimeType, actualOptions.outMimeType);
+ assertEquals(expectedBitmap.getWidth(), actualBitmap.getWidth());
+ assertEquals(expectedBitmap.getHeight(), actualBitmap.getHeight());
+ }
+
+ /**
+ * Asserts that saving the file the second time (without modifying any attributes) produces
+ * exactly the same length file as the first save. The first save (with no modifications) is
+ * expected to (possibly) change the file length because {@link ExifInterface} may move/reformat
+ * the Exif block within the file, but the second save should not make further modifications.
+ */
+ private void assertSecondSaveProducesSameSizeFile(File imageFileAfterOneSave)
+ throws IOException {
+ File imageFileAfterTwoSaves = clone(imageFileAfterOneSave);
+ ExifInterface exifInterface = new ExifInterface(imageFileAfterTwoSaves.getAbsolutePath());
+ exifInterface.saveAttributes();
+ if (imageFileAfterOneSave.getAbsolutePath().endsWith(".png")
+ || imageFileAfterOneSave.getAbsolutePath().endsWith(".webp")) {
+ // PNG and (some) WebP files are (surprisingly) modified between the first and second
+ // save (b/249097443), so we check the difference between second and third save instead.
+ File imageFileAfterThreeSaves = clone(imageFileAfterTwoSaves);
+ exifInterface = new ExifInterface(imageFileAfterThreeSaves.getAbsolutePath());
+ exifInterface.saveAttributes();
+ assertEquals(imageFileAfterTwoSaves.length(), imageFileAfterThreeSaves.length());
+ } else {
+ assertEquals(imageFileAfterOneSave.length(), imageFileAfterTwoSaves.length());
+ }
+ }
+
+ private static File clone(File original) throws IOException {
+ final File cloned =
+ File.createTempFile("tmp_", +System.nanoTime() + "_" + original.getName());
+ FileUtils.copyFileOrThrow(original, cloned);
+ return cloned;
+ }
}
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetXmlUtil.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetXmlUtil.java
index 6a5dcc8..2aca99c 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetXmlUtil.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetXmlUtil.java
@@ -111,7 +111,7 @@
info.minWidth = parser.getAttributeInt(null, ATTR_MIN_WIDTH, 0);
info.minHeight = parser.getAttributeInt(null, ATTR_MIN_HEIGHT, 0);
info.minResizeWidth = parser.getAttributeInt(null, ATTR_MIN_RESIZE_WIDTH, 0);
- info.minResizeWidth = parser.getAttributeInt(null, ATTR_MIN_RESIZE_HEIGHT, 0);
+ info.minResizeHeight = parser.getAttributeInt(null, ATTR_MIN_RESIZE_HEIGHT, 0);
info.maxResizeWidth = parser.getAttributeInt(null, ATTR_MAX_RESIZE_WIDTH, 0);
info.maxResizeHeight = parser.getAttributeInt(null, ATTR_MAX_RESIZE_HEIGHT, 0);
info.targetCellWidth = parser.getAttributeInt(null, ATTR_TARGET_CELL_WIDTH, 0);
diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java
index 76cac93..61f7f30 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -18,8 +18,11 @@
import static android.Manifest.permission.DUMP;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_TEST;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static android.net.vcn.VcnGatewayConnectionConfig.ALLOWED_CAPABILITIES;
+import static android.net.vcn.VcnManager.VCN_RESTRICTED_TRANSPORTS_INT_ARRAY_KEY;
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE;
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_INACTIVE;
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED;
@@ -53,6 +56,7 @@
import android.net.vcn.VcnUnderlyingNetworkPolicy;
import android.net.wifi.WifiInfo;
import android.os.Binder;
+import android.os.Build;
import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread;
@@ -68,6 +72,7 @@
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.LocalLog;
import android.util.Log;
import android.util.Slog;
@@ -83,6 +88,7 @@
import com.android.server.vcn.VcnContext;
import com.android.server.vcn.VcnNetworkProvider;
import com.android.server.vcn.util.PersistableBundleUtils;
+import com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper;
import java.io.File;
import java.io.FileDescriptor;
@@ -159,6 +165,9 @@
private static final long DUMP_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(5);
private static final int LOCAL_LOG_LINE_COUNT = 512;
+ private static final Set<Integer> RESTRICTED_TRANSPORTS_DEFAULT =
+ Collections.singleton(TRANSPORT_WIFI);
+
// Public for use in all other VCN classes
@NonNull public static final LocalLog LOCAL_LOG = new LocalLog(LOCAL_LOG_LINE_COUNT);
@@ -361,6 +370,34 @@
public LocationPermissionChecker newLocationPermissionChecker(@NonNull Context context) {
return new LocationPermissionChecker(context);
}
+
+ /** Gets the transports that need to be marked as restricted by the VCN */
+ public Set<Integer> getRestrictedTransports(
+ ParcelUuid subGrp, TelephonySubscriptionSnapshot lastSnapshot) {
+ if (!Build.IS_ENG && !Build.IS_USERDEBUG) {
+ return RESTRICTED_TRANSPORTS_DEFAULT;
+ }
+
+ final PersistableBundleWrapper carrierConfig =
+ lastSnapshot.getCarrierConfigForSubGrp(subGrp);
+ if (carrierConfig == null) {
+ return RESTRICTED_TRANSPORTS_DEFAULT;
+ }
+
+ final int[] defaultValue =
+ RESTRICTED_TRANSPORTS_DEFAULT.stream().mapToInt(i -> i).toArray();
+ final int[] restrictedTransportsArray =
+ carrierConfig.getIntArray(
+ VCN_RESTRICTED_TRANSPORTS_INT_ARRAY_KEY,
+ defaultValue);
+
+ // Convert to a boxed set
+ final Set<Integer> restrictedTransports = new ArraySet<>();
+ for (int transport : restrictedTransportsArray) {
+ restrictedTransports.add(transport);
+ }
+ return restrictedTransports;
+ }
}
/** Notifies the VcnManagementService that external dependencies can be set up. */
@@ -517,6 +554,7 @@
}
}
+ boolean needNotifyAllPolicyListeners = false;
// Schedule teardown of any VCN instances that have lost carrier privileges (after a
// delay)
for (Entry<ParcelUuid, Vcn> entry : mVcns.entrySet()) {
@@ -564,6 +602,10 @@
} else {
// If this VCN's status has not changed, update it with the new snapshot
entry.getValue().updateSubscriptionSnapshot(mLastSnapshot);
+ needNotifyAllPolicyListeners |=
+ !Objects.equals(
+ oldSnapshot.getCarrierConfigForSubGrp(subGrp),
+ mLastSnapshot.getCarrierConfigForSubGrp(subGrp));
}
}
@@ -573,6 +615,10 @@
getSubGroupToSubIdMappings(mLastSnapshot);
if (!currSubGrpMappings.equals(oldSubGrpMappings)) {
garbageCollectAndWriteVcnConfigsLocked();
+ needNotifyAllPolicyListeners = true;
+ }
+
+ if (needNotifyAllPolicyListeners) {
notifyAllPolicyListenersLocked();
}
}
@@ -917,6 +963,14 @@
});
}
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ void addVcnUnderlyingNetworkPolicyListenerForTest(
+ @NonNull IVcnUnderlyingNetworkPolicyListener listener) {
+ synchronized (mLock) {
+ addVcnUnderlyingNetworkPolicyListener(listener);
+ }
+ }
+
/** Removes the provided listener from receiving VcnUnderlyingNetworkPolicy updates. */
@GuardedBy("mLock")
@Override
@@ -1000,7 +1054,7 @@
final ParcelUuid subGrp = getSubGroupForNetworkCapabilities(ncCopy);
boolean isVcnManagedNetwork = false;
- boolean isRestrictedCarrierWifi = false;
+ boolean isRestricted = false;
synchronized (mLock) {
final Vcn vcn = mVcns.get(subGrp);
if (vcn != null) {
@@ -1008,9 +1062,19 @@
isVcnManagedNetwork = true;
}
- if (ncCopy.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
- // Carrier WiFi always restricted if VCN exists (even in safe mode).
- isRestrictedCarrierWifi = true;
+ final Set<Integer> restrictedTransports =
+ mDeps.getRestrictedTransports(subGrp, mLastSnapshot);
+ for (int restrictedTransport : restrictedTransports) {
+ if (ncCopy.hasTransport(restrictedTransport)) {
+ if (restrictedTransport == TRANSPORT_CELLULAR) {
+ // Only make a cell network as restricted when the VCN is in
+ // active mode.
+ isRestricted |= (vcn.getStatus() == VCN_STATUS_CODE_ACTIVE);
+ } else {
+ isRestricted = true;
+ break;
+ }
+ }
}
}
}
@@ -1024,14 +1088,16 @@
ncBuilder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED);
}
- if (isRestrictedCarrierWifi) {
+ if (isRestricted) {
ncBuilder.removeCapability(
NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
}
final NetworkCapabilities result = ncBuilder.build();
final VcnUnderlyingNetworkPolicy policy = new VcnUnderlyingNetworkPolicy(
- mTrackingNetworkCallback.requiresRestartForCarrierWifi(result), result);
+ mTrackingNetworkCallback
+ .requiresRestartForImmutableCapabilityChanges(result),
+ result);
logVdbg("getUnderlyingNetworkPolicy() called for caps: " + networkCapabilities
+ "; and lp: " + linkProperties + "; result = " + policy);
@@ -1296,15 +1362,38 @@
}
}
- private boolean requiresRestartForCarrierWifi(NetworkCapabilities caps) {
- if (!caps.hasTransport(TRANSPORT_WIFI) || caps.getSubscriptionIds() == null) {
+ private Set<Integer> getNonTestTransportTypes(NetworkCapabilities caps) {
+ final Set<Integer> transportTypes = new ArraySet<>();
+ for (int t : caps.getTransportTypes()) {
+ transportTypes.add(t);
+ }
+ return transportTypes;
+ }
+
+ private boolean hasSameTransportsAndCapabilities(
+ NetworkCapabilities caps, NetworkCapabilities capsOther) {
+ if (!Objects.equals(
+ getNonTestTransportTypes(caps), getNonTestTransportTypes(capsOther))) {
+ return false;
+ }
+
+ for (int capability : ALLOWED_CAPABILITIES) {
+ if (caps.hasCapability(capability) != capsOther.hasCapability(capability)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private boolean requiresRestartForImmutableCapabilityChanges(NetworkCapabilities caps) {
+ if (caps.getSubscriptionIds() == null) {
return false;
}
synchronized (mCaps) {
for (NetworkCapabilities existing : mCaps.values()) {
- if (existing.hasTransport(TRANSPORT_WIFI)
- && caps.getSubscriptionIds().equals(existing.getSubscriptionIds())) {
+ if (caps.getSubscriptionIds().equals(existing.getSubscriptionIds())
+ && hasSameTransportsAndCapabilities(caps, existing)) {
// Restart if any immutable capabilities have changed
return existing.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)
!= caps.hasCapability(NET_CAPABILITY_NOT_RESTRICTED);
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 9bce471f..8a22ab9 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -837,7 +837,7 @@
void enableAudioReturnChannel(boolean enabled) {
assertRunOnServiceThread();
HdmiDeviceInfo avr = getAvrDeviceInfo();
- if (avr != null) {
+ if (avr != null && avr.getPortId() != Constants.INVALID_PORT_ID) {
mService.enableAudioReturnChannel(avr.getPortId(), enabled);
}
}
@@ -1336,19 +1336,31 @@
}
@ServiceThreadOnly
+ private void forceDisableArcOnAllPins() {
+ List<HdmiPortInfo> ports = mService.getPortInfo();
+ for (HdmiPortInfo port : ports) {
+ if (isArcFeatureEnabled(port.getId())) {
+ mService.enableAudioReturnChannel(port.getId(), false);
+ }
+ }
+ }
+
+ @ServiceThreadOnly
private void disableArcIfExist() {
assertRunOnServiceThread();
HdmiDeviceInfo avr = getAvrDeviceInfo();
if (avr == null) {
return;
}
- disableArc();
// Seq #44.
removeAllRunningArcAction();
if (!hasAction(RequestArcTerminationAction.class) && isArcEstablished()) {
addAndStartAction(new RequestArcTerminationAction(this, avr.getLogicalAddress()));
}
+
+ // Disable ARC Pin earlier, prevent the case where AVR doesn't send <Terminate ARC> in time
+ forceDisableArcOnAllPins();
}
@ServiceThreadOnly
diff --git a/services/core/java/com/android/server/locales/OWNERS b/services/core/java/com/android/server/locales/OWNERS
index 4d93bff..e1e946b 100644
--- a/services/core/java/com/android/server/locales/OWNERS
+++ b/services/core/java/com/android/server/locales/OWNERS
@@ -2,3 +2,6 @@
pratyushmore@google.com
goldmanj@google.com
ankitavyas@google.com
+allenwtsu@google.com
+calvinpan@google.com
+joshhou@google.com
diff --git a/services/core/java/com/android/server/notification/PermissionHelper.java b/services/core/java/com/android/server/notification/PermissionHelper.java
index 09ed567..14e82f3 100644
--- a/services/core/java/com/android/server/notification/PermissionHelper.java
+++ b/services/core/java/com/android/server/notification/PermissionHelper.java
@@ -257,9 +257,11 @@
private boolean packageRequestsNotificationPermission(String packageName,
@UserIdInt int userId) {
try {
- String[] permissions = mPackageManager.getPackageInfo(packageName, GET_PERMISSIONS,
- userId).requestedPermissions;
- return ArrayUtils.contains(permissions, NOTIFICATION_PERMISSION);
+ PackageInfo pi = mPackageManager.getPackageInfo(packageName, GET_PERMISSIONS, userId);
+ if (pi != null) {
+ String[] permissions = pi.requestedPermissions;
+ return ArrayUtils.contains(permissions, NOTIFICATION_PERMISSION);
+ }
} catch (RemoteException e) {
Slog.e(TAG, "Could not reach system server", e);
}
diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java
index 259ca65..52cc83a 100644
--- a/services/core/java/com/android/server/pm/ComputerEngine.java
+++ b/services/core/java/com/android/server/pm/ComputerEngine.java
@@ -5718,7 +5718,8 @@
return PackageInfoUtils.generateProcessInfo(sus.processes, 0);
} else if (settingBase instanceof PackageSetting) {
final PackageSetting ps = (PackageSetting) settingBase;
- return PackageInfoUtils.generateProcessInfo(ps.getPkg().getProcesses(), 0);
+ final AndroidPackage pkg = ps.getPkg();
+ return pkg == null ? null : PackageInfoUtils.generateProcessInfo(pkg.getProcesses(), 0);
}
return null;
}
diff --git a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
index 5c305c6..ca4a32f 100644
--- a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
+++ b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
@@ -390,8 +390,13 @@
Objects.requireNonNull(privilegedPackages, "privilegedPackages was null");
Objects.requireNonNull(subIdToCarrierConfigMap, "subIdToCarrierConfigMap was null");
- mSubIdToInfoMap = Collections.unmodifiableMap(subIdToInfoMap);
- mSubIdToCarrierConfigMap = Collections.unmodifiableMap(subIdToCarrierConfigMap);
+ mSubIdToInfoMap =
+ Collections.unmodifiableMap(
+ new HashMap<Integer, SubscriptionInfo>(subIdToInfoMap));
+ mSubIdToCarrierConfigMap =
+ Collections.unmodifiableMap(
+ new HashMap<Integer, PersistableBundleWrapper>(
+ subIdToCarrierConfigMap));
final Map<ParcelUuid, Set<String>> unmodifiableInnerSets = new ArrayMap<>();
for (Entry<ParcelUuid, Set<String>> entry : privilegedPackages.entrySet()) {
diff --git a/services/core/java/com/android/server/vcn/util/PersistableBundleUtils.java b/services/core/java/com/android/server/vcn/util/PersistableBundleUtils.java
index 999d406..d22ec0a 100644
--- a/services/core/java/com/android/server/vcn/util/PersistableBundleUtils.java
+++ b/services/core/java/com/android/server/vcn/util/PersistableBundleUtils.java
@@ -544,6 +544,20 @@
return mBundle.getInt(key, defaultValue);
}
+ /**
+ * Returns the value associated with the given key, or null if no mapping of the desired
+ * type exists for the given key or a null value is explicitly associated with the key.
+ *
+ * @param key a String, or null
+ * @param defaultValue the value to return if key does not exist
+ * @return an int[] value, or null
+ */
+ @Nullable
+ public int[] getIntArray(@Nullable String key, @Nullable int[] defaultValue) {
+ final int[] value = mBundle.getIntArray(key);
+ return value == null ? defaultValue : value;
+ }
+
@Override
public int hashCode() {
return getHashCode(mBundle);
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 301fca7..93a4ebf 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -132,6 +132,7 @@
"libschedulerservicehidl",
"libsensorservice",
"libsensorservicehidl",
+ "libsensorserviceaidl",
"libgui",
"libtimestats_atoms_proto",
"libusbhost",
@@ -180,6 +181,7 @@
"android.hidl.token@1.0-utils",
"android.frameworks.schedulerservice@1.0",
"android.frameworks.sensorservice@1.0",
+ "android.frameworks.sensorservice-V1-ndk",
"android.frameworks.stats@1.0",
"android.frameworks.stats-V1-ndk",
"android.system.suspend.control-V1-cpp",
diff --git a/services/core/jni/com_android_server_SystemServer.cpp b/services/core/jni/com_android_server_SystemServer.cpp
index b171a07..be18f64 100644
--- a/services/core/jni/com_android_server_SystemServer.cpp
+++ b/services/core/jni/com_android_server_SystemServer.cpp
@@ -14,35 +14,31 @@
* limitations under the License.
*/
-#include <dlfcn.h>
-#include <pthread.h>
-
-#include <chrono>
-#include <thread>
-
-#include <jni.h>
-#include <nativehelper/JNIHelp.h>
-
+#include <android-base/properties.h>
#include <android/binder_manager.h>
#include <android/binder_stability.h>
#include <android/hidl/manager/1.2/IServiceManager.h>
#include <binder/IServiceManager.h>
+#include <bionic/malloc.h>
+#include <bionic/reserved_signals.h>
+#include <dlfcn.h>
#include <hidl/HidlTransportSupport.h>
#include <incremental_service.h>
-
+#include <jni.h>
#include <memtrackproxy/MemtrackProxy.h>
+#include <nativehelper/JNIHelp.h>
+#include <pthread.h>
#include <schedulerservice/SchedulingPolicyService.h>
+#include <sensorserviceaidl/SensorManagerAidl.h>
#include <sensorservicehidl/SensorManager.h>
#include <stats/StatsAidl.h>
#include <stats/StatsHal.h>
-
-#include <bionic/malloc.h>
-#include <bionic/reserved_signals.h>
-
-#include <android-base/properties.h>
+#include <utils/AndroidThreads.h>
#include <utils/Log.h>
#include <utils/misc.h>
-#include <utils/AndroidThreads.h>
+
+#include <chrono>
+#include <thread>
using namespace std::chrono_literals;
@@ -57,7 +53,9 @@
const std::string instance = std::string() + IStats::descriptor + "/default";
const binder_exception_t err =
AServiceManager_addService(statsService->asBinder().get(), instance.c_str());
- LOG_ALWAYS_FATAL_IF(err != EX_NONE, "Cannot register AIDL %s: %d", instance.c_str(), err);
+ if (err != EX_NONE) {
+ ALOGW("Cannot register AIDL %s: %d", instance.c_str(), err);
+ }
}
static void startStatsHidlService() {
@@ -69,6 +67,42 @@
ALOGW_IF(err != android::OK, "Cannot register HIDL %s: %d", IStats::descriptor, err);
}
+static void startSensorManagerAidlService(JNIEnv* env) {
+ using ::aidl::android::frameworks::sensorservice::ISensorManager;
+ using ::android::frameworks::sensorservice::implementation::SensorManagerAidl;
+
+ JavaVM* vm;
+ LOG_ALWAYS_FATAL_IF(env->GetJavaVM(&vm) != JNI_OK, "Cannot get Java VM");
+
+ std::shared_ptr<SensorManagerAidl> sensorService =
+ ndk::SharedRefBase::make<SensorManagerAidl>(vm);
+ const std::string instance = std::string() + ISensorManager::descriptor + "/default";
+ const binder_exception_t err =
+ AServiceManager_addService(sensorService->asBinder().get(), instance.c_str());
+ LOG_ALWAYS_FATAL_IF(err != EX_NONE, "Cannot register AIDL %s: %d", instance.c_str(), err);
+}
+
+static void startSensorManagerHidlService(JNIEnv* env) {
+ using ::android::frameworks::sensorservice::V1_0::ISensorManager;
+ using ::android::frameworks::sensorservice::V1_0::implementation::SensorManager;
+ using ::android::hardware::configureRpcThreadpool;
+ using ::android::hidl::manager::V1_0::IServiceManager;
+
+ JavaVM* vm;
+ LOG_ALWAYS_FATAL_IF(env->GetJavaVM(&vm) != JNI_OK, "Cannot get Java VM");
+
+ android::sp<ISensorManager> sensorService = new SensorManager(vm);
+ if (IServiceManager::Transport::HWBINDER ==
+ android::hardware::defaultServiceManager1_2()->getTransport(ISensorManager::descriptor,
+ "default")) {
+ android::status_t err = sensorService->registerAsService();
+ LOG_ALWAYS_FATAL_IF(err != android::OK, "Cannot register %s: %d",
+ ISensorManager::descriptor, err);
+ } else {
+ ALOGW("%s is deprecated. Skipping registration.", ISensorManager::descriptor);
+ }
+}
+
} // namespace
namespace android {
@@ -78,6 +112,12 @@
startStatsAidlService();
}
+static void android_server_SystemServer_startISensorManagerService(JNIEnv* env,
+ jobject /* clazz */) {
+ startSensorManagerHidlService(env);
+ startSensorManagerAidlService(env);
+}
+
static void android_server_SystemServer_startMemtrackProxyService(JNIEnv* env,
jobject /* clazz */) {
using aidl::android::hardware::memtrack::MemtrackProxy;
@@ -93,35 +133,19 @@
LOG_ALWAYS_FATAL_IF(err != EX_NONE, "Cannot register %s: %d", memtrackProxyService, err);
}
-static void android_server_SystemServer_startHidlServices(JNIEnv* env, jobject /* clazz */) {
+static void android_server_SystemServer_startHidlServices(JNIEnv* /* env */, jobject /* clazz */) {
using ::android::frameworks::schedulerservice::V1_0::ISchedulingPolicyService;
using ::android::frameworks::schedulerservice::V1_0::implementation::SchedulingPolicyService;
- using ::android::frameworks::sensorservice::V1_0::ISensorManager;
- using ::android::frameworks::sensorservice::V1_0::implementation::SensorManager;
using ::android::hardware::configureRpcThreadpool;
using ::android::hidl::manager::V1_0::IServiceManager;
- status_t err;
-
configureRpcThreadpool(5, false /* callerWillJoin */);
- JavaVM *vm;
- LOG_ALWAYS_FATAL_IF(env->GetJavaVM(&vm) != JNI_OK, "Cannot get Java VM");
-
- sp<ISensorManager> sensorService = new SensorManager(vm);
- if (IServiceManager::Transport::HWBINDER ==
- hardware::defaultServiceManager1_2()->getTransport(ISensorManager::descriptor, "default")) {
- err = sensorService->registerAsService();
- LOG_ALWAYS_FATAL_IF(err != OK, "Cannot register %s: %d", ISensorManager::descriptor, err);
- } else {
- ALOGW("%s is deprecated. Skipping registration.", ISensorManager::descriptor);
- }
-
sp<ISchedulingPolicyService> schedulingService = new SchedulingPolicyService();
if (IServiceManager::Transport::HWBINDER ==
hardware::defaultServiceManager1_2()->getTransport(ISchedulingPolicyService::descriptor,
"default")) {
- err = schedulingService->registerAsService("default");
+ status_t err = schedulingService->registerAsService("default");
LOG_ALWAYS_FATAL_IF(err != OK, "Cannot register %s: %d",
ISchedulingPolicyService::descriptor, err);
} else {
@@ -156,6 +180,8 @@
static const JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
{"startIStatsService", "()V", (void*)android_server_SystemServer_startIStatsService},
+ {"startISensorManagerService", "()V",
+ (void*)android_server_SystemServer_startISensorManagerService},
{"startMemtrackProxyService", "()V",
(void*)android_server_SystemServer_startMemtrackProxyService},
{"startHidlServices", "()V", (void*)android_server_SystemServer_startHidlServices},
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index c2a6944..a953bcb 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -466,6 +466,7 @@
private final long mRuntimeStartUptime;
private static final String START_HIDL_SERVICES = "StartHidlServices";
+ private static final String START_SENSOR_MANAGER_SERVICE = "StartISensorManagerService";
private static final String START_BLOB_STORE_SERVICE = "startBlobStoreManagerService";
private static final String SYSPROP_START_COUNT = "sys.system_server.start_count";
@@ -484,6 +485,9 @@
/** Start the IStats services. This is a blocking call and can take time. */
private static native void startIStatsService();
+ /** Start the ISensorManager service. This is a blocking call and can take time. */
+ private static native void startISensorManagerService();
+
/**
* Start the memtrack proxy service.
*/
@@ -1597,11 +1601,18 @@
wm.onInitReady();
t.traceEnd();
- // Start receiving calls from HIDL services. Start in in a separate thread
+ // Start receiving calls from SensorManager services. Start in a separate thread
// because it need to connect to SensorManager. This has to start
// after PHASE_WAIT_FOR_SENSOR_SERVICE is done.
SystemServerInitThreadPool.submit(() -> {
TimingsTraceAndSlog traceLog = TimingsTraceAndSlog.newAsyncLog();
+ traceLog.traceBegin(START_SENSOR_MANAGER_SERVICE);
+ startISensorManagerService();
+ traceLog.traceEnd();
+ }, START_SENSOR_MANAGER_SERVICE);
+
+ SystemServerInitThreadPool.submit(() -> {
+ TimingsTraceAndSlog traceLog = TimingsTraceAndSlog.newAsyncLog();
traceLog.traceBegin(START_HIDL_SERVICES);
startHidlServices();
traceLog.traceEnd();
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/hidl/Face10Test.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/hidl/Face10Test.java
index 116d2d5..cc9a917f 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/hidl/Face10Test.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/hidl/Face10Test.java
@@ -102,7 +102,8 @@
FaceSensorProperties.TYPE_UNKNOWN, supportsFaceDetection, supportsSelfIllumination,
resetLockoutRequiresChallenge);
- Face10.sSystemClock = Clock.fixed(Instant.ofEpochMilli(100), ZoneId.of("PST"));
+ Face10.sSystemClock = Clock.fixed(
+ Instant.ofEpochMilli(100), ZoneId.of("America/Los_Angeles"));
mFace10 = new Face10(mContext, sensorProps, mLockoutResetDispatcher, mHandler, mScheduler,
mBiometricContext);
mBinder = new Binder();
@@ -112,7 +113,7 @@
waitForIdle();
Face10.sSystemClock = Clock.fixed(Instant.ofEpochSecond(
Face10.sSystemClock.instant().getEpochSecond() + seconds),
- ZoneId.of("PST"));
+ ZoneId.of("America/Los_Angeles"));
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
index 8112ca8..aceae72 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
@@ -842,4 +842,53 @@
verify(mAudioManager, never()).setStreamVolume(eq(AudioManager.STREAM_MUSIC), anyInt(),
anyInt());
}
+
+ @Test
+ public void tvSendRequestArcTerminationOnSleep() {
+ // Emulate Audio device on port 0x2000 (supports ARC)
+
+ mNativeWrapper.setPortConnectionStatus(2, true);
+ HdmiCecMessage hdmiCecMessage = HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
+ ADDR_AUDIO_SYSTEM, 0x2000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
+ mNativeWrapper.onCecMessage(hdmiCecMessage);
+ mTestLooper.dispatchAll();
+
+ mHdmiCecLocalDeviceTv.startArcAction(true);
+ mTestLooper.dispatchAll();
+ HdmiCecMessage requestArcInitiation = HdmiCecMessageBuilder.buildRequestArcInitiation(
+ ADDR_TV,
+ ADDR_AUDIO_SYSTEM);
+ HdmiCecMessage requestArcTermination = HdmiCecMessageBuilder.buildRequestArcTermination(
+ ADDR_TV,
+ ADDR_AUDIO_SYSTEM);
+ HdmiCecMessage initiateArc = HdmiCecMessageBuilder.buildInitiateArc(
+ ADDR_AUDIO_SYSTEM,
+ ADDR_TV);
+ HdmiCecMessage reportArcInitiated = HdmiCecMessageBuilder.buildReportArcInitiated(
+ ADDR_TV,
+ ADDR_AUDIO_SYSTEM);
+
+ assertThat(mNativeWrapper.getResultMessages()).contains(requestArcInitiation);
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(requestArcTermination);
+
+ mNativeWrapper.onCecMessage(initiateArc);
+ mTestLooper.dispatchAll();
+
+ // Finish querying SADs
+ assertThat(mNativeWrapper.getResultMessages()).contains(SAD_QUERY);
+ mNativeWrapper.clearResultMessages();
+ mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS);
+ mTestLooper.dispatchAll();
+ assertThat(mNativeWrapper.getResultMessages()).contains(SAD_QUERY);
+ mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS);
+ mTestLooper.dispatchAll();
+
+ // ARC should be established after RequestSadAction is finished
+ assertThat(mNativeWrapper.getResultMessages()).contains(reportArcInitiated);
+
+ mHdmiControlService.onStandby(HdmiControlService.STANDBY_SCREEN_OFF);
+ mTestLooper.dispatchAll();
+ assertThat(mNativeWrapper.getResultMessages()).contains(requestArcTermination);
+ }
+
}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index a081bc3..3b376fb 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -9409,12 +9409,13 @@
/**
* 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
+ * <p>Requires permission: {@link android.Manifest.permission#MODIFY_PHONE_STATE} or
* that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
- * This can be called for following reasons
+ * This can be called for following reasons:
* <ol>
- * <li>Allowed network types control by USER {@link #ALLOWED_NETWORK_TYPES_REASON_USER}
+ * <li>Allowed network types control by USER
+ * {@link TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_USER}
* <li>Allowed network types control by carrier {@link #ALLOWED_NETWORK_TYPES_REASON_CARRIER}
* </ol>
* This API will result in allowing an intersection of allowed network types for all reasons,
@@ -9424,7 +9425,13 @@
* @param allowedNetworkTypes The bitmask of allowed network type
* @throws IllegalStateException if the Telephony process is not currently available.
* @throws IllegalArgumentException if invalid AllowedNetworkTypesReason is passed.
- * @throws SecurityException if the caller does not have the required privileges
+ * @throws SecurityException if the caller does not have the required privileges or if the
+ * caller tries to use one of the following security-based reasons without
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE} permissions.
+ * <ol>
+ * <li>{@code TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G}</li>
+ * <li>{@code TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS}</li>
+ * </ol>
*/
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
@RequiresFeature(
diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
index ad06830..258642ac 100644
--- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
+++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
@@ -17,10 +17,12 @@
package com.android.server;
import static android.net.ConnectivityManager.NetworkCallback;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static android.net.vcn.VcnManager.VCN_RESTRICTED_TRANSPORTS_INT_ARRAY_KEY;
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE;
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE;
import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
@@ -95,6 +97,7 @@
import com.android.server.vcn.VcnContext;
import com.android.server.vcn.VcnNetworkProvider;
import com.android.server.vcn.util.PersistableBundleUtils;
+import com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper;
import org.junit.Before;
import org.junit.Test;
@@ -252,6 +255,10 @@
.when(mMockContext)
.enforceCallingOrSelfPermission(
eq(android.Manifest.permission.NETWORK_FACTORY), any());
+
+ doReturn(Collections.singleton(TRANSPORT_WIFI))
+ .when(mMockDeps)
+ .getRestrictedTransports(any(), any());
}
@@ -1031,63 +1038,188 @@
new LinkProperties());
}
+ private void checkGetRestrictedTransports(
+ ParcelUuid subGrp,
+ TelephonySubscriptionSnapshot lastSnapshot,
+ Set<Integer> expectedTransports) {
+ Set<Integer> result =
+ new VcnManagementService.Dependencies()
+ .getRestrictedTransports(subGrp, lastSnapshot);
+ assertEquals(expectedTransports, result);
+ }
+
@Test
- public void testGetUnderlyingNetworkPolicyCellular() throws Exception {
+ public void testGetRestrictedTransports() {
+ final Set<Integer> restrictedTransports = new ArraySet<>();
+ restrictedTransports.add(TRANSPORT_CELLULAR);
+ restrictedTransports.add(TRANSPORT_WIFI);
+
+ PersistableBundle carrierConfigBundle = new PersistableBundle();
+ carrierConfigBundle.putIntArray(
+ VCN_RESTRICTED_TRANSPORTS_INT_ARRAY_KEY,
+ restrictedTransports.stream().mapToInt(i -> i).toArray());
+ final PersistableBundleWrapper carrierConfig =
+ new PersistableBundleWrapper(carrierConfigBundle);
+
+ final TelephonySubscriptionSnapshot lastSnapshot =
+ mock(TelephonySubscriptionSnapshot.class);
+ doReturn(carrierConfig).when(lastSnapshot).getCarrierConfigForSubGrp(eq(TEST_UUID_2));
+
+ checkGetRestrictedTransports(TEST_UUID_2, lastSnapshot, restrictedTransports);
+ }
+
+ @Test
+ public void testGetRestrictedTransports_noRestrictPolicyConfigured() {
+ final Set<Integer> restrictedTransports = Collections.singleton(TRANSPORT_WIFI);
+
+ final PersistableBundleWrapper carrierConfig =
+ new PersistableBundleWrapper(new PersistableBundle());
+ final TelephonySubscriptionSnapshot lastSnapshot =
+ mock(TelephonySubscriptionSnapshot.class);
+ doReturn(carrierConfig).when(lastSnapshot).getCarrierConfigForSubGrp(eq(TEST_UUID_2));
+
+ checkGetRestrictedTransports(TEST_UUID_2, lastSnapshot, restrictedTransports);
+ }
+
+ @Test
+ public void testGetRestrictedTransports_noCarrierConfig() {
+ final Set<Integer> restrictedTransports = Collections.singleton(TRANSPORT_WIFI);
+
+ final TelephonySubscriptionSnapshot lastSnapshot =
+ mock(TelephonySubscriptionSnapshot.class);
+
+ checkGetRestrictedTransports(TEST_UUID_2, lastSnapshot, restrictedTransports);
+ }
+
+ private void checkGetUnderlyingNetworkPolicy(
+ int transportType,
+ boolean isTransportRestricted,
+ boolean isActive,
+ boolean expectVcnManaged,
+ boolean expectRestricted)
+ throws Exception {
+
+ final Set<Integer> restrictedTransports = new ArraySet();
+ if (isTransportRestricted) {
+ restrictedTransports.add(transportType);
+ }
+ doReturn(restrictedTransports).when(mMockDeps).getRestrictedTransports(any(), any());
+
final VcnUnderlyingNetworkPolicy policy =
startVcnAndGetPolicyForTransport(
- TEST_SUBSCRIPTION_ID, TEST_UUID_2, true /* isActive */, TRANSPORT_CELLULAR);
+ TEST_SUBSCRIPTION_ID, TEST_UUID_2, isActive, transportType);
+
+ assertFalse(policy.isTeardownRequested());
+ verifyMergedNetworkCapabilities(
+ policy.getMergedNetworkCapabilities(),
+ transportType,
+ expectVcnManaged,
+ expectRestricted);
+ }
+
+ @Test
+ public void testGetUnderlyingNetworkPolicy_unrestrictCell() throws Exception {
+ checkGetUnderlyingNetworkPolicy(
+ TRANSPORT_CELLULAR,
+ false /* isTransportRestricted */,
+ true /* isActive */,
+ true /* expectVcnManaged */,
+ false /* expectRestricted */);
+ }
+
+ @Test
+ public void testGetUnderlyingNetworkPolicy_unrestrictCellSafeMode() throws Exception {
+ checkGetUnderlyingNetworkPolicy(
+ TRANSPORT_CELLULAR,
+ false /* isTransportRestricted */,
+ false /* isActive */,
+ false /* expectVcnManaged */,
+ false /* expectRestricted */);
+ }
+
+ @Test
+ public void testGetUnderlyingNetworkPolicy_restrictCell() throws Exception {
+ checkGetUnderlyingNetworkPolicy(
+ TRANSPORT_CELLULAR,
+ true /* isTransportRestricted */,
+ true /* isActive */,
+ true /* expectVcnManaged */,
+ true /* expectRestricted */);
+ }
+
+ @Test
+ public void testGetUnderlyingNetworkPolicy_restrictCellSafeMode() throws Exception {
+ checkGetUnderlyingNetworkPolicy(
+ TRANSPORT_CELLULAR,
+ true /* isTransportRestricted */,
+ false /* isActive */,
+ false /* expectVcnManaged */,
+ false /* expectRestricted */);
+ }
+
+ @Test
+ public void testGetUnderlyingNetworkPolicy_unrestrictWifi() throws Exception {
+ checkGetUnderlyingNetworkPolicy(
+ TRANSPORT_WIFI,
+ false /* isTransportRestricted */,
+ true /* isActive */,
+ true /* expectVcnManaged */,
+ false /* expectRestricted */);
+ }
+
+ @Test
+ public void testGetUnderlyingNetworkPolicy_unrestrictWifiSafeMode() throws Exception {
+ checkGetUnderlyingNetworkPolicy(
+ TRANSPORT_WIFI,
+ false /* isTransportRestricted */,
+ false /* isActive */,
+ false /* expectVcnManaged */,
+ false /* expectRestricted */);
+ }
+
+ @Test
+ public void testGetUnderlyingNetworkPolicy_restrictWifi() throws Exception {
+ checkGetUnderlyingNetworkPolicy(
+ TRANSPORT_WIFI,
+ true /* isTransportRestricted */,
+ true /* isActive */,
+ true /* expectVcnManaged */,
+ true /* expectRestricted */);
+ }
+
+ @Test
+ public void testGetUnderlyingNetworkPolicy_restrictWifiSafeMode() throws Exception {
+ checkGetUnderlyingNetworkPolicy(
+ TRANSPORT_WIFI,
+ true /* isTransportRestricted */,
+ false /* isActive */,
+ false /* expectVcnManaged */,
+ true /* expectRestricted */);
+ }
+
+ @Test
+ public void testGetUnderlyingNetworkPolicyCell_restrictWifi() throws Exception {
+ doReturn(Collections.singleton(TRANSPORT_WIFI))
+ .when(mMockDeps)
+ .getRestrictedTransports(any(), any());
+
+ setupSubscriptionAndStartVcn(TEST_SUBSCRIPTION_ID, TEST_UUID_2, true /* isVcnActive */);
+
+ // Get the policy for a cellular network and expect it won't be affected by the wifi
+ // restriction policy
+ final VcnUnderlyingNetworkPolicy policy =
+ mVcnMgmtSvc.getUnderlyingNetworkPolicy(
+ getNetworkCapabilitiesBuilderForTransport(
+ TEST_SUBSCRIPTION_ID, TRANSPORT_CELLULAR)
+ .build(),
+ new LinkProperties());
assertFalse(policy.isTeardownRequested());
verifyMergedNetworkCapabilities(
policy.getMergedNetworkCapabilities(),
TRANSPORT_CELLULAR,
- true /* isVcnManaged */,
- false /* isRestricted */);
- }
-
- @Test
- public void testGetUnderlyingNetworkPolicyCellular_safeMode() throws Exception {
- final VcnUnderlyingNetworkPolicy policy =
- startVcnAndGetPolicyForTransport(
- TEST_SUBSCRIPTION_ID,
- TEST_UUID_2,
- false /* isActive */,
- TRANSPORT_CELLULAR);
-
- assertFalse(policy.isTeardownRequested());
- verifyMergedNetworkCapabilities(
- policy.getMergedNetworkCapabilities(),
- NetworkCapabilities.TRANSPORT_CELLULAR,
- false /* isVcnManaged */,
- false /* isRestricted */);
- }
-
- @Test
- public void testGetUnderlyingNetworkPolicyWifi() throws Exception {
- final VcnUnderlyingNetworkPolicy policy =
- startVcnAndGetPolicyForTransport(
- TEST_SUBSCRIPTION_ID, TEST_UUID_2, true /* isActive */, TRANSPORT_WIFI);
-
- assertFalse(policy.isTeardownRequested());
- verifyMergedNetworkCapabilities(
- policy.getMergedNetworkCapabilities(),
- NetworkCapabilities.TRANSPORT_WIFI,
- true /* isVcnManaged */,
- true /* isRestricted */);
- }
-
- @Test
- public void testGetUnderlyingNetworkPolicyVcnWifi_safeMode() throws Exception {
- final VcnUnderlyingNetworkPolicy policy =
- startVcnAndGetPolicyForTransport(
- TEST_SUBSCRIPTION_ID, TEST_UUID_2, false /* isActive */, TRANSPORT_WIFI);
-
- assertFalse(policy.isTeardownRequested());
- verifyMergedNetworkCapabilities(
- policy.getMergedNetworkCapabilities(),
- NetworkCapabilities.TRANSPORT_WIFI,
- false /* isVcnManaged */,
- true /* isRestricted */);
+ true /* expectVcnManaged */,
+ false /* expectRestricted */);
}
private void setupTrackedCarrierWifiNetwork(NetworkCapabilities caps) {
@@ -1138,6 +1270,27 @@
}
@Test
+ public void testGetUnderlyingNetworkPolicyForRestrictedImsWhenUnrestrictingCell()
+ throws Exception {
+ final NetworkCapabilities existingNetworkCaps =
+ getNetworkCapabilitiesBuilderForTransport(TEST_SUBSCRIPTION_ID, TRANSPORT_CELLULAR)
+ .addCapability(NET_CAPABILITY_NOT_RESTRICTED)
+ .removeCapability(NET_CAPABILITY_IMS)
+ .build();
+ setupTrackedCarrierWifiNetwork(existingNetworkCaps);
+
+ final VcnUnderlyingNetworkPolicy policy =
+ mVcnMgmtSvc.getUnderlyingNetworkPolicy(
+ getNetworkCapabilitiesBuilderForTransport(
+ TEST_SUBSCRIPTION_ID, TRANSPORT_CELLULAR)
+ .addCapability(NET_CAPABILITY_IMS)
+ .removeCapability(NET_CAPABILITY_NOT_RESTRICTED)
+ .build(),
+ new LinkProperties());
+ assertFalse(policy.isTeardownRequested());
+ }
+
+ @Test
public void testGetUnderlyingNetworkPolicyNonVcnNetwork() throws Exception {
setupSubscriptionAndStartVcn(TEST_SUBSCRIPTION_ID, TEST_UUID_1, true /* isActive */);
@@ -1217,6 +1370,30 @@
verify(mMockPolicyListener).onPolicyChanged();
}
+ @Test
+ public void testVcnCarrierConfigChangeUpdatesPolicyListener() throws Exception {
+ setupActiveSubscription(TEST_UUID_2);
+
+ mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
+ mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListenerForTest(mMockPolicyListener);
+
+ final TelephonySubscriptionSnapshot snapshot =
+ buildSubscriptionSnapshot(
+ TEST_SUBSCRIPTION_ID,
+ TEST_UUID_2,
+ Collections.singleton(TEST_UUID_2),
+ Collections.emptyMap(),
+ true /* hasCarrierPrivileges */);
+
+ final PersistableBundleWrapper mockCarrierConfig = mock(PersistableBundleWrapper.class);
+ doReturn(mockCarrierConfig).when(snapshot).getCarrierConfigForSubGrp(eq(TEST_UUID_2));
+
+ final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback();
+ cb.onNewSnapshot(snapshot);
+
+ verify(mMockPolicyListener).onPolicyChanged();
+ }
+
private void triggerVcnSafeMode(
@NonNull ParcelUuid subGroup,
@NonNull TelephonySubscriptionSnapshot snapshot,
diff --git a/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java b/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java
index 09080be..965b073 100644
--- a/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java
+++ b/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java
@@ -16,6 +16,9 @@
package com.android.server.vcn;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static android.net.vcn.VcnManager.VCN_RESTRICTED_TRANSPORTS_INT_ARRAY_KEY;
import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED;
import static android.telephony.CarrierConfigManager.EXTRA_SLOT_INDEX;
import static android.telephony.CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX;
@@ -39,6 +42,7 @@
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -494,6 +498,37 @@
}
@Test
+ public void testCarrierConfigUpdatedAfterValidTriggersCallbacks() throws Exception {
+ mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true));
+ mTestLooper.dispatchAll();
+ verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(TEST_PRIVILEGED_PACKAGES)));
+ reset(mCallback);
+
+ final PersistableBundle updatedConfig = new PersistableBundle();
+ updatedConfig.putIntArray(
+ VCN_RESTRICTED_TRANSPORTS_INT_ARRAY_KEY,
+ new int[] {TRANSPORT_WIFI, TRANSPORT_CELLULAR});
+ doReturn(updatedConfig)
+ .when(mCarrierConfigManager)
+ .getConfigForSubId(eq(TEST_SUBSCRIPTION_ID_1));
+
+ Map<Integer, PersistableBundleWrapper> subIdToCarrierConfigMap = new HashMap<>();
+ subIdToCarrierConfigMap.put(
+ TEST_SUBSCRIPTION_ID_1, new PersistableBundleWrapper(updatedConfig));
+ mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true));
+ mTestLooper.dispatchAll();
+
+ verify(mCallback)
+ .onNewSnapshot(
+ eq(
+ buildExpectedSnapshot(
+ 0,
+ TEST_SUBID_TO_INFO_MAP,
+ subIdToCarrierConfigMap,
+ TEST_PRIVILEGED_PACKAGES)));
+ }
+
+ @Test
public void testSlotClearedAfterValidTriggersCallbacks() throws Exception {
mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true));
mTestLooper.dispatchAll();