diff options
293 files changed, 6693 insertions, 3453 deletions
diff --git a/Android.bp b/Android.bp index d976b9172602..00b419897f34 100644 --- a/Android.bp +++ b/Android.bp @@ -294,6 +294,7 @@ java_defaults { srcs: [ ":framework-non-updatable-sources", "core/java/**/*.logtags", + ":apex-info-list", ], aidl: { generate_get_transaction_name: true, diff --git a/ApiDocs.bp b/ApiDocs.bp index c1816467146d..8af2e02f8d08 100644 --- a/ApiDocs.bp +++ b/ApiDocs.bp @@ -112,7 +112,6 @@ stubs_defaults { } // Defaults module for doc-stubs targets that use module source code as input. -// This is the default/normal. stubs_defaults { name: "framework-doc-stubs-sources-default", defaults: ["framework-doc-stubs-default"], @@ -147,12 +146,6 @@ droidstubs { } droidstubs { - name: "framework-doc-stubs", - defaults: ["framework-doc-stubs-sources-default"], - args: metalava_framework_docs_args, -} - -droidstubs { name: "framework-doc-system-stubs", defaults: ["framework-doc-stubs-sources-default"], args: metalava_framework_docs_args + @@ -160,11 +153,8 @@ droidstubs { api_levels_sdk_type: "system", } -// Experimental target building doc stubs with module stub source code as input. -// This is intended to eventually replace framework-doc-stubs, once all diffs -// have been eliminated. droidstubs { - name: "framework-doc-stubs-module-stubs", + name: "framework-doc-stubs", defaults: ["framework-doc-stubs-default"], args: metalava_framework_docs_args, srcs: [ @@ -192,6 +182,42 @@ droidstubs { }, } +// This produces the same annotations.zip as framework-doc-stubs, but by using +// outputs from individual modules instead of all the source code. +genrule { + name: "sdk-annotations.zip", + srcs: [ + ":android-non-updatable-doc-stubs{.annotations.zip}", + + // Conscrypt and i18n currently do not enable annotations + // ":conscrypt.module.public.api{.public.annotations.zip}", + // ":i18n.module.public.api{.public.annotations.zip}", + + // Modules that enable annotations below + ":android.net.ipsec.ike{.public.annotations.zip}", + ":art.module.public.api{.public.annotations.zip}", + ":framework-appsearch{.public.annotations.zip}", + ":framework-connectivity{.public.annotations.zip}", + ":framework-graphics{.public.annotations.zip}", + ":framework-media{.public.annotations.zip}", + ":framework-mediaprovider{.public.annotations.zip}", + ":framework-permission{.public.annotations.zip}", + ":framework-permission-s{.public.annotations.zip}", + ":framework-scheduling{.public.annotations.zip}", + ":framework-sdkextensions{.public.annotations.zip}", + ":framework-statsd{.public.annotations.zip}", + ":framework-tethering{.public.annotations.zip}", + ":framework-wifi{.public.annotations.zip}", + ], + out: ["annotations.zip"], + tools: [ + "merge_annotation_zips", + "soong_zip", + ], + cmd: "$(location merge_annotation_zips) $(genDir)/out $(in) && " + + "$(location soong_zip) -o $(out) -C $(genDir)/out -D $(genDir)/out", +} + ///////////////////////////////////////////////////////////////////// // API docs are created from the generated stub source files // using droiddoc diff --git a/PACKAGE_MANAGER_OWNERS b/PACKAGE_MANAGER_OWNERS new file mode 100644 index 000000000000..e4549b4de164 --- /dev/null +++ b/PACKAGE_MANAGER_OWNERS @@ -0,0 +1,3 @@ +chiuwinson@google.com +patb@google.com +schfan@google.com
\ No newline at end of file diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java index 591e8ba859fc..4becc6b7c44a 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java @@ -1008,13 +1008,21 @@ public class JobSchedulerService extends com.android.server.SystemService } @Override - public void onUserUnlocked(@NonNull TargetUser user) { + public void onUserStarting(@NonNull TargetUser user) { synchronized (mLock) { - // Note that the user has started after its unlocked instead of when the user - // actually starts because the storage won't be decrypted until unlock. mStartedUsers = ArrayUtils.appendInt(mStartedUsers, user.getUserIdentifier()); } - // Let's kick any outstanding jobs for this user. + // The user is starting but credential encrypted storage is still locked. + // Only direct-boot-aware jobs can safely run. + // Let's kick off any eligible jobs for this user. + mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget(); + } + + @Override + public void onUserUnlocked(@NonNull TargetUser user) { + // The user is fully unlocked and credential encrypted storage is now decrypted. + // Direct-boot-UNaware jobs can now safely run. + // Let's kick off any outstanding jobs for this user. mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget(); } diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java index 4e46aa3f42d5..9564dde7fe06 100644 --- a/cmds/am/src/com/android/commands/am/Am.java +++ b/cmds/am/src/com/android/commands/am/Am.java @@ -41,6 +41,10 @@ public class Am extends BaseCommand { private IActivityManager mAm; private IPackageManager mPm; + Am() { + svcInit(); + } + /** * Command-line entry point. * @@ -50,6 +54,20 @@ public class Am extends BaseCommand { (new Am()).run(args); } + private void svcInit() { + mAm = ActivityManager.getService(); + if (mAm == null) { + System.err.println(NO_SYSTEM_ERROR_CODE); + return; + } + + mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package")); + if (mPm == null) { + System.err.println(NO_SYSTEM_ERROR_CODE); + return; + } + } + @Override public void onShowUsage(PrintStream out) { try { @@ -61,19 +79,6 @@ public class Am extends BaseCommand { @Override public void onRun() throws Exception { - - mAm = ActivityManager.getService(); - if (mAm == null) { - System.err.println(NO_SYSTEM_ERROR_CODE); - throw new AndroidException("Can't connect to activity manager; is the system running?"); - } - - mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package")); - if (mPm == null) { - System.err.println(NO_SYSTEM_ERROR_CODE); - throw new AndroidException("Can't connect to package manager; is the system running?"); - } - String op = nextArgRequired(); if (op.equals("instrument")) { diff --git a/cmds/am/src/com/android/commands/am/Instrument.java b/cmds/am/src/com/android/commands/am/Instrument.java index 1e72ddf8ecfc..0b439df403e0 100644 --- a/cmds/am/src/com/android/commands/am/Instrument.java +++ b/cmds/am/src/com/android/commands/am/Instrument.java @@ -545,6 +545,8 @@ public class Instrument { mWm.setAnimationScales(oldAnims); } } + // Exit from here instead of going down the path of normal shutdown which is slow. + System.exit(0); } private static String readLogcat(long startTimeMs) { diff --git a/core/api/current.txt b/core/api/current.txt index 131db7320f3f..9d1a171088eb 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -112,6 +112,7 @@ package android { field public static final String MODIFY_PHONE_STATE = "android.permission.MODIFY_PHONE_STATE"; field public static final String MOUNT_FORMAT_FILESYSTEMS = "android.permission.MOUNT_FORMAT_FILESYSTEMS"; field public static final String MOUNT_UNMOUNT_FILESYSTEMS = "android.permission.MOUNT_UNMOUNT_FILESYSTEMS"; + field public static final String NEARBY_WIFI_DEVICES = "android.permission.NEARBY_WIFI_DEVICES"; field public static final String NFC = "android.permission.NFC"; field public static final String NFC_PREFERRED_PAYMENT_INFO = "android.permission.NFC_PREFERRED_PAYMENT_INFO"; field public static final String NFC_TRANSACTION_EVENT = "android.permission.NFC_TRANSACTION_EVENT"; @@ -8647,12 +8648,14 @@ package android.bluetooth { method public android.bluetooth.BluetoothDevice getRemoteDevice(byte[]); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public int getScanMode(); method public int getState(); + method public int isCisCentralSupported(); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public boolean isDiscovering(); method public boolean isEnabled(); method public boolean isLe2MPhySupported(); method public boolean isLeCodedPhySupported(); method public boolean isLeExtendedAdvertisingSupported(); method public boolean isLePeriodicAdvertisingSupported(); + method public int isLePeriodicAdvertisingSyncTransferSenderSupported(); method public boolean isMultipleAdvertisementSupported(); method public boolean isOffloadedFilteringSupported(); method public boolean isOffloadedScanBatchingSupported(); @@ -9122,8 +9125,10 @@ package android.bluetooth { method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean requestMtu(int); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean setCharacteristicNotification(android.bluetooth.BluetoothGattCharacteristic, boolean); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public void setPreferredPhy(int, int, int); - method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean writeCharacteristic(android.bluetooth.BluetoothGattCharacteristic); - method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean writeDescriptor(android.bluetooth.BluetoothGattDescriptor); + method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean writeCharacteristic(android.bluetooth.BluetoothGattCharacteristic); + method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int writeCharacteristic(@NonNull android.bluetooth.BluetoothGattCharacteristic, @NonNull byte[], int); + method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean writeDescriptor(android.bluetooth.BluetoothGattDescriptor); + method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int writeDescriptor(@NonNull android.bluetooth.BluetoothGattDescriptor, @NonNull byte[]); field public static final int CONNECTION_PRIORITY_BALANCED = 0; // 0x0 field public static final int CONNECTION_PRIORITY_HIGH = 1; // 0x1 field public static final int CONNECTION_PRIORITY_LOW_POWER = 2; // 0x2 @@ -9142,11 +9147,14 @@ package android.bluetooth { public abstract class BluetoothGattCallback { ctor public BluetoothGattCallback(); - method public void onCharacteristicChanged(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic); - method public void onCharacteristicRead(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic, int); + method @Deprecated public void onCharacteristicChanged(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic); + method public void onCharacteristicChanged(@NonNull android.bluetooth.BluetoothGatt, @NonNull android.bluetooth.BluetoothGattCharacteristic, @NonNull byte[]); + method @Deprecated public void onCharacteristicRead(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic, int); + method public void onCharacteristicRead(@NonNull android.bluetooth.BluetoothGatt, @NonNull android.bluetooth.BluetoothGattCharacteristic, @NonNull byte[], int); method public void onCharacteristicWrite(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic, int); method public void onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int); - method public void onDescriptorRead(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattDescriptor, int); + method @Deprecated public void onDescriptorRead(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattDescriptor, int); + method public void onDescriptorRead(@NonNull android.bluetooth.BluetoothGatt, @NonNull android.bluetooth.BluetoothGattDescriptor, int, @NonNull byte[]); method public void onDescriptorWrite(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattDescriptor, int); method public void onMtuChanged(android.bluetooth.BluetoothGatt, int, int); method public void onPhyRead(android.bluetooth.BluetoothGatt, int, int, int); @@ -9163,20 +9171,20 @@ package android.bluetooth { method public int describeContents(); method public android.bluetooth.BluetoothGattDescriptor getDescriptor(java.util.UUID); method public java.util.List<android.bluetooth.BluetoothGattDescriptor> getDescriptors(); - method public Float getFloatValue(int, int); + method @Deprecated public Float getFloatValue(int, int); method public int getInstanceId(); - method public Integer getIntValue(int, int); + method @Deprecated public Integer getIntValue(int, int); method public int getPermissions(); method public int getProperties(); method public android.bluetooth.BluetoothGattService getService(); - method public String getStringValue(int); + method @Deprecated public String getStringValue(int); method public java.util.UUID getUuid(); - method public byte[] getValue(); + method @Deprecated public byte[] getValue(); method public int getWriteType(); - method public boolean setValue(byte[]); - method public boolean setValue(int, int, int); - method public boolean setValue(int, int, int, int); - method public boolean setValue(String); + method @Deprecated public boolean setValue(byte[]); + method @Deprecated public boolean setValue(int, int, int); + method @Deprecated public boolean setValue(int, int, int, int); + method @Deprecated public boolean setValue(String); method public void setWriteType(int); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothGattCharacteristic> CREATOR; @@ -9216,8 +9224,8 @@ package android.bluetooth { method public android.bluetooth.BluetoothGattCharacteristic getCharacteristic(); method public int getPermissions(); method public java.util.UUID getUuid(); - method public byte[] getValue(); - method public boolean setValue(byte[]); + method @Deprecated public byte[] getValue(); + method @Deprecated public boolean setValue(byte[]); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothGattDescriptor> CREATOR; field public static final byte[] DISABLE_NOTIFICATION_VALUE; @@ -9505,7 +9513,12 @@ package android.bluetooth { field public static final int ERROR_BLUETOOTH_NOT_ALLOWED = 2; // 0x2 field public static final int ERROR_BLUETOOTH_NOT_ENABLED = 1; // 0x1 field public static final int ERROR_DEVICE_NOT_BONDED = 3; // 0x3 + field public static final int ERROR_FEATURE_NOT_SUPPORTED = 10; // 0xa + field public static final int ERROR_GATT_WRITE_NOT_ALLOWED = 101; // 0x65 + field public static final int ERROR_GATT_WRITE_REQUEST_BUSY = 102; // 0x66 field public static final int ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION = 6; // 0x6 + field public static final int ERROR_MISSING_BLUETOOTH_PRIVILEGED_PERMISSION = 8; // 0x8 + field public static final int ERROR_PROFILE_SERVICE_NOT_BOUND = 9; // 0x9 field public static final int ERROR_UNKNOWN = 2147483647; // 0x7fffffff field public static final int SUCCESS = 0; // 0x0 } @@ -31427,11 +31440,14 @@ package android.os { method public int dataSize(); method public void enforceInterface(@NonNull String); method public boolean hasFileDescriptors(); + method public boolean hasFileDescriptors(int, int); method public byte[] marshall(); method @NonNull public static android.os.Parcel obtain(); method @NonNull public static android.os.Parcel obtain(@NonNull android.os.IBinder); method @Nullable public Object[] readArray(@Nullable ClassLoader); + method @Nullable public <T> T[] readArray(@Nullable ClassLoader, @NonNull Class<T>); method @Nullable public java.util.ArrayList readArrayList(@Nullable ClassLoader); + method @Nullable public <T> java.util.ArrayList<T> readArrayList(@Nullable ClassLoader, @NonNull Class<? extends T>); method public void readBinderArray(@NonNull android.os.IBinder[]); method public void readBinderList(@NonNull java.util.List<android.os.IBinder>); method public boolean readBoolean(); @@ -31459,15 +31475,18 @@ package android.os { method @Nullable public <T extends android.os.Parcelable> T readParcelable(@Nullable ClassLoader); method @Nullable public <T extends android.os.Parcelable> T readParcelable(@Nullable ClassLoader, @NonNull Class<T>); method @Nullable public android.os.Parcelable[] readParcelableArray(@Nullable ClassLoader); + method @Nullable public <T> T[] readParcelableArray(@Nullable ClassLoader, @NonNull Class<T>); method @Nullable public android.os.Parcelable.Creator<?> readParcelableCreator(@Nullable ClassLoader); method @Nullable public <T> android.os.Parcelable.Creator<T> readParcelableCreator(@Nullable ClassLoader, @NonNull Class<T>); method @NonNull public <T extends android.os.Parcelable> java.util.List<T> readParcelableList(@NonNull java.util.List<T>, @Nullable ClassLoader); method @Nullable public android.os.PersistableBundle readPersistableBundle(); method @Nullable public android.os.PersistableBundle readPersistableBundle(@Nullable ClassLoader); method @Nullable public java.io.Serializable readSerializable(); + method @Nullable public <T extends java.io.Serializable> T readSerializable(@Nullable ClassLoader, @NonNull Class<T>); method @NonNull public android.util.Size readSize(); method @NonNull public android.util.SizeF readSizeF(); method @Nullable public <T> android.util.SparseArray<T> readSparseArray(@Nullable ClassLoader); + method @Nullable public <T> android.util.SparseArray<T> readSparseArray(@Nullable ClassLoader, @NonNull Class<? extends T>); method @Nullable public android.util.SparseBooleanArray readSparseBooleanArray(); method @Nullable public String readString(); method public void readStringArray(@NonNull String[]); diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt index b574d0441258..9af6c1b340b6 100644 --- a/core/api/module-lib-current.txt +++ b/core/api/module-lib-current.txt @@ -113,6 +113,11 @@ package android.media { public class AudioManager { method public void adjustStreamVolumeForUid(int, int, int, @NonNull String, int, int, int); method public void adjustSuggestedStreamVolumeForUid(int, int, int, @NonNull String, int, int, int); + method @RequiresPermission("android.permission.BLUETOOTH_STACK") public void setA2dpSuspended(boolean); + method @RequiresPermission("android.permission.BLUETOOTH_STACK") public void setBluetoothHeadsetProperties(@NonNull String, boolean, boolean); + method @RequiresPermission("android.permission.BLUETOOTH_STACK") public void setHfpEnabled(boolean); + method @RequiresPermission("android.permission.BLUETOOTH_STACK") public void setHfpSamplingRate(int); + method @RequiresPermission("android.permission.BLUETOOTH_STACK") public void setHfpVolume(int); method public void setStreamVolumeForUid(int, int, int, @NonNull String, int, int, int); field public static final int FLAG_FROM_KEY = 4096; // 0x1000 } @@ -292,6 +297,10 @@ package android.os { method @Nullable public android.os.IBinder getOrThrow() throws android.os.StatsServiceManager.ServiceNotFoundException; } + public class SystemConfigManager { + method @NonNull public java.util.List<android.content.ComponentName> getEnabledComponentOverrides(@NonNull String); + } + } package android.os.storage { @@ -311,6 +320,10 @@ package android.os.storage { package android.provider { + public static final class ContactsContract.RawContactsEntity implements android.provider.BaseColumns android.provider.ContactsContract.DataColumns android.provider.ContactsContract.RawContactsColumns { + method @NonNull @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public static java.util.Map<java.lang.String,java.util.List<android.content.ContentValues>> queryRawContactEntity(@NonNull android.content.ContentResolver, long); + } + public final class DeviceConfig { field public static final String NAMESPACE_ALARM_MANAGER = "alarm_manager"; field public static final String NAMESPACE_APP_STANDBY = "app_standby"; diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 4a732e544722..78e6a07c8705 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -475,6 +475,8 @@ package android.app { field public static final String OPSTR_AUTO_REVOKE_PERMISSIONS_IF_UNUSED = "android:auto_revoke_permissions_if_unused"; field public static final String OPSTR_BIND_ACCESSIBILITY_SERVICE = "android:bind_accessibility_service"; field public static final String OPSTR_CHANGE_WIFI_STATE = "android:change_wifi_state"; + field public static final String OPSTR_ESTABLISH_VPN_MANAGER = "android:establish_vpn_manager"; + field public static final String OPSTR_ESTABLISH_VPN_SERVICE = "android:establish_vpn_service"; field public static final String OPSTR_GET_ACCOUNTS = "android:get_accounts"; field public static final String OPSTR_GPS = "android:gps"; field public static final String OPSTR_INSTANT_APP_START_FOREGROUND = "android:instant_app_start_foreground"; @@ -1935,6 +1937,22 @@ package android.bluetooth { field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.a2dp-sink.profile.action.CONNECTION_STATE_CHANGED"; } + public final class BluetoothActivityEnergyInfo implements android.os.Parcelable { + method public int getBluetoothStackState(); + method public long getControllerEnergyUsed(); + method public long getControllerIdleTimeMillis(); + method public long getControllerRxTimeMillis(); + method public long getControllerTxTimeMillis(); + method public long getTimestampMillis(); + method @NonNull public java.util.List<android.bluetooth.UidTraffic> getUidTraffic(); + method public boolean isValid(); + field public static final int BT_STACK_STATE_INVALID = 0; // 0x0 + field public static final int BT_STACK_STATE_STATE_ACTIVE = 1; // 0x1 + field public static final int BT_STACK_STATE_STATE_IDLE = 3; // 0x3 + field public static final int BT_STACK_STATE_STATE_SCANNING = 2; // 0x2 + field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothActivityEnergyInfo> CREATOR; + } + public final class BluetoothAdapter { method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean addOnMetadataChangedListener(@NonNull android.bluetooth.BluetoothDevice, @NonNull java.util.concurrent.Executor, @NonNull android.bluetooth.BluetoothAdapter.OnMetadataChangedListener); method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean disable(boolean); @@ -2128,6 +2146,7 @@ package android.bluetooth { field @NonNull public static final android.os.ParcelUuid AVRCP_TARGET; field @NonNull public static final android.os.ParcelUuid BASE_UUID; field @NonNull public static final android.os.ParcelUuid BNEP; + field @NonNull public static final android.os.ParcelUuid CAP; field @NonNull public static final android.os.ParcelUuid COORDINATED_SET; field @NonNull public static final android.os.ParcelUuid DIP; field @NonNull public static final android.os.ParcelUuid GENERIC_MEDIA_CONTROL; @@ -2233,6 +2252,13 @@ package android.bluetooth { method @NonNull public android.bluetooth.OobData.LeBuilder setRandomizerHash(@NonNull byte[]); } + public final class UidTraffic implements java.lang.Cloneable android.os.Parcelable { + method public long getRxBytes(); + method public long getTxBytes(); + method public int getUid(); + field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.UidTraffic> CREATOR; + } + } package android.bluetooth.le { @@ -8555,7 +8581,6 @@ package android.os { public class SystemConfigManager { method @NonNull @RequiresPermission(android.Manifest.permission.READ_CARRIER_APP_INFO) public java.util.Set<java.lang.String> getDisabledUntilUsedPreinstalledCarrierApps(); method @NonNull @RequiresPermission(android.Manifest.permission.READ_CARRIER_APP_INFO) public java.util.Map<java.lang.String,java.util.List<java.lang.String>> getDisabledUntilUsedPreinstalledCarrierAssociatedApps(); - method @NonNull public java.util.List<java.lang.String> getEnabledComponentOverrides(@NonNull String); method @NonNull @RequiresPermission(android.Manifest.permission.GET_RUNTIME_PERMISSIONS) public int[] getSystemPermissionUids(@NonNull String); } @@ -9125,6 +9150,7 @@ package android.provider { field public static final String NAMESPACE_BIOMETRICS = "biometrics"; field public static final String NAMESPACE_BLOBSTORE = "blobstore"; field public static final String NAMESPACE_BLUETOOTH = "bluetooth"; + field public static final String NAMESPACE_CAPTIVEPORTALLOGIN = "captive_portal_login"; field public static final String NAMESPACE_CLIPBOARD = "clipboard"; field public static final String NAMESPACE_CONNECTIVITY = "connectivity"; field public static final String NAMESPACE_CONTENT_CAPTURE = "content_capture"; @@ -9138,6 +9164,7 @@ package android.provider { field public static final String NAMESPACE_MEDIA = "media"; field public static final String NAMESPACE_MEDIA_NATIVE = "media_native"; field public static final String NAMESPACE_NETD_NATIVE = "netd_native"; + field public static final String NAMESPACE_NNAPI_NATIVE = "nnapi_native"; field public static final String NAMESPACE_OTA = "ota"; field public static final String NAMESPACE_PACKAGE_MANAGER_SERVICE = "package_manager_service"; field public static final String NAMESPACE_PERMISSIONS = "permissions"; @@ -9159,6 +9186,7 @@ package android.provider { field public static final String NAMESPACE_SYSTEMUI = "systemui"; field public static final String NAMESPACE_SYSTEM_TIME = "system_time"; field public static final String NAMESPACE_TELEPHONY = "telephony"; + field public static final String NAMESPACE_TETHERING = "tethering"; field public static final String NAMESPACE_TEXTCLASSIFIER = "textclassifier"; field public static final String NAMESPACE_WINDOW_MANAGER_NATIVE_BOOT = "window_manager_native_boot"; } diff --git a/core/java/Android.bp b/core/java/Android.bp index 5f2c456bc388..e08a4931fc7d 100644 --- a/core/java/Android.bp +++ b/core/java/Android.bp @@ -158,10 +158,7 @@ filegroup { "android/util/LocalLog.java", // This should be android.util.IndentingPrintWriter, but it's not available in all branches. "com/android/internal/util/IndentingPrintWriter.java", - "com/android/internal/util/IState.java", "com/android/internal/util/MessageUtils.java", - "com/android/internal/util/State.java", - "com/android/internal/util/StateMachine.java", "com/android/internal/util/WakeupMessage.java", ], } diff --git a/core/java/android/accounts/Account.java b/core/java/android/accounts/Account.java index 0d6a07938e95..e6cdcc0ee742 100644 --- a/core/java/android/accounts/Account.java +++ b/core/java/android/accounts/Account.java @@ -31,6 +31,7 @@ import android.util.Log; import com.android.internal.annotations.GuardedBy; +import java.util.Objects; import java.util.Set; /** @@ -86,6 +87,12 @@ public class Account implements Parcelable { if (TextUtils.isEmpty(type)) { throw new IllegalArgumentException("the type must not be empty: " + type); } + if (name.length() > 200) { + throw new IllegalArgumentException("account name is longer than 200 characters"); + } + if (type.length() > 200) { + throw new IllegalArgumentException("account type is longer than 200 characters"); + } this.name = name; this.type = type; this.accessId = accessId; diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 6c3795d7c607..bfff27a82f5b 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -464,11 +464,7 @@ public final class ActivityThread extends ClientTransactionHandler @Override public int hashCode() { - return hashCode(authority, userId); - } - - public static int hashCode(final String auth, final int userIdent) { - return ((auth != null) ? auth.hashCode() : 0) ^ userIdent; + return ((authority != null) ? authority.hashCode() : 0) ^ userId; } } @@ -490,7 +486,7 @@ public final class ActivityThread extends ClientTransactionHandler // Note we never removes items from this map but that's okay because there are only so many // users and so many authorities. @GuardedBy("mGetProviderKeys") - final SparseArray<ProviderKey> mGetProviderKeys = new SparseArray<>(); + final ArrayMap<ProviderKey, ProviderKey> mGetProviderKeys = new ArrayMap<>(); final ArrayMap<Activity, ArrayList<OnActivityPausedListener>> mOnPauseListeners = new ArrayMap<Activity, ArrayList<OnActivityPausedListener>>(); @@ -7020,11 +7016,11 @@ public final class ActivityThread extends ClientTransactionHandler } private ProviderKey getGetProviderKey(String auth, int userId) { - final int key = ProviderKey.hashCode(auth, userId); + final ProviderKey key = new ProviderKey(auth, userId); synchronized (mGetProviderKeys) { ProviderKey lock = mGetProviderKeys.get(key); if (lock == null) { - lock = new ProviderKey(auth, userId); + lock = key; mGetProviderKeys.put(key, lock); } return lock; diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index d932a29beca6..63f700b8883c 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -1292,6 +1292,9 @@ public class AppOpsManager { /** @hide */ public static final int OP_UWB_RANGING = AppProtoEnums.APP_OP_UWB_RANGING; + /** @hide */ + public static final int OP_NEARBY_WIFI_DEVICES = AppProtoEnums.APP_OP_NEARBY_WIFI_DEVICES; + /** * Activity recognition being accessed by an activity recognition source, which * is a component that already has access since it is the one that detects @@ -1310,9 +1313,23 @@ public class AppOpsManager { public static final int OP_RECORD_INCOMING_PHONE_AUDIO = AppProtoEnums.APP_OP_RECORD_INCOMING_PHONE_AUDIO; + /** + * VPN app establishes a connection through the VpnService API. + * + * @hide + */ + public static final int OP_ESTABLISH_VPN_SERVICE = AppProtoEnums.APP_OP_ESTABLISH_VPN_SERVICE; + + /** + * VPN app establishes a connection through the VpnManager API. + * + * @hide + */ + public static final int OP_ESTABLISH_VPN_MANAGER = AppProtoEnums.APP_OP_ESTABLISH_VPN_MANAGER; + /** @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public static final int _NUM_OP = 116; + public static final int _NUM_OP = 119; /** Access to coarse location information. */ public static final String OPSTR_COARSE_LOCATION = "android:coarse_location"; @@ -1731,6 +1748,8 @@ public class AppOpsManager { public static final String OPSTR_MANAGE_MEDIA = "android:manage_media"; /** @hide */ public static final String OPSTR_UWB_RANGING = "android:uwb_ranging"; + /** @hide */ + public static final String OPSTR_NEARBY_WIFI_DEVICES = "android:nearby_wifi_devices"; /** * Activity recognition being accessed by an activity recognition source, which @@ -1749,6 +1768,22 @@ public class AppOpsManager { public static final String OPSTR_RECORD_INCOMING_PHONE_AUDIO = "android:record_incoming_phone_audio"; + /** + * VPN app establishes a connection through the VpnService API. + * + * @hide + */ + @SystemApi + public static final String OPSTR_ESTABLISH_VPN_SERVICE = "android:establish_vpn_service"; + + /** + * VPN app establishes a connection through the VpnManager API. + * + * @hide + */ + @SystemApi + public static final String OPSTR_ESTABLISH_VPN_MANAGER = "android:establish_vpn_manager"; + /** {@link #sAppOpsToNote} not initialized yet for this op */ private static final byte SHOULD_COLLECT_NOTE_OP_NOT_INITIALIZED = 0; /** Should not collect noting of this app-op in {@link #sAppOpsToNote} */ @@ -1819,6 +1854,7 @@ public class AppOpsManager { OP_BLUETOOTH_CONNECT, OP_BLUETOOTH_ADVERTISE, OP_UWB_RANGING, + OP_NEARBY_WIFI_DEVICES, // APPOP PERMISSIONS OP_ACCESS_NOTIFICATIONS, @@ -1963,6 +1999,9 @@ public class AppOpsManager { OP_ACTIVITY_RECOGNITION, // OP_ACTIVITY_RECOGNITION_SOURCE OP_BLUETOOTH_ADVERTISE, // OP_BLUETOOTH_ADVERTISE OP_RECORD_INCOMING_PHONE_AUDIO, // OP_RECORD_INCOMING_PHONE_AUDIO + OP_NEARBY_WIFI_DEVICES, // OP_NEARBY_WIFI_DEVICES + OP_ESTABLISH_VPN_SERVICE, // OP_ESTABLISH_VPN_SERVICE + OP_ESTABLISH_VPN_MANAGER, // OP_ESTABLISH_VPN_MANAGER }; /** @@ -2085,6 +2124,9 @@ public class AppOpsManager { OPSTR_ACTIVITY_RECOGNITION_SOURCE, OPSTR_BLUETOOTH_ADVERTISE, OPSTR_RECORD_INCOMING_PHONE_AUDIO, + OPSTR_NEARBY_WIFI_DEVICES, + OPSTR_ESTABLISH_VPN_SERVICE, + OPSTR_ESTABLISH_VPN_MANAGER, }; /** @@ -2208,6 +2250,9 @@ public class AppOpsManager { "ACTIVITY_RECOGNITION_SOURCE", "BLUETOOTH_ADVERTISE", "RECORD_INCOMING_PHONE_AUDIO", + "NEARBY_WIFI_DEVICES", + "ESTABLISH_VPN_SERVICE", + "ESTABLISH_VPN_MANAGER", }; /** @@ -2332,6 +2377,9 @@ public class AppOpsManager { null, // no permission for OP_ACTIVITY_RECOGNITION_SOURCE, Manifest.permission.BLUETOOTH_ADVERTISE, null, // no permission for OP_RECORD_INCOMING_PHONE_AUDIO, + Manifest.permission.NEARBY_WIFI_DEVICES, + null, // no permission for OP_ESTABLISH_VPN_SERVICE + null, // no permission for OP_ESTABLISH_VPN_MANAGER }; /** @@ -2456,6 +2504,9 @@ public class AppOpsManager { null, // ACTIVITY_RECOGNITION_SOURCE null, // BLUETOOTH_ADVERTISE null, // RECORD_INCOMING_PHONE_AUDIO + null, // NEARBY_WIFI_DEVICES + null, // ESTABLISH_VPN_SERVICE + null, // ESTABLISH_VPN_MANAGER }; /** @@ -2579,6 +2630,9 @@ public class AppOpsManager { null, // ACTIVITY_RECOGNITION_SOURCE null, // BLUETOOTH_ADVERTISE null, // RECORD_INCOMING_PHONE_AUDIO + null, // NEARBY_WIFI_DEVICES + null, // ESTABLISH_VPN_SERVICE + null, // ESTABLISH_VPN_MANAGER }; /** @@ -2701,6 +2755,9 @@ public class AppOpsManager { AppOpsManager.MODE_ALLOWED, // ACTIVITY_RECOGNITION_SOURCE AppOpsManager.MODE_ALLOWED, // BLUETOOTH_ADVERTISE AppOpsManager.MODE_ALLOWED, // RECORD_INCOMING_PHONE_AUDIO + AppOpsManager.MODE_ALLOWED, // NEARBY_WIFI_DEVICES + AppOpsManager.MODE_ALLOWED, // ESTABLISH_VPN_SERVICE + AppOpsManager.MODE_ALLOWED, // ESTABLISH_VPN_MANAGER }; /** @@ -2827,6 +2884,9 @@ public class AppOpsManager { false, // ACTIVITY_RECOGNITION_SOURCE false, // BLUETOOTH_ADVERTISE false, // RECORD_INCOMING_PHONE_AUDIO + false, // NEARBY_WIFI_DEVICES + false, // OP_ESTABLISH_VPN_SERVICE + false, // OP_ESTABLISH_VPN_MANAGER }; /** diff --git a/core/java/android/app/ApplicationLoaders.java b/core/java/android/app/ApplicationLoaders.java index 08cd0b34ee0a..53b16d3a8170 100644 --- a/core/java/android/app/ApplicationLoaders.java +++ b/core/java/android/app/ApplicationLoaders.java @@ -48,18 +48,19 @@ public class ApplicationLoaders { ClassLoader parent, String classLoaderName) { return getClassLoaderWithSharedLibraries(zip, targetSdkVersion, isBundled, librarySearchPath, libraryPermittedPath, parent, classLoaderName, - null, null); + null, null, null); } ClassLoader getClassLoaderWithSharedLibraries( String zip, int targetSdkVersion, boolean isBundled, String librarySearchPath, String libraryPermittedPath, ClassLoader parent, String classLoaderName, - List<ClassLoader> sharedLibraries, List<String> nativeSharedLibraries) { + List<ClassLoader> sharedLibraries, List<String> nativeSharedLibraries, + List<ClassLoader> sharedLibrariesLoadedAfterApp) { // For normal usage the cache key used is the same as the zip path. return getClassLoader(zip, targetSdkVersion, isBundled, librarySearchPath, libraryPermittedPath, parent, zip, classLoaderName, sharedLibraries, - nativeSharedLibraries); + nativeSharedLibraries, sharedLibrariesLoadedAfterApp); } /** @@ -71,7 +72,8 @@ public class ApplicationLoaders { */ ClassLoader getSharedLibraryClassLoaderWithSharedLibraries(String zip, int targetSdkVersion, boolean isBundled, String librarySearchPath, String libraryPermittedPath, - ClassLoader parent, String classLoaderName, List<ClassLoader> sharedLibraries) { + ClassLoader parent, String classLoaderName, List<ClassLoader> sharedLibraries, + List<ClassLoader> sharedLibrariesAfter) { ClassLoader loader = getCachedNonBootclasspathSystemLib(zip, parent, classLoaderName, sharedLibraries); if (loader != null) { @@ -86,14 +88,15 @@ public class ApplicationLoaders { nativeSharedLibraries.add("ALL"); return getClassLoaderWithSharedLibraries(zip, targetSdkVersion, isBundled, librarySearchPath, libraryPermittedPath, parent, classLoaderName, sharedLibraries, - nativeSharedLibraries); + nativeSharedLibraries, sharedLibrariesAfter); } private ClassLoader getClassLoader(String zip, int targetSdkVersion, boolean isBundled, String librarySearchPath, String libraryPermittedPath, ClassLoader parent, String cacheKey, String classLoaderName, List<ClassLoader> sharedLibraries, - List<String> nativeSharedLibraries) { + List<String> nativeSharedLibraries, + List<ClassLoader> sharedLibrariesLoadedAfterApp) { /* * This is the parent we use if they pass "null" in. In theory * this should be the "system" class loader; in practice we @@ -123,7 +126,7 @@ public class ApplicationLoaders { ClassLoader classloader = ClassLoaderFactory.createClassLoader( zip, librarySearchPath, libraryPermittedPath, parent, targetSdkVersion, isBundled, classLoaderName, sharedLibraries, - nativeSharedLibraries); + nativeSharedLibraries, sharedLibrariesLoadedAfterApp); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); @@ -140,7 +143,8 @@ public class ApplicationLoaders { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, zip); ClassLoader loader = ClassLoaderFactory.createClassLoader( - zip, null, parent, classLoaderName, sharedLibraries); + zip, null, parent, classLoaderName, sharedLibraries, + null /*sharedLibrariesLoadedAfterApp*/); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); return loader; } @@ -196,7 +200,7 @@ public class ApplicationLoaders { ClassLoader classLoader = getClassLoader(path, Build.VERSION.SDK_INT, true /*isBundled*/, null /*librarySearchPath*/, null /*libraryPermittedPath*/, null /*parent*/, null /*cacheKey*/, null /*classLoaderName*/, sharedLibraries /*sharedLibraries*/, - null /* nativeSharedLibraries */); + null /* nativeSharedLibraries */, null /*sharedLibrariesLoadedAfterApp*/); if (classLoader == null) { // bad configuration or break in classloading code @@ -267,7 +271,8 @@ public class ApplicationLoaders { // stub's APK path, when the actual package path is the donor APK. return getClassLoader(packagePath, Build.VERSION.SDK_INT, false, libsPath, null, null, cacheKey, null /* classLoaderName */, null /* sharedLibraries */, - null /* nativeSharedLibraries */); + null /* nativeSharedLibraries */, + null /*sharedLibrariesLoadedAfterApp*/); } /** diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java index a2c9795204ad..f6d27e125cd7 100644 --- a/core/java/android/app/LoadedApk.java +++ b/core/java/android/app/LoadedApk.java @@ -54,10 +54,12 @@ import android.text.TextUtils; import android.util.AndroidRuntimeException; import android.util.ArrayMap; import android.util.Log; +import android.util.Pair; import android.util.Slog; import android.util.SparseArray; import android.view.DisplayAdjustments; +import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.ArrayUtils; @@ -76,6 +78,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Enumeration; +import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Objects; @@ -700,7 +703,7 @@ public final class LoadedApk { ClassLoader createSharedLibraryLoader(SharedLibraryInfo sharedLibrary, boolean isBundledApp, String librarySearchPath, String libraryPermittedPath) { List<String> paths = sharedLibrary.getAllCodePaths(); - List<ClassLoader> sharedLibraries = createSharedLibrariesLoaders( + Pair<List<ClassLoader>, List<ClassLoader>> sharedLibraries = createSharedLibrariesLoaders( sharedLibrary.getDependencies(), isBundledApp, librarySearchPath, libraryPermittedPath); final String jars = (paths.size() == 1) ? paths.get(0) : @@ -711,15 +714,31 @@ public final class LoadedApk { return ApplicationLoaders.getDefault().getSharedLibraryClassLoaderWithSharedLibraries(jars, mApplicationInfo.targetSdkVersion, isBundledApp, librarySearchPath, libraryPermittedPath, /* parent */ null, - /* classLoaderName */ null, sharedLibraries); + /* classLoaderName */ null, sharedLibraries.first, sharedLibraries.second); } - private List<ClassLoader> createSharedLibrariesLoaders(List<SharedLibraryInfo> sharedLibraries, + /** + * + * @return a {@link Pair} of List<ClassLoader> where the first is for standard shared libraries + * and the second is list for shared libraries that code should be loaded after the dex + */ + private Pair<List<ClassLoader>, List<ClassLoader>> createSharedLibrariesLoaders( + List<SharedLibraryInfo> sharedLibraries, boolean isBundledApp, String librarySearchPath, String libraryPermittedPath) { - if (sharedLibraries == null) { - return null; + if (sharedLibraries == null || sharedLibraries.isEmpty()) { + return new Pair<>(null, null); } + + // if configured to do so, shared libs are split into 2 collections: those that are + // on the class path before the applications code, which is standard, and those + // specified to be loaded after the applications code. + HashSet<String> libsToLoadAfter = new HashSet<>(); + Resources systemR = Resources.getSystem(); + Collections.addAll(libsToLoadAfter, systemR.getStringArray( + R.array.config_sharedLibrariesLoadedAfterApp)); + List<ClassLoader> loaders = new ArrayList<>(); + List<ClassLoader> after = new ArrayList<>(); for (SharedLibraryInfo info : sharedLibraries) { if (info.isNative()) { // Native shared lib doesn't contribute to the native lib search path. Its name is @@ -727,10 +746,19 @@ public final class LoadedApk { // default linker namespace. continue; } - loaders.add(createSharedLibraryLoader( - info, isBundledApp, librarySearchPath, libraryPermittedPath)); + if (libsToLoadAfter.contains(info.getName())) { + if (DEBUG) { + Slog.v(ActivityThread.TAG, + info.getName() + " will be loaded after application code"); + } + after.add(createSharedLibraryLoader( + info, isBundledApp, librarySearchPath, libraryPermittedPath)); + } else { + loaders.add(createSharedLibraryLoader( + info, isBundledApp, librarySearchPath, libraryPermittedPath)); + } } - return loaders; + return new Pair<>(loaders, after); } private StrictMode.ThreadPolicy allowThreadDiskReads() { @@ -955,9 +983,9 @@ public final class LoadedApk { // as this is early and necessary. StrictMode.ThreadPolicy oldPolicy = allowThreadDiskReads(); - List<ClassLoader> sharedLibraries = createSharedLibrariesLoaders( - mApplicationInfo.sharedLibraryInfos, isBundledApp, librarySearchPath, - libraryPermittedPath); + Pair<List<ClassLoader>, List<ClassLoader>> sharedLibraries = + createSharedLibrariesLoaders(mApplicationInfo.sharedLibraryInfos, isBundledApp, + librarySearchPath, libraryPermittedPath); List<String> nativeSharedLibraries = new ArrayList<>(); if (mApplicationInfo.sharedLibraryInfos != null) { @@ -971,7 +999,8 @@ public final class LoadedApk { mDefaultClassLoader = ApplicationLoaders.getDefault().getClassLoaderWithSharedLibraries( zip, mApplicationInfo.targetSdkVersion, isBundledApp, librarySearchPath, libraryPermittedPath, mBaseClassLoader, - mApplicationInfo.classLoaderName, sharedLibraries, nativeSharedLibraries); + mApplicationInfo.classLoaderName, sharedLibraries.first, nativeSharedLibraries, + sharedLibraries.second); mAppComponentFactory = createAppFactory(mApplicationInfo, mDefaultClassLoader); setThreadPolicy(oldPolicy); diff --git a/core/java/android/app/OWNERS b/core/java/android/app/OWNERS index e0e9b62d3809..4da51c13045b 100644 --- a/core/java/android/app/OWNERS +++ b/core/java/android/app/OWNERS @@ -28,6 +28,7 @@ per-file ProfilerInfo* = file:/services/core/java/com/android/server/am/OWNERS per-file Service* = file:/services/core/java/com/android/server/am/OWNERS per-file SystemServiceRegistry.java = file:/services/core/java/com/android/server/am/OWNERS per-file *UserSwitchObserver* = file:/services/core/java/com/android/server/am/OWNERS +per-file UiAutomation.java = file:/services/accessibility/OWNERS # ActivityThread per-file ActivityThread.java = file:/services/core/java/com/android/server/am/OWNERS diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index 32ea41b2c75f..e2fd35940b52 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -1914,39 +1914,6 @@ public final class SystemServiceRegistry { public abstract T createService() throws ServiceNotFoundException; } - /** - * Like StaticServiceFetcher, creates only one instance of the service per application, but when - * creating the service for the first time, passes it the application context of the creating - * application. - * - * TODO: Delete this once its only user (ConnectivityManager) is known to work well in the - * case where multiple application components each have their own ConnectivityManager object. - */ - static abstract class StaticApplicationContextServiceFetcher<T> implements ServiceFetcher<T> { - private T mCachedInstance; - - @Override - public final T getService(ContextImpl ctx) { - synchronized (StaticApplicationContextServiceFetcher.this) { - if (mCachedInstance == null) { - Context appContext = ctx.getApplicationContext(); - // If the application context is null, we're either in the system process or - // it's the application context very early in app initialization. In both these - // cases, the passed-in ContextImpl will not be freed, so it's safe to pass it - // to the service. http://b/27532714 . - try { - mCachedInstance = createService(appContext != null ? appContext : ctx); - } catch (ServiceNotFoundException e) { - onServiceNotFound(e); - } - } - return mCachedInstance; - } - } - - public abstract T createService(Context applicationContext) throws ServiceNotFoundException; - } - /** @hide */ public static void onServiceNotFound(ServiceNotFoundException e) { // We're mostly interested in tracking down long-lived core system diff --git a/core/java/android/app/admin/EnterprisePlatformSecurity_OWNERS b/core/java/android/app/admin/EnterprisePlatformSecurity_OWNERS new file mode 100644 index 000000000000..f5604347065e --- /dev/null +++ b/core/java/android/app/admin/EnterprisePlatformSecurity_OWNERS @@ -0,0 +1,4 @@ +rubinxu@google.com +acjohnston@google.com +pgrafov@google.com +alexkershaw@google.com #{LAST_RESORT_SUGGESTION}
\ No newline at end of file diff --git a/core/java/android/app/admin/EnterprisePlatform_OWNERS b/core/java/android/app/admin/EnterprisePlatform_OWNERS new file mode 100644 index 000000000000..fb00fe506ed1 --- /dev/null +++ b/core/java/android/app/admin/EnterprisePlatform_OWNERS @@ -0,0 +1,2 @@ +file:WorkDeviceExperience_OWNERS +file:EnterprisePlatformSecurity_OWNERS
\ No newline at end of file diff --git a/core/java/android/app/admin/OWNERS b/core/java/android/app/admin/OWNERS index 6acbef29bec3..10a5f14dca9e 100644 --- a/core/java/android/app/admin/OWNERS +++ b/core/java/android/app/admin/OWNERS @@ -1,11 +1,5 @@ # Bug component: 142675 -# Android Enterprise team -rubinxu@google.com -sandness@google.com -alexkershaw@google.com -pgrafov@google.com +file:EnterprisePlatform_OWNERS -# Emeritus -yamasani@google.com -eranm@google.com +yamasani@google.com #{LAST_RESORT_SUGGESTION}
\ No newline at end of file diff --git a/core/java/android/app/admin/WorkDeviceExperience_OWNERS b/core/java/android/app/admin/WorkDeviceExperience_OWNERS new file mode 100644 index 000000000000..dcacaa25a236 --- /dev/null +++ b/core/java/android/app/admin/WorkDeviceExperience_OWNERS @@ -0,0 +1,5 @@ +work-device-experience+reviews@google.com +scottjonathan@google.com +arangelov@google.com +kholoudm@google.com +alexkershaw@google.com #{LAST_RESORT_SUGGESTION}
\ No newline at end of file diff --git a/core/java/android/app/time/OWNERS b/core/java/android/app/time/OWNERS index 8f8089717e3b..ef357e5a3b6a 100644 --- a/core/java/android/app/time/OWNERS +++ b/core/java/android/app/time/OWNERS @@ -1,3 +1,4 @@ # Bug component: 847766 -mingaleev@google.com -include /core/java/android/app/timedetector/OWNERS +# The app-facing APIs related to both time and time zone detection. +include /services/core/java/com/android/server/timedetector/OWNERS +include /services/core/java/com/android/server/timezonedetector/OWNERS diff --git a/core/java/android/app/timedetector/OWNERS b/core/java/android/app/timedetector/OWNERS index 941eed8de631..e9dbe4a0007d 100644 --- a/core/java/android/app/timedetector/OWNERS +++ b/core/java/android/app/timedetector/OWNERS @@ -1,4 +1,3 @@ # Bug component: 847766 -mingaleev@google.com -narayan@google.com -nfuller@google.com +# Internal APIs related to time detection. SDK APIs are in android.app.time. +include /services/core/java/com/android/server/timedetector/OWNERS diff --git a/core/java/android/app/timezone/OWNERS b/core/java/android/app/timezone/OWNERS index 8f8089717e3b..04d78f23517f 100644 --- a/core/java/android/app/timezone/OWNERS +++ b/core/java/android/app/timezone/OWNERS @@ -1,3 +1,4 @@ -# Bug component: 847766 -mingaleev@google.com -include /core/java/android/app/timedetector/OWNERS +# Bug component: 24949 +# Internal APIs related to APK-based time zone rule updates. +# Deprecated, deletion tracked by b/148144561 +include /services/core/java/com/android/server/timezone/OWNERS diff --git a/core/java/android/app/timezonedetector/OWNERS b/core/java/android/app/timezonedetector/OWNERS index 8f8089717e3b..fa03f1e835fd 100644 --- a/core/java/android/app/timezonedetector/OWNERS +++ b/core/java/android/app/timezonedetector/OWNERS @@ -1,3 +1,3 @@ # Bug component: 847766 -mingaleev@google.com -include /core/java/android/app/timedetector/OWNERS +# Internal APIs related to time zone detection. SDK APIs are in android.app.time. +include /services/core/java/com/android/server/timezonedetector/OWNERS diff --git a/core/java/android/bluetooth/BluetoothActivityEnergyInfo.java b/core/java/android/bluetooth/BluetoothActivityEnergyInfo.java index df065bf1bf8d..c17a7b4b3dfd 100644 --- a/core/java/android/bluetooth/BluetoothActivityEnergyInfo.java +++ b/core/java/android/bluetooth/BluetoothActivityEnergyInfo.java @@ -16,18 +16,26 @@ package android.bluetooth; +import android.annotation.ElapsedRealtimeLong; +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; -import java.util.Arrays; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Collections; +import java.util.List; /** * Record of energy and activity information from controller and * underlying bt stack state.Timestamp the record with system - * time + * time. * * @hide */ +@SystemApi(client = SystemApi.Client.PRIVILEGED_APPS) public final class BluetoothActivityEnergyInfo implements Parcelable { private final long mTimestamp; private int mBluetoothStackState; @@ -35,13 +43,24 @@ public final class BluetoothActivityEnergyInfo implements Parcelable { private long mControllerRxTimeMs; private long mControllerIdleTimeMs; private long mControllerEnergyUsed; - private UidTraffic[] mUidTraffic; + private List<UidTraffic> mUidTraffic; + + /** @hide */ + @IntDef(prefix = { "BT_STACK_STATE_" }, value = { + BT_STACK_STATE_INVALID, + BT_STACK_STATE_STATE_ACTIVE, + BT_STACK_STATE_STATE_SCANNING, + BT_STACK_STATE_STATE_IDLE + }) + @Retention(RetentionPolicy.SOURCE) + public @interface BluetoothStackState {} public static final int BT_STACK_STATE_INVALID = 0; public static final int BT_STACK_STATE_STATE_ACTIVE = 1; public static final int BT_STACK_STATE_STATE_SCANNING = 2; public static final int BT_STACK_STATE_STATE_IDLE = 3; + /** @hide */ public BluetoothActivityEnergyInfo(long timestamp, int stackState, long txTime, long rxTime, long idleTime, long energyUsed) { mTimestamp = timestamp; @@ -52,17 +71,18 @@ public final class BluetoothActivityEnergyInfo implements Parcelable { mControllerEnergyUsed = energyUsed; } - @SuppressWarnings("unchecked") - BluetoothActivityEnergyInfo(Parcel in) { + /** @hide */ + private BluetoothActivityEnergyInfo(Parcel in) { mTimestamp = in.readLong(); mBluetoothStackState = in.readInt(); mControllerTxTimeMs = in.readLong(); mControllerRxTimeMs = in.readLong(); mControllerIdleTimeMs = in.readLong(); mControllerEnergyUsed = in.readLong(); - mUidTraffic = in.createTypedArray(UidTraffic.CREATOR); + mUidTraffic = in.createTypedArrayList(UidTraffic.CREATOR); } + /** @hide */ @Override public String toString() { return "BluetoothActivityEnergyInfo{" @@ -72,11 +92,11 @@ public final class BluetoothActivityEnergyInfo implements Parcelable { + " mControllerRxTimeMs=" + mControllerRxTimeMs + " mControllerIdleTimeMs=" + mControllerIdleTimeMs + " mControllerEnergyUsed=" + mControllerEnergyUsed - + " mUidTraffic=" + Arrays.toString(mUidTraffic) + + " mUidTraffic=" + mUidTraffic + " }"; } - public static final @android.annotation.NonNull Parcelable.Creator<BluetoothActivityEnergyInfo> CREATOR = + public static final @NonNull Parcelable.Creator<BluetoothActivityEnergyInfo> CREATOR = new Parcelable.Creator<BluetoothActivityEnergyInfo>() { public BluetoothActivityEnergyInfo createFromParcel(Parcel in) { return new BluetoothActivityEnergyInfo(in); @@ -87,9 +107,8 @@ public final class BluetoothActivityEnergyInfo implements Parcelable { } }; - + /** @hide */ @Override - @SuppressWarnings("unchecked") public void writeToParcel(Parcel out, int flags) { out.writeLong(mTimestamp); out.writeInt(mBluetoothStackState); @@ -97,17 +116,21 @@ public final class BluetoothActivityEnergyInfo implements Parcelable { out.writeLong(mControllerRxTimeMs); out.writeLong(mControllerIdleTimeMs); out.writeLong(mControllerEnergyUsed); - out.writeTypedArray(mUidTraffic, flags); + out.writeTypedList(mUidTraffic); } + /** @hide */ @Override public int describeContents() { return 0; } /** - * @return bt stack reported state + * Get the Bluetooth stack state associated with the energy info. + * + * @return one of {@link #BluetoothStackState} states */ + @BluetoothStackState public int getBluetoothStackState() { return mBluetoothStackState; } @@ -134,7 +157,7 @@ public final class BluetoothActivityEnergyInfo implements Parcelable { } /** - * product of current(mA), voltage(V) and time(ms) + * Get the product of current (mA), voltage (V), and time (ms). * * @return energy used */ @@ -143,22 +166,31 @@ public final class BluetoothActivityEnergyInfo implements Parcelable { } /** - * @return timestamp(real time elapsed in milliseconds since boot) of record creation. + * @return timestamp (real time elapsed in milliseconds since boot) of record creation */ - public long getTimeStamp() { + public @ElapsedRealtimeLong long getTimestampMillis() { return mTimestamp; } - public UidTraffic[] getUidTraffic() { + /** + * Get the {@link List} of each application {@link android.bluetooth.UidTraffic}. + * + * @return current {@link List} of {@link android.bluetooth.UidTraffic} + */ + public @NonNull List<UidTraffic> getUidTraffic() { + if (mUidTraffic == null) { + return Collections.emptyList(); + } return mUidTraffic; } - public void setUidTraffic(UidTraffic[] traffic) { + /** @hide */ + public void setUidTraffic(List<UidTraffic> traffic) { mUidTraffic = traffic; } /** - * @return if the record is valid + * @return true if the record Tx time, Rx time, and Idle time are more than 0. */ public boolean isValid() { return ((mControllerTxTimeMs >= 0) && (mControllerRxTimeMs >= 0) diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java index 3b744a73e75e..dac8ffe5e008 100644 --- a/core/java/android/bluetooth/BluetoothAdapter.java +++ b/core/java/android/bluetooth/BluetoothAdapter.java @@ -2099,7 +2099,7 @@ public final class BluetoothAdapter { try { return mManagerService.isBleScanAlwaysAvailable(); } catch (RemoteException e) { - Log.e(TAG, "remote expection when calling isBleScanAlwaysAvailable", e); + Log.e(TAG, "remote exception when calling isBleScanAlwaysAvailable", e); return false; } } @@ -2272,6 +2272,66 @@ public final class BluetoothAdapter { return false; } + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(value = { + BluetoothStatusCodes.SUCCESS, + BluetoothStatusCodes.ERROR_UNKNOWN, + BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED, + BluetoothStatusCodes.ERROR_FEATURE_NOT_SUPPORTED, + }) + public @interface LeFeatureReturnValues {} + + /** + * Returns {@link BluetoothStatusCodes#SUCCESS} if LE Connected Isochronous Stream Central + * feature is supported, returns {@link BluetoothStatusCodes#ERROR_FEATURE_NOT_SUPPORTED} if + * the feature is not supported or an error code. + * + * @return whether the chipset supports the LE Connected Isochronous Stream Central feature + */ + @RequiresNoPermission + public @LeFeatureReturnValues int isCisCentralSupported() { + if (!getLeAccess()) { + return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; + } + try { + mServiceLock.readLock().lock(); + if (mService != null) { + return mService.isCisCentralSupported(); + } + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } finally { + mServiceLock.readLock().unlock(); + } + return BluetoothStatusCodes.ERROR_UNKNOWN; + } + + /** + * Returns {@link BluetoothStatusCodes#SUCCESS} if LE Periodic Advertising Sync Transfer Sender + * feature is supported, returns {@link BluetoothStatusCodes#ERROR_FEATURE_NOT_SUPPORTED} if the + * feature is not supported or an error code + * + * @return whether the chipset supports the LE Periodic Advertising Sync Transfer Sender feature + */ + @RequiresNoPermission + public @LeFeatureReturnValues int isLePeriodicAdvertisingSyncTransferSenderSupported() { + if (!getLeAccess()) { + return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; + } + try { + mServiceLock.readLock().lock(); + if (mService != null) { + return mService.isLePeriodicAdvertisingSyncTransferSenderSupported(); + } + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } finally { + mServiceLock.readLock().unlock(); + } + return BluetoothStatusCodes.ERROR_UNKNOWN; + } + /** * Return the maximum LE advertising data length in bytes, * if LE Extended Advertising feature is supported, 0 otherwise. @@ -2307,7 +2367,7 @@ public final class BluetoothAdapter { try { return mManagerService.isHearingAidProfileSupported(); } catch (RemoteException e) { - Log.e(TAG, "remote expection when calling isHearingAidProfileSupported", e); + Log.e(TAG, "remote exception when calling isHearingAidProfileSupported", e); return false; } } diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java index c71fcc637cb9..6e918bd6243d 100644 --- a/core/java/android/bluetooth/BluetoothDevice.java +++ b/core/java/android/bluetooth/BluetoothDevice.java @@ -1340,7 +1340,10 @@ public final class BluetoothDevice implements Parcelable, Attributable { if (alias == null) { return getName(); } - return alias; + return alias + .replace('\t', ' ') + .replace('\n', ' ') + .replace('\r', ' '); } catch (RemoteException e) { Log.e(TAG, "", e); } diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java index ca898bd6a5ef..4e7c01ad2db1 100644 --- a/core/java/android/bluetooth/BluetoothGatt.java +++ b/core/java/android/bluetooth/BluetoothGatt.java @@ -16,6 +16,8 @@ package android.bluetooth; +import android.annotation.IntDef; +import android.annotation.NonNull; import android.annotation.RequiresNoPermission; import android.annotation.RequiresPermission; import android.annotation.SuppressLint; @@ -29,6 +31,8 @@ import android.os.ParcelUuid; import android.os.RemoteException; import android.util.Log; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.List; import java.util.UUID; @@ -140,27 +144,6 @@ public final class BluetoothGatt implements BluetoothProfile { public static final int CONNECTION_PRIORITY_LOW_POWER = 2; /** - * A GATT writeCharacteristic request is started successfully. - * - * @hide - */ - public static final int GATT_WRITE_REQUEST_SUCCESS = 0; - - /** - * A GATT writeCharacteristic request failed to start. - * - * @hide - */ - public static final int GATT_WRITE_REQUEST_FAIL = 1; - - /** - * A GATT writeCharacteristic request is issued to a busy remote device. - * - * @hide - */ - public static final int GATT_WRITE_REQUEST_BUSY = 2; - - /** * No authentication required. * * @hide @@ -430,6 +413,9 @@ public final class BluetoothGatt implements BluetoothProfile { if (callback != null) { if (status == 0) characteristic.setValue(value); callback.onCharacteristicRead(BluetoothGatt.this, characteristic, + value, status); + // Keep calling deprecated callback to maintain app compatibility + callback.onCharacteristicRead(BluetoothGatt.this, characteristic, status); } } @@ -443,7 +429,8 @@ public final class BluetoothGatt implements BluetoothProfile { */ @Override @SuppressLint("AndroidFrameworkRequiresPermission") - public void onCharacteristicWrite(String address, int status, int handle) { + public void onCharacteristicWrite(String address, int status, int handle, + byte[] value) { if (VDBG) { Log.d(TAG, "onCharacteristicWrite() - Device=" + address + " handle=" + handle + " Status=" + status); @@ -467,12 +454,13 @@ public final class BluetoothGatt implements BluetoothProfile { try { final int authReq = (mAuthRetryState == AUTH_RETRY_STATE_IDLE) ? AUTHENTICATION_NO_MITM : AUTHENTICATION_MITM; - int requestStatus = GATT_WRITE_REQUEST_FAIL; + int requestStatus = BluetoothStatusCodes.ERROR_UNKNOWN; for (int i = 0; i < WRITE_CHARACTERISTIC_MAX_RETRIES; i++) { requestStatus = mService.writeCharacteristic(mClientIf, address, handle, characteristic.getWriteType(), authReq, - characteristic.getValue(), mAttributionSource); - if (requestStatus != GATT_WRITE_REQUEST_BUSY) { + value, mAttributionSource); + if (requestStatus + != BluetoothStatusCodes.ERROR_GATT_WRITE_REQUEST_BUSY) { break; } try { @@ -488,7 +476,6 @@ public final class BluetoothGatt implements BluetoothProfile { } mAuthRetryState = AUTH_RETRY_STATE_IDLE; - runOrQueueCallback(new Runnable() { @Override public void run() { @@ -525,6 +512,9 @@ public final class BluetoothGatt implements BluetoothProfile { if (callback != null) { characteristic.setValue(value); callback.onCharacteristicChanged(BluetoothGatt.this, + characteristic, value); + // Keep calling deprecated callback to maintain app compatibility + callback.onCharacteristicChanged(BluetoothGatt.this, characteristic); } } @@ -578,6 +568,9 @@ public final class BluetoothGatt implements BluetoothProfile { final BluetoothGattCallback callback = mCallback; if (callback != null) { if (status == 0) descriptor.setValue(value); + callback.onDescriptorRead(BluetoothGatt.this, descriptor, status, + value); + // Keep calling deprecated callback to maintain app compatibility callback.onDescriptorRead(BluetoothGatt.this, descriptor, status); } } @@ -590,7 +583,8 @@ public final class BluetoothGatt implements BluetoothProfile { */ @Override @SuppressLint("AndroidFrameworkRequiresPermission") - public void onDescriptorWrite(String address, int status, int handle) { + public void onDescriptorWrite(String address, int status, int handle, + byte[] value) { if (VDBG) { Log.d(TAG, "onDescriptorWrite() - Device=" + address + " handle=" + handle); @@ -614,7 +608,7 @@ public final class BluetoothGatt implements BluetoothProfile { final int authReq = (mAuthRetryState == AUTH_RETRY_STATE_IDLE) ? AUTHENTICATION_NO_MITM : AUTHENTICATION_MITM; mService.writeDescriptor(mClientIf, address, handle, - authReq, descriptor.getValue(), mAttributionSource); + authReq, value, mAttributionSource); mAuthRetryState++; return; } catch (RemoteException e) { @@ -1194,8 +1188,8 @@ public final class BluetoothGatt implements BluetoothProfile { * Reads the requested characteristic from the associated remote device. * * <p>This is an asynchronous operation. The result of the read operation - * is reported by the {@link BluetoothGattCallback#onCharacteristicRead} - * callback. + * is reported by the {@link BluetoothGattCallback#onCharacteristicRead(BluetoothGatt, + * BluetoothGattCharacteristic, byte[], int)} callback. * * @param characteristic Characteristic to read from the remote device * @return true, if the read operation was initiated successfully @@ -1240,8 +1234,8 @@ public final class BluetoothGatt implements BluetoothProfile { * Reads the characteristic using its UUID from the associated remote device. * * <p>This is an asynchronous operation. The result of the read operation - * is reported by the {@link BluetoothGattCallback#onCharacteristicRead} - * callback. + * is reported by the {@link BluetoothGattCallback#onCharacteristicRead(BluetoothGatt, + * BluetoothGattCharacteristic, byte[], int)} callback. * * @param uuid UUID of characteristic to read from the remote device * @return true, if the read operation was initiated successfully @@ -1284,40 +1278,94 @@ public final class BluetoothGatt implements BluetoothProfile { * * @param characteristic Characteristic to write on the remote device * @return true, if the write operation was initiated successfully + * @throws IllegalArgumentException if characteristic or its value are null + * + * @deprecated Use {@link BluetoothGatt#writeCharacteristic(BluetoothGattCharacteristic, byte[], + * int)} as this is not memory safe. */ + @Deprecated @RequiresLegacyBluetoothPermission @RequiresBluetoothConnectPermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean writeCharacteristic(BluetoothGattCharacteristic characteristic) { - if ((characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_WRITE) == 0 - && (characteristic.getProperties() - & BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) == 0) { + try { + return writeCharacteristic(characteristic, characteristic.getValue(), + characteristic.getWriteType()) == BluetoothStatusCodes.SUCCESS; + } catch (Exception e) { return false; } + } + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(value = { + BluetoothStatusCodes.SUCCESS, + BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION, + BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_PRIVILEGED_PERMISSION, + BluetoothStatusCodes.ERROR_DEVICE_NOT_CONNECTED, + BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND, + BluetoothStatusCodes.ERROR_GATT_WRITE_NOT_ALLOWED, + BluetoothStatusCodes.ERROR_GATT_WRITE_REQUEST_BUSY, + BluetoothStatusCodes.ERROR_UNKNOWN + }) + public @interface WriteOperationReturnValues{} + /** + * Writes a given characteristic and its values to the associated remote device. + * + * <p>Once the write operation has been completed, the + * {@link BluetoothGattCallback#onCharacteristicWrite} callback is invoked, + * reporting the result of the operation. + * + * @param characteristic Characteristic to write on the remote device + * @return whether the characteristic was successfully written to + * @throws IllegalArgumentException if characteristic or value are null + */ + @RequiresBluetoothConnectPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) + @WriteOperationReturnValues + public int writeCharacteristic(@NonNull BluetoothGattCharacteristic characteristic, + @NonNull byte[] value, int writeType) { + if (characteristic == null) { + throw new IllegalArgumentException("characteristic must not be null"); + } + if (value == null) { + throw new IllegalArgumentException("value must not be null"); + } if (VDBG) Log.d(TAG, "writeCharacteristic() - uuid: " + characteristic.getUuid()); - if (mService == null || mClientIf == 0 || characteristic.getValue() == null) return false; + if ((characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_WRITE) == 0 + && (characteristic.getProperties() + & BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) == 0) { + return BluetoothStatusCodes.ERROR_GATT_WRITE_NOT_ALLOWED; + } + if (mService == null || mClientIf == 0) { + return BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND; + } BluetoothGattService service = characteristic.getService(); - if (service == null) return false; + if (service == null) { + throw new IllegalArgumentException("Characteristic must have a non-null service"); + } BluetoothDevice device = service.getDevice(); - if (device == null) return false; + if (device == null) { + throw new IllegalArgumentException("Service must have a non-null device"); + } synchronized (mDeviceBusyLock) { if (mDeviceBusy) { - return false; + return BluetoothStatusCodes.ERROR_GATT_WRITE_REQUEST_BUSY; } mDeviceBusy = true; } - int requestStatus = GATT_WRITE_REQUEST_FAIL; + int requestStatus = BluetoothStatusCodes.ERROR_UNKNOWN; try { for (int i = 0; i < WRITE_CHARACTERISTIC_MAX_RETRIES; i++) { requestStatus = mService.writeCharacteristic(mClientIf, device.getAddress(), - characteristic.getInstanceId(), characteristic.getWriteType(), - AUTHENTICATION_NONE, characteristic.getValue(), mAttributionSource); - if (requestStatus != GATT_WRITE_REQUEST_BUSY) { + characteristic.getInstanceId(), writeType, AUTHENTICATION_NONE, value, + mAttributionSource); + if (requestStatus != BluetoothStatusCodes.ERROR_GATT_WRITE_REQUEST_BUSY) { break; } try { @@ -1330,10 +1378,10 @@ public final class BluetoothGatt implements BluetoothProfile { synchronized (mDeviceBusyLock) { mDeviceBusy = false; } - return false; + throw e.rethrowFromSystemServer(); } - return requestStatus == GATT_WRITE_REQUEST_SUCCESS; + return requestStatus; } /** @@ -1384,45 +1432,86 @@ public final class BluetoothGatt implements BluetoothProfile { /** * Write the value of a given descriptor to the associated remote device. * - * <p>A {@link BluetoothGattCallback#onDescriptorWrite} callback is - * triggered to report the result of the write operation. + * <p>A {@link BluetoothGattCallback#onDescriptorWrite} callback is triggered to report the + * result of the write operation. * * @param descriptor Descriptor to write to the associated remote device * @return true, if the write operation was initiated successfully + * @throws IllegalArgumentException if descriptor or its value are null + * + * @deprecated Use {@link BluetoothGatt#writeDescriptor(BluetoothGattDescriptor, byte[])} as + * this is not memory safe. */ + @Deprecated @RequiresLegacyBluetoothPermission @RequiresBluetoothConnectPermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean writeDescriptor(BluetoothGattDescriptor descriptor) { + try { + return writeDescriptor(descriptor, descriptor.getValue()) + == BluetoothStatusCodes.SUCCESS; + } catch (Exception e) { + return false; + } + } + + /** + * Write the value of a given descriptor to the associated remote device. + * + * <p>A {@link BluetoothGattCallback#onDescriptorWrite} callback is triggered to report the + * result of the write operation. + * + * @param descriptor Descriptor to write to the associated remote device + * @return true, if the write operation was initiated successfully + * @throws IllegalArgumentException if descriptor or value are null + */ + @RequiresBluetoothConnectPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) + @WriteOperationReturnValues + public int writeDescriptor(@NonNull BluetoothGattDescriptor descriptor, + @NonNull byte[] value) { + if (descriptor == null) { + throw new IllegalArgumentException("descriptor must not be null"); + } + if (value == null) { + throw new IllegalArgumentException("value must not be null"); + } if (VDBG) Log.d(TAG, "writeDescriptor() - uuid: " + descriptor.getUuid()); - if (mService == null || mClientIf == 0 || descriptor.getValue() == null) return false; + if (mService == null || mClientIf == 0) { + return BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND; + } BluetoothGattCharacteristic characteristic = descriptor.getCharacteristic(); - if (characteristic == null) return false; + if (characteristic == null) { + throw new IllegalArgumentException("Descriptor must have a non-null characteristic"); + } BluetoothGattService service = characteristic.getService(); - if (service == null) return false; + if (service == null) { + throw new IllegalArgumentException("Characteristic must have a non-null service"); + } BluetoothDevice device = service.getDevice(); - if (device == null) return false; + if (device == null) { + throw new IllegalArgumentException("Service must have a non-null device"); + } synchronized (mDeviceBusyLock) { - if (mDeviceBusy) return false; + if (mDeviceBusy) return BluetoothStatusCodes.ERROR_GATT_WRITE_REQUEST_BUSY; mDeviceBusy = true; } try { - mService.writeDescriptor(mClientIf, device.getAddress(), descriptor.getInstanceId(), - AUTHENTICATION_NONE, descriptor.getValue(), mAttributionSource); + return mService.writeDescriptor(mClientIf, device.getAddress(), + descriptor.getInstanceId(), AUTHENTICATION_NONE, value, mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "", e); synchronized (mDeviceBusyLock) { mDeviceBusy = false; } - return false; + e.rethrowFromSystemServer(); } - - return true; + return BluetoothStatusCodes.ERROR_UNKNOWN; } /** @@ -1431,9 +1520,9 @@ public final class BluetoothGatt implements BluetoothProfile { * <p>Once a reliable write transaction has been initiated, all calls * to {@link #writeCharacteristic} are sent to the remote device for * verification and queued up for atomic execution. The application will - * receive an {@link BluetoothGattCallback#onCharacteristicWrite} callback - * in response to every {@link #writeCharacteristic} call and is responsible - * for verifying if the value has been transmitted accurately. + * receive a {@link BluetoothGattCallback#onCharacteristicWrite} callback in response to every + * {@link #writeCharacteristic(BluetoothGattCharacteristic, byte[], int)} call and is + * responsible for verifying if the value has been transmitted accurately. * * <p>After all characteristics have been queued up and verified, * {@link #executeReliableWrite} will execute all writes. If a characteristic @@ -1530,9 +1619,9 @@ public final class BluetoothGatt implements BluetoothProfile { * Enable or disable notifications/indications for a given characteristic. * * <p>Once notifications are enabled for a characteristic, a - * {@link BluetoothGattCallback#onCharacteristicChanged} callback will be - * triggered if the remote device indicates that the given characteristic - * has changed. + * {@link BluetoothGattCallback#onCharacteristicChanged(BluetoothGatt, + * BluetoothGattCharacteristic, byte[])} callback will be triggered if the remote device + * indicates that the given characteristic has changed. * * @param characteristic The characteristic for which to enable notifications * @param enable Set to true to enable notifications/indications diff --git a/core/java/android/bluetooth/BluetoothGattCallback.java b/core/java/android/bluetooth/BluetoothGattCallback.java index 1c40cff076f6..d0a5a1e729fe 100644 --- a/core/java/android/bluetooth/BluetoothGattCallback.java +++ b/core/java/android/bluetooth/BluetoothGattCallback.java @@ -80,16 +80,34 @@ public abstract class BluetoothGattCallback { /** * Callback reporting the result of a characteristic read operation. * - * @param gatt GATT client invoked {@link BluetoothGatt#readCharacteristic} + * @param gatt GATT client invoked + * {@link BluetoothGatt#readCharacteristic(BluetoothGattCharacteristic)} * @param characteristic Characteristic that was read from the associated remote device. - * @param status {@link BluetoothGatt#GATT_SUCCESS} if the read operation was completed - * successfully. + * @param status {@link BluetoothGatt#GATT_SUCCESS} if the read operation was completed + * successfully. + * @deprecated Use {@link BluetoothGattCallback#onCharacteristicRead(BluetoothGatt, + * BluetoothGattCharacteristic, byte[], int)} as it is memory safe */ + @Deprecated public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { } /** + * Callback reporting the result of a characteristic read operation. + * + * @param gatt GATT client invoked + * {@link BluetoothGatt#readCharacteristic(BluetoothGattCharacteristic)} + * @param characteristic Characteristic that was read from the associated remote device. + * @param value the value of the characteristic + * @param status {@link BluetoothGatt#GATT_SUCCESS} if the read operation was completed + * successfully. + */ + public void onCharacteristicRead(@NonNull BluetoothGatt gatt, @NonNull + BluetoothGattCharacteristic characteristic, @NonNull byte[] value, int status) { + } + + /** * Callback indicating the result of a characteristic write operation. * * <p>If this callback is invoked while a reliable write transaction is @@ -98,10 +116,13 @@ public abstract class BluetoothGattCallback { * value to the desired value to be written. If the values don't match, * the application must abort the reliable write transaction. * - * @param gatt GATT client invoked {@link BluetoothGatt#writeCharacteristic} + * @param gatt GATT client that invoked + * {@link BluetoothGatt#writeCharacteristic(BluetoothGattCharacteristic, + * byte[], int)} * @param characteristic Characteristic that was written to the associated remote device. - * @param status The result of the write operation {@link BluetoothGatt#GATT_SUCCESS} if the - * operation succeeds. + * @param status The result of the write operation {@link BluetoothGatt#GATT_SUCCESS} if + * the + * operation succeeds. */ public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { @@ -110,33 +131,68 @@ public abstract class BluetoothGattCallback { /** * Callback triggered as a result of a remote characteristic notification. * - * @param gatt GATT client the characteristic is associated with + * @param gatt GATT client the characteristic is associated with * @param characteristic Characteristic that has been updated as a result of a remote - * notification event. + * notification event. + * @deprecated Use {@link BluetoothGattCallback#onCharacteristicChanged(BluetoothGatt, + * BluetoothGattCharacteristic, byte[])} as it is memory safe by providing the characteristic + * value at the time of notification. */ + @Deprecated public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { } /** + * Callback triggered as a result of a remote characteristic notification. Note that the value + * within the characteristic object may have changed since receiving the remote characteristic + * notification, so check the parameter value for the value at the time of notification. + * + * @param gatt GATT client the characteristic is associated with + * @param characteristic Characteristic that has been updated as a result of a remote + * notification event. + * @param value notified characteristic value + */ + public void onCharacteristicChanged(@NonNull BluetoothGatt gatt, + @NonNull BluetoothGattCharacteristic characteristic, @NonNull byte[] value) { + } + + /** * Callback reporting the result of a descriptor read operation. * - * @param gatt GATT client invoked {@link BluetoothGatt#readDescriptor} + * @param gatt GATT client invoked {@link BluetoothGatt#readDescriptor} * @param descriptor Descriptor that was read from the associated remote device. - * @param status {@link BluetoothGatt#GATT_SUCCESS} if the read operation was completed - * successfully + * @param status {@link BluetoothGatt#GATT_SUCCESS} if the read operation was completed + * successfully + * @deprecated Use {@link BluetoothGattCallback#onDescriptorRead(BluetoothGatt, + * BluetoothGattDescriptor, int, byte[])} as it is memory safe by providing the descriptor + * value at the time it was read. */ + @Deprecated public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { } /** + * Callback reporting the result of a descriptor read operation. + * + * @param gatt GATT client invoked {@link BluetoothGatt#readDescriptor} + * @param descriptor Descriptor that was read from the associated remote device. + * @param status {@link BluetoothGatt#GATT_SUCCESS} if the read operation was completed + * successfully + * @param value the descriptor value at the time of the read operation + */ + public void onDescriptorRead(@NonNull BluetoothGatt gatt, + @NonNull BluetoothGattDescriptor descriptor, int status, @NonNull byte[] value) { + } + + /** * Callback indicating the result of a descriptor write operation. * - * @param gatt GATT client invoked {@link BluetoothGatt#writeDescriptor} + * @param gatt GATT client invoked {@link BluetoothGatt#writeDescriptor} * @param descriptor Descriptor that was writte to the associated remote device. - * @param status The result of the write operation {@link BluetoothGatt#GATT_SUCCESS} if the - * operation succeeds. + * @param status The result of the write operation {@link BluetoothGatt#GATT_SUCCESS} if the + * operation succeeds. */ public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { diff --git a/core/java/android/bluetooth/BluetoothGattCharacteristic.java b/core/java/android/bluetooth/BluetoothGattCharacteristic.java index 8a7d4baf5add..c5e986e895b2 100644 --- a/core/java/android/bluetooth/BluetoothGattCharacteristic.java +++ b/core/java/android/bluetooth/BluetoothGattCharacteristic.java @@ -451,8 +451,8 @@ public class BluetoothGattCharacteristic implements Parcelable { * Set the write type for this characteristic * * <p>Setting the write type of a characteristic determines how the - * {@link BluetoothGatt#writeCharacteristic} function write this - * characteristic. + * {@link BluetoothGatt#writeCharacteristic(BluetoothGattCharacteristic, byte[], int)} function + * write this characteristic. * * @param writeType The write type to for this characteristic. Can be one of: {@link * #WRITE_TYPE_DEFAULT}, {@link #WRITE_TYPE_NO_RESPONSE} or {@link #WRITE_TYPE_SIGNED}. @@ -504,7 +504,10 @@ public class BluetoothGattCharacteristic implements Parcelable { * operation or if a characteristic update notification has been received. * * @return Cached value of the characteristic + * + * @deprecated Use {@link BluetoothGatt#readCharacteristic(BluetoothGattCharacteristic)} instead */ + @Deprecated public byte[] getValue() { return mValue; } @@ -521,7 +524,11 @@ public class BluetoothGattCharacteristic implements Parcelable { * @param formatType The format type used to interpret the characteristic value. * @param offset Offset at which the integer value can be found. * @return Cached value of the characteristic or null of offset exceeds value size. + * + * @deprecated Use {@link BluetoothGatt#readCharacteristic(BluetoothGattCharacteristic)} to get + * the characteristic value */ + @Deprecated public Integer getIntValue(int formatType, int offset) { if ((offset + getTypeLen(formatType)) > mValue.length) return null; @@ -558,7 +565,11 @@ public class BluetoothGattCharacteristic implements Parcelable { * @param offset Offset at which the float value can be found. * @return Cached value of the characteristic at a given offset or null if the requested offset * exceeds the value size. + * + * @deprecated Use {@link BluetoothGatt#readCharacteristic(BluetoothGattCharacteristic)} to get + * the characteristic value */ + @Deprecated public Float getFloatValue(int formatType, int offset) { if ((offset + getTypeLen(formatType)) > mValue.length) return null; @@ -580,7 +591,11 @@ public class BluetoothGattCharacteristic implements Parcelable { * * @param offset Offset at which the string value can be found. * @return Cached value of the characteristic + * + * @deprecated Use {@link BluetoothGatt#readCharacteristic(BluetoothGattCharacteristic)} to get + * the characteristic value */ + @Deprecated public String getStringValue(int offset) { if (mValue == null || offset > mValue.length) return null; byte[] strBytes = new byte[mValue.length - offset]; @@ -599,7 +614,11 @@ public class BluetoothGattCharacteristic implements Parcelable { * @param value New value for this characteristic * @return true if the locally stored value has been set, false if the requested value could not * be stored locally. + * + * @deprecated Pass the characteristic value directly into + * {@link BluetoothGatt#writeCharacteristic(BluetoothGattCharacteristic, byte[], int)} */ + @Deprecated public boolean setValue(byte[] value) { mValue = value; return true; @@ -613,7 +632,11 @@ public class BluetoothGattCharacteristic implements Parcelable { * @param formatType Integer format type used to transform the value parameter * @param offset Offset at which the value should be placed * @return true if the locally stored value has been set + * + * @deprecated Pass the characteristic value directly into + * {@link BluetoothGatt#writeCharacteristic(BluetoothGattCharacteristic, byte[], int)} */ + @Deprecated public boolean setValue(int value, int formatType, int offset) { int len = offset + getTypeLen(formatType); if (mValue == null) mValue = new byte[len]; @@ -660,7 +683,11 @@ public class BluetoothGattCharacteristic implements Parcelable { * @param formatType Float format type used to transform the value parameter * @param offset Offset at which the value should be placed * @return true if the locally stored value has been set + * + * @deprecated Pass the characteristic value directly into + * {@link BluetoothGatt#writeCharacteristic(BluetoothGattCharacteristic, byte[], int)} */ + @Deprecated public boolean setValue(int mantissa, int exponent, int formatType, int offset) { int len = offset + getTypeLen(formatType); if (mValue == null) mValue = new byte[len]; @@ -697,7 +724,11 @@ public class BluetoothGattCharacteristic implements Parcelable { * * @param value New value for this characteristic * @return true if the locally stored value has been set + * + * @deprecated Pass the characteristic value directly into + * {@link BluetoothGatt#writeCharacteristic(BluetoothGattCharacteristic, byte[], int)} */ + @Deprecated public boolean setValue(String value) { mValue = value.getBytes(); return true; diff --git a/core/java/android/bluetooth/BluetoothGattDescriptor.java b/core/java/android/bluetooth/BluetoothGattDescriptor.java index ed5ea0873020..a35d5b99fd7b 100644 --- a/core/java/android/bluetooth/BluetoothGattDescriptor.java +++ b/core/java/android/bluetooth/BluetoothGattDescriptor.java @@ -260,7 +260,10 @@ public class BluetoothGattDescriptor implements Parcelable { * operation. * * @return Cached value of the descriptor + * + * @deprecated Use {@link BluetoothGatt#readDescriptor(BluetoothGattDescriptor)} instead */ + @Deprecated public byte[] getValue() { return mValue; } @@ -276,7 +279,11 @@ public class BluetoothGattDescriptor implements Parcelable { * @param value New value for this descriptor * @return true if the locally stored value has been set, false if the requested value could not * be stored locally. + * + * @deprecated Pass the descriptor value directly into + * {@link BluetoothGatt#writeDescriptor(BluetoothGattDescriptor, byte[])} */ + @Deprecated public boolean setValue(byte[] value) { mValue = value; return true; diff --git a/core/java/android/bluetooth/BluetoothHeadsetClient.java b/core/java/android/bluetooth/BluetoothHeadsetClient.java index 83108d22e0c3..a5a247087209 100644 --- a/core/java/android/bluetooth/BluetoothHeadsetClient.java +++ b/core/java/android/bluetooth/BluetoothHeadsetClient.java @@ -817,7 +817,7 @@ public final class BluetoothHeadsetClient implements BluetoothProfile { @RequiresBluetoothConnectPermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public Bundle getCurrentAgEvents(BluetoothDevice device) { - if (DBG) log("getCurrentCalls()"); + if (DBG) log("getCurrentAgEvents()"); final IBluetoothHeadsetClient service = getService(); if (service != null && isEnabled() && isValidDevice(device)) { diff --git a/core/java/android/bluetooth/BluetoothLeAudio.java b/core/java/android/bluetooth/BluetoothLeAudio.java index c30c933b6ef8..d7940eb9d3a4 100644 --- a/core/java/android/bluetooth/BluetoothLeAudio.java +++ b/core/java/android/bluetooth/BluetoothLeAudio.java @@ -156,6 +156,12 @@ public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable { "android.bluetooth.action.LE_AUDIO_CONF_CHANGED"; /** + * Indicates unspecified audio content. + * @hide + */ + public static final int CONTEXT_TYPE_UNSPECIFIED = 0x0001; + + /** * Indicates conversation between humans as, for example, in telephony or video calls. * @hide */ @@ -168,6 +174,66 @@ public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable { public static final int CONTEXT_TYPE_MEDIA = 0x0004; /** + * Indicates instructional audio as, for example, in navigation, traffic announcements + * or user guidance. + * @hide + */ + public static final int CONTEXT_TYPE_INSTRUCTIONAL = 0x0008; + + /** + * Indicates attention seeking audio as, for example, in beeps signalling arrival of a message + * or keyboard clicks. + * @hide + */ + public static final int CONTEXT_TYPE_ATTENTION_SEEKING = 0x0010; + + /** + * Indicates immediate alerts as, for example, in a low battery alarm, timer expiry or alarm + * clock. + * @hide + */ + public static final int CONTEXT_TYPE_IMMEDIATE_ALERT = 0x0020; + + /** + * Indicates man machine communication as, for example, with voice recognition or virtual + * assistant. + * @hide + */ + public static final int CONTEXT_TYPE_MAN_MACHINE = 0x0040; + + /** + * Indicates emergency alerts as, for example, with fire alarms or other urgent alerts. + * @hide + */ + public static final int CONTEXT_TYPE_EMERGENCY_ALERT = 0x0080; + + /** + * Indicates ringtone as in a call alert. + * @hide + */ + public static final int CONTEXT_TYPE_RINGTONE = 0x0100; + + /** + * Indicates audio associated with a television program and/or with metadata conforming to the + * Bluetooth Broadcast TV profile. + * @hide + */ + public static final int CONTEXT_TYPE_TV = 0x0200; + + /** + * Indicates audio associated with a low latency live audio stream. + * + * @hide + */ + public static final int CONTEXT_TYPE_LIVE = 0x0400; + + /** + * Indicates audio associated with a video game stream. + * @hide + */ + public static final int CONTEXT_TYPE_GAME = 0x0800; + + /** * This represents an invalid group ID. * * @hide @@ -250,6 +316,17 @@ public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable { */ public static final int GROUP_STATUS_INACTIVE = IBluetoothLeAudio.GROUP_STATUS_INACTIVE; + /** + * Indicating that node has been added to the group. + * @hide + */ + public static final int GROUP_NODE_ADDED = IBluetoothLeAudio.GROUP_NODE_ADDED; + + /** + * Indicating that node has been removed from the group. + * @hide + */ + public static final int GROUP_NODE_REMOVED = IBluetoothLeAudio.GROUP_NODE_REMOVED; private final BluetoothProfileConnector<IBluetoothLeAudio> mProfileConnector = new BluetoothProfileConnector(this, BluetoothProfile.LE_AUDIO, "BluetoothLeAudio", @@ -546,6 +623,61 @@ public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable { } /** + * Add device to the given group. + * @param group_id group ID the device is being added to + * @param device the active device + * @return true on success, otherwise false + * @hide + */ + @RequiresBluetoothConnectPermission + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED + }) + public boolean groupAddNode(int group_id, @NonNull BluetoothDevice device) { + if (VDBG) log("groupAddNode()"); + final IBluetoothLeAudio service = getService(); + try { + if (service != null && mAdapter.isEnabled()) { + return service.groupAddNode(group_id, device, mAttributionSource); + } + if (service == null) Log.w(TAG, "Proxy not attached to service"); + return false; + } catch (RemoteException e) { + Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); + return false; + } + } + + /** + * Remove device from a given group. + * @param group_id group ID the device is being removed from + * @param device the active device + * @return true on success, otherwise false + * + * @hide + */ + @RequiresBluetoothConnectPermission + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED + }) + public boolean groupRemoveNode(int group_id, @NonNull BluetoothDevice device) { + if (VDBG) log("groupRemoveNode()"); + final IBluetoothLeAudio service = getService(); + try { + if (service != null && mAdapter.isEnabled()) { + return service.groupRemoveNode(group_id, device, mAttributionSource); + } + if (service == null) Log.w(TAG, "Proxy not attached to service"); + return false; + } catch (RemoteException e) { + Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); + return false; + } + } + + /** * Set connection policy of the profile * * <p> The device should already be paired. diff --git a/core/java/android/bluetooth/BluetoothStatusCodes.java b/core/java/android/bluetooth/BluetoothStatusCodes.java index 3e46c498e336..ca01784efd88 100644 --- a/core/java/android/bluetooth/BluetoothStatusCodes.java +++ b/core/java/android/bluetooth/BluetoothStatusCodes.java @@ -79,6 +79,33 @@ public final class BluetoothStatusCodes { public static final int ERROR_MISSING_BLUETOOTH_SCAN_PERMISSION = 7; /** + * Error code indicating that the caller does not have the + * {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} permission + */ + public static final int ERROR_MISSING_BLUETOOTH_PRIVILEGED_PERMISSION = 8; + + /** + * Error code indicating that the profile service is not bound. You can bind a profile service + * by calling {@link BluetoothAdapter#getProfileProxy} + */ + public static final int ERROR_PROFILE_SERVICE_NOT_BOUND = 9; + + /** + * Error code indicating that the feature is not supported. + */ + public static final int ERROR_FEATURE_NOT_SUPPORTED = 10; + + /** + * A GATT writeCharacteristic request is not permitted on the remote device. + */ + public static final int ERROR_GATT_WRITE_NOT_ALLOWED = 101; + + /** + * A GATT writeCharacteristic request is issued to a busy remote device. + */ + public static final int ERROR_GATT_WRITE_REQUEST_BUSY = 102; + + /** * If another application has already requested {@link OobData} then another fetch will be * disallowed until the callback is removed. * diff --git a/core/java/android/bluetooth/BluetoothUuid.java b/core/java/android/bluetooth/BluetoothUuid.java index 325a77107255..858819e15abc 100644 --- a/core/java/android/bluetooth/BluetoothUuid.java +++ b/core/java/android/bluetooth/BluetoothUuid.java @@ -188,6 +188,11 @@ public final class BluetoothUuid { /** @hide */ @NonNull @SystemApi + public static final ParcelUuid CAP = + ParcelUuid.fromString("EEEEEEEE-EEEE-EEEE-EEEE-EEEEEEEEEEEE"); + /** @hide */ + @NonNull + @SystemApi public static final ParcelUuid BASE_UUID = ParcelUuid.fromString("00000000-0000-1000-8000-00805F9B34FB"); diff --git a/core/java/android/bluetooth/UidTraffic.java b/core/java/android/bluetooth/UidTraffic.java index 2ee786a59091..9982fa6121e4 100644 --- a/core/java/android/bluetooth/UidTraffic.java +++ b/core/java/android/bluetooth/UidTraffic.java @@ -15,6 +15,7 @@ */ package android.bluetooth; +import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; @@ -23,27 +24,27 @@ import android.os.Parcelable; * * @hide */ -public class UidTraffic implements Cloneable, Parcelable { +@SystemApi(client = SystemApi.Client.PRIVILEGED_APPS) +public final class UidTraffic implements Cloneable, Parcelable { private final int mAppUid; private long mRxBytes; private long mTxBytes; - public UidTraffic(int appUid) { - mAppUid = appUid; - } - + /** @hide */ public UidTraffic(int appUid, long rx, long tx) { mAppUid = appUid; mRxBytes = rx; mTxBytes = tx; } - UidTraffic(Parcel in) { + /** @hide */ + private UidTraffic(Parcel in) { mAppUid = in.readInt(); mRxBytes = in.readLong(); mTxBytes = in.readLong(); } + /** @hide */ @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(mAppUid); @@ -51,44 +52,60 @@ public class UidTraffic implements Cloneable, Parcelable { dest.writeLong(mTxBytes); } + /** @hide */ public void setRxBytes(long bytes) { mRxBytes = bytes; } + /** @hide */ public void setTxBytes(long bytes) { mTxBytes = bytes; } + /** @hide */ public void addRxBytes(long bytes) { mRxBytes += bytes; } + /** @hide */ public void addTxBytes(long bytes) { mTxBytes += bytes; } + /** + * @return corresponding app Uid + */ public int getUid() { return mAppUid; } + /** + * @return rx bytes count + */ public long getRxBytes() { return mRxBytes; } + /** + * @return tx bytes count + */ public long getTxBytes() { return mTxBytes; } + /** @hide */ @Override public int describeContents() { return 0; } + /** @hide */ @Override public UidTraffic clone() { return new UidTraffic(mAppUid, mRxBytes, mTxBytes); } + /** @hide */ @Override public String toString() { return "UidTraffic{mAppUid=" + mAppUid + ", mRxBytes=" + mRxBytes + ", mTxBytes=" diff --git a/core/java/android/bluetooth/le/BluetoothLeUtils.java b/core/java/android/bluetooth/le/BluetoothLeUtils.java index 6381f557c1b2..ed50b09597bb 100644 --- a/core/java/android/bluetooth/le/BluetoothLeUtils.java +++ b/core/java/android/bluetooth/le/BluetoothLeUtils.java @@ -24,6 +24,7 @@ import java.util.Iterator; import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.UUID; /** * Helper class for Bluetooth LE utils. @@ -137,4 +138,21 @@ public class BluetoothLeUtils { } } + /** + * Compares two UUIDs with a UUID mask. + * + * @param data first {@link #UUID} to compare. + * @param uuid second {@link #UUID} to compare. + * @param mask mask {@link #UUID}. + * @return true if both UUIDs are equals when masked, false otherwise. + */ + static boolean maskedEquals(UUID data, UUID uuid, UUID mask) { + if (mask == null) { + return Objects.equals(data, uuid); + } + return (data.getLeastSignificantBits() & mask.getLeastSignificantBits()) + == (uuid.getLeastSignificantBits() & mask.getLeastSignificantBits()) + && (data.getMostSignificantBits() & mask.getMostSignificantBits()) + == (uuid.getMostSignificantBits() & mask.getMostSignificantBits()); + } } diff --git a/core/java/android/bluetooth/le/ScanFilter.java b/core/java/android/bluetooth/le/ScanFilter.java index 8ff018121ab0..b059193ae03f 100644 --- a/core/java/android/bluetooth/le/ScanFilter.java +++ b/core/java/android/bluetooth/le/ScanFilter.java @@ -28,8 +28,6 @@ import android.os.Parcel; import android.os.ParcelUuid; import android.os.Parcelable; -import com.android.internal.util.BitUtils; - import java.util.Arrays; import java.util.List; import java.util.Objects; @@ -448,7 +446,7 @@ public final class ScanFilter implements Parcelable { // Check if the uuid pattern matches the particular service uuid. private static boolean matchesServiceUuid(UUID uuid, UUID mask, UUID data) { - return BitUtils.maskedEquals(data, uuid, mask); + return BluetoothLeUtils.maskedEquals(data, uuid, mask); } /** @@ -478,7 +476,7 @@ public final class ScanFilter implements Parcelable { // Check if the solicitation uuid pattern matches the particular service solicitation uuid. private static boolean matchesServiceSolicitationUuid(UUID solicitationUuid, UUID solicitationUuidMask, UUID data) { - return BitUtils.maskedEquals(data, solicitationUuid, solicitationUuidMask); + return BluetoothLeUtils.maskedEquals(data, solicitationUuid, solicitationUuidMask); } // Check whether the data pattern matches the parsed data. diff --git a/core/java/android/companion/BluetoothDeviceFilterUtils.java b/core/java/android/companion/BluetoothDeviceFilterUtils.java index 5e2340cee0f9..ef5f84c42a16 100644 --- a/core/java/android/companion/BluetoothDeviceFilterUtils.java +++ b/core/java/android/companion/BluetoothDeviceFilterUtils.java @@ -22,7 +22,6 @@ import static android.text.TextUtils.firstNotEmpty; import android.annotation.NonNull; import android.annotation.Nullable; import android.bluetooth.BluetoothDevice; -import android.bluetooth.le.ScanFilter; import android.compat.annotation.UnsupportedAppUsage; import android.net.wifi.ScanResult; import android.os.Build; @@ -30,9 +29,13 @@ import android.os.ParcelUuid; import android.os.Parcelable; import android.util.Log; +import com.android.internal.annotations.VisibleForTesting; + import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Objects; +import java.util.UUID; import java.util.regex.Pattern; /** @hide */ @@ -73,12 +76,19 @@ public class BluetoothDeviceFilterUtils { static boolean matchesServiceUuid(ParcelUuid serviceUuid, ParcelUuid serviceUuidMask, BluetoothDevice device) { - ParcelUuid[] uuids = device.getUuids(); - final boolean result = serviceUuid == null || - ScanFilter.matchesServiceUuids( - serviceUuid, - serviceUuidMask, - uuids == null ? Collections.emptyList() : Arrays.asList(uuids)); + boolean result = false; + List<ParcelUuid> deviceUuids = device.getUuids() == null + ? Collections.emptyList() : Arrays.asList(device.getUuids()); + if (serviceUuid == null) { + result = true; + } else { + for (ParcelUuid parcelUuid : deviceUuids) { + UUID uuidMask = serviceUuidMask == null ? null : serviceUuidMask.getUuid(); + if (uuidsMaskedEquals(parcelUuid.getUuid(), serviceUuid.getUuid(), uuidMask)) { + result = true; + } + } + } if (DEBUG) debugLogMatchResult(result, device, serviceUuid); return result; } @@ -143,4 +153,23 @@ public class BluetoothDeviceFilterUtils { throw new IllegalArgumentException("Unknown device type: " + device); } } + + /** + * Compares two {@link #UUID} with a {@link #UUID} mask. + * + * @param data first {@link #UUID}. + * @param uuid second {@link #UUID}. + * @param mask mask {@link #UUID}. + * @return true if both UUIDs are equals when masked, false otherwise. + */ + @VisibleForTesting + public static boolean uuidsMaskedEquals(UUID data, UUID uuid, UUID mask) { + if (mask == null) { + return Objects.equals(data, uuid); + } + return (data.getLeastSignificantBits() & mask.getLeastSignificantBits()) + == (uuid.getLeastSignificantBits() & mask.getLeastSignificantBits()) + && (data.getMostSignificantBits() & mask.getMostSignificantBits()) + == (uuid.getMostSignificantBits() & mask.getMostSignificantBits()); + } } diff --git a/core/java/android/companion/BluetoothLeDeviceFilter.java b/core/java/android/companion/BluetoothLeDeviceFilter.java index 828d482a0e6a..58898cc095be 100644 --- a/core/java/android/companion/BluetoothLeDeviceFilter.java +++ b/core/java/android/companion/BluetoothLeDeviceFilter.java @@ -75,7 +75,7 @@ public final class BluetoothLeDeviceFilter implements DeviceFilter<ScanResult> { String renameSuffix, int renameBytesFrom, int renameBytesLength, int renameNameFrom, int renameNameLength, boolean renameBytesReverseOrder) { mNamePattern = namePattern; - mScanFilter = ObjectUtils.firstNotNull(scanFilter, ScanFilter.EMPTY); + mScanFilter = ObjectUtils.firstNotNull(scanFilter, new ScanFilter.Builder().build()); mRawDataFilter = rawDataFilter; mRawDataFilterMask = rawDataFilterMask; mRenamePrefix = renamePrefix; diff --git a/core/java/android/content/OWNERS b/core/java/android/content/OWNERS index c7f92c9714f0..660368aeca14 100644 --- a/core/java/android/content/OWNERS +++ b/core/java/android/content/OWNERS @@ -2,11 +2,9 @@ per-file Context.java = * per-file ContextWrapper.java = * per-file Content* = file:/services/core/java/com/android/server/am/OWNERS -per-file IntentFilter.java = toddke@google.com -per-file IntentFilter.java = patb@google.com +per-file IntentFilter.java = file:/PACKAGE_MANAGER_OWNERS per-file IntentFilter.java = file:/services/core/java/com/android/server/am/OWNERS -per-file Intent.java = toddke@google.com -per-file Intent.java = patb@google.com +per-file Intent.java = file:/PACKAGE_MANAGER_OWNERS per-file Intent.java = file:/services/core/java/com/android/server/wm/OWNERS per-file Intent.java = file:/services/core/java/com/android/server/am/OWNERS per-file AutofillOptions* = file:/core/java/android/service/autofill/OWNERS diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java index b66f048b829d..755114e0ac67 100644 --- a/core/java/android/content/res/Configuration.java +++ b/core/java/android/content/res/Configuration.java @@ -1736,35 +1736,9 @@ public final class Configuration implements Parcelable, Comparable<Configuration * object and the given one. Does not change the values of either. Any * undefined fields in <var>delta</var> are ignored. * @return Returns a bit mask indicating which configuration - * values has changed, containing any combination of - * {@link android.content.pm.ActivityInfo#CONFIG_FONT_SCALE - * PackageManager.ActivityInfo.CONFIG_FONT_SCALE}, - * {@link android.content.pm.ActivityInfo#CONFIG_MCC - * PackageManager.ActivityInfo.CONFIG_MCC}, - * {@link android.content.pm.ActivityInfo#CONFIG_MNC - * PackageManager.ActivityInfo.CONFIG_MNC}, - * {@link android.content.pm.ActivityInfo#CONFIG_LOCALE - * PackageManager.ActivityInfo.CONFIG_LOCALE}, - * {@link android.content.pm.ActivityInfo#CONFIG_TOUCHSCREEN - * PackageManager.ActivityInfo.CONFIG_TOUCHSCREEN}, - * {@link android.content.pm.ActivityInfo#CONFIG_KEYBOARD - * PackageManager.ActivityInfo.CONFIG_KEYBOARD}, - * {@link android.content.pm.ActivityInfo#CONFIG_NAVIGATION - * PackageManager.ActivityInfo.CONFIG_NAVIGATION}, - * {@link android.content.pm.ActivityInfo#CONFIG_ORIENTATION - * PackageManager.ActivityInfo.CONFIG_ORIENTATION}, - * {@link android.content.pm.ActivityInfo#CONFIG_SCREEN_LAYOUT - * PackageManager.ActivityInfo.CONFIG_SCREEN_LAYOUT}, or - * {@link android.content.pm.ActivityInfo#CONFIG_SCREEN_SIZE - * PackageManager.ActivityInfo.CONFIG_SCREEN_SIZE}, or - * {@link android.content.pm.ActivityInfo#CONFIG_SMALLEST_SCREEN_SIZE - * PackageManager.ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE}. - * {@link android.content.pm.ActivityInfo#CONFIG_LAYOUT_DIRECTION - * PackageManager.ActivityInfo.CONFIG_LAYOUT_DIRECTION}. - * {@link android.content.pm.ActivityInfo#CONFIG_FONT_WEIGHT_ADJUSTMENT - * PackageManager.ActivityInfo.CONFIG_FONT_WEIGHT_ADJUSTMENT. - */ - public int diff(Configuration delta) { + * values have changed. + */ + public @Config int diff(Configuration delta) { return diff(delta, false /* compareUndefined */, false /* publicOnly */); } diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index 1d07a0330bc5..eb8f43e3d073 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -220,8 +220,10 @@ public class NetworkIdentity implements Comparable<NetworkIdentity> { String networkId = null; boolean roaming = !snapshot.getNetworkCapabilities().hasCapability( NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING); - boolean metered = !snapshot.getNetworkCapabilities().hasCapability( - NetworkCapabilities.NET_CAPABILITY_NOT_METERED); + boolean metered = !(snapshot.getNetworkCapabilities().hasCapability( + NetworkCapabilities.NET_CAPABILITY_NOT_METERED) + || snapshot.getNetworkCapabilities().hasCapability( + NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED)); final int oemManaged = getOemBitfield(snapshot.getNetworkCapabilities()); diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index 08f75df5d82d..ee24084e63c6 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -160,19 +160,19 @@ public class NetworkTemplate implements Parcelable { } /** - * Template to match cellular networks with the given IMSI and {@code ratType}. - * Use {@link #NETWORK_TYPE_ALL} to include all network types when filtering. - * See {@code TelephonyManager.NETWORK_TYPE_*}. + * Template to match cellular networks with the given IMSI, {@code ratType} and + * {@code metered}. Use {@link #NETWORK_TYPE_ALL} to include all network types when + * filtering. See {@code TelephonyManager.NETWORK_TYPE_*}. */ public static NetworkTemplate buildTemplateMobileWithRatType(@Nullable String subscriberId, - @NetworkType int ratType) { + @NetworkType int ratType, int metered) { if (TextUtils.isEmpty(subscriberId)) { return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null, null, - METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL, + metered, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_EXACT); } return new NetworkTemplate(MATCH_MOBILE, subscriberId, new String[]{subscriberId}, null, - METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL, + metered, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_EXACT); } @@ -305,6 +305,7 @@ public class NetworkTemplate implements Parcelable { } } + // TODO: Deprecate this constructor, mark it @UnsupportedAppUsage(maxTargetSdk = S) @UnsupportedAppUsage public NetworkTemplate(int matchRule, String subscriberId, String networkId) { this(matchRule, subscriberId, new String[] { subscriberId }, networkId); @@ -312,9 +313,14 @@ public class NetworkTemplate implements Parcelable { public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, String networkId) { - this(matchRule, subscriberId, matchSubscriberIds, networkId, METERED_ALL, ROAMING_ALL, - DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL, - SUBSCRIBER_ID_MATCH_RULE_EXACT); + // Older versions used to only match MATCH_MOBILE and MATCH_MOBILE_WILDCARD templates + // to metered networks. It is now possible to match mobile with any meteredness, but + // in order to preserve backward compatibility of @UnsupportedAppUsage methods, this + //constructor passes METERED_YES for these types. + this(matchRule, subscriberId, matchSubscriberIds, networkId, + (matchRule == MATCH_MOBILE || matchRule == MATCH_MOBILE_WILDCARD) ? METERED_YES + : METERED_ALL , ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, + OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_EXACT); } // TODO: Remove it after updating all of the caller. @@ -589,11 +595,7 @@ public class NetworkTemplate implements Parcelable { // TODO: consider matching against WiMAX subscriber identity return true; } else { - // Only metered mobile network would be matched regardless of metered filter. - // This is used to exclude non-metered APNs, e.g. IMS. See ag/908650. - // TODO: Respect metered filter and remove mMetered condition. - return (ident.mType == TYPE_MOBILE && ident.mMetered) - && !ArrayUtils.isEmpty(mMatchSubscriberIds) + return ident.mType == TYPE_MOBILE && !ArrayUtils.isEmpty(mMatchSubscriberIds) && ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId) && matchesCollapsedRatType(ident); } @@ -707,8 +709,7 @@ public class NetworkTemplate implements Parcelable { if (ident.mType == TYPE_WIMAX) { return true; } else { - return (ident.mType == TYPE_MOBILE && ident.mMetered) - && matchesCollapsedRatType(ident); + return ident.mType == TYPE_MOBILE && matchesCollapsedRatType(ident); } } @@ -776,8 +777,8 @@ public class NetworkTemplate implements Parcelable { } /** - * Examine the given template and normalize if it refers to a "merged" - * mobile subscriber. We pick the "lowest" merged subscriber as the primary + * Examine the given template and normalize it. + * We pick the "lowest" merged subscriber as the primary * for key purposes, and expand the template to match all other merged * subscribers. * <p> @@ -792,8 +793,8 @@ public class NetworkTemplate implements Parcelable { } /** - * Examine the given template and normalize if it refers to a "merged" - * mobile subscriber. We pick the "lowest" merged subscriber as the primary + * Examine the given template and normalize it. + * We pick the "lowest" merged subscriber as the primary * for key purposes, and expand the template to match all other merged * subscribers. * @@ -805,7 +806,12 @@ public class NetworkTemplate implements Parcelable { * A, but also matches B. */ public static NetworkTemplate normalize(NetworkTemplate template, List<String[]> mergedList) { - if (!template.isMatchRuleMobile()) return template; + // Now there are several types of network which uses SubscriberId to store network + // information. For instances: + // The TYPE_WIFI with subscriberId means that it is a merged carrier wifi network. + // The TYPE_CARRIER means that the network associate to specific carrier network. + + if (template.mSubscriberId == null) return template; for (String[] merged : mergedList) { if (ArrayUtils.contains(merged, template.mSubscriberId)) { diff --git a/core/java/android/net/OWNERS b/core/java/android/net/OWNERS index 4ea8a54828b3..f55bcd31feb7 100644 --- a/core/java/android/net/OWNERS +++ b/core/java/android/net/OWNERS @@ -2,4 +2,5 @@ set noparent include platform/frameworks/base:/services/core/java/com/android/server/net/OWNERS -per-file SSL*, Uri*, Url* = prb@google.com, dauletz@google.com, narayan@google.com, ngeoffray@google.com +per-file SSL*,Uri*,Url* = prb@google.com,oth@google.com,narayan@google.com,ngeoffray@google.com +per-file SntpClient* = file:/services/core/java/com/android/server/timedetector/OWNERS diff --git a/core/java/android/net/SntpClient.java b/core/java/android/net/SntpClient.java index f6852e681439..0eb4cf3ecadf 100644 --- a/core/java/android/net/SntpClient.java +++ b/core/java/android/net/SntpClient.java @@ -17,16 +17,26 @@ package android.net; import android.compat.annotation.UnsupportedAppUsage; +import android.net.sntp.Duration64; +import android.net.sntp.Timestamp64; import android.os.SystemClock; import android.util.Log; +import android.util.Slog; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.TrafficStatsConstants; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.UnknownHostException; -import java.util.Arrays; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.time.Duration; +import java.time.Instant; +import java.util.Objects; +import java.util.Random; +import java.util.function.Supplier; /** * {@hide} @@ -60,17 +70,21 @@ public class SntpClient { private static final int NTP_STRATUM_DEATH = 0; private static final int NTP_STRATUM_MAX = 15; - // Number of seconds between Jan 1, 1900 and Jan 1, 1970 - // 70 years plus 17 leap days - private static final long OFFSET_1900_TO_1970 = ((365L * 70L) + 17L) * 24L * 60L * 60L; + // The source of the current system clock time, replaceable for testing. + private final Supplier<Instant> mSystemTimeSupplier; - // system time computed from NTP server response + private final Random mRandom; + + // The last offset calculated from an NTP server response + private long mClockOffset; + + // The last system time computed from an NTP server response private long mNtpTime; - // value of SystemClock.elapsedRealtime() corresponding to mNtpTime + // The value of SystemClock.elapsedRealtime() corresponding to mNtpTime / mClockOffset private long mNtpTimeReference; - // round trip time in milliseconds + // The round trip (network) time in milliseconds private long mRoundTripTime; private static class InvalidServerReplyException extends Exception { @@ -81,6 +95,13 @@ public class SntpClient { @UnsupportedAppUsage public SntpClient() { + this(Instant::now, defaultRandom()); + } + + @VisibleForTesting + public SntpClient(Supplier<Instant> systemTimeSupplier, Random random) { + mSystemTimeSupplier = Objects.requireNonNull(systemTimeSupplier); + mRandom = Objects.requireNonNull(random); } /** @@ -126,9 +147,13 @@ public class SntpClient { buffer[0] = NTP_MODE_CLIENT | (NTP_VERSION << 3); // get current time and write it to the request packet - final long requestTime = System.currentTimeMillis(); + final Instant requestTime = mSystemTimeSupplier.get(); + final Timestamp64 requestTimestamp = Timestamp64.fromInstant(requestTime); + + final Timestamp64 randomizedRequestTimestamp = + requestTimestamp.randomizeSubMillis(mRandom); final long requestTicks = SystemClock.elapsedRealtime(); - writeTimeStamp(buffer, TRANSMIT_TIME_OFFSET, requestTime); + writeTimeStamp(buffer, TRANSMIT_TIME_OFFSET, randomizedRequestTimestamp); socket.send(request); @@ -136,42 +161,44 @@ public class SntpClient { DatagramPacket response = new DatagramPacket(buffer, buffer.length); socket.receive(response); final long responseTicks = SystemClock.elapsedRealtime(); - final long responseTime = requestTime + (responseTicks - requestTicks); + final Instant responseTime = requestTime.plusMillis(responseTicks - requestTicks); + final Timestamp64 responseTimestamp = Timestamp64.fromInstant(responseTime); // extract the results final byte leap = (byte) ((buffer[0] >> 6) & 0x3); final byte mode = (byte) (buffer[0] & 0x7); final int stratum = (int) (buffer[1] & 0xff); - final long originateTime = readTimeStamp(buffer, ORIGINATE_TIME_OFFSET); - final long receiveTime = readTimeStamp(buffer, RECEIVE_TIME_OFFSET); - final long transmitTime = readTimeStamp(buffer, TRANSMIT_TIME_OFFSET); - final long referenceTime = readTimeStamp(buffer, REFERENCE_TIME_OFFSET); + final Timestamp64 referenceTimestamp = readTimeStamp(buffer, REFERENCE_TIME_OFFSET); + final Timestamp64 originateTimestamp = readTimeStamp(buffer, ORIGINATE_TIME_OFFSET); + final Timestamp64 receiveTimestamp = readTimeStamp(buffer, RECEIVE_TIME_OFFSET); + final Timestamp64 transmitTimestamp = readTimeStamp(buffer, TRANSMIT_TIME_OFFSET); /* Do validation according to RFC */ - // TODO: validate originateTime == requestTime. - checkValidServerReply(leap, mode, stratum, transmitTime, referenceTime); - - long roundTripTime = responseTicks - requestTicks - (transmitTime - receiveTime); - // receiveTime = originateTime + transit + skew - // responseTime = transmitTime + transit - skew - // clockOffset = ((receiveTime - originateTime) + (transmitTime - responseTime))/2 - // = ((originateTime + transit + skew - originateTime) + - // (transmitTime - (transmitTime + transit - skew)))/2 - // = ((transit + skew) + (transmitTime - transmitTime - transit + skew))/2 - // = (transit + skew - transit + skew)/2 - // = (2 * skew)/2 = skew - long clockOffset = ((receiveTime - originateTime) + (transmitTime - responseTime))/2; - EventLogTags.writeNtpSuccess(address.toString(), roundTripTime, clockOffset); + checkValidServerReply(leap, mode, stratum, transmitTimestamp, referenceTimestamp, + randomizedRequestTimestamp, originateTimestamp); + + long totalTransactionDurationMillis = responseTicks - requestTicks; + long serverDurationMillis = + Duration64.between(receiveTimestamp, transmitTimestamp).toDuration().toMillis(); + long roundTripTimeMillis = totalTransactionDurationMillis - serverDurationMillis; + + Duration clockOffsetDuration = calculateClockOffset(requestTimestamp, + receiveTimestamp, transmitTimestamp, responseTimestamp); + long clockOffsetMillis = clockOffsetDuration.toMillis(); + + EventLogTags.writeNtpSuccess( + address.toString(), roundTripTimeMillis, clockOffsetMillis); if (DBG) { - Log.d(TAG, "round trip: " + roundTripTime + "ms, " + - "clock offset: " + clockOffset + "ms"); + Log.d(TAG, "round trip: " + roundTripTimeMillis + "ms, " + + "clock offset: " + clockOffsetMillis + "ms"); } // save our results - use the times on this side of the network latency // (response rather than request time) - mNtpTime = responseTime + clockOffset; + mClockOffset = clockOffsetMillis; + mNtpTime = responseTime.plus(clockOffsetDuration).toEpochMilli(); mNtpTimeReference = responseTicks; - mRoundTripTime = roundTripTime; + mRoundTripTime = roundTripTimeMillis; } catch (Exception e) { EventLogTags.writeNtpFailure(address.toString(), e.toString()); if (DBG) Log.d(TAG, "request time failed: " + e); @@ -186,6 +213,28 @@ public class SntpClient { return true; } + /** Performs the NTP clock offset calculation. */ + @VisibleForTesting + public static Duration calculateClockOffset(Timestamp64 clientRequestTimestamp, + Timestamp64 serverReceiveTimestamp, Timestamp64 serverTransmitTimestamp, + Timestamp64 clientResponseTimestamp) { + // According to RFC4330: + // t is the system clock offset (the adjustment we are trying to find) + // t = ((T2 - T1) + (T3 - T4)) / 2 + // + // Which is: + // t = (([server]receiveTimestamp - [client]requestTimestamp) + // + ([server]transmitTimestamp - [client]responseTimestamp)) / 2 + // + // See the NTP spec and tests: the numeric types used are deliberate: + // + Duration64.between() uses 64-bit arithmetic (32-bit for the seconds). + // + plus() / dividedBy() use Duration, which isn't the double precision floating point + // used in NTPv4, but is good enough. + return Duration64.between(clientRequestTimestamp, serverReceiveTimestamp) + .plus(Duration64.between(clientResponseTimestamp, serverTransmitTimestamp)) + .dividedBy(2); + } + @Deprecated @UnsupportedAppUsage public boolean requestTime(String host, int timeout) { @@ -194,6 +243,14 @@ public class SntpClient { } /** + * Returns the offset calculated to apply to the client clock to arrive at {@link #getNtpTime()} + */ + @VisibleForTesting + public long getClockOffset() { + return mClockOffset; + } + + /** * Returns the time computed from the NTP transaction. * * @return time value computed from NTP server response. @@ -225,8 +282,9 @@ public class SntpClient { } private static void checkValidServerReply( - byte leap, byte mode, int stratum, long transmitTime, long referenceTime) - throws InvalidServerReplyException { + byte leap, byte mode, int stratum, Timestamp64 transmitTimestamp, + Timestamp64 referenceTimestamp, Timestamp64 randomizedRequestTimestamp, + Timestamp64 originateTimestamp) throws InvalidServerReplyException { if (leap == NTP_LEAP_NOSYNC) { throw new InvalidServerReplyException("unsynchronized server"); } @@ -236,73 +294,68 @@ public class SntpClient { if ((stratum == NTP_STRATUM_DEATH) || (stratum > NTP_STRATUM_MAX)) { throw new InvalidServerReplyException("untrusted stratum: " + stratum); } - if (transmitTime == 0) { - throw new InvalidServerReplyException("zero transmitTime"); + if (!randomizedRequestTimestamp.equals(originateTimestamp)) { + throw new InvalidServerReplyException( + "originateTimestamp != randomizedRequestTimestamp"); + } + if (transmitTimestamp.equals(Timestamp64.ZERO)) { + throw new InvalidServerReplyException("zero transmitTimestamp"); } - if (referenceTime == 0) { - throw new InvalidServerReplyException("zero reference timestamp"); + if (referenceTimestamp.equals(Timestamp64.ZERO)) { + throw new InvalidServerReplyException("zero referenceTimestamp"); } } /** * Reads an unsigned 32 bit big endian number from the given offset in the buffer. */ - private long read32(byte[] buffer, int offset) { - byte b0 = buffer[offset]; - byte b1 = buffer[offset+1]; - byte b2 = buffer[offset+2]; - byte b3 = buffer[offset+3]; - - // convert signed bytes to unsigned values - int i0 = ((b0 & 0x80) == 0x80 ? (b0 & 0x7F) + 0x80 : b0); - int i1 = ((b1 & 0x80) == 0x80 ? (b1 & 0x7F) + 0x80 : b1); - int i2 = ((b2 & 0x80) == 0x80 ? (b2 & 0x7F) + 0x80 : b2); - int i3 = ((b3 & 0x80) == 0x80 ? (b3 & 0x7F) + 0x80 : b3); - - return ((long)i0 << 24) + ((long)i1 << 16) + ((long)i2 << 8) + (long)i3; + private long readUnsigned32(byte[] buffer, int offset) { + int i0 = buffer[offset++] & 0xFF; + int i1 = buffer[offset++] & 0xFF; + int i2 = buffer[offset++] & 0xFF; + int i3 = buffer[offset] & 0xFF; + + int bits = (i0 << 24) | (i1 << 16) | (i2 << 8) | i3; + return bits & 0xFFFF_FFFFL; } /** - * Reads the NTP time stamp at the given offset in the buffer and returns - * it as a system time (milliseconds since January 1, 1970). + * Reads the NTP time stamp from the given offset in the buffer. */ - private long readTimeStamp(byte[] buffer, int offset) { - long seconds = read32(buffer, offset); - long fraction = read32(buffer, offset + 4); - // Special case: zero means zero. - if (seconds == 0 && fraction == 0) { - return 0; - } - return ((seconds - OFFSET_1900_TO_1970) * 1000) + ((fraction * 1000L) / 0x100000000L); + private Timestamp64 readTimeStamp(byte[] buffer, int offset) { + long seconds = readUnsigned32(buffer, offset); + int fractionBits = (int) readUnsigned32(buffer, offset + 4); + return Timestamp64.fromComponents(seconds, fractionBits); } /** - * Writes system time (milliseconds since January 1, 1970) as an NTP time stamp - * at the given offset in the buffer. + * Writes the NTP time stamp at the given offset in the buffer. */ - private void writeTimeStamp(byte[] buffer, int offset, long time) { - // Special case: zero means zero. - if (time == 0) { - Arrays.fill(buffer, offset, offset + 8, (byte) 0x00); - return; - } - - long seconds = time / 1000L; - long milliseconds = time - seconds * 1000L; - seconds += OFFSET_1900_TO_1970; - + private void writeTimeStamp(byte[] buffer, int offset, Timestamp64 timestamp) { + long seconds = timestamp.getEraSeconds(); // write seconds in big endian format - buffer[offset++] = (byte)(seconds >> 24); - buffer[offset++] = (byte)(seconds >> 16); - buffer[offset++] = (byte)(seconds >> 8); - buffer[offset++] = (byte)(seconds >> 0); + buffer[offset++] = (byte) (seconds >>> 24); + buffer[offset++] = (byte) (seconds >>> 16); + buffer[offset++] = (byte) (seconds >>> 8); + buffer[offset++] = (byte) (seconds); - long fraction = milliseconds * 0x100000000L / 1000L; + int fractionBits = timestamp.getFractionBits(); // write fraction in big endian format - buffer[offset++] = (byte)(fraction >> 24); - buffer[offset++] = (byte)(fraction >> 16); - buffer[offset++] = (byte)(fraction >> 8); - // low order bits should be random data - buffer[offset++] = (byte)(Math.random() * 255.0); + buffer[offset++] = (byte) (fractionBits >>> 24); + buffer[offset++] = (byte) (fractionBits >>> 16); + buffer[offset++] = (byte) (fractionBits >>> 8); + buffer[offset] = (byte) (fractionBits); + } + + private static Random defaultRandom() { + Random random; + try { + random = SecureRandom.getInstanceStrong(); + } catch (NoSuchAlgorithmException e) { + // This should never happen. + Slog.wtf(TAG, "Unable to access SecureRandom", e); + random = new Random(System.currentTimeMillis()); + } + return random; } } diff --git a/core/java/android/net/TEST_MAPPING b/core/java/android/net/TEST_MAPPING index 8c13ef98bedb..a379c33316f0 100644 --- a/core/java/android/net/TEST_MAPPING +++ b/core/java/android/net/TEST_MAPPING @@ -16,5 +16,24 @@ { "path": "frameworks/opt/net/wifi" } + ], + "postsubmit": [ + { + "name": "FrameworksCoreTests", + "options": [ + { + "include-filter": "android.net" + }, + { + "include-annotation": "android.platform.test.annotations.Presubmit" + }, + { + "exclude-annotation": "androidx.test.filters.FlakyTest" + }, + { + "exclude-annotation": "org.junit.Ignore" + } + ] + } ] } diff --git a/core/java/android/net/sntp/Duration64.java b/core/java/android/net/sntp/Duration64.java new file mode 100644 index 000000000000..7f29cdb989d8 --- /dev/null +++ b/core/java/android/net/sntp/Duration64.java @@ -0,0 +1,141 @@ +/* + * 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. + */ +package android.net.sntp; + +import java.time.Duration; + +/** + * A type similar to {@link Timestamp64} but used when calculating the difference between two + * timestamps. As such, it is a signed type, but still uses 64-bits in total and so can only + * represent half the magnitude of {@link Timestamp64}. + * + * <p>See <a href="https://www.eecis.udel.edu/~mills/time.html">4. Time Difference Calculations</a>. + * + * @hide + */ +public final class Duration64 { + + public static final Duration64 ZERO = new Duration64(0); + private final long mBits; + + private Duration64(long bits) { + this.mBits = bits; + } + + /** + * Returns the difference between two 64-bit NTP timestamps as a {@link Duration64}, as + * described in the NTP spec. The times represented by the timestamps have to be within {@link + * Timestamp64#MAX_SECONDS_IN_ERA} (~68 years) of each other for the calculation to produce a + * correct answer. + */ + public static Duration64 between(Timestamp64 startInclusive, Timestamp64 endExclusive) { + long oneBits = (startInclusive.getEraSeconds() << 32) + | (startInclusive.getFractionBits() & 0xFFFF_FFFFL); + long twoBits = (endExclusive.getEraSeconds() << 32) + | (endExclusive.getFractionBits() & 0xFFFF_FFFFL); + long resultBits = twoBits - oneBits; + return new Duration64(resultBits); + } + + /** + * Add two {@link Duration64} instances together. This performs the calculation in {@link + * Duration} and returns a {@link Duration} to increase the magnitude of accepted arguments, + * since {@link Duration64} only supports signed 32-bit seconds. The use of {@link Duration} + * limits precision to nanoseconds. + */ + public Duration plus(Duration64 other) { + // From https://www.eecis.udel.edu/~mills/time.html: + // "The offset and delay calculations require sums and differences of these raw timestamp + // differences that can span no more than from 34 years in the future to 34 years in the + // past without overflow. This is a fundamental limitation in 64-bit integer calculations. + // + // In the NTPv4 reference implementation, all calculations involving offset and delay values + // use 64-bit floating double arithmetic, with the exception of raw timestamp subtraction, + // as mentioned above. The raw timestamp differences are then converted to 64-bit floating + // double format without loss of precision or chance of overflow in subsequent + // calculations." + // + // Here, we use Duration instead, which provides sufficient range, but loses precision below + // nanos. + return this.toDuration().plus(other.toDuration()); + } + + /** + * Returns a {@link Duration64} equivalent of the supplied duration, if the magnitude can be + * represented. Because {@link Duration64} uses a fixed point type for sub-second values it + * cannot represent all nanosecond values precisely and so the conversion can be lossy. + * + * @throws IllegalArgumentException if the supplied duration is too big to be represented + */ + public static Duration64 fromDuration(Duration duration) { + long seconds = duration.getSeconds(); + if (seconds < Integer.MIN_VALUE || seconds > Integer.MAX_VALUE) { + throw new IllegalArgumentException(); + } + long bits = (seconds << 32) + | (Timestamp64.nanosToFractionBits(duration.getNano()) & 0xFFFF_FFFFL); + return new Duration64(bits); + } + + /** + * Returns a {@link Duration} equivalent of this duration. Because {@link Duration64} uses a + * fixed point type for sub-second values it can values smaller than nanosecond precision and so + * the conversion can be lossy. + */ + public Duration toDuration() { + int seconds = getSeconds(); + int nanos = getNanos(); + return Duration.ofSeconds(seconds, nanos); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Duration64 that = (Duration64) o; + return mBits == that.mBits; + } + + @Override + public int hashCode() { + return java.util.Objects.hash(mBits); + } + + @Override + public String toString() { + Duration duration = toDuration(); + return Long.toHexString(mBits) + + "(" + duration.getSeconds() + "s " + duration.getNano() + "ns)"; + } + + /** + * Returns the <em>signed</em> seconds in this duration. + */ + public int getSeconds() { + return (int) (mBits >> 32); + } + + /** + * Returns the <em>unsigned</em> nanoseconds in this duration (truncated). + */ + public int getNanos() { + return Timestamp64.fractionBitsToNanos((int) (mBits & 0xFFFF_FFFFL)); + } +} diff --git a/core/java/android/net/sntp/OWNERS b/core/java/android/net/sntp/OWNERS new file mode 100644 index 000000000000..9a3e264a067f --- /dev/null +++ b/core/java/android/net/sntp/OWNERS @@ -0,0 +1 @@ +include /services/core/java/com/android/server/timedetector/OWNERS diff --git a/core/java/android/net/sntp/Timestamp64.java b/core/java/android/net/sntp/Timestamp64.java new file mode 100644 index 000000000000..8ddfd77ea7dc --- /dev/null +++ b/core/java/android/net/sntp/Timestamp64.java @@ -0,0 +1,188 @@ +/* + * 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. + */ +package android.net.sntp; + +import android.text.TextUtils; + +import com.android.internal.annotations.VisibleForTesting; + +import java.time.Instant; +import java.util.Objects; +import java.util.Random; + +/** + * The 64-bit type ("timestamp") that NTP uses to represent a point in time. It only holds the + * lowest 32-bits of the number of seconds since 1900-01-01 00:00:00. Consequently, to turn an + * instance into an unambiguous point in time the era number must be known. Era zero runs from + * 1900-01-01 00:00:00 to a date in 2036. + * + * It stores sub-second values using a 32-bit fixed point type, so it can resolve values smaller + * than a nanosecond, but is imprecise (i.e. it truncates). + * + * See also <a href=https://www.eecis.udel.edu/~mills/y2k.html>NTP docs</a>. + * + * @hide + */ +public final class Timestamp64 { + + public static final Timestamp64 ZERO = fromComponents(0, 0); + static final int SUB_MILLIS_BITS_TO_RANDOMIZE = 32 - 10; + + // Number of seconds between Jan 1, 1900 and Jan 1, 1970 + // 70 years plus 17 leap days + static final long OFFSET_1900_TO_1970 = ((365L * 70L) + 17L) * 24L * 60L * 60L; + static final long MAX_SECONDS_IN_ERA = 0xFFFF_FFFFL; + static final long SECONDS_IN_ERA = MAX_SECONDS_IN_ERA + 1; + + static final int NANOS_PER_SECOND = 1_000_000_000; + + /** Creates a {@link Timestamp64} from the seconds and fraction components. */ + public static Timestamp64 fromComponents(long eraSeconds, int fractionBits) { + return new Timestamp64(eraSeconds, fractionBits); + } + + /** Creates a {@link Timestamp64} by decoding a string in the form "e4dc720c.4d4fc9eb". */ + public static Timestamp64 fromString(String string) { + final int requiredLength = 17; + if (string.length() != requiredLength || string.charAt(8) != '.') { + throw new IllegalArgumentException(string); + } + String eraSecondsString = string.substring(0, 8); + String fractionString = string.substring(9); + long eraSeconds = Long.parseLong(eraSecondsString, 16); + + // Use parseLong() because the type is unsigned. Integer.parseInt() will reject 0x70000000 + // or above as being out of range. + long fractionBitsAsLong = Long.parseLong(fractionString, 16); + if (fractionBitsAsLong < 0 || fractionBitsAsLong > 0xFFFFFFFFL) { + throw new IllegalArgumentException("Invalid fractionBits:" + fractionString); + } + return new Timestamp64(eraSeconds, (int) fractionBitsAsLong); + } + + /** + * Converts an {@link Instant} into a {@link Timestamp64}. This is lossy: Timestamp64 only + * contains the number of seconds in a given era, but the era is not stored. Also, sub-second + * values are not stored precisely. + */ + public static Timestamp64 fromInstant(Instant instant) { + long ntpEraSeconds = instant.getEpochSecond() + OFFSET_1900_TO_1970; + if (ntpEraSeconds < 0) { + ntpEraSeconds = SECONDS_IN_ERA - (-ntpEraSeconds % SECONDS_IN_ERA); + } + ntpEraSeconds %= SECONDS_IN_ERA; + + long nanos = instant.getNano(); + int fractionBits = nanosToFractionBits(nanos); + + return new Timestamp64(ntpEraSeconds, fractionBits); + } + + private final long mEraSeconds; + private final int mFractionBits; + + private Timestamp64(long eraSeconds, int fractionBits) { + if (eraSeconds < 0 || eraSeconds > MAX_SECONDS_IN_ERA) { + throw new IllegalArgumentException( + "Invalid parameters. seconds=" + eraSeconds + ", fraction=" + fractionBits); + } + this.mEraSeconds = eraSeconds; + this.mFractionBits = fractionBits; + } + + /** Returns the number of seconds in the NTP era. */ + public long getEraSeconds() { + return mEraSeconds; + } + + /** Returns the fraction of a second as 32-bit, unsigned fixed-point bits. */ + public int getFractionBits() { + return mFractionBits; + } + + @Override + public String toString() { + return TextUtils.formatSimple("%08x.%08x", mEraSeconds, mFractionBits); + } + + /** Returns the instant represented by this value in the specified NTP era. */ + public Instant toInstant(int ntpEra) { + long secondsSinceEpoch = mEraSeconds - OFFSET_1900_TO_1970; + secondsSinceEpoch += ntpEra * SECONDS_IN_ERA; + + int nanos = fractionBitsToNanos(mFractionBits); + return Instant.ofEpochSecond(secondsSinceEpoch, nanos); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Timestamp64 that = (Timestamp64) o; + return mEraSeconds == that.mEraSeconds && mFractionBits == that.mFractionBits; + } + + @Override + public int hashCode() { + return Objects.hash(mEraSeconds, mFractionBits); + } + + static int fractionBitsToNanos(int fractionBits) { + long fractionBitsLong = fractionBits & 0xFFFF_FFFFL; + return (int) ((fractionBitsLong * NANOS_PER_SECOND) >>> 32); + } + + static int nanosToFractionBits(long nanos) { + if (nanos > NANOS_PER_SECOND) { + throw new IllegalArgumentException(); + } + return (int) ((nanos << 32) / NANOS_PER_SECOND); + } + + /** + * Randomizes the fraction bits that represent sub-millisecond values. i.e. the randomization + * won't change the number of milliseconds represented after truncation. This is used to + * implement the part of the NTP spec that calls for clients with millisecond accuracy clocks + * to send randomized LSB values rather than zeros. + */ + public Timestamp64 randomizeSubMillis(Random random) { + int randomizedFractionBits = + randomizeLowestBits(random, this.mFractionBits, SUB_MILLIS_BITS_TO_RANDOMIZE); + return new Timestamp64(mEraSeconds, randomizedFractionBits); + } + + /** + * Randomizes the specified number of LSBs in {@code value} by using replacement bits from + * {@code Random.getNextInt()}. + */ + @VisibleForTesting + public static int randomizeLowestBits(Random random, int value, int bitsToRandomize) { + if (bitsToRandomize < 1 || bitsToRandomize >= Integer.SIZE) { + // There's no point in randomizing all bits or none of the bits. + throw new IllegalArgumentException(Integer.toString(bitsToRandomize)); + } + + int upperBitMask = 0xFFFF_FFFF << bitsToRandomize; + int lowerBitMask = ~upperBitMask; + + int randomValue = random.nextInt(); + return (value & upperBitMask) | (randomValue & lowerBitMask); + } +} diff --git a/core/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java b/core/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java index 09f528369ffb..be573721936b 100644 --- a/core/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java +++ b/core/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java @@ -79,6 +79,7 @@ public final class IkeSessionParamsUtils { IKE_OPTIONS.add(IkeSessionParams.IKE_OPTION_EAP_ONLY_AUTH); IKE_OPTIONS.add(IkeSessionParams.IKE_OPTION_MOBIKE); IKE_OPTIONS.add(IkeSessionParams.IKE_OPTION_FORCE_PORT_4500); + IKE_OPTIONS.add(IkeSessionParams.IKE_OPTION_INITIAL_CONTACT); } /** Serializes an IkeSessionParams to a PersistableBundle. */ diff --git a/core/java/android/os/BaseBundle.java b/core/java/android/os/BaseBundle.java index 2a344f6c2b6b..ad3de25fecc2 100644 --- a/core/java/android/os/BaseBundle.java +++ b/core/java/android/os/BaseBundle.java @@ -103,7 +103,7 @@ public class BaseBundle { * are unparcelled, mParcelledData willbe set to null. */ @UnsupportedAppUsage - Parcel mParcelledData = null; + volatile Parcel mParcelledData = null; /** * Whether {@link #mParcelledData} was generated by native code or not. @@ -182,13 +182,56 @@ public class BaseBundle { * @param b a Bundle to be copied. */ BaseBundle(BaseBundle b) { - copyInternal(b, false); + this(b, /* deep */ false); } /** - * Special constructor that does not initialize the bundle. + * Constructs a {@link BaseBundle} containing a copy of {@code from}. + * + * @param from The bundle to be copied. + * @param deep Whether is a deep or shallow copy. + * + * @hide */ - BaseBundle(boolean doInit) { + BaseBundle(BaseBundle from, boolean deep) { + synchronized (from) { + mClassLoader = from.mClassLoader; + + if (from.mMap != null) { + if (!deep) { + mMap = new ArrayMap<>(from.mMap); + } else { + final ArrayMap<String, Object> fromMap = from.mMap; + final int n = fromMap.size(); + mMap = new ArrayMap<>(n); + for (int i = 0; i < n; i++) { + mMap.append(fromMap.keyAt(i), deepCopyValue(fromMap.valueAt(i))); + } + } + } else { + mMap = null; + } + + final Parcel parcelledData; + if (from.mParcelledData != null) { + if (from.isEmptyParcel()) { + parcelledData = NoImagePreloadHolder.EMPTY_PARCEL; + mParcelledByNative = false; + } else { + parcelledData = Parcel.obtain(); + parcelledData.appendFrom(from.mParcelledData, 0, + from.mParcelledData.dataSize()); + parcelledData.setDataPosition(0); + mParcelledByNative = from.mParcelledByNative; + } + } else { + parcelledData = null; + mParcelledByNative = false; + } + + // Keep as last statement to ensure visibility of other fields + mParcelledData = parcelledData; + } } /** @@ -323,8 +366,8 @@ public class BaseBundle { } else { mMap.erase(); } - mParcelledData = null; mParcelledByNative = false; + mParcelledData = null; return; } @@ -358,8 +401,8 @@ public class BaseBundle { if (recycleParcel) { recycleParcel(parcelledData); } - mParcelledData = null; mParcelledByNative = false; + mParcelledData = null; } if (DEBUG) { Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this)) @@ -501,44 +544,7 @@ public class BaseBundle { mMap.clear(); } - void copyInternal(BaseBundle from, boolean deep) { - synchronized (from) { - if (from.mParcelledData != null) { - if (from.isEmptyParcel()) { - mParcelledData = NoImagePreloadHolder.EMPTY_PARCEL; - mParcelledByNative = false; - } else { - mParcelledData = Parcel.obtain(); - mParcelledData.appendFrom(from.mParcelledData, 0, - from.mParcelledData.dataSize()); - mParcelledData.setDataPosition(0); - mParcelledByNative = from.mParcelledByNative; - } - } else { - mParcelledData = null; - mParcelledByNative = false; - } - - if (from.mMap != null) { - if (!deep) { - mMap = new ArrayMap<>(from.mMap); - } else { - final ArrayMap<String, Object> fromMap = from.mMap; - final int N = fromMap.size(); - mMap = new ArrayMap<>(N); - for (int i = 0; i < N; i++) { - mMap.append(fromMap.keyAt(i), deepCopyValue(fromMap.valueAt(i))); - } - } - } else { - mMap = null; - } - - mClassLoader = from.mClassLoader; - } - } - - Object deepCopyValue(Object value) { + private Object deepCopyValue(Object value) { if (value == null) { return null; } @@ -570,7 +576,7 @@ public class BaseBundle { return value; } - ArrayList deepcopyArrayList(ArrayList from) { + private ArrayList deepcopyArrayList(ArrayList from) { final int N = from.size(); ArrayList out = new ArrayList(N); for (int i=0; i<N; i++) { @@ -1717,9 +1723,9 @@ public class BaseBundle { if (length < 0) { throw new RuntimeException("Bad length in parcel: " + length); } else if (length == 0) { + mParcelledByNative = false; // Empty Bundle or end of data. mParcelledData = NoImagePreloadHolder.EMPTY_PARCEL; - mParcelledByNative = false; return; } else if (length % 4 != 0) { throw new IllegalStateException("Bundle length is not aligned by 4: " + length); @@ -1757,8 +1763,8 @@ public class BaseBundle { + ": " + length + " bundle bytes starting at " + offset); p.setDataPosition(0); - mParcelledData = p; mParcelledByNative = isNativeBundle; + mParcelledData = p; } /** {@hide} */ diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java index 635f58182b34..b069fb336d55 100644 --- a/core/java/android/os/Binder.java +++ b/core/java/android/os/Binder.java @@ -53,7 +53,7 @@ import java.lang.reflect.Modifier; * * <p>Most developers will not implement this class directly, instead using the * <a href="{@docRoot}guide/components/aidl.html">aidl</a> tool to describe the desired - * interface, having it generate the appropriate Binder subclass. You can, + * interface, having it generate the appropriate Binder subclass. You can, * however, derive directly from Binder to implement your own custom RPC * protocol or simply instantiate a raw Binder object directly to use as a * token that can be shared across processes. @@ -63,17 +63,17 @@ import java.lang.reflect.Modifier; * To use this correctly, you must be doing so within the context of a top-level * application component (a {@link android.app.Service}, {@link android.app.Activity}, * or {@link android.content.ContentProvider}) that lets the system know your process - * should remain running.</p> + * should remain running. * * <p>You must keep in mind the situations in which your process * could go away, and thus require that you later re-create a new Binder and re-attach - * it when the process starts again. For example, if you are using this within an + * it when the process starts again. For example, if you are using this within an * {@link android.app.Activity}, your activity's process may be killed any time the * activity is not started; if the activity is later re-created you will need to * create a new Binder and hand it back to the correct place again; you need to be * aware that your process may be started for another reason (for example to receive * a broadcast) that will not involve re-creating the activity and thus run its code - * to create a new Binder.</p> + * to create a new Binder. * * @see IBinder */ @@ -94,14 +94,15 @@ public class Binder implements IBinder { /** * Value to represents that a calling work source is not set. * - * This constatnt needs to be kept in sync with IPCThreadState::kUnsetWorkSource. + * <p>This constant needs to be kept in sync with IPCThreadState::kUnsetWorkSource. * * @hide */ public static final int UNSET_WORKSOURCE = -1; /** - * Control whether dump() calls are allowed. + * Control whether {@link #dump(FileDescriptor, PrintWriter, String[]) dump()} + * calls are allowed. */ private static volatile String sDumpDisabled = null; @@ -188,7 +189,7 @@ public class Binder implements IBinder { sObserver = observer; } - /** {@hide} */ + /** @hide */ static volatile boolean sWarnOnBlocking = false; /** @@ -207,8 +208,8 @@ public class Binder implements IBinder { /** * Allow blocking calls on the given interface, overriding the requested * value of {@link #setWarnOnBlocking(boolean)}. - * <p> - * This should only be rarely called when you are <em>absolutely sure</em> + * + * <p>This should only be rarely called when you are <em>absolutely sure</em> * the remote interface is a built-in system component that can never be * upgraded. In particular, this <em>must never</em> be called for * interfaces hosted by package that could be upgraded or replaced, @@ -258,7 +259,9 @@ public class Binder implements IBinder { ThreadLocal.withInitial(() -> sWarnOnBlocking); /** - * Allow blocking calls for the current thread. See {@link #allowBlocking}. + * Allow blocking calls for the current thread. + * + * @see {@link #allowBlocking}. * * @hide */ @@ -267,7 +270,9 @@ public class Binder implements IBinder { } /** - * Reset the current thread to the default blocking behavior. See {@link #defaultBlocking}. + * Reset the current thread to the default blocking behavior. + * + * @see {@link #defaultBlocking}. * * @hide */ @@ -286,10 +291,10 @@ public class Binder implements IBinder { /** * Return the ID of the process that sent you the current transaction - * that is being processed. This pid can be used with higher-level + * that is being processed. This PID can be used with higher-level * system services to determine its identity and check permissions. * If the current thread is not currently executing an incoming transaction, - * then its own pid is returned. + * then its own PID is returned. * * Warning: oneway transactions do not receive PID. */ @@ -297,11 +302,11 @@ public class Binder implements IBinder { public static final native int getCallingPid(); /** - * Return the Linux uid assigned to the process that sent you the - * current transaction that is being processed. This uid can be used with + * Return the Linux UID assigned to the process that sent you the + * current transaction that is being processed. This UID can be used with * higher-level system services to determine its identity and check - * permissions. If the current thread is not currently executing an - * incoming transaction, then its own uid is returned. + * permissions. If the current thread is not currently executing an + * incoming transaction, then its own UID is returned. */ @CriticalNative public static final native int getCallingUid(); @@ -313,17 +318,17 @@ public class Binder implements IBinder { * @hide */ @CriticalNative - public static final native boolean isHandlingTransaction(); + public static final native boolean isDirectlyHandlingTransaction(); /** - * Return the Linux uid assigned to the process that sent the transaction + * 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. */ public static final int getCallingUidOrThrow() { - if (!isHandlingTransaction()) { + if (!isDirectlyHandlingTransaction()) { throw new IllegalStateException( "Thread is not in a binder transcation"); } @@ -332,18 +337,20 @@ public class Binder implements IBinder { /** * Return the UserHandle assigned to the process that sent you the - * current transaction that is being processed. This is the user - * of the caller. It is distinct from {@link #getCallingUid()} in that a + * current transaction that is being processed. This is the user + * of the caller. It is distinct from {@link #getCallingUid()} in that a * particular user will have multiple distinct apps running under it each - * with their own uid. If the current thread is not currently executing an + * with their own UID. If the current thread is not currently executing an * incoming transaction, then its own UserHandle is returned. + * + * @see UserHandle */ public static final @NonNull UserHandle getCallingUserHandle() { return UserHandle.of(UserHandle.getUserId(getCallingUid())); } /** - * Reset the identity of the incoming IPC on the current thread. This can + * Reset the identity of the incoming IPC on the current thread. This can * be useful if, while handling an incoming call, you will be calling * on interfaces of other objects that may be local to your process and * need to do permission checks on the calls coming into them (so they @@ -376,10 +383,10 @@ public class Binder implements IBinder { /** * Convenience method for running the provided action enclosed in - * {@link #clearCallingIdentity}/{@link #restoreCallingIdentity} + * {@link #clearCallingIdentity}/{@link #restoreCallingIdentity}. * - * Any exception thrown by the given action will be caught and rethrown after the call to - * {@link #restoreCallingIdentity} + * <p>Any exception thrown by the given action will be caught and + * rethrown after the call to {@link #restoreCallingIdentity}. * * @hide */ @@ -400,10 +407,10 @@ public class Binder implements IBinder { /** * Convenience method for running the provided action enclosed in - * {@link #clearCallingIdentity}/{@link #restoreCallingIdentity} returning the result + * {@link #clearCallingIdentity}/{@link #restoreCallingIdentity} returning the result. * - * Any exception thrown by the given action will be caught and rethrown after the call to - * {@link #restoreCallingIdentity} + * <p>Any exception thrown by the given action will be caught and rethrown after + * the call to {@link #restoreCallingIdentity}. * * @hide */ @@ -428,12 +435,13 @@ public class Binder implements IBinder { * * <p>The StrictMode settings are kept in two places: a Java-level * threadlocal for libcore/Dalvik, and a native threadlocal (set - * here) for propagation via Binder calls. This is a little + * here) for propagation via Binder calls. This is a little * unfortunate, but necessary to break otherwise more unfortunate * dependencies either of Dalvik on Android, or Android * native-only code on Dalvik. * * @see StrictMode + * * @hide */ @CriticalNative @@ -443,6 +451,7 @@ public class Binder implements IBinder { * Gets the current native thread-local StrictMode policy mask. * * @see #setThreadStrictModePolicy + * * @hide */ @CriticalNative @@ -459,7 +468,7 @@ public class Binder implements IBinder { * reasons, we only support one UID. This UID represents the original user responsible for the * binder calls. * - * <p>{@link Binder#restoreCallingWorkSource(long)} must always be called after setting the + * <p>{@link #restoreCallingWorkSource(long)} must always be called after setting the * worksource. * * <p>A typical use case would be @@ -477,16 +486,16 @@ public class Binder implements IBinder { * * @param workSource The original UID responsible for the binder call. * @return token to restore original work source. - **/ + */ @CriticalNative public static final native long setCallingWorkSourceUid(int workSource); /** * Returns the work source set by the caller. * - * Unlike {@link Binder#getCallingUid()}, this result of this method cannot be trusted. The + * <p>Unlike {@link #getCallingUid()}, this result of this method cannot be trusted. The * caller can set the value to whatever they want. Only use this value if you trust the calling - * uid. + * UID. * * @return The original UID responsible for the binder transaction. */ @@ -499,7 +508,7 @@ public class Binder implements IBinder { * <p>The work source will be propagated for future outgoing binder transactions * executed on this thread. * - * <p>{@link Binder#restoreCallingWorkSource(long)} must always be called after clearing the + * <p>{@link #restoreCallingWorkSource(long)} must always be called after clearing the * worksource. * * <p>A typical use case would be @@ -513,13 +522,13 @@ public class Binder implements IBinder { * </pre> * * @return token to restore original work source. - **/ + */ @CriticalNative public static final native long clearCallingWorkSource(); /** * Restores the work source on this thread using a token returned by - * {@link #setCallingWorkSourceUid(int) or {@link clearCallingWorkSource()}. + * {@link #setCallingWorkSourceUid(int)} or {@link #clearCallingWorkSource()}. * * <p>A typical use case would be * <pre> @@ -530,7 +539,7 @@ public class Binder implements IBinder { * Binder.restoreCallingWorkSource(token); * } * </pre> - **/ + */ @CriticalNative public static final native void restoreCallingWorkSource(long token); @@ -553,7 +562,7 @@ public class Binder implements IBinder { * Use a VINTF-stability binder w/o VINTF requirements. Should be called * on a binder before it is sent out of process. * - * This must be called before the object is sent to another process. + * <p>This must be called before the object is sent to another process. * * @hide */ @@ -561,7 +570,7 @@ public class Binder implements IBinder { /** * Flush any Binder commands pending in the current thread to the kernel - * driver. This can be + * driver. This can be * useful to call before performing an operation that may block for a long * time, to ensure that any pending object references have been released * in order to prevent the process from holding on to objects longer than @@ -570,7 +579,7 @@ public class Binder implements IBinder { public static final native void flushPendingCommands(); /** - * Add the calling thread to the IPC thread pool. This function does + * Add the calling thread to the IPC thread pool. This function does * not return until the current process is exiting. */ public static final void joinThreadPool() { @@ -579,6 +588,7 @@ public class Binder implements IBinder { /** * Returns true if the specified interface is a proxy. + * * @hide */ public static final boolean isProxy(IInterface iface) { @@ -588,6 +598,7 @@ public class Binder implements IBinder { /** * Call blocks until the number of executing binder threads is less * than the maximum number of binder threads allowed for this process. + * * @hide */ public static final native void blockUntilThreadAvailable(); @@ -595,7 +606,7 @@ public class Binder implements IBinder { /** * Default constructor just initializes the object. * - * If you're creating a Binder token (a Binder object without an attached interface), + * <p>If you're creating a Binder token (a Binder object without an attached interface), * you should use {@link #Binder(String)} instead. */ public Binder() { @@ -605,7 +616,7 @@ public class Binder implements IBinder { /** * Constructor for creating a raw Binder object (token) along with a descriptor. * - * The descriptor of binder objects usually specifies the interface they are implementing. + * <p>The descriptor of binder objects usually specifies the interface they are implementing. * In case of binder tokens, no interface is implemented, and the descriptor can be used * as a sort of tag to help identify the binder token. This will help identify remote * references to these objects more easily when debugging. @@ -614,7 +625,7 @@ public class Binder implements IBinder { * Instead of creating multiple tokens with the same descriptor, consider adding a suffix to * help identify them. */ - public Binder(@Nullable String descriptor) { + public Binder(@Nullable String descriptor) { mObject = getNativeBBinderHolder(); NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mObject); @@ -631,9 +642,9 @@ public class Binder implements IBinder { /** * Convenience method for associating a specific interface with the Binder. - * After calling, queryLocalInterface() will be implemented for you - * to return the given owner IInterface when the corresponding - * descriptor is requested. + * After calling, {@link #queryLocalInterface(String) queryLocalInterface()} + * will be implemented for you to return the given owner IInterface when + * the corresponding descriptor is requested. */ public void attachInterface(@Nullable IInterface owner, @Nullable String descriptor) { mOwner = owner; @@ -666,8 +677,8 @@ public class Binder implements IBinder { } /** - * Use information supplied to attachInterface() to return the - * associated IInterface if it matches the requested + * Use information supplied to {@link #attachInterface attachInterface()} + * to return the associated {@link IInterface} if it matches the requested * descriptor. */ public @Nullable IInterface queryLocalInterface(@NonNull String descriptor) { @@ -678,14 +689,15 @@ public class Binder implements IBinder { } /** - * Control disabling of dump calls in this process. This is used by the system + * Control disabling of dump calls in this process. This is used by the system * process watchdog to disable incoming dump calls while it has detecting the system - * is hung and is reporting that back to the activity controller. This is to + * is hung and is reporting that back to the activity controller. This is to * prevent the controller from getting hung up on bug reports at this point. - * @hide * * @param msg The message to show instead of the dump; if null, dumps are * re-enabled. + * + * @hide */ public static void setDumpDisabled(String msg) { sDumpDisabled = msg; @@ -694,7 +706,8 @@ public class Binder implements IBinder { /** * Listener to be notified about each proxy-side binder call. * - * See {@link setProxyTransactListener}. + * @see {@link #setProxyTransactListener}. + * * @hide */ @SystemApi @@ -702,7 +715,8 @@ public class Binder implements IBinder { /** * Called before onTransact. * - * @return an object that will be passed back to #onTransactEnded (or null). + * @return an object that will be passed back to {@link #onTransactEnded} (or null)., + * * @hide */ @Nullable @@ -713,15 +727,15 @@ public class Binder implements IBinder { /** * Called before onTransact. * - * @return an object that will be passed back to #onTransactEnded (or null). + * @return an object that will be passed back to {@link #onTransactEnded} (or null). */ @Nullable Object onTransactStarted(@NonNull IBinder binder, int transactionCode); /** - * Called after onTranact (even when an exception is thrown). + * Called after onTransact (even when an exception is thrown). * - * @param session The object return by #onTransactStarted. + * @param session The object return by {@link #onTransactStarted}. */ void onTransactEnded(@Nullable Object session); } @@ -732,16 +746,17 @@ public class Binder implements IBinder { * <li>By default, this listener will propagate the worksource if the outgoing call happens on * the same thread as the incoming binder call. * <li>Custom attribution can be done by calling {@link ThreadLocalWorkSource#setUid(int)}. + * * @hide */ public static class PropagateWorkSourceTransactListener implements ProxyTransactListener { @Override public Object onTransactStarted(IBinder binder, int transactionCode) { - // Note that {@link Binder#getCallingUid()} is already set to the UID of the current - // process when this method is called. - // - // We use ThreadLocalWorkSource instead. It also allows feature owners to set - // {@link ThreadLocalWorkSource#set(int) manually to attribute resources to a UID. + // Note that {@link #getCallingUid()} is already set to the UID of the current + // process when this method is called. + // + // We use {@link ThreadLocalWorkSource} instead. It also allows feature owners to set + // {@link ThreadLocalWorkSource#set(int)} manually to attribute resources to a UID. int uid = ThreadLocalWorkSource.getUid(); if (uid != ThreadLocalWorkSource.UID_NONE) { return Binder.setCallingWorkSourceUid(uid); @@ -770,6 +785,7 @@ public class Binder implements IBinder { * <li>The listener is called on the critical path of the binder transaction so be careful about * performance. * <li>Never execute another binder transaction inside the listener. + * * @hide */ @SystemApi @@ -778,7 +794,7 @@ public class Binder implements IBinder { } /** - * Default implementation is a stub that returns false. You will want + * Default implementation is a stub that returns false. You will want * to override this to do the appropriate unmarshalling of transactions. * * <p>If you want to call this, call transact(). @@ -786,15 +802,14 @@ public class Binder implements IBinder { * <p>Implementations that are returning a result should generally use * {@link Parcel#writeNoException() Parcel.writeNoException} and * {@link Parcel#writeException(Exception) Parcel.writeException} to propagate - * exceptions back to the caller.</p> + * exceptions back to the caller. * - * @param code The action to perform. This should - * be a number between {@link #FIRST_CALL_TRANSACTION} and - * {@link #LAST_CALL_TRANSACTION}. + * @param code The action to perform. This should be a number between + * {@link #FIRST_CALL_TRANSACTION} and {@link #LAST_CALL_TRANSACTION}. * @param data Marshalled data being received from the caller. * @param reply If the caller is expecting a result back, it should be marshalled * in to here. - * @param flags Additional operation flags. Either 0 for a normal + * @param flags Additional operation flags. Either 0 for a normal * RPC, or {@link #FLAG_ONEWAY} for a one-way RPC. * * @return Return true on a successful call; returning false is generally used to @@ -856,10 +871,12 @@ public class Binder implements IBinder { * Resolves a transaction code to a human readable name. * * <p>Default implementation is a stub that returns null. + * * <p>AIDL generated code will return the original method name. * * @param transactionCode The code to resolve. * @return A human readable name. + * * @hide */ public @Nullable String getTransactionName(int transactionCode) { @@ -925,7 +942,7 @@ public class Binder implements IBinder { * Print the object's state into the given stream. * * @param fd The raw file descriptor that the dump is being sent to. - * @param fout The file to which you should dump your state. This will be + * @param fout The file to which you should dump your state. This will be * closed for you after you return. * @param args additional arguments to the dump request. */ @@ -941,6 +958,7 @@ public class Binder implements IBinder { * @param callback Callback through which to interact with the invoking shell. * @param resultReceiver Called when the command has finished executing, with the result code. * @throws RemoteException + * * @hide */ public void shellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out, @@ -958,7 +976,8 @@ public class Binder implements IBinder { * * <p class="caution">Note: no permission checking is done before calling this method; you must * apply any security checks as appropriate for the command being executed. - * Consider using {@link ShellCommand} to help in the implementation.</p> + * Consider using {@link ShellCommand} to help in the implementation. + * * @hide */ public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out, @@ -1013,7 +1032,7 @@ public class Binder implements IBinder { * System services can implement this method to implement ADB shell commands. * * <p>A system binder service can implement it to handle shell commands on ADB. For example, - * the Job Scheduler service implements it to handle <code>adb shell cmd jobscheduler</code>. + * the Job Scheduler service implements it to handle {@code adb shell cmd jobscheduler}. * * <p>Commands are only executable by ADB shell; i.e. only {@link Process#SHELL_UID} and * {@link Process#ROOT_UID} can call them. @@ -1022,8 +1041,8 @@ public class Binder implements IBinder { * @param out standard output * @param err standard error * @param args arguments passed to the command. Can be empty. The first argument is typically - * a subcommand, such as {@code run} for {@code adb shell cmd jobscheduler run}. - * @return the status code returned from the <code>cmd</code> command. + * a subcommand, such as {@code run} for {@code adb shell cmd jobscheduler run}. + * @return the status code returned from the {@code cmd} command. * * @hide */ @@ -1051,7 +1070,7 @@ public class Binder implements IBinder { public final native void setExtension(@Nullable IBinder extension); /** - * Default implementation rewinds the parcels and calls onTransact. On + * Default implementation rewinds the parcels and calls onTransact. On * the remote side, transact calls into the binder to do the IPC. */ public final boolean transact(int code, @NonNull Parcel data, @Nullable Parcel reply, @@ -1083,7 +1102,7 @@ public class Binder implements IBinder { static void checkParcel(IBinder obj, int code, Parcel parcel, String msg) { if (CHECK_PARCEL_SIZE && parcel.dataSize() >= 800*1024) { - // Trying to send > 800k, this is way too much + // Trying to send > 800k, this is way too much. StringBuilder sb = new StringBuilder(); sb.append(msg); sb.append(": on "); @@ -1107,7 +1126,7 @@ public class Binder implements IBinder { private static native long getNativeBBinderHolder(); /** - * By default, we use the calling uid since we can always trust it. + * By default, we use the calling UID since we can always trust it. */ private static volatile BinderInternal.WorkSourceProvider sWorkSourceProvider = (x) -> Binder.getCallingUid(); @@ -1122,6 +1141,7 @@ public class Binder implements IBinder { * <li>The callback is called on the critical path of the binder transaction so be careful about * performance. * <li>Never execute another binder transaction inside the callback. + * * @hide */ public static void setWorkSourceProvider(BinderInternal.WorkSourceProvider workSourceProvider) { @@ -1131,12 +1151,12 @@ public class Binder implements IBinder { sWorkSourceProvider = workSourceProvider; } - // Entry point from android_util_Binder.cpp's onTransact + // Entry point from android_util_Binder.cpp's onTransact. @UnsupportedAppUsage private boolean execTransact(int code, long dataObj, long replyObj, int flags) { // At that point, the parcel request headers haven't been parsed so we do not know what - // WorkSource the caller has set. Use calling uid as the default. + // {@link WorkSource} the caller has set. Use calling UID as the default. final int callingUid = Binder.getCallingUid(); final long origWorkSource = ThreadLocalWorkSource.setUid(callingUid); try { @@ -1154,17 +1174,18 @@ public class Binder implements IBinder { 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, + // 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. boolean res; // Log any exceptions as warnings, don't silently suppress them. - // If the call was FLAG_ONEWAY then these exceptions disappear into the ether. + // If the call was {@link IBinder#FLAG_ONEWAY} then these exceptions + // disappear into the ether. final boolean tracingEnabled = Binder.isTracingEnabled(); try { final BinderCallHeavyHitterWatcher heavyHitterWatcher = sHeavyHitterWatcher; if (heavyHitterWatcher != null) { - // Notify the heavy hitter watcher, if it's enabled + // Notify the heavy hitter watcher, if it's enabled. heavyHitterWatcher.onTransaction(callingUid, getClass(), code); } if (tracingEnabled) { @@ -1197,7 +1218,7 @@ public class Binder implements IBinder { Log.w(TAG, "Caught a RuntimeException from the binder stub implementation.", e); } } else { - // Clear the parcel before writing the exception + // Clear the parcel before writing the exception. reply.setDataSize(0); reply.setDataPosition(0); reply.writeException(e); @@ -1209,7 +1230,7 @@ public class Binder implements IBinder { } if (observer != null) { // The parcel RPC headers have been called during onTransact so we can now access - // the worksource uid from the parcel. + // the worksource UID from the parcel. final int workSourceUid = sWorkSourceProvider.resolveWorkSourceUid( data.readCallingWorkSourceUid()); observer.callEnded(callSession, data.dataSize(), reply.dataSize(), workSourceUid); @@ -1220,9 +1241,9 @@ public class Binder implements IBinder { data.recycle(); // Just in case -- we are done with the IPC, so there should be no more strict - // mode violations that have gathered for this thread. Either they have been + // mode violations that have gathered for this thread. Either they have been // parceled and are now in transport off to the caller, or we are returning back - // to the main transaction loop to wait for another incoming transaction. Either + // to the main transaction loop to wait for another incoming transaction. Either // way, strict mode begone! StrictMode.clearGatheredViolations(); return res; diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java index 92eb7a5d047e..b2bbfd6c163d 100644 --- a/core/java/android/os/Bundle.java +++ b/core/java/android/os/Bundle.java @@ -102,6 +102,18 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable { } /** + * Constructs a {@link Bundle} containing a copy of {@code from}. + * + * @param from The bundle to be copied. + * @param deep Whether is a deep or shallow copy. + * + * @hide + */ + Bundle(Bundle from, boolean deep) { + super(from, deep); + } + + /** * If {@link #mParcelledData} is not null, copy the HAS FDS bit from it because it's fast. * Otherwise (if {@link #mParcelledData} is already null), leave {@link #FLAG_HAS_FDS_KNOWN} * unset, because scanning a map is slower. We'll do it lazily in @@ -167,13 +179,6 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable { } /** - * Constructs a Bundle without initializing it. - */ - Bundle(boolean doInit) { - super(doInit); - } - - /** * Make a Bundle for a single key/value pair. * * @hide @@ -260,9 +265,7 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable { * are referenced as-is and not copied in any way. */ public Bundle deepCopy() { - Bundle b = new Bundle(false); - b.copyInternal(this, true); - return b; + return new Bundle(this, /* deep */ true); } /** @@ -324,28 +327,10 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable { */ public boolean hasFileDescriptors() { if ((mFlags & FLAG_HAS_FDS_KNOWN) == 0) { - boolean fdFound = false; // keep going until we find one or run out of data - - if (mParcelledData != null) { - if (mParcelledData.hasFileDescriptors()) { - fdFound = true; - } - } else { - // It's been unparcelled, so we need to walk the map - for (int i=mMap.size()-1; i>=0; i--) { - Object obj = mMap.valueAt(i); - if (Parcel.hasFileDescriptors(obj)) { - fdFound = true; - break; - } - } - } - - if (fdFound) { - mFlags |= FLAG_HAS_FDS; - } else { - mFlags &= ~FLAG_HAS_FDS; - } + Parcel p = mParcelledData; + mFlags = (Parcel.hasFileDescriptors((p != null) ? p : mMap)) + ? mFlags | FLAG_HAS_FDS + : mFlags & ~FLAG_HAS_FDS; mFlags |= FLAG_HAS_FDS_KNOWN; } return (mFlags & FLAG_HAS_FDS) != 0; diff --git a/core/java/android/os/BytesMatcher.java b/core/java/android/os/BytesMatcher.java deleted file mode 100644 index 8974c5ee4e32..000000000000 --- a/core/java/android/os/BytesMatcher.java +++ /dev/null @@ -1,315 +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. - */ - -package android.os; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.bluetooth.BluetoothUuid; -import android.net.MacAddress; -import android.text.TextUtils; -import android.util.Log; - -import com.android.internal.util.HexDump; - -import java.util.ArrayList; -import java.util.function.Predicate; - -/** - * Predicate that tests if a given {@code byte[]} value matches a set of - * configured rules. - * <p> - * Rules are tested in the order in which they were originally added, which - * means a narrow rule can reject a specific value before a later broader rule - * might accept that same value, or vice versa. - * <p> - * Matchers can contain rules of varying lengths, and tested values will only be - * matched against rules of the exact same length. This is designed to support - * {@link BluetoothUuid} style values which can be variable length. - * - * @hide - */ -public class BytesMatcher implements Predicate<byte[]> { - private static final String TAG = "BytesMatcher"; - - private static final char TYPE_EXACT_ACCEPT = '+'; - private static final char TYPE_EXACT_REJECT = '-'; - private static final char TYPE_PREFIX_ACCEPT = '⊆'; - private static final char TYPE_PREFIX_REJECT = '⊈'; - - private final ArrayList<Rule> mRules = new ArrayList<>(); - - private static class Rule { - public final char type; - public final @NonNull byte[] value; - public final @Nullable byte[] mask; - - public Rule(char type, @NonNull byte[] value, @Nullable byte[] mask) { - if (mask != null && value.length != mask.length) { - throw new IllegalArgumentException( - "Expected length " + value.length + " but found " + mask.length); - } - this.type = type; - this.value = value; - this.mask = mask; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - encode(builder); - return builder.toString(); - } - - public void encode(@NonNull StringBuilder builder) { - builder.append(type); - builder.append(HexDump.toHexString(value)); - if (mask != null) { - builder.append('/'); - builder.append(HexDump.toHexString(mask)); - } - } - - public boolean test(@NonNull byte[] value) { - switch (type) { - case TYPE_EXACT_ACCEPT: - case TYPE_EXACT_REJECT: - if (value.length != this.value.length) { - return false; - } - break; - case TYPE_PREFIX_ACCEPT: - case TYPE_PREFIX_REJECT: - if (value.length < this.value.length) { - return false; - } - break; - } - for (int i = 0; i < this.value.length; i++) { - byte local = this.value[i]; - byte remote = value[i]; - if (this.mask != null) { - local &= this.mask[i]; - remote &= this.mask[i]; - } - if (local != remote) { - return false; - } - } - return true; - } - } - - /** - * Add a rule that will result in {@link #test(byte[])} returning - * {@code true} when a value being tested matches it. This rule will only - * match values of the exact same length. - * <p> - * Rules are tested in the order in which they were originally added, which - * means a narrow rule can reject a specific value before a later broader - * rule might accept that same value, or vice versa. - * - * @param value to be matched - * @param mask to be applied to both values before testing for equality; if - * {@code null} then both values must match exactly - */ - public void addExactAcceptRule(@NonNull byte[] value, @Nullable byte[] mask) { - mRules.add(new Rule(TYPE_EXACT_ACCEPT, value, mask)); - } - - /** - * Add a rule that will result in {@link #test(byte[])} returning - * {@code false} when a value being tested matches it. This rule will only - * match values of the exact same length. - * <p> - * Rules are tested in the order in which they were originally added, which - * means a narrow rule can reject a specific value before a later broader - * rule might accept that same value, or vice versa. - * - * @param value to be matched - * @param mask to be applied to both values before testing for equality; if - * {@code null} then both values must match exactly - */ - public void addExactRejectRule(@NonNull byte[] value, @Nullable byte[] mask) { - mRules.add(new Rule(TYPE_EXACT_REJECT, value, mask)); - } - - /** - * Add a rule that will result in {@link #test(byte[])} returning - * {@code true} when a value being tested matches it. This rule will match - * values of the exact same length or longer. - * <p> - * Rules are tested in the order in which they were originally added, which - * means a narrow rule can reject a specific value before a later broader - * rule might accept that same value, or vice versa. - * - * @param value to be matched - * @param mask to be applied to both values before testing for equality; if - * {@code null} then both values must match exactly - */ - public void addPrefixAcceptRule(@NonNull byte[] value, @Nullable byte[] mask) { - mRules.add(new Rule(TYPE_PREFIX_ACCEPT, value, mask)); - } - - /** - * Add a rule that will result in {@link #test(byte[])} returning - * {@code false} when a value being tested matches it. This rule will match - * values of the exact same length or longer. - * <p> - * Rules are tested in the order in which they were originally added, which - * means a narrow rule can reject a specific value before a later broader - * rule might accept that same value, or vice versa. - * - * @param value to be matched - * @param mask to be applied to both values before testing for equality; if - * {@code null} then both values must match exactly - */ - public void addPrefixRejectRule(@NonNull byte[] value, @Nullable byte[] mask) { - mRules.add(new Rule(TYPE_PREFIX_REJECT, value, mask)); - } - - /** - * Test if the given {@code ParcelUuid} value matches the set of rules - * configured in this matcher. - */ - public boolean testBluetoothUuid(@NonNull ParcelUuid value) { - return test(BluetoothUuid.uuidToBytes(value)); - } - - /** - * Test if the given {@code MacAddress} value matches the set of rules - * configured in this matcher. - */ - public boolean testMacAddress(@NonNull MacAddress value) { - return test(value.toByteArray()); - } - - /** - * Test if the given {@code byte[]} value matches the set of rules - * configured in this matcher. - */ - @Override - public boolean test(@NonNull byte[] value) { - return test(value, false); - } - - /** - * Test if the given {@code byte[]} value matches the set of rules - * configured in this matcher. - */ - public boolean test(@NonNull byte[] value, boolean defaultValue) { - final int size = mRules.size(); - for (int i = 0; i < size; i++) { - final Rule rule = mRules.get(i); - if (rule.test(value)) { - switch (rule.type) { - case TYPE_EXACT_ACCEPT: - case TYPE_PREFIX_ACCEPT: - return true; - case TYPE_EXACT_REJECT: - case TYPE_PREFIX_REJECT: - return false; - } - } - } - return defaultValue; - } - - /** - * Encode the given matcher into a human-readable {@link String} which can - * be used to transport matchers across device boundaries. - * <p> - * The human-readable format is an ordered list separated by commas, where - * each rule is a {@code +} or {@code -} symbol indicating if the match - * should be accepted or rejected, then followed by a hex value and an - * optional hex mask. For example, {@code -caff,+cafe/ff00} is a valid - * encoded matcher. - * - * @see #decode(String) - */ - public static @NonNull String encode(@NonNull BytesMatcher matcher) { - final StringBuilder builder = new StringBuilder(); - final int size = matcher.mRules.size(); - for (int i = 0; i < size; i++) { - final Rule rule = matcher.mRules.get(i); - rule.encode(builder); - builder.append(','); - } - if (builder.length() > 0) { - builder.deleteCharAt(builder.length() - 1); - } - return builder.toString(); - } - - /** - * Decode the given human-readable {@link String} used to transport matchers - * across device boundaries. - * <p> - * The human-readable format is an ordered list separated by commas, where - * each rule is a {@code +} or {@code -} symbol indicating if the match - * should be accepted or rejected, then followed by a hex value and an - * optional hex mask. For example, {@code -caff,+cafe/ff00} is a valid - * encoded matcher. - * - * @see #encode(BytesMatcher) - */ - public static @NonNull BytesMatcher decode(@Nullable String value) { - final BytesMatcher matcher = new BytesMatcher(); - if (TextUtils.isEmpty(value)) return matcher; - - final int length = value.length(); - for (int i = 0; i < length;) { - final char type = value.charAt(i); - - int nextRule = value.indexOf(',', i); - int nextMask = value.indexOf('/', i); - - if (nextRule == -1) nextRule = length; - if (nextMask > nextRule) nextMask = -1; - - final byte[] ruleValue; - final byte[] ruleMask; - if (nextMask >= 0) { - ruleValue = HexDump.hexStringToByteArray(value.substring(i + 1, nextMask)); - ruleMask = HexDump.hexStringToByteArray(value.substring(nextMask + 1, nextRule)); - } else { - ruleValue = HexDump.hexStringToByteArray(value.substring(i + 1, nextRule)); - ruleMask = null; - } - - switch (type) { - case TYPE_EXACT_ACCEPT: - matcher.addExactAcceptRule(ruleValue, ruleMask); - break; - case TYPE_EXACT_REJECT: - matcher.addExactRejectRule(ruleValue, ruleMask); - break; - case TYPE_PREFIX_ACCEPT: - matcher.addPrefixAcceptRule(ruleValue, ruleMask); - break; - case TYPE_PREFIX_REJECT: - matcher.addPrefixRejectRule(ruleValue, ruleMask); - break; - default: - Log.w(TAG, "Ignoring unknown type " + type); - break; - } - - i = nextRule + 1; - } - return matcher; - } -} diff --git a/core/java/android/os/ISystemConfig.aidl b/core/java/android/os/ISystemConfig.aidl index d83d94a8ec77..15e3ce25122b 100644 --- a/core/java/android/os/ISystemConfig.aidl +++ b/core/java/android/os/ISystemConfig.aidl @@ -16,6 +16,8 @@ package android.os; +import android.content.ComponentName; + /** * Binder interface to query SystemConfig in the system server. * {@hide} @@ -44,5 +46,5 @@ interface ISystemConfig { /** * @see SystemConfigManager#getEnabledComponentOverrides */ - List<String> getEnabledComponentOverrides(String packageName); + List<ComponentName> getEnabledComponentOverrides(String packageName); } diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java index 44d51db80f86..d1e671691897 100644 --- a/core/java/android/os/Parcel.java +++ b/core/java/android/os/Parcel.java @@ -20,6 +20,7 @@ import static java.util.Objects.requireNonNull; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SuppressLint; import android.annotation.TestApi; import android.app.AppOpsManager; import android.compat.annotation.UnsupportedAppUsage; @@ -380,10 +381,14 @@ public final class Parcel { private static native void nativeUnmarshall( long nativePtr, byte[] data, int offset, int length); private static native int nativeCompareData(long thisNativePtr, long otherNativePtr); + private static native boolean nativeCompareDataInRange( + long ptrA, int offsetA, long ptrB, int offsetB, int length); private static native void nativeAppendFrom( long thisNativePtr, long otherNativePtr, int offset, int length); @CriticalNative private static native boolean nativeHasFileDescriptors(long nativePtr); + private static native boolean nativeHasFileDescriptorsInRange( + long nativePtr, int offset, int length); private static native void nativeWriteInterfaceToken(long nativePtr, String interfaceName); private static native void nativeEnforceInterface(long nativePtr, String interfaceName); @@ -399,7 +404,7 @@ public final class Parcel { private static final int WRITE_EXCEPTION_STACK_TRACE_THRESHOLD_MS = 1000; @CriticalNative - private static native long nativeGetBlobAshmemSize(long nativePtr); + private static native long nativeGetOpenAshmemSize(long nativePtr); public final static Parcelable.Creator<String> STRING_CREATOR = new Parcelable.Creator<String>() { @@ -675,11 +680,16 @@ public final class Parcel { } /** @hide */ - public final int compareData(Parcel other) { + public int compareData(Parcel other) { return nativeCompareData(mNativePtr, other.mNativePtr); } /** @hide */ + public static boolean compareData(Parcel a, int offsetA, Parcel b, int offsetB, int length) { + return nativeCompareDataInRange(a.mNativePtr, offsetA, b.mNativePtr, offsetB, length); + } + + /** @hide */ public final void setClassCookie(Class clz, Object cookie) { if (mClassCookies == null) { mClassCookies = new ArrayMap<>(); @@ -717,62 +727,90 @@ public final class Parcel { /** * Report whether the parcel contains any marshalled file descriptors. */ - public final boolean hasFileDescriptors() { + public boolean hasFileDescriptors() { return nativeHasFileDescriptors(mNativePtr); } /** - * Check if the object used in {@link #readValue(ClassLoader)} / {@link #writeValue(Object)} - * has file descriptors. + * Report whether the parcel contains any marshalled file descriptors in the range defined by + * {@code offset} and {@code length}. + * + * @param offset The offset from which the range starts. Should be between 0 and + * {@link #dataSize()}. + * @param length The length of the range. Should be between 0 and {@link #dataSize()} - {@code + * offset}. + * @return whether there are file descriptors or not. + * @throws IllegalArgumentException if the parameters are out of the permitted ranges. + */ + public boolean hasFileDescriptors(int offset, int length) { + return nativeHasFileDescriptorsInRange(mNativePtr, offset, length); + } + + /** + * Check if the object has file descriptors. + * + * <p>Objects supported are {@link Parcel} and objects that can be passed to {@link + * #writeValue(Object)}} * * <p>For most cases, it will use the self-reported {@link Parcelable#describeContents()} method * for that. * - * @throws IllegalArgumentException if you provide any object not supported by above methods. - * Most notably, if you pass {@link Parcel}, this method will throw, for that check - * {@link Parcel#hasFileDescriptors()} + * @throws IllegalArgumentException if you provide any object not supported by above methods + * (including if the unsupported object is inside a nested container). * * @hide */ public static boolean hasFileDescriptors(Object value) { - if (value instanceof LazyValue) { - return ((LazyValue) value).hasFileDescriptors(); + if (value instanceof Parcel) { + Parcel parcel = (Parcel) value; + if (parcel.hasFileDescriptors()) { + return true; + } + } else if (value instanceof LazyValue) { + LazyValue lazy = (LazyValue) value; + if (lazy.hasFileDescriptors()) { + return true; + } } else if (value instanceof Parcelable) { - if ((((Parcelable) value).describeContents() - & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0) { + Parcelable parcelable = (Parcelable) value; + if ((parcelable.describeContents() & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0) { return true; } - } else if (value instanceof Parcelable[]) { - Parcelable[] array = (Parcelable[]) value; - for (int n = array.length - 1; n >= 0; n--) { - Parcelable p = array[n]; - if (p != null && ((p.describeContents() - & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0)) { + } else if (value instanceof ArrayMap<?, ?>) { + ArrayMap<?, ?> map = (ArrayMap<?, ?>) value; + for (int i = 0, n = map.size(); i < n; i++) { + if (hasFileDescriptors(map.keyAt(i)) + || hasFileDescriptors(map.valueAt(i))) { + return true; + } + } + } else if (value instanceof Map<?, ?>) { + Map<?, ?> map = (Map<?, ?>) value; + for (Map.Entry<?, ?> entry : map.entrySet()) { + if (hasFileDescriptors(entry.getKey()) + || hasFileDescriptors(entry.getValue())) { + return true; + } + } + } else if (value instanceof List<?>) { + List<?> list = (List<?>) value; + for (int i = 0, n = list.size(); i < n; i++) { + if (hasFileDescriptors(list.get(i))) { return true; } } } else if (value instanceof SparseArray<?>) { SparseArray<?> array = (SparseArray<?>) value; - for (int n = array.size() - 1; n >= 0; n--) { - Object object = array.valueAt(n); - if (object instanceof Parcelable) { - Parcelable p = (Parcelable) object; - if (p != null && (p.describeContents() - & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0) { - return true; - } + for (int i = 0, n = array.size(); i < n; i++) { + if (hasFileDescriptors(array.valueAt(i))) { + return true; } } - } else if (value instanceof ArrayList<?>) { - ArrayList<?> array = (ArrayList<?>) value; - for (int n = array.size() - 1; n >= 0; n--) { - Object object = array.get(n); - if (object instanceof Parcelable) { - Parcelable p = (Parcelable) object; - if (p != null && ((p.describeContents() - & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0)) { - return true; - } + } else if (value instanceof Object[]) { + Object[] array = (Object[]) value; + for (int i = 0, n = array.length; i < n; i++) { + if (hasFileDescriptors(array[i])) { + return true; } } } else { @@ -2423,9 +2461,9 @@ public final class Parcel { writeByteArray(baos.toByteArray()); } catch (IOException ioe) { - throw new RuntimeException("Parcelable encountered " + - "IOException writing serializable object (name = " + name + - ")", ioe); + throw new BadParcelableException("Parcelable encountered " + + "IOException writing serializable object (name = " + + name + ")", ioe); } } @@ -2874,9 +2912,11 @@ public final class Parcel { /** * Same as {@link #readList(List, ClassLoader)} but accepts {@code clazz} parameter as - * the type required for each item. If the item to be deserialized is not an instance - * of that class or any of its children class - * a {@link BadParcelableException} will be thrown. + * the type required for each item. + * + * @throws BadParcelableException Throws BadParcelableException if the item to be deserialized + * is not an instance of that class or any of its children classes or there was an error + * trying to instantiate an element. */ public <T> void readList(@NonNull List<? super T> outVal, @Nullable ClassLoader loader, @NonNull Class<T> clazz) { @@ -3075,14 +3115,24 @@ public final class Parcel { * Parcelables. */ @Nullable - public final ArrayList readArrayList(@Nullable ClassLoader loader) { - int N = readInt(); - if (N < 0) { - return null; - } - ArrayList l = new ArrayList(N); - readListInternal(l, N, loader, /* clazz */ null); - return l; + public ArrayList readArrayList(@Nullable ClassLoader loader) { + return readArrayListInternal(loader, /* clazz */ null); + } + + /** + * Same as {@link #readArrayList(ClassLoader)} but accepts {@code clazz} parameter as + * the type required for each item. + * + * @throws BadParcelableException Throws BadParcelableException if the item to be deserialized + * is not an instance of that class or any of its children classes or there was an error + * trying to instantiate an element. + */ + @SuppressLint({"ConcreteCollection", "NullableCollection"}) + @Nullable + public <T> ArrayList<T> readArrayList(@Nullable ClassLoader loader, + @NonNull Class<? extends T> clazz) { + Objects.requireNonNull(clazz); + return readArrayListInternal(loader, clazz); } /** @@ -3092,14 +3142,23 @@ public final class Parcel { * Parcelables. */ @Nullable - public final Object[] readArray(@Nullable ClassLoader loader) { - int N = readInt(); - if (N < 0) { - return null; - } - Object[] l = new Object[N]; - readArrayInternal(l, N, loader); - return l; + public Object[] readArray(@Nullable ClassLoader loader) { + return readArrayInternal(loader, /* clazz */ null); + } + + /** + * Same as {@link #readArray(ClassLoader)} but accepts {@code clazz} parameter as + * the type required for each item. + * + * @throws BadParcelableException Throws BadParcelableException if the item to be deserialized + * is not an instance of that class or any of its children classes or there was an error + * trying to instantiate an element. + */ + @SuppressLint({"ArrayReturn", "NullableCollection"}) + @Nullable + public <T> T[] readArray(@Nullable ClassLoader loader, @NonNull Class<T> clazz) { + Objects.requireNonNull(clazz); + return readArrayInternal(loader, clazz); } /** @@ -3109,14 +3168,23 @@ public final class Parcel { * Parcelables. */ @Nullable - public final <T> SparseArray<T> readSparseArray(@Nullable ClassLoader loader) { - int N = readInt(); - if (N < 0) { - return null; - } - SparseArray sa = new SparseArray(N); - readSparseArrayInternal(sa, N, loader); - return sa; + public <T> SparseArray<T> readSparseArray(@Nullable ClassLoader loader) { + return readSparseArrayInternal(loader, /* clazz */ null); + } + + /** + * Same as {@link #readSparseArray(ClassLoader)} but accepts {@code clazz} parameter as + * the type required for each item. + * + * @throws BadParcelableException Throws BadParcelableException if the item to be deserialized + * is not an instance of that class or any of its children classes or there was an error + * trying to instantiate an element. + */ + @Nullable + public <T> SparseArray<T> readSparseArray(@Nullable ClassLoader loader, + @NonNull Class<? extends T> clazz) { + Objects.requireNonNull(clazz); + return readSparseArrayInternal(loader, clazz); } /** @@ -3536,21 +3604,31 @@ public final class Parcel { int start = dataPosition(); int type = readInt(); if (isLengthPrefixed(type)) { - int length = readInt(); - setDataPosition(MathUtils.addOrThrow(dataPosition(), length)); - return new LazyValue(this, start, length, type, loader); + int objectLength = readInt(); + int end = MathUtils.addOrThrow(dataPosition(), objectLength); + int valueLength = end - start; + setDataPosition(end); + return new LazyValue(this, start, valueLength, type, loader); } else { return readValue(type, loader, /* clazz */ null); } } + private static final class LazyValue implements Supplier<Object> { + /** + * | 4B | 4B | + * mSource = Parcel{... | type | length | object | ...} + * a b c d + * length = d - c + * mPosition = a + * mLength = d - a + */ private final int mPosition; private final int mLength; private final int mType; @Nullable private final ClassLoader mLoader; @Nullable private Object mObject; - @Nullable private volatile Parcel mValueParcel; /** * This goes from non-null to null once. Always check the nullability of this object before @@ -3592,7 +3670,7 @@ public final class Parcel { public void writeToParcel(Parcel out) { Parcel source = mSource; if (source != null) { - out.appendFrom(source, mPosition, mLength + 8); + out.appendFrom(source, mPosition, mLength); } else { out.writeValue(mObject); } @@ -3601,7 +3679,7 @@ public final class Parcel { public boolean hasFileDescriptors() { Parcel source = mSource; return (source != null) - ? getValueParcel(source).hasFileDescriptors() + ? source.hasFileDescriptors(mPosition, mLength) : Parcel.hasFileDescriptors(mObject); } @@ -3648,7 +3726,7 @@ public final class Parcel { return false; } // Finally we compare the payload. - return getValueParcel(source).compareData(value.getValueParcel(otherSource)) == 0; + return Parcel.compareData(source, mPosition, otherSource, value.mPosition, mLength); } @Override @@ -3656,20 +3734,6 @@ public final class Parcel { // Accessing mSource first to provide memory barrier for mObject return Objects.hash(mSource == null, mObject, mLoader, mType, mLength); } - - /** This extracts the parcel section responsible for the object and returns it. */ - private Parcel getValueParcel(Parcel source) { - Parcel parcel = mValueParcel; - if (parcel == null) { - parcel = Parcel.obtain(); - // mLength is the length of object representation, excluding the type and length. - // mPosition is the position of the entire value container, right before the type. - // So, we add 4 bytes for the type + 4 bytes for the length written. - parcel.appendFrom(source, mPosition, mLength + 8); - mValueParcel = parcel; - } - return parcel; - } } /** @@ -3767,7 +3831,7 @@ public final class Parcel { break; case VAL_SERIALIZABLE: - object = readSerializable(loader); + object = readSerializableInternal(loader, clazz); break; case VAL_PARCELABLEARRAY: @@ -3824,7 +3888,7 @@ public final class Parcel { "Parcel " + this + ": Unmarshalling unknown type code " + type + " at offset " + off); } - if (clazz != null && !clazz.isInstance(object)) { + if (object != null && clazz != null && !clazz.isInstance(object)) { throw new BadParcelableException("Unparcelled object " + object + " is not an instance of required class " + clazz.getName() + " provided in the parameter"); @@ -3869,8 +3933,11 @@ public final class Parcel { /** * Same as {@link #readParcelable(ClassLoader)} but accepts {@code clazz} parameter as the type - * required for each item. If the item to be deserialized is not an instance of that class or - * any of its children classes a {@link BadParcelableException} will be thrown. + * required for each item. + * + * @throws BadParcelableException Throws BadParcelableException if the item to be deserialized + * is not an instance of that class or any of its children classes or there was an error + * trying to instantiate an element. */ @Nullable public <T extends Parcelable> T readParcelable(@Nullable ClassLoader loader, @@ -3880,7 +3947,6 @@ public final class Parcel { } /** - * * @param clazz The type of the parcelable expected or {@code null} for performing no checks. */ @SuppressWarnings("unchecked") @@ -3936,8 +4002,11 @@ public final class Parcel { /** * Same as {@link #readParcelableCreator(ClassLoader)} but accepts {@code clazz} parameter - * as the required type. If the item to be deserialized is not an instance of that class - * or any of its children classes a {@link BadParcelableException} will be thrown. + * as the required type. + * + * @throws BadParcelableException Throws BadParcelableException if the item to be deserialized + * is not an instance of that class or any of its children classes or there there was an error + * trying to read the {@link Parcelable.Creator}. */ @Nullable public <T> Parcelable.Creator<T> readParcelableCreator( @@ -4059,17 +4128,25 @@ public final class Parcel { return p; } - /** @hide */ + /** + * Same as {@link #readParcelableArray(ClassLoader)} but accepts {@code clazz} parameter as + * the type required for each item. + * + * @throws BadParcelableException Throws BadParcelableException if the item to be deserialized + * is not an instance of that class or any of its children classes or there was an error + * trying to instantiate an element. + */ + @SuppressLint({"ArrayReturn", "NullableCollection"}) + @SuppressWarnings("unchecked") @Nullable - public final <T extends Parcelable> T[] readParcelableArray(@Nullable ClassLoader loader, - @NonNull Class<T> clazz) { - int N = readInt(); - if (N < 0) { + public <T> T[] readParcelableArray(@Nullable ClassLoader loader, @NonNull Class<T> clazz) { + int n = readInt(); + if (n < 0) { return null; } - T[] p = (T[]) Array.newInstance(clazz, N); - for (int i = 0; i < N; i++) { - p[i] = readParcelable(loader); + T[] p = (T[]) Array.newInstance(clazz, n); + for (int i = 0; i < n; i++) { + p[i] = readParcelableInternal(loader, clazz); } return p; } @@ -4080,12 +4157,37 @@ public final class Parcel { * wasn't found in the parcel. */ @Nullable - public final Serializable readSerializable() { - return readSerializable(null); + public Serializable readSerializable() { + return readSerializableInternal(/* loader */ null, /* clazz */ null); } + /** + * Same as {@link #readSerializable()} but accepts {@code loader} parameter + * as the primary classLoader for resolving the Serializable class; and {@code clazz} parameter + * as the required type. + * + * @throws BadParcelableException Throws BadParcelableException if the item to be deserialized + * is not an instance of that class or any of its children class or there there was an error + * deserializing the object. + */ @Nullable - private final Serializable readSerializable(@Nullable final ClassLoader loader) { + public <T extends Serializable> T readSerializable(@Nullable ClassLoader loader, + @NonNull Class<T> clazz) { + Objects.requireNonNull(clazz); + return readSerializableInternal(loader, clazz); + } + + /** + * @param clazz The type of the serializable expected or {@code null} for performing no checks + */ + @Nullable + private <T> T readSerializableInternal(@Nullable final ClassLoader loader, + @Nullable Class<T> clazz) { + if (clazz != null && !Serializable.class.isAssignableFrom(clazz)) { + throw new BadParcelableException("About to unparcel a serializable object " + + " but class required " + clazz.getName() + " is not Serializable"); + } + String name = readString(); if (name == null) { // For some reason we were unable to read the name of the Serializable (either there @@ -4094,9 +4196,20 @@ public final class Parcel { return null; } - byte[] serializedData = createByteArray(); - ByteArrayInputStream bais = new ByteArrayInputStream(serializedData); try { + if (clazz != null && loader != null) { + // If custom classloader is provided, resolve the type of serializable using the + // name, then check the type before deserialization. As in this case we can resolve + // the class the same way as ObjectInputStream, using the provided classloader. + Class<?> cl = Class.forName(name, false, loader); + if (!clazz.isAssignableFrom(cl)) { + throw new BadParcelableException("Serializable object " + + cl.getName() + " is not a subclass of required class " + + clazz.getName() + " provided in the parameter"); + } + } + byte[] serializedData = createByteArray(); + ByteArrayInputStream bais = new ByteArrayInputStream(serializedData); ObjectInputStream ois = new ObjectInputStream(bais) { @Override protected Class<?> resolveClass(ObjectStreamClass osClass) @@ -4104,22 +4217,31 @@ public final class Parcel { // try the custom classloader if provided if (loader != null) { Class<?> c = Class.forName(osClass.getName(), false, loader); - if (c != null) { - return c; - } + return Objects.requireNonNull(c); } return super.resolveClass(osClass); } }; - return (Serializable) ois.readObject(); + T object = (T) ois.readObject(); + if (clazz != null && loader == null) { + // If custom classloader is not provided, check the type of the serializable using + // the deserialized object, as we cannot resolve the class the same way as + // ObjectInputStream. + if (!clazz.isAssignableFrom(object.getClass())) { + throw new BadParcelableException("Serializable object " + + object.getClass().getName() + " is not a subclass of required class " + + clazz.getName() + " provided in the parameter"); + } + } + return object; } catch (IOException ioe) { - throw new RuntimeException("Parcelable encountered " + - "IOException reading a Serializable object (name = " + name + - ")", ioe); + throw new BadParcelableException("Parcelable encountered " + + "IOException reading a Serializable object (name = " + + name + ")", ioe); } catch (ClassNotFoundException cnfe) { - throw new RuntimeException("Parcelable encountered " + - "ClassNotFoundException reading a Serializable object (name = " - + name + ")", cnfe); + throw new BadParcelableException("Parcelable encountered " + + "ClassNotFoundException reading a Serializable object (name = " + + name + ")", cnfe); } } @@ -4287,9 +4409,12 @@ public final class Parcel { return result; } - private void readListInternal(@NonNull List outVal, int n, - @Nullable ClassLoader loader) { - readListInternal(outVal, n, loader, null); + /** + * The method is replaced by {@link #readListInternal(List, int, ClassLoader, Class)}, however + * we are keeping this unused method here to allow unsupported app usages. + */ + private void readListInternal(@NonNull List outVal, int n, @Nullable ClassLoader loader) { + readListInternal(outVal, n, loader, /* clazz */ null); } /** @@ -4305,26 +4430,88 @@ public final class Parcel { } } + /** + * @param clazz The type of the object expected or {@code null} for performing no checks. + */ + @SuppressLint({"ConcreteCollection", "NullableCollection"}) + @Nullable + private <T> ArrayList<T> readArrayListInternal(@Nullable ClassLoader loader, + @Nullable Class<? extends T> clazz) { + int n = readInt(); + if (n < 0) { + return null; + } + ArrayList<T> l = new ArrayList<>(n); + readListInternal(l, n, loader, clazz); + return l; + } + + /** + * The method is replaced by {@link #readArrayInternal(ClassLoader, Class)}, however + * we are keeping this unused method here to allow unsupported app usages. + */ private void readArrayInternal(@NonNull Object[] outVal, int N, @Nullable ClassLoader loader) { for (int i = 0; i < N; i++) { - Object value = readValue(loader); - //Log.d(TAG, "Unmarshalling value=" + value); + Object value = readValue(loader, /* clazz */ null); outVal[i] = value; } } + /** + * @param clazz The type of the object expected or {@code null} for performing no checks. + */ + @SuppressWarnings("unchecked") + @Nullable + private <T> T[] readArrayInternal(@Nullable ClassLoader loader, @Nullable Class<T> clazz) { + int n = readInt(); + if (n < 0) { + return null; + } + T[] outVal = (T[]) ((clazz == null) ? new Object[n] : Array.newInstance(clazz, n)); + + for (int i = 0; i < n; i++) { + T value = readValue(loader, clazz); + outVal[i] = value; + } + return outVal; + } + + /** + * The method is replaced by {@link #readSparseArray(ClassLoader, Class)}, however + * we are keeping this unused method here to allow unsupported app usages. + */ private void readSparseArrayInternal(@NonNull SparseArray outVal, int N, @Nullable ClassLoader loader) { while (N > 0) { int key = readInt(); Object value = readValue(loader); - //Log.i(TAG, "Unmarshalling key=" + key + " value=" + value); outVal.append(key, value); N--; } } + /** + * @param clazz The type of the object expected or {@code null} for performing no checks. + */ + @Nullable + private <T> SparseArray<T> readSparseArrayInternal(@Nullable ClassLoader loader, + @Nullable Class<? extends T> clazz) { + int n = readInt(); + if (n < 0) { + return null; + } + SparseArray<T> outVal = new SparseArray<>(n); + + while (n > 0) { + int key = readInt(); + T value = readValue(loader, clazz); + outVal.append(key, value); + n--; + } + return outVal; + } + private void readSparseBooleanArrayInternal(@NonNull SparseBooleanArray outVal, int N) { while (N > 0) { @@ -4348,8 +4535,8 @@ public final class Parcel { /** * @hide For testing */ - public long getBlobAshmemSize() { - return nativeGetBlobAshmemSize(mNativePtr); + public long getOpenAshmemSize() { + return nativeGetOpenAshmemSize(mNativePtr); } private static String valueTypeToString(int type) { diff --git a/core/java/android/os/PersistableBundle.java b/core/java/android/os/PersistableBundle.java index 7b55e710caeb..f4edcb1317f4 100644 --- a/core/java/android/os/PersistableBundle.java +++ b/core/java/android/os/PersistableBundle.java @@ -156,10 +156,15 @@ public final class PersistableBundle extends BaseBundle implements Cloneable, Pa } /** - * Constructs a PersistableBundle without initializing it. + * Constructs a {@link PersistableBundle} containing a copy of {@code from}. + * + * @param from The bundle to be copied. + * @param deep Whether is a deep or shallow copy. + * + * @hide */ - PersistableBundle(boolean doInit) { - super(doInit); + PersistableBundle(PersistableBundle from, boolean deep) { + super(from, deep); } /** @@ -190,9 +195,7 @@ public final class PersistableBundle extends BaseBundle implements Cloneable, Pa * are referenced as-is and not copied in any way. */ public PersistableBundle deepCopy() { - PersistableBundle b = new PersistableBundle(false); - b.copyInternal(this, true); - return b; + return new PersistableBundle(this, /* deep */ true); } /** diff --git a/core/java/android/os/SystemConfigManager.java b/core/java/android/os/SystemConfigManager.java index a6316df0780c..cde2063fdba5 100644 --- a/core/java/android/os/SystemConfigManager.java +++ b/core/java/android/os/SystemConfigManager.java @@ -17,10 +17,10 @@ package android.os; import android.Manifest; import android.annotation.NonNull; -import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; +import android.content.ComponentName; import android.content.Context; import android.util.ArraySet; import android.util.Log; @@ -138,9 +138,9 @@ public class SystemConfigManager { * @return The enabled component * {@hide} */ - @SystemApi + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @NonNull - public List<String> getEnabledComponentOverrides(@NonNull String packageName) { + public List<ComponentName> getEnabledComponentOverrides(@NonNull String packageName) { try { return mInterface.getEnabledComponentOverrides(packageName); } catch (RemoteException e) { diff --git a/core/java/android/permission/DEFAULT_PERMISSION_GRANT_POLICY_OWNERS b/core/java/android/permission/DEFAULT_PERMISSION_GRANT_POLICY_OWNERS new file mode 100644 index 000000000000..cb521c842816 --- /dev/null +++ b/core/java/android/permission/DEFAULT_PERMISSION_GRANT_POLICY_OWNERS @@ -0,0 +1,8 @@ +ewol@google.com +hackbod@google.com +jsharkey@google.com +narayan@google.com +patb@google.com +svetoslavganov@google.com +yamasani@google.com +zhanghai@google.com diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java index 51f19ebee987..b4acb67d2979 100644 --- a/core/java/android/provider/CallLog.java +++ b/core/java/android/provider/CallLog.java @@ -706,6 +706,25 @@ public class CallLog { /** * Contains the recent calls. + * <p> + * Note: If you want to query the call log and limit the results to a single value, you should + * append the {@link #LIMIT_PARAM_KEY} parameter to the content URI. For example: + * <pre> + * {@code + * getContentResolver().query( + * Calls.CONTENT_URI.buildUpon().appendQueryParameter(LIMIT_PARAM_KEY, "1") + * .build(), + * null, null, null, null); + * } + * </pre> + * <p> + * The call log provider enforces strict SQL grammar, so you CANNOT append "LIMIT" to the SQL + * query as below: + * <pre> + * {@code + * getContentResolver().query(Calls.CONTENT_URI, null, "LIMIT 1", null, null); + * } + * </pre> */ public static class Calls implements BaseColumns { /** diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java index 0f0f123ca162..eda369984120 100644 --- a/core/java/android/provider/ContactsContract.java +++ b/core/java/android/provider/ContactsContract.java @@ -37,6 +37,7 @@ import android.content.Context; import android.content.ContextWrapper; import android.content.CursorEntityIterator; import android.content.Entity; +import android.content.Entity.NamedContentValues; import android.content.EntityIterator; import android.content.Intent; import android.content.IntentFilter; @@ -55,6 +56,7 @@ import android.os.RemoteException; import android.telecom.PhoneAccountHandle; import android.text.TextUtils; import android.util.DisplayMetrics; +import android.util.Log; import android.util.Pair; import android.view.View; @@ -64,7 +66,9 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Set; @@ -5135,6 +5139,8 @@ public final class ContactsContract { */ public final static class RawContactsEntity implements BaseColumns, DataColumns, RawContactsColumns { + private static final String TAG = "ContactsContract.RawContactsEntity"; + /** * This utility class cannot be instantiated */ @@ -5187,6 +5193,73 @@ public final class ContactsContract { * <P>Type: INTEGER</P> */ public static final String DATA_ID = "data_id"; + + /** + * Query raw contacts entity by a contact ID, which can potentially be a corp profile + * contact ID + * + * @param context A context to get the ContentResolver from + * @param contactId Contact ID, which can potentialy be a corp profile contact ID. + * + * @return A map from a mimetype to a List of the entity content values. + * {@hide} + */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) + public static @NonNull Map<String, List<ContentValues>> queryRawContactEntity( + @NonNull ContentResolver contentResolver, long contactId) { + Uri uri = RawContactsEntity.CONTENT_URI; + long realContactId = contactId; + + if (Contacts.isEnterpriseContactId(contactId)) { + uri = RawContactsEntity.CORP_CONTENT_URI; + realContactId = contactId - Contacts.ENTERPRISE_CONTACT_ID_BASE; + } + final Map<String, List<ContentValues>> contentValuesListMap = + new HashMap<String, List<ContentValues>>(); + // The resolver may return the entity iterator with no data. It is possible. + // e.g. If all the data in the contact of the given contact id are not exportable ones, + // they are hidden from the view of this method, though contact id itself exists. + EntityIterator entityIterator = null; + try { + final String selection = Data.CONTACT_ID + "=?"; + final String[] selectionArgs = new String[] {String.valueOf(realContactId)}; + + entityIterator = RawContacts.newEntityIterator(contentResolver.query( + uri, null, selection, selectionArgs, null)); + + if (entityIterator == null) { + Log.e(TAG, "EntityIterator is null"); + return contentValuesListMap; + } + + if (!entityIterator.hasNext()) { + Log.w(TAG, "Data does not exist. contactId: " + realContactId); + return contentValuesListMap; + } + + while (entityIterator.hasNext()) { + Entity entity = entityIterator.next(); + for (NamedContentValues namedContentValues : entity.getSubValues()) { + ContentValues contentValues = namedContentValues.values; + String key = contentValues.getAsString(Data.MIMETYPE); + if (key != null) { + List<ContentValues> contentValuesList = contentValuesListMap.get(key); + if (contentValuesList == null) { + contentValuesList = new ArrayList<ContentValues>(); + contentValuesListMap.put(key, contentValuesList); + } + contentValuesList.add(contentValues); + } + } + } + } finally { + if (entityIterator != null) { + entityIterator.close(); + } + } + return contentValuesListMap; + } } /** diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java index f5f5eb880d54..8ac5c0397734 100644 --- a/core/java/android/provider/DeviceConfig.java +++ b/core/java/android/provider/DeviceConfig.java @@ -181,6 +181,22 @@ public final class DeviceConfig { public static final String NAMESPACE_CONNECTIVITY = "connectivity"; /** + * Namespace for CaptivePortalLogin module. + * + * @hide + */ + @SystemApi + public static final String NAMESPACE_CAPTIVEPORTALLOGIN = "captive_portal_login"; + + /** + * Namespace for Tethering module. + * + * @hide + */ + @SystemApi + public static final String NAMESPACE_TETHERING = "tethering"; + + /** * Namespace for content capture feature used by on-device machine intelligence * to provide suggestions in a privacy-safe manner. * @@ -298,6 +314,14 @@ public final class DeviceConfig { public static final String NAMESPACE_NETD_NATIVE = "netd_native"; /** + * Namespace for all Android NNAPI related features. + * + * @hide + */ + @SystemApi + public static final String NAMESPACE_NNAPI_NATIVE = "nnapi_native"; + + /** * Namespace for features related to the Package Manager Service. * * @hide diff --git a/core/java/android/security/attestationverification/OWNERS b/core/java/android/security/attestationverification/OWNERS new file mode 100644 index 000000000000..80a1f44b8427 --- /dev/null +++ b/core/java/android/security/attestationverification/OWNERS @@ -0,0 +1,4 @@ +# Bug component: 1111194 + +dlm@google.com +dkrahn@google.com diff --git a/core/java/android/service/timezone/OWNERS b/core/java/android/service/timezone/OWNERS index 28aff188dbd8..b5144d17a14c 100644 --- a/core/java/android/service/timezone/OWNERS +++ b/core/java/android/service/timezone/OWNERS @@ -1,3 +1,3 @@ # Bug component: 847766 -nfuller@google.com -include /core/java/android/app/timedetector/OWNERS +# System APIs for system server time zone detection plugins. +include /services/core/java/com/android/server/timezonedetector/OWNERS diff --git a/core/java/android/telephony/PhoneStateListener.java b/core/java/android/telephony/PhoneStateListener.java index d39b56ddabed..5b9d69c2f9ff 100644 --- a/core/java/android/telephony/PhoneStateListener.java +++ b/core/java/android/telephony/PhoneStateListener.java @@ -191,20 +191,6 @@ public class PhoneStateListener { public static final int LISTEN_SIGNAL_STRENGTHS = 0x00000100; /** - * Listen for changes of the network signal strengths (cellular) always reported from modem, - * even in some situations such as the screen of the device is off. - * - * @see #onSignalStrengthsChanged - * - * @hide - * @deprecated Use TelephonyManager#setSignalStrengthUpdateRequest - * instead. - */ - @Deprecated - @RequiresPermission(android.Manifest.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH) - public static final int LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH = 0x00000200; - - /** * Listen for changes to observed cell info. * * Listening to this event requires the {@link Manifest.permission#READ_PHONE_STATE} and diff --git a/core/java/android/telephony/TelephonyCallback.java b/core/java/android/telephony/TelephonyCallback.java index dd4de0a81392..3028a6d8f97a 100644 --- a/core/java/android/telephony/TelephonyCallback.java +++ b/core/java/android/telephony/TelephonyCallback.java @@ -691,6 +691,11 @@ public class TelephonyCallback { * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the * subscription ID. Otherwise, this callback applies to * {@link SubscriptionManager#getDefaultSubscriptionId()}. + * + * The calling app should have carrier privileges + * (see {@link TelephonyManager#hasCarrierPrivileges}) if it does not have the + * {@link android.Manifest.permission#READ_PHONE_STATE}. + * */ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) void onMessageWaitingIndicatorChanged(boolean mwi); @@ -710,6 +715,11 @@ public class TelephonyCallback { * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the * subscription ID. Otherwise, this callback applies to * {@link SubscriptionManager#getDefaultSubscriptionId()}. + * + * The calling app should have carrier privileges + * (see {@link TelephonyManager#hasCarrierPrivileges}) if it does not have the + * {@link android.Manifest.permission#READ_PHONE_STATE}. + * */ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) void onCallForwardingIndicatorChanged(boolean cfi); @@ -868,6 +878,10 @@ public class TelephonyCallback { * subscription ID. Otherwise, this callback applies to * {@link SubscriptionManager#getDefaultSubscriptionId()}. * + * The calling app should have carrier privileges + * (see {@link TelephonyManager#hasCarrierPrivileges}) if it does not have the + * {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}. + * * @param callState {@link PreciseCallState} */ @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) @@ -910,6 +924,10 @@ public class TelephonyCallback { * subscription ID. Otherwise, this callback applies to * {@link SubscriptionManager#getDefaultSubscriptionId()}. * + * The calling app should have carrier privileges + * (see {@link TelephonyManager#hasCarrierPrivileges}) if it does not have the + * {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}. + * * @param imsReasonInfo {@link ImsReasonInfo} contains details on why IMS call failed. */ @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) @@ -932,9 +950,9 @@ public class TelephonyCallback { * subscription ID. Otherwise, this callback applies to * {@link SubscriptionManager#getDefaultSubscriptionId()}. * - * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE} - * or the calling app has carrier privileges - * (see {@link TelephonyManager#hasCarrierPrivileges}). + * The calling app should have carrier privileges + * (see {@link TelephonyManager#hasCarrierPrivileges}) if it does not have the + * {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}. * * @param dataConnectionState {@link PreciseDataConnectionState} */ @@ -1063,6 +1081,10 @@ public class TelephonyCallback { * given subscription ID. Otherwise, this callback applies to * {@link SubscriptionManager#getDefaultSubscriptionId()}. * + * The calling app should have carrier privileges + * (see {@link TelephonyManager#hasCarrierPrivileges}) if it does not have the + * {@link android.Manifest.permission#READ_PHONE_STATE}. + * * @param emergencyNumberList Map associating all active subscriptions on the device with * the list of emergency numbers originating from that * subscription. @@ -1157,6 +1179,11 @@ public class TelephonyCallback { * For example, it could be the current active opportunistic subscription * in use, or the subscription user selected as default data subscription in * DSDS mode. + * + * The calling app should have carrier privileges + * (see {@link TelephonyManager#hasCarrierPrivileges}) if it does not have the + * {@link android.Manifest.permission#READ_PHONE_STATE}. + * */ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) void onActiveDataSubscriptionIdChanged(int subId); @@ -1225,6 +1252,11 @@ public class TelephonyCallback { * <p>Because registration failures are ephemeral, this callback is not sticky. * Registrants will not receive the most recent past value when registering. * + * The calling app should have carrier privileges + * (see {@link TelephonyManager#hasCarrierPrivileges}) if it does not have the + * {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE} and + * {@link android.Manifest.permission#ACCESS_FINE_LOCATION}. + * * @param cellIdentity the CellIdentity, which must include the globally unique * identifier * for the cell (for example, all components of the CGI or ECGI). @@ -1308,6 +1340,10 @@ public class TelephonyCallback { * subscription ID. Otherwise, this callback applies to * {@link SubscriptionManager#getDefaultSubscriptionId()}. * + * The calling app should have carrier privileges + * (see {@link TelephonyManager#hasCarrierPrivileges}) if it does not have the + * {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}. + * * @param callAttributes the call attributes */ @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE) @@ -1324,6 +1360,11 @@ public class TelephonyCallback { * <p>Barring info is provided for all services applicable to the current camped/registered * cell, for the registered PLMN and current access class/access category. * + * The calling app should have carrier privileges + * (see {@link TelephonyManager#hasCarrierPrivileges}) if it does not have the + * {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE} and + * {@link android.Manifest.permission#ACCESS_FINE_LOCATION}. + * * @param barringInfo for all services on the current cell. * @see android.telephony.BarringInfo */ @@ -1341,6 +1382,10 @@ public class TelephonyCallback { /** * Callback invoked when the current physical channel configuration has changed * + * The calling app should have carrier privileges + * (see {@link TelephonyManager#hasCarrierPrivileges}) if it does not have the + * {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}. + * * @param configs List of the current {@link PhysicalChannelConfig}s */ @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE) @@ -1357,6 +1402,10 @@ public class TelephonyCallback { /** * Callback invoked when the data enabled changes. * + * The calling app should have carrier privileges + * (see {@link TelephonyManager#hasCarrierPrivileges}) if it does not have the + * {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}. + * * @param enabled {@code true} if data is enabled, otherwise disabled. * @param reason Reason for data enabled/disabled. * See {@link TelephonyManager.DataEnabledReason}. diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java index bedad7344e9d..cb1cff9cda22 100644 --- a/core/java/android/telephony/TelephonyRegistryManager.java +++ b/core/java/android/telephony/TelephonyRegistryManager.java @@ -1041,10 +1041,6 @@ public class TelephonyRegistryManager { eventList.add(TelephonyCallback.EVENT_SIGNAL_STRENGTHS_CHANGED); } - if ((eventMask & PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH) != 0) { - eventList.add(TelephonyCallback.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED); - } - if ((eventMask & PhoneStateListener.LISTEN_CELL_INFO) != 0) { eventList.add(TelephonyCallback.EVENT_CELL_INFO_CHANGED); } diff --git a/core/java/android/timezone/OWNERS b/core/java/android/timezone/OWNERS index 8f8089717e3b..8b5e15635a73 100644 --- a/core/java/android/timezone/OWNERS +++ b/core/java/android/timezone/OWNERS @@ -1,3 +1,5 @@ -# Bug component: 847766 -mingaleev@google.com -include /core/java/android/app/timedetector/OWNERS +# Bug component: 24949 +# APIs originally intended to provide a stable API surface to access time zone rules data for use by +# unbundled components like a telephony mainline module and the ART module. Not exposed, potentially +# deletable if callers do not unbundle. +include platform/libcore:/OWNERS diff --git a/core/java/com/android/internal/content/om/OverlayConfig.java b/core/java/com/android/internal/content/om/OverlayConfig.java index 3f3c9bdbe5f5..7c391186c839 100644 --- a/core/java/com/android/internal/content/om/OverlayConfig.java +++ b/core/java/com/android/internal/content/om/OverlayConfig.java @@ -25,17 +25,22 @@ import android.os.Trace; import android.util.ArrayMap; import android.util.Log; +import com.android.apex.ApexInfo; +import com.android.apex.XmlParser; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.content.om.OverlayConfigParser.OverlayPartition; import com.android.internal.content.om.OverlayConfigParser.ParsedConfiguration; import com.android.internal.content.om.OverlayScanner.ParsedOverlayInfo; import com.android.internal.util.Preconditions; +import com.android.internal.util.function.TriConsumer; import java.io.File; +import java.io.FileInputStream; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.Comparator; -import java.util.function.BiConsumer; +import java.util.List; import java.util.function.Supplier; /** @@ -73,7 +78,7 @@ public class OverlayConfig { public interface PackageProvider { /** Performs the given action for each package. */ - void forEachPackage(BiConsumer<ParsingPackageRead, Boolean> p); + void forEachPackage(TriConsumer<ParsingPackageRead, Boolean, File> p); } private static final Comparator<ParsedConfiguration> sStaticOverlayComparator = (c1, c2) -> { @@ -115,6 +120,8 @@ public class OverlayConfig { p))); } + ArrayMap<Integer, List<String>> activeApexesPerPartition = getActiveApexes(partitions); + boolean foundConfigFile = false; ArrayList<ParsedOverlayInfo> packageManagerOverlayInfos = null; @@ -123,7 +130,9 @@ public class OverlayConfig { final OverlayPartition partition = partitions.get(i); final OverlayScanner scanner = (scannerFactory == null) ? null : scannerFactory.get(); final ArrayList<ParsedConfiguration> partitionOverlays = - OverlayConfigParser.getConfigurations(partition, scanner); + OverlayConfigParser.getConfigurations(partition, scanner, + activeApexesPerPartition.getOrDefault(partition.type, + Collections.emptyList())); if (partitionOverlays != null) { foundConfigFile = true; overlays.addAll(partitionOverlays); @@ -145,7 +154,8 @@ public class OverlayConfig { // Filter out overlays not present in the partition. partitionOverlayInfos = new ArrayList<>(packageManagerOverlayInfos); for (int j = partitionOverlayInfos.size() - 1; j >= 0; j--) { - if (!partition.containsFile(partitionOverlayInfos.get(j).path)) { + if (!partition.containsFile(partitionOverlayInfos.get(j) + .getOriginalPartitionPath())) { partitionOverlayInfos.remove(j); } } @@ -292,16 +302,49 @@ public class OverlayConfig { private static ArrayList<ParsedOverlayInfo> getOverlayPackageInfos( @NonNull PackageProvider packageManager) { final ArrayList<ParsedOverlayInfo> overlays = new ArrayList<>(); - packageManager.forEachPackage((ParsingPackageRead p, Boolean isSystem) -> { + packageManager.forEachPackage((ParsingPackageRead p, Boolean isSystem, + @Nullable File preInstalledApexPath) -> { if (p.getOverlayTarget() != null && isSystem) { overlays.add(new ParsedOverlayInfo(p.getPackageName(), p.getOverlayTarget(), p.getTargetSdkVersion(), p.isOverlayIsStatic(), p.getOverlayPriority(), - new File(p.getBaseApkPath()))); + new File(p.getBaseApkPath()), preInstalledApexPath)); } }); return overlays; } + /** Returns a map of PartitionType to List of active APEX module names. */ + @NonNull + private static ArrayMap<Integer, List<String>> getActiveApexes( + @NonNull List<OverlayPartition> partitions) { + // An Overlay in an APEX, which is an update of an APEX in a given partition, + // is considered as belonging to that partition. + ArrayMap<Integer, List<String>> result = new ArrayMap<>(); + for (OverlayPartition partition : partitions) { + result.put(partition.type, new ArrayList<String>()); + } + // Read from apex-info-list because ApexManager is not accessible to zygote. + File apexInfoList = new File("/apex/apex-info-list.xml"); + if (apexInfoList.exists() && apexInfoList.canRead()) { + try (FileInputStream stream = new FileInputStream(apexInfoList)) { + List<ApexInfo> apexInfos = XmlParser.readApexInfoList(stream).getApexInfo(); + for (ApexInfo info : apexInfos) { + if (info.getIsActive()) { + for (OverlayPartition partition : partitions) { + if (partition.containsPath(info.getPreinstalledModulePath())) { + result.get(partition.type).add(info.getModuleName()); + break; + } + } + } + } + } catch (Exception e) { + Log.w(TAG, "Error reading apex-info-list: " + e); + } + } + return result; + } + /** Represents a single call to idmap create-multiple. */ @VisibleForTesting public static class IdmapInvocation { diff --git a/core/java/com/android/internal/content/om/OverlayConfigParser.java b/core/java/com/android/internal/content/om/OverlayConfigParser.java index a86e5950c2f6..d48c2e764625 100644 --- a/core/java/com/android/internal/content/om/OverlayConfigParser.java +++ b/core/java/com/android/internal/content/om/OverlayConfigParser.java @@ -40,6 +40,7 @@ import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; +import java.util.List; /** * Responsible for parsing configurations of Runtime Resource Overlays that control mutability, @@ -192,13 +193,19 @@ final class OverlayConfigParser { */ @Nullable static ArrayList<ParsedConfiguration> getConfigurations( - @NonNull OverlayPartition partition, @Nullable OverlayScanner scanner) { - if (partition.getOverlayFolder() == null) { - return null; + @NonNull OverlayPartition partition, @Nullable OverlayScanner scanner, + @NonNull List<String> activeApexes) { + if (scanner != null) { + if (partition.getOverlayFolder() != null) { + scanner.scanDir(partition.getOverlayFolder()); + } + for (String apex : activeApexes) { + scanner.scanDir(new File("/apex/" + apex + "/overlay/")); + } } - if (scanner != null) { - scanner.scanDir(partition.getOverlayFolder()); + if (partition.getOverlayFolder() == null) { + return null; } final File configFile = new File(partition.getOverlayFolder(), CONFIG_DEFAULT_FILENAME); diff --git a/core/java/com/android/internal/content/om/OverlayScanner.java b/core/java/com/android/internal/content/om/OverlayScanner.java index 6b5cb8d9b850..138d1ce91719 100644 --- a/core/java/com/android/internal/content/om/OverlayScanner.java +++ b/core/java/com/android/internal/content/om/OverlayScanner.java @@ -47,23 +47,38 @@ public class OverlayScanner { public final boolean isStatic; public final int priority; public final File path; + @Nullable public final File preInstalledApexPath; public ParsedOverlayInfo(String packageName, String targetPackageName, - int targetSdkVersion, boolean isStatic, int priority, File path) { + int targetSdkVersion, boolean isStatic, int priority, File path, + @Nullable File preInstalledApexPath) { this.packageName = packageName; this.targetPackageName = targetPackageName; this.targetSdkVersion = targetSdkVersion; this.isStatic = isStatic; this.priority = priority; this.path = path; + this.preInstalledApexPath = preInstalledApexPath; } @Override public String toString() { return getClass().getSimpleName() + String.format("{packageName=%s" + ", targetPackageName=%s, targetSdkVersion=%s, isStatic=%s" - + ", priority=%s, path=%s}", - packageName, targetPackageName, targetSdkVersion, isStatic, priority, path); + + ", priority=%s, path=%s, preInstalledApexPath=%s}", + packageName, targetPackageName, targetSdkVersion, isStatic, + priority, path, preInstalledApexPath); + } + + /** + * Retrieves the path of the overlay in its original installation partition. + * + * An Overlay in an APEX, which is an update of an APEX in a given partition, + * is considered as belonging to that partition. + */ + @NonNull + public File getOriginalPartitionPath() { + return preInstalledApexPath != null ? preInstalledApexPath : path; } } @@ -138,6 +153,6 @@ public class OverlayScanner { return apkLite.getTargetPackageName() == null ? null : new ParsedOverlayInfo(apkLite.getPackageName(), apkLite.getTargetPackageName(), apkLite.getTargetSdkVersion(), apkLite.isOverlayIsStatic(), - apkLite.getOverlayPriority(), new File(apkLite.getPath())); + apkLite.getOverlayPriority(), new File(apkLite.getPath()), null); } } diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 8c63f38494ea..630851d126cc 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -12143,7 +12143,7 @@ public class BatteryStatsImpl extends BatteryStats { rxTimeMs = info.getControllerRxTimeMillis(); txTimeMs = info.getControllerTxTimeMillis(); energy = info.getControllerEnergyUsed(); - if (info.getUidTraffic() != null) { + if (!info.getUidTraffic().isEmpty()) { for (UidTraffic traffic : info.getUidTraffic()) { uidRxBytes.put(traffic.getUid(), traffic.getRxBytes()); uidTxBytes.put(traffic.getUid(), traffic.getTxBytes()); @@ -12294,10 +12294,10 @@ public class BatteryStatsImpl extends BatteryStats { long totalTxBytes = 0; long totalRxBytes = 0; - final UidTraffic[] uidTraffic = info.getUidTraffic(); - final int numUids = uidTraffic != null ? uidTraffic.length : 0; + final List<UidTraffic> uidTraffic = info.getUidTraffic(); + final int numUids = uidTraffic.size(); for (int i = 0; i < numUids; i++) { - final UidTraffic traffic = uidTraffic[i]; + final UidTraffic traffic = uidTraffic.get(i); final long rxBytes = traffic.getRxBytes() - mLastBluetoothActivityInfo.uidRxBytes.get( traffic.getUid()); final long txBytes = traffic.getTxBytes() - mLastBluetoothActivityInfo.uidTxBytes.get( @@ -12320,7 +12320,7 @@ public class BatteryStatsImpl extends BatteryStats { if ((totalTxBytes != 0 || totalRxBytes != 0) && (leftOverRxTimeMs != 0 || leftOverTxTimeMs != 0)) { for (int i = 0; i < numUids; i++) { - final UidTraffic traffic = uidTraffic[i]; + final UidTraffic traffic = uidTraffic.get(i); final int uid = traffic.getUid(); final long rxBytes = traffic.getRxBytes() - mLastBluetoothActivityInfo.uidRxBytes.get(uid); diff --git a/core/java/com/android/internal/os/ClassLoaderFactory.java b/core/java/com/android/internal/os/ClassLoaderFactory.java index d347f2e21dd2..8b0411de5477 100644 --- a/core/java/com/android/internal/os/ClassLoaderFactory.java +++ b/core/java/com/android/internal/os/ClassLoaderFactory.java @@ -80,15 +80,20 @@ public class ClassLoaderFactory { */ public static ClassLoader createClassLoader(String dexPath, String librarySearchPath, ClassLoader parent, String classloaderName, - List<ClassLoader> sharedLibraries) { + List<ClassLoader> sharedLibraries, List<ClassLoader> sharedLibrariesLoadedAfter) { ClassLoader[] arrayOfSharedLibraries = (sharedLibraries == null) ? null : sharedLibraries.toArray(new ClassLoader[sharedLibraries.size()]); + ClassLoader[] arrayOfSharedLibrariesLoadedAfterApp = (sharedLibrariesLoadedAfter == null) + ? null + : sharedLibrariesLoadedAfter.toArray( + new ClassLoader[sharedLibrariesLoadedAfter.size()]); if (isPathClassLoaderName(classloaderName)) { - return new PathClassLoader(dexPath, librarySearchPath, parent, arrayOfSharedLibraries); + return new PathClassLoader(dexPath, librarySearchPath, parent, arrayOfSharedLibraries, + arrayOfSharedLibrariesLoadedAfterApp); } else if (isDelegateLastClassLoaderName(classloaderName)) { return new DelegateLastClassLoader(dexPath, librarySearchPath, parent, - arrayOfSharedLibraries); + arrayOfSharedLibraries, arrayOfSharedLibrariesLoadedAfterApp); } throw new AssertionError("Invalid classLoaderName: " + classloaderName); @@ -102,20 +107,20 @@ public class ClassLoaderFactory { String librarySearchPath, String libraryPermittedPath, ClassLoader parent, int targetSdkVersion, boolean isNamespaceShared, String classLoaderName) { return createClassLoader(dexPath, librarySearchPath, libraryPermittedPath, - parent, targetSdkVersion, isNamespaceShared, classLoaderName, null, null); + parent, targetSdkVersion, isNamespaceShared, classLoaderName, null, null, null); } - /** * Create a ClassLoader and initialize a linker-namespace for it. */ public static ClassLoader createClassLoader(String dexPath, String librarySearchPath, String libraryPermittedPath, ClassLoader parent, int targetSdkVersion, boolean isNamespaceShared, String classLoaderName, - List<ClassLoader> sharedLibraries, List<String> nativeSharedLibraries) { + List<ClassLoader> sharedLibraries, List<String> nativeSharedLibraries, + List<ClassLoader> sharedLibrariesAfter) { final ClassLoader classLoader = createClassLoader(dexPath, librarySearchPath, parent, - classLoaderName, sharedLibraries); + classLoaderName, sharedLibraries, sharedLibrariesAfter); String sonameList = ""; if (nativeSharedLibraries != null) { diff --git a/core/java/com/android/internal/os/SomeArgs.java b/core/java/com/android/internal/os/SomeArgs.java index 5ec882cee3c8..475caa5dc85c 100644 --- a/core/java/com/android/internal/os/SomeArgs.java +++ b/core/java/com/android/internal/os/SomeArgs.java @@ -63,6 +63,8 @@ public final class SomeArgs { public int argi4; public int argi5; public int argi6; + public long argl1; + public long argl2; private SomeArgs() { /* do nothing - reduce visibility */ @@ -129,5 +131,7 @@ public final class SomeArgs { argi4 = 0; argi5 = 0; argi6 = 0; + argl1 = 0; + argl2 = 0; } } diff --git a/core/jni/android_os_Parcel.cpp b/core/jni/android_os_Parcel.cpp index 42ff39535567..0d530f6aa2bb 100644 --- a/core/jni/android_os_Parcel.cpp +++ b/core/jni/android_os_Parcel.cpp @@ -604,6 +604,25 @@ static jint android_os_Parcel_compareData(JNIEnv* env, jclass clazz, jlong thisN return thisParcel->compareData(*otherParcel); } +static jboolean android_os_Parcel_compareDataInRange(JNIEnv* env, jclass clazz, jlong thisNativePtr, + jint thisOffset, jlong otherNativePtr, + jint otherOffset, jint length) { + Parcel* thisParcel = reinterpret_cast<Parcel*>(thisNativePtr); + LOG_ALWAYS_FATAL_IF(thisParcel == nullptr, "Should not be null"); + + Parcel* otherParcel = reinterpret_cast<Parcel*>(otherNativePtr); + LOG_ALWAYS_FATAL_IF(otherParcel == nullptr, "Should not be null"); + + int result; + status_t err = + thisParcel->compareDataInRange(thisOffset, *otherParcel, otherOffset, length, &result); + if (err != NO_ERROR) { + signalExceptionForError(env, clazz, err); + return JNI_FALSE; + } + return (result == 0) ? JNI_TRUE : JNI_FALSE; +} + static void android_os_Parcel_appendFrom(JNIEnv* env, jclass clazz, jlong thisNativePtr, jlong otherNativePtr, jint offset, jint length) { @@ -635,6 +654,22 @@ static jboolean android_os_Parcel_hasFileDescriptors(jlong nativePtr) return ret; } +static jboolean android_os_Parcel_hasFileDescriptorsInRange(JNIEnv* env, jclass clazz, + jlong nativePtr, jint offset, + jint length) { + Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr); + if (parcel != NULL) { + bool result; + status_t err = parcel->hasFileDescriptorsInRange(offset, length, &result); + if (err != NO_ERROR) { + signalExceptionForError(env, clazz, err); + return JNI_FALSE; + } + return result ? JNI_TRUE : JNI_FALSE; + } + return JNI_FALSE; +} + // String tries to allocate itself on the stack, within a known size, but will // make a heap allocation if not. template <size_t StackReserve> @@ -724,11 +759,11 @@ static jlong android_os_Parcel_getGlobalAllocCount(JNIEnv* env, jclass clazz) return Parcel::getGlobalAllocCount(); } -static jlong android_os_Parcel_getBlobAshmemSize(jlong nativePtr) +static jlong android_os_Parcel_getOpenAshmemSize(jlong nativePtr) { Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr); if (parcel != NULL) { - return parcel->getBlobAshmemSize(); + return parcel->getOpenAshmemSize(); } return 0; } @@ -825,9 +860,11 @@ static const JNINativeMethod gParcelMethods[] = { {"nativeMarshall", "(J)[B", (void*)android_os_Parcel_marshall}, {"nativeUnmarshall", "(J[BII)V", (void*)android_os_Parcel_unmarshall}, {"nativeCompareData", "(JJ)I", (void*)android_os_Parcel_compareData}, + {"nativeCompareDataInRange", "(JIJII)Z", (void*)android_os_Parcel_compareDataInRange}, {"nativeAppendFrom", "(JJII)V", (void*)android_os_Parcel_appendFrom}, // @CriticalNative {"nativeHasFileDescriptors", "(J)Z", (void*)android_os_Parcel_hasFileDescriptors}, + {"nativeHasFileDescriptorsInRange", "(JII)Z", (void*)android_os_Parcel_hasFileDescriptorsInRange}, {"nativeWriteInterfaceToken", "(JLjava/lang/String;)V", (void*)android_os_Parcel_writeInterfaceToken}, {"nativeEnforceInterface", "(JLjava/lang/String;)V", (void*)android_os_Parcel_enforceInterface}, @@ -835,7 +872,7 @@ static const JNINativeMethod gParcelMethods[] = { {"getGlobalAllocCount", "()J", (void*)android_os_Parcel_getGlobalAllocCount}, // @CriticalNative - {"nativeGetBlobAshmemSize", "(J)J", (void*)android_os_Parcel_getBlobAshmemSize}, + {"nativeGetOpenAshmemSize", "(J)J", (void*)android_os_Parcel_getOpenAshmemSize}, // @CriticalNative {"nativeReadCallingWorkSourceUid", "(J)I", (void*)android_os_Parcel_readCallingWorkSourceUid}, diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp index 793b4eba788c..61b91ddaa2e7 100644 --- a/core/jni/android_util_Binder.cpp +++ b/core/jni/android_util_Binder.cpp @@ -959,8 +959,7 @@ static jint android_os_Binder_getCallingUid() return IPCThreadState::self()->getCallingUid(); } -static jboolean android_os_Binder_isHandlingTransaction() -{ +static jboolean android_os_Binder_isDirectlyHandlingTransaction() { return getCurrentServingCall() == BinderCallType::BINDER; } @@ -1056,6 +1055,7 @@ static void android_os_Binder_setExtension(JNIEnv* env, jobject obj, jobject ext // ---------------------------------------------------------------------------- +// clang-format off static const JNINativeMethod gBinderMethods[] = { /* name, signature, funcPtr */ // @CriticalNative @@ -1063,7 +1063,7 @@ static const JNINativeMethod gBinderMethods[] = { // @CriticalNative { "getCallingUid", "()I", (void*)android_os_Binder_getCallingUid }, // @CriticalNative - { "isHandlingTransaction", "()Z", (void*)android_os_Binder_isHandlingTransaction }, + { "isDirectlyHandlingTransaction", "()Z", (void*)android_os_Binder_isDirectlyHandlingTransaction }, // @CriticalNative { "clearCallingIdentity", "()J", (void*)android_os_Binder_clearCallingIdentity }, // @CriticalNative @@ -1088,6 +1088,7 @@ static const JNINativeMethod gBinderMethods[] = { { "getExtension", "()Landroid/os/IBinder;", (void*)android_os_Binder_getExtension }, { "setExtension", "(Landroid/os/IBinder;)V", (void*)android_os_Binder_setExtension }, }; +// clang-format on const char* const kBinderPathName = "android/os/Binder"; diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp index 6f5cc5314d0b..40f6e4f63cd7 100644 --- a/core/jni/fd_utils.cpp +++ b/core/jni/fd_utils.cpp @@ -138,6 +138,14 @@ bool FileDescriptorAllowlist::IsAllowed(const std::string& path) const { return true; } + // Allow Runtime Resource Overlays inside APEXes. + static const char* kOverlayPathSuffix = "/overlay"; + if (android::base::StartsWith(path, kApexPrefix) && + android::base::EndsWith(android::base::Dirname(path), kOverlayPathSuffix) && + android::base::EndsWith(path, kApkSuffix) && path.find("/../") == std::string::npos) { + return true; + } + static const char* kOverlayIdmapPrefix = "/data/resource-cache/"; static const char* kOverlayIdmapSuffix = ".apk@idmap"; if (android::base::StartsWith(path, kOverlayIdmapPrefix) && diff --git a/core/proto/OWNERS b/core/proto/OWNERS index 44ea23fdf685..78650ed34813 100644 --- a/core/proto/OWNERS +++ b/core/proto/OWNERS @@ -8,9 +8,6 @@ yaochen@google.com yro@google.com zhouwenjie@google.com -# Settings UI -per-file settings_enums.proto=tmfang@google.com - # Frameworks ogunwale@google.com jjaggi@google.com diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto index fa1e9d4afcdf..a62ddd084aab 100644 --- a/core/proto/android/server/windowmanagerservice.proto +++ b/core/proto/android/server/windowmanagerservice.proto @@ -351,6 +351,7 @@ message ActivityRecordProto { optional bool translucent = 30; optional bool pip_auto_enter_enabled = 31; optional bool in_size_compat_mode = 32; + optional float min_aspect_ratio = 33; } /* represents WindowToken */ diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index bd89578f4208..d727a55615f2 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -252,6 +252,11 @@ android:name="com.android.bluetooth.BluetoothMapContentObserver.action.MESSAGE_DELIVERY" /> <protected-broadcast android:name="android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED" /> + <protected-broadcast android:name="android.bluetooth.action.LE_AUDIO_CONNECTION_STATE_CHANGED" /> + <protected-broadcast android:name="android.bluetooth.action.LE_AUDIO_ACTIVE_DEVICE_CHANGED" /> + <protected-broadcast android:name="android.bluetooth.action.LE_AUDIO_CONF_CHANGED" /> + <protected-broadcast android:name="android.bluetooth.action.LE_AUDIO_GROUP_NODE_STATUS_CHANGED" /> + <protected-broadcast android:name="android.bluetooth.action.LE_AUDIO_GROUP_STATUS_CHANGED" /> <protected-broadcast android:name="android.bluetooth.action.TETHERING_STATE_CHANGED" /> <protected-broadcast android:name="android.bluetooth.pbap.profile.action.CONNECTION_STATE_CHANGED" /> @@ -1976,6 +1981,14 @@ android:label="@string/permlab_uwb_ranging" android:protectionLevel="dangerous" /> + <!-- Required to be able to advertise and connect to nearby devices via Wi-Fi. + <p>Protection level: dangerous --> + <permission android:name="android.permission.NEARBY_WIFI_DEVICES" + android:permissionGroup="android.permission-group.UNDEFINED" + android:description="@string/permdesc_nearby_wifi_devices" + android:label="@string/permlab_nearby_wifi_devices" + android:protectionLevel="dangerous" /> + <!-- @SystemApi @TestApi Allows an application to suspend other apps, which will prevent the user from using them until they are unsuspended. @hide @@ -2386,7 +2399,7 @@ <permission android:name="android.permission.READ_ACTIVE_EMERGENCY_SESSION" android:protectionLevel="signature" /> - <!-- Allows listen permission to always reported signal strength. + <!-- Allows listen permission to always reported system signal strength. @hide Used internally. --> <permission android:name="android.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH" android:protectionLevel="signature" /> diff --git a/core/res/OWNERS b/core/res/OWNERS index 684202bdb29e..165dcad896c9 100644 --- a/core/res/OWNERS +++ b/core/res/OWNERS @@ -28,3 +28,6 @@ yamasani@google.com # Multiuser per-file res/xml/config_user_types.xml = file:/MULTIUSER_OWNERS + +# Car +per-file res/values/dimens_car.xml = file:/platform/packages/services/Car:/OWNERS
\ No newline at end of file diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index aa05b13984ec..8496a478af97 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -5047,6 +5047,14 @@ to 0, the seconds hand will be disabled. --> <integer name="config_defaultAnalogClockSecondsHandFps">1</integer> + <!-- List of shared library packages that should be loaded by the classloader after the + code and resources provided by applications. This value will be set by the manufacturer --> + <string-array name="config_sharedLibrariesLoadedAfterApp" translatable="false"> + </string-array> + <!-- the number of the max cached processes in the system. --> <integer name="config_customizedMaxCachedProcesses">32</integer> + + <!-- Whether this device should support taking app snapshots on closure --> + <bool name="config_disableTaskSnapshots">false</bool> </resources> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index a99a22009e3b..a350d14d92ab 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -1488,6 +1488,11 @@ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=120]--> <string name="permdesc_uwb_ranging">Allow the app to determine relative position between nearby Ultra-Wideband devices</string> + <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=50]--> + <string name="permlab_nearby_wifi_devices">interact with nearby Wi\u2011Fi devices</string> + <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=120]--> + <string name="permdesc_nearby_wifi_devices">Allows the app to advertise, connect, and determine the relative position of nearby Wi\u2011Fi devices</string> + <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> <string name="permlab_preferredPaymentInfo">Preferred NFC Payment Service Information</string> <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 092be40c499e..d06dafe9b3e7 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -4403,7 +4403,7 @@ <java-symbol type="string" name="view_and_control_notification_title" /> <java-symbol type="string" name="view_and_control_notification_content" /> <java-symbol type="array" name="config_accessibility_allowed_install_source" /> - + <!-- Translation --> <java-symbol type="string" name="ui_translation_accessibility_translated_text" /> <java-symbol type="string" name="ui_translation_accessibility_translation_finished" /> @@ -4425,5 +4425,12 @@ <java-symbol type="bool" name="config_volumeShowRemoteSessions" /> + <!-- List of shared library packages that should be loaded by the classloader after the + code and resources provided by applications. --> + <java-symbol type="array" name="config_sharedLibrariesLoadedAfterApp" /> + <java-symbol type="integer" name="config_customizedMaxCachedProcesses" /> + + <java-symbol type="bool" name="config_disableTaskSnapshots" /> + </resources> diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml index f1c66c5891f2..4c20ae1b099c 100644 --- a/core/res/res/xml/sms_short_codes.xml +++ b/core/res/res/xml/sms_short_codes.xml @@ -105,6 +105,9 @@ http://www.tja.ee/public/documents/Elektrooniline_side/Oigusaktid/ENG/Estonian_Numbering_Plan_annex_06_09_2010.mht --> <shortcode country="ee" pattern="1\\d{2,4}" premium="90\\d{5}|15330|1701[0-3]" free="116\\d{3}|95034" /> + <!-- Egypt: 4 digits, known codes listed --> + <shortcode country="eg" pattern="\\d{4}" free="1499" /> + <!-- Spain: 5-6 digits: 25xxx, 27xxx, 280xx, 35xxx, 37xxx, 795xxx, 797xxx, 995xxx, 997xxx, plus EU. http://www.legallink.es/?q=en/content/which-current-regulatory-status-premium-rate-services-spain --> <shortcode country="es" premium="[23][57]\\d{3}|280\\d{2}|[79]9[57]\\d{3}" free="116\\d{3}|22791|222145|22189" /> @@ -196,7 +199,7 @@ <shortcode country="nl" pattern="\\d{4}" premium="4466|5040" free="116\\d{3}|2223|6225|2223|1662" /> <!-- Nigeria --> - <shortcode country="ng" pattern="\\d{1,5}" free="2441|55019" /> + <shortcode country="ng" pattern="\\d{1,5}" free="2441|55020" /> <!-- Norway: 4-5 digits (not confirmed), known premium codes listed --> <shortcode country="no" pattern="\\d{4,5}" premium="2201|222[67]" free="2171" /> diff --git a/core/tests/bluetoothtests/Android.bp b/core/tests/bluetoothtests/Android.bp index a2e4dff8f826..68416dd65466 100644 --- a/core/tests/bluetoothtests/Android.bp +++ b/core/tests/bluetoothtests/Android.bp @@ -15,7 +15,10 @@ android_test { "android.test.runner", "android.test.base", ], - static_libs: ["junit"], + static_libs: [ + "junit", + "modules-utils-bytesmatcher", + ], platform_apis: true, certificate: "platform", } diff --git a/core/tests/bluetoothtests/src/android/bluetooth/le/ScanRecordTest.java b/core/tests/bluetoothtests/src/android/bluetooth/le/ScanRecordTest.java index c287ea9d8567..4e817d4a0d91 100644 --- a/core/tests/bluetoothtests/src/android/bluetooth/le/ScanRecordTest.java +++ b/core/tests/bluetoothtests/src/android/bluetooth/le/ScanRecordTest.java @@ -16,11 +16,11 @@ package android.bluetooth.le; -import android.os.BytesMatcher; import android.os.ParcelUuid; import android.test.suitebuilder.annotation.SmallTest; import com.android.internal.util.HexDump; +import com.android.modules.utils.BytesMatcher; import junit.framework.TestCase; diff --git a/core/tests/companiontests/Android.bp b/core/tests/companiontests/Android.bp new file mode 100644 index 000000000000..d31b8f470108 --- /dev/null +++ b/core/tests/companiontests/Android.bp @@ -0,0 +1,21 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + +android_test { + name: "CompanionTests", + // Include all test java files. + srcs: ["src/**/*.java"], + libs: [ + "android.test.runner", + "android.test.base", + ], + static_libs: ["junit"], + platform_apis: true, + certificate: "platform", +} diff --git a/core/tests/companiontests/AndroidManifest.xml b/core/tests/companiontests/AndroidManifest.xml new file mode 100644 index 000000000000..f436d972a1d9 --- /dev/null +++ b/core/tests/companiontests/AndroidManifest.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2011 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. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.companion.tests" + android:sharedUserId="android.uid.system" > + + <application > + <uses-library android:name="android.test.runner" /> + </application> + <instrumentation android:name="android.companion.CompanionTestRunner" + android:targetPackage="com.android.companion.tests" + android:label="Companion Tests" /> + +</manifest> diff --git a/core/tests/companiontests/src/android/companion/BluetoothDeviceFilterUtilsTest.java b/core/tests/companiontests/src/android/companion/BluetoothDeviceFilterUtilsTest.java new file mode 100644 index 000000000000..1ddbbd8a4634 --- /dev/null +++ b/core/tests/companiontests/src/android/companion/BluetoothDeviceFilterUtilsTest.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2010 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.companion; + +import android.os.ParcelUuid; +import android.test.InstrumentationTestCase; + +public class BluetoothDeviceFilterUtilsTest extends InstrumentationTestCase { + private static final String TAG = "BluetoothDeviceFilterUtilsTest"; + + private final ParcelUuid mServiceUuid = + ParcelUuid.fromString("F0FFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF"); + private final ParcelUuid mNonMatchingDeviceUuid = + ParcelUuid.fromString("FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF"); + private final ParcelUuid mMatchingDeviceUuid = + ParcelUuid.fromString("F0FFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF"); + private final ParcelUuid mMaskUuid = + ParcelUuid.fromString("FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF"); + private final ParcelUuid mMatchingMaskUuid = + ParcelUuid.fromString("F0FFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF"); + + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + public void testUuidsMaskedEquals() { + assertFalse(BluetoothDeviceFilterUtils.uuidsMaskedEquals( + mNonMatchingDeviceUuid.getUuid(), + mServiceUuid.getUuid(), + mMaskUuid.getUuid())); + + assertTrue(BluetoothDeviceFilterUtils.uuidsMaskedEquals( + mMatchingDeviceUuid.getUuid(), + mServiceUuid.getUuid(), + mMaskUuid.getUuid())); + + assertTrue(BluetoothDeviceFilterUtils.uuidsMaskedEquals( + mNonMatchingDeviceUuid.getUuid(), + mServiceUuid.getUuid(), + mMatchingMaskUuid.getUuid())); + } +} diff --git a/core/tests/companiontests/src/android/companion/CompanionTestRunner.java b/core/tests/companiontests/src/android/companion/CompanionTestRunner.java new file mode 100644 index 000000000000..caa2c685accc --- /dev/null +++ b/core/tests/companiontests/src/android/companion/CompanionTestRunner.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2010 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.companion; + +import android.os.Bundle; +import android.test.InstrumentationTestRunner; +import android.test.InstrumentationTestSuite; + +import junit.framework.TestSuite; + + +/** + * Instrumentation test runner for Companion tests. + */ +public class CompanionTestRunner extends InstrumentationTestRunner { + private static final String TAG = "CompanionTestRunner"; + + @Override + public TestSuite getAllTests() { + TestSuite suite = new InstrumentationTestSuite(this); + suite.addTestSuite(BluetoothDeviceFilterUtilsTest.class); + return suite; + } + + @Override + public ClassLoader getLoader() { + return CompanionTestRunner.class.getClassLoader(); + } + + @Override + public void onCreate(Bundle arguments) { + super.onCreate(arguments); + } +} diff --git a/core/tests/coretests/src/android/app/time/OWNERS b/core/tests/coretests/src/android/app/time/OWNERS index 8f8089717e3b..292cb72f2dbe 100644 --- a/core/tests/coretests/src/android/app/time/OWNERS +++ b/core/tests/coretests/src/android/app/time/OWNERS @@ -1,3 +1,2 @@ # Bug component: 847766 -mingaleev@google.com -include /core/java/android/app/timedetector/OWNERS +include /core/java/android/app/time/OWNERS diff --git a/core/tests/coretests/src/android/app/timedetector/OWNERS b/core/tests/coretests/src/android/app/timedetector/OWNERS index 8f8089717e3b..c6124734bc5c 100644 --- a/core/tests/coretests/src/android/app/timedetector/OWNERS +++ b/core/tests/coretests/src/android/app/timedetector/OWNERS @@ -1,3 +1,2 @@ # Bug component: 847766 -mingaleev@google.com include /core/java/android/app/timedetector/OWNERS diff --git a/core/tests/coretests/src/android/app/timezone/OWNERS b/core/tests/coretests/src/android/app/timezone/OWNERS index 8f8089717e3b..381ecf1abda5 100644 --- a/core/tests/coretests/src/android/app/timezone/OWNERS +++ b/core/tests/coretests/src/android/app/timezone/OWNERS @@ -1,3 +1,2 @@ -# Bug component: 847766 -mingaleev@google.com -include /core/java/android/app/timedetector/OWNERS +# Bug component: 24949 +include /core/java/android/app/timezone/OWNERS diff --git a/core/tests/coretests/src/android/app/timezonedetector/OWNERS b/core/tests/coretests/src/android/app/timezonedetector/OWNERS index 8f8089717e3b..2e9c3246e4fc 100644 --- a/core/tests/coretests/src/android/app/timezonedetector/OWNERS +++ b/core/tests/coretests/src/android/app/timezonedetector/OWNERS @@ -1,3 +1,2 @@ # Bug component: 847766 -mingaleev@google.com -include /core/java/android/app/timedetector/OWNERS +include /core/java/android/app/timezonedetector/OWNERS diff --git a/core/tests/coretests/src/android/net/OWNERS b/core/tests/coretests/src/android/net/OWNERS index aa87958f1d53..4e5136f93b94 100644 --- a/core/tests/coretests/src/android/net/OWNERS +++ b/core/tests/coretests/src/android/net/OWNERS @@ -1 +1,3 @@ include /services/core/java/com/android/server/net/OWNERS + +per-file SntpClient* = file:/services/core/java/com/android/server/timedetector/OWNERS diff --git a/core/tests/coretests/src/android/net/SntpClientTest.java b/core/tests/coretests/src/android/net/SntpClientTest.java index bf9978c2c447..b400b9bf41dd 100644 --- a/core/tests/coretests/src/android/net/SntpClientTest.java +++ b/core/tests/coretests/src/android/net/SntpClientTest.java @@ -22,7 +22,10 @@ import static junit.framework.Assert.assertTrue; import static org.mockito.Mockito.CALLS_REAL_METHODS; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import android.net.sntp.Duration64; +import android.net.sntp.Timestamp64; import android.util.Log; import androidx.test.runner.AndroidJUnit4; @@ -38,7 +41,13 @@ import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketException; +import java.time.Duration; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneOffset; import java.util.Arrays; +import java.util.Random; +import java.util.function.Supplier; @RunWith(AndroidJUnit4.class) public class SntpClientTest { @@ -54,41 +63,232 @@ public class SntpClientTest { // // Server, Leap indicator: (0), Stratum 2 (secondary reference), poll 6 (64s), precision -20 // Root Delay: 0.005447, Root dispersion: 0.002716, Reference-ID: 221.253.71.41 - // Reference Timestamp: 3653932102.507969856 (2015/10/15 14:08:22) - // Originator Timestamp: 3653932113.576327741 (2015/10/15 14:08:33) - // Receive Timestamp: 3653932113.581012725 (2015/10/15 14:08:33) - // Transmit Timestamp: 3653932113.581012725 (2015/10/15 14:08:33) + // Reference Timestamp: + // d9ca9446.820a5000 / ERA0: 2015-10-15 21:08:22 UTC / ERA1: 2151-11-22 03:36:38 UTC + // Originator Timestamp: + // d9ca9451.938a3771 / ERA0: 2015-10-15 21:08:33 UTC / ERA1: 2151-11-22 03:36:49 UTC + // Receive Timestamp: + // d9ca9451.94bd3fff / ERA0: 2015-10-15 21:08:33 UTC / ERA1: 2151-11-22 03:36:49 UTC + // Transmit Timestamp: + // d9ca9451.94bd4001 / ERA0: 2015-10-15 21:08:33 UTC / ERA1: 2151-11-22 03:36:49 UTC + // // Originator - Receive Timestamp: +0.004684958 // Originator - Transmit Timestamp: +0.004684958 - private static final String WORKING_VERSION4 = - "240206ec" + - "00000165" + - "000000b2" + - "ddfd4729" + - "d9ca9446820a5000" + - "d9ca9451938a3771" + - "d9ca945194bd3fff" + - "d9ca945194bd4001"; + private static final String LATE_ERA_RESPONSE = + "240206ec" + + "00000165" + + "000000b2" + + "ddfd4729" + + "d9ca9446820a5000" + + "d9ca9451938a3771" + + "d9ca945194bd3fff" + + "d9ca945194bd4001"; + + /** This is the actual UTC time in the server if it is in ERA0 */ + private static final Instant LATE_ERA0_SERVER_TIME = + calculateIdealServerTime("d9ca9451.94bd3fff", "d9ca9451.94bd4001", 0); + + /** + * This is the Unix epoch time matches the originate timestamp from {@link #LATE_ERA_RESPONSE} + * when interpreted as an ERA0 timestamp. + */ + private static final Instant LATE_ERA0_REQUEST_TIME = + Timestamp64.fromString("d9ca9451.938a3771").toInstant(0); + + // A tweaked version of the ERA0 response to represent an ERA 1 response. + // + // Server, Leap indicator: (0), Stratum 2 (secondary reference), poll 6 (64s), precision -20 + // Root Delay: 0.005447, Root dispersion: 0.002716, Reference-ID: 221.253.71.41 + // Reference Timestamp: + // 1db2d246.820a5000 / ERA0: 1915-10-16 21:08:22 UTC / ERA1: 2051-11-22 03:36:38 UTC + // Originate Timestamp: + // 1db2d251.938a3771 / ERA0: 1915-10-16 21:08:33 UTC / ERA1: 2051-11-22 03:36:49 UTC + // Receive Timestamp: + // 1db2d251.94bd3fff / ERA0: 1915-10-16 21:08:33 UTC / ERA1: 2051-11-22 03:36:49 UTC + // Transmit Timestamp: + // 1db2d251.94bd4001 / ERA0: 1915-10-16 21:08:33 UTC / ERA1: 2051-11-22 03:36:49 UTC + // + // Originate - Receive Timestamp: +0.004684958 + // Originate - Transmit Timestamp: +0.004684958 + private static final String EARLY_ERA_RESPONSE = + "240206ec" + + "00000165" + + "000000b2" + + "ddfd4729" + + "1db2d246820a5000" + + "1db2d251938a3771" + + "1db2d25194bd3fff" + + "1db2d25194bd4001"; + + /** This is the actual UTC time in the server if it is in ERA0 */ + private static final Instant EARLY_ERA1_SERVER_TIME = + calculateIdealServerTime("1db2d251.94bd3fff", "1db2d251.94bd4001", 1); + + /** + * This is the Unix epoch time matches the originate timestamp from {@link #EARLY_ERA_RESPONSE} + * when interpreted as an ERA1 timestamp. + */ + private static final Instant EARLY_ERA1_REQUEST_TIME = + Timestamp64.fromString("1db2d251.938a3771").toInstant(1); private SntpTestServer mServer; private SntpClient mClient; private Network mNetwork; + private Supplier<Instant> mSystemTimeSupplier; + private Random mRandom; + @SuppressWarnings("unchecked") @Before public void setUp() throws Exception { + mServer = new SntpTestServer(); + // A mock network has NETID_UNSET, which allows the test to run, with a loopback server, // even w/o external networking. mNetwork = mock(Network.class, CALLS_REAL_METHODS); - mServer = new SntpTestServer(); - mClient = new SntpClient(); + mRandom = mock(Random.class); + + mSystemTimeSupplier = mock(Supplier.class); + // Returning zero means the "randomized" bottom bits of the clients transmit timestamp / + // server's originate timestamp will be zeros. + when(mRandom.nextInt()).thenReturn(0); + mClient = new SntpClient(mSystemTimeSupplier, mRandom); + } + + /** Tests when the client and server are in ERA0. b/199481251. */ + @Test + public void testRequestTime_era0ClientEra0RServer() throws Exception { + when(mSystemTimeSupplier.get()).thenReturn(LATE_ERA0_REQUEST_TIME); + + mServer.setServerReply(HexEncoding.decode(LATE_ERA_RESPONSE.toCharArray(), false)); + assertTrue(mClient.requestTime(mServer.getAddress(), mServer.getPort(), 500, mNetwork)); + assertEquals(1, mServer.numRequestsReceived()); + assertEquals(1, mServer.numRepliesSent()); + + checkRequestTimeCalcs(LATE_ERA0_REQUEST_TIME, LATE_ERA0_SERVER_TIME, mClient); } + /** Tests when the client is behind the server and in the previous ERA. b/199481251. */ @Test - public void testBasicWorkingSntpClientQuery() throws Exception { - mServer.setServerReply(HexEncoding.decode(WORKING_VERSION4.toCharArray(), false)); + public void testRequestTime_era0ClientEra1Server() throws Exception { + when(mSystemTimeSupplier.get()).thenReturn(LATE_ERA0_REQUEST_TIME); + + mServer.setServerReply(HexEncoding.decode(EARLY_ERA_RESPONSE.toCharArray(), false)); assertTrue(mClient.requestTime(mServer.getAddress(), mServer.getPort(), 500, mNetwork)); assertEquals(1, mServer.numRequestsReceived()); assertEquals(1, mServer.numRepliesSent()); + + checkRequestTimeCalcs(LATE_ERA0_REQUEST_TIME, EARLY_ERA1_SERVER_TIME, mClient); + + } + + /** Tests when the client is ahead of the server and in the next ERA. b/199481251. */ + @Test + public void testRequestTime_era1ClientEra0Server() throws Exception { + when(mSystemTimeSupplier.get()).thenReturn(EARLY_ERA1_REQUEST_TIME); + + mServer.setServerReply(HexEncoding.decode(LATE_ERA_RESPONSE.toCharArray(), false)); + assertTrue(mClient.requestTime(mServer.getAddress(), mServer.getPort(), 500, mNetwork)); + assertEquals(1, mServer.numRequestsReceived()); + assertEquals(1, mServer.numRepliesSent()); + + checkRequestTimeCalcs(EARLY_ERA1_REQUEST_TIME, LATE_ERA0_SERVER_TIME, mClient); + } + + /** Tests when the client and server are in ERA1. b/199481251. */ + @Test + public void testRequestTime_era1ClientEra1Server() throws Exception { + when(mSystemTimeSupplier.get()).thenReturn(EARLY_ERA1_REQUEST_TIME); + + mServer.setServerReply(HexEncoding.decode(EARLY_ERA_RESPONSE.toCharArray(), false)); + assertTrue(mClient.requestTime(mServer.getAddress(), mServer.getPort(), 500, mNetwork)); + assertEquals(1, mServer.numRequestsReceived()); + assertEquals(1, mServer.numRepliesSent()); + + checkRequestTimeCalcs(EARLY_ERA1_REQUEST_TIME, EARLY_ERA1_SERVER_TIME, mClient); + } + + private static void checkRequestTimeCalcs( + Instant clientTime, Instant serverTime, SntpClient client) { + // The tests don't attempt to control the elapsed time tracking, which influences the + // round trip time (i.e. time spent in due to the network), but they control everything + // else, so assertions are allowed some slop and round trip time just has to be >= 0. + assertTrue("getRoundTripTime()=" + client.getRoundTripTime(), + client.getRoundTripTime() >= 0); + + // Calculate the ideal offset if nothing took any time. + long expectedOffset = serverTime.toEpochMilli() - clientTime.toEpochMilli(); + long allowedSlop = (client.getRoundTripTime() / 2) + 1; // +1 to allow for truncation loss. + assertNearlyEquals(expectedOffset, client.getClockOffset(), allowedSlop); + assertNearlyEquals(clientTime.toEpochMilli() + expectedOffset, + client.getNtpTime(), allowedSlop); + } + + /** + * Unit tests for the low-level offset calculations. More targeted / easier to write than the + * end-to-end tests above that simulate the server. b/199481251. + */ + @Test + public void testCalculateClockOffset() { + Instant era0Time1 = utcInstant(2021, 10, 5, 2, 2, 2, 2); + // Confirm what happens when the client and server are completely in sync. + checkCalculateClockOffset(era0Time1, era0Time1); + + Instant era0Time2 = utcInstant(2021, 10, 6, 1, 1, 1, 1); + checkCalculateClockOffset(era0Time1, era0Time2); + checkCalculateClockOffset(era0Time2, era0Time1); + + Instant era1Time1 = utcInstant(2061, 10, 5, 2, 2, 2, 2); + checkCalculateClockOffset(era1Time1, era1Time1); + + Instant era1Time2 = utcInstant(2061, 10, 6, 1, 1, 1, 1); + checkCalculateClockOffset(era1Time1, era1Time2); + checkCalculateClockOffset(era1Time2, era1Time1); + + // Cross-era calcs (requires they are still within 68 years of each other). + checkCalculateClockOffset(era0Time1, era1Time1); + checkCalculateClockOffset(era1Time1, era0Time1); + } + + private void checkCalculateClockOffset(Instant clientTime, Instant serverTime) { + // The expected (ideal) offset is the difference between the client and server clocks. NTP + // assumes delays are symmetric, i.e. that the server time is between server + // receive/transmit time, client time is between request/response time, and send networking + // delay == receive networking delay. + Duration expectedOffset = Duration.between(clientTime, serverTime); + + // Try simulating various round trip delays, including zero. + for (long totalElapsedTimeMillis : Arrays.asList(0, 20, 200, 2000, 20000)) { + // Simulate that a 10% of the elapsed time is due to time spent in the server, the rest + // is network / client processing time. + long simulatedServerElapsedTimeMillis = totalElapsedTimeMillis / 10; + long simulatedClientElapsedTimeMillis = totalElapsedTimeMillis; + + // Create some symmetrical timestamps. + Timestamp64 clientRequestTimestamp = Timestamp64.fromInstant( + clientTime.minusMillis(simulatedClientElapsedTimeMillis / 2)); + Timestamp64 clientResponseTimestamp = Timestamp64.fromInstant( + clientTime.plusMillis(simulatedClientElapsedTimeMillis / 2)); + Timestamp64 serverReceiveTimestamp = Timestamp64.fromInstant( + serverTime.minusMillis(simulatedServerElapsedTimeMillis / 2)); + Timestamp64 serverTransmitTimestamp = Timestamp64.fromInstant( + serverTime.plusMillis(simulatedServerElapsedTimeMillis / 2)); + + Duration actualOffset = SntpClient.calculateClockOffset( + clientRequestTimestamp, serverReceiveTimestamp, + serverTransmitTimestamp, clientResponseTimestamp); + + // We allow up to 1ms variation because NTP types are lossy and the simulated elapsed + // time millis may not divide exactly. + int allowedSlopMillis = 1; + assertNearlyEquals( + expectedOffset.toMillis(), actualOffset.toMillis(), allowedSlopMillis); + } + } + + private static Instant utcInstant( + int year, int monthOfYear, int day, int hour, int minute, int second, int nanos) { + return LocalDateTime.of(year, monthOfYear, day, hour, minute, second, nanos) + .toInstant(ZoneOffset.UTC); } @Test @@ -98,6 +298,8 @@ public class SntpClientTest { @Test public void testTimeoutFailure() throws Exception { + when(mSystemTimeSupplier.get()).thenReturn(LATE_ERA0_REQUEST_TIME); + mServer.clearServerReply(); assertFalse(mClient.requestTime(mServer.getAddress(), mServer.getPort(), 500, mNetwork)); assertEquals(1, mServer.numRequestsReceived()); @@ -106,7 +308,9 @@ public class SntpClientTest { @Test public void testIgnoreLeapNoSync() throws Exception { - final byte[] reply = HexEncoding.decode(WORKING_VERSION4.toCharArray(), false); + when(mSystemTimeSupplier.get()).thenReturn(LATE_ERA0_REQUEST_TIME); + + final byte[] reply = HexEncoding.decode(LATE_ERA_RESPONSE.toCharArray(), false); reply[0] |= (byte) 0xc0; mServer.setServerReply(reply); assertFalse(mClient.requestTime(mServer.getAddress(), mServer.getPort(), 500, mNetwork)); @@ -116,7 +320,9 @@ public class SntpClientTest { @Test public void testAcceptOnlyServerAndBroadcastModes() throws Exception { - final byte[] reply = HexEncoding.decode(WORKING_VERSION4.toCharArray(), false); + when(mSystemTimeSupplier.get()).thenReturn(LATE_ERA0_REQUEST_TIME); + + final byte[] reply = HexEncoding.decode(LATE_ERA_RESPONSE.toCharArray(), false); for (int i = 0; i <= 7; i++) { final String logMsg = "mode: " + i; reply[0] &= (byte) 0xf8; @@ -140,10 +346,12 @@ public class SntpClientTest { @Test public void testAcceptableStrataOnly() throws Exception { + when(mSystemTimeSupplier.get()).thenReturn(LATE_ERA0_REQUEST_TIME); + final int STRATUM_MIN = 1; final int STRATUM_MAX = 15; - final byte[] reply = HexEncoding.decode(WORKING_VERSION4.toCharArray(), false); + final byte[] reply = HexEncoding.decode(LATE_ERA_RESPONSE.toCharArray(), false); for (int i = 0; i < 256; i++) { final String logMsg = "stratum: " + i; reply[1] = (byte) i; @@ -162,7 +370,9 @@ public class SntpClientTest { @Test public void testZeroTransmitTime() throws Exception { - final byte[] reply = HexEncoding.decode(WORKING_VERSION4.toCharArray(), false); + when(mSystemTimeSupplier.get()).thenReturn(LATE_ERA0_REQUEST_TIME); + + final byte[] reply = HexEncoding.decode(LATE_ERA_RESPONSE.toCharArray(), false); Arrays.fill(reply, TRANSMIT_TIME_OFFSET, TRANSMIT_TIME_OFFSET + 8, (byte) 0x00); mServer.setServerReply(reply); assertFalse(mClient.requestTime(mServer.getAddress(), mServer.getPort(), 500, mNetwork)); @@ -170,6 +380,19 @@ public class SntpClientTest { assertEquals(1, mServer.numRepliesSent()); } + @Test + public void testNonMatchingOriginateTime() throws Exception { + when(mSystemTimeSupplier.get()).thenReturn(LATE_ERA0_REQUEST_TIME); + + final byte[] reply = HexEncoding.decode(LATE_ERA_RESPONSE.toCharArray(), false); + mServer.setServerReply(reply); + mServer.setGenerateValidOriginateTimestamp(false); + + assertFalse(mClient.requestTime(mServer.getAddress(), mServer.getPort(), 500, mNetwork)); + assertEquals(1, mServer.numRequestsReceived()); + assertEquals(1, mServer.numRepliesSent()); + } + private static class SntpTestServer { private final Object mLock = new Object(); @@ -177,6 +400,7 @@ public class SntpClientTest { private final InetAddress mAddress; private final int mPort; private byte[] mReply; + private boolean mGenerateValidOriginateTimestamp = true; private int mRcvd; private int mSent; private Thread mListeningThread; @@ -201,10 +425,16 @@ public class SntpClientTest { synchronized (mLock) { mRcvd++; if (mReply == null) { continue; } - // Copy transmit timestamp into originate timestamp. - // TODO: bounds checking. - System.arraycopy(ntpMsg.getData(), TRANSMIT_TIME_OFFSET, - mReply, ORIGINATE_TIME_OFFSET, 8); + if (mGenerateValidOriginateTimestamp) { + // Copy the transmit timestamp into originate timestamp: This is + // validated by well-behaved clients. + System.arraycopy(ntpMsg.getData(), TRANSMIT_TIME_OFFSET, + mReply, ORIGINATE_TIME_OFFSET, 8); + } else { + // Fill it with junk instead. + Arrays.fill(mReply, ORIGINATE_TIME_OFFSET, + ORIGINATE_TIME_OFFSET + 8, (byte) 0xFF); + } ntpMsg.setData(mReply); ntpMsg.setLength(mReply.length); try { @@ -245,9 +475,38 @@ public class SntpClientTest { } } + /** + * Controls the test server's behavior of copying the client's transmit timestamp into the + * response's originate timestamp (which is required of a real server). + */ + public void setGenerateValidOriginateTimestamp(boolean enabled) { + synchronized (mLock) { + mGenerateValidOriginateTimestamp = enabled; + } + } + public InetAddress getAddress() { return mAddress; } public int getPort() { return mPort; } public int numRequestsReceived() { synchronized (mLock) { return mRcvd; } } public int numRepliesSent() { synchronized (mLock) { return mSent; } } } + + /** + * Generates the "real" server time assuming it is exactly between the receive and transmit + * timestamp and in the NTP era specified. + */ + private static Instant calculateIdealServerTime(String receiveTimestampString, + String transmitTimestampString, int era) { + Timestamp64 receiveTimestamp = Timestamp64.fromString(receiveTimestampString); + Timestamp64 transmitTimestamp = Timestamp64.fromString(transmitTimestampString); + Duration serverProcessingTime = + Duration64.between(receiveTimestamp, transmitTimestamp).toDuration(); + return receiveTimestamp.toInstant(era) + .plusMillis(serverProcessingTime.dividedBy(2).toMillis()); + } + + private static void assertNearlyEquals(long expected, long actual, long allowedSlop) { + assertTrue("expected=" + expected + ", actual=" + actual + ", allowedSlop=" + allowedSlop, + actual >= expected - allowedSlop && actual <= expected + allowedSlop); + } } diff --git a/core/tests/coretests/src/android/net/sntp/Duration64Test.java b/core/tests/coretests/src/android/net/sntp/Duration64Test.java new file mode 100644 index 000000000000..60b69f622221 --- /dev/null +++ b/core/tests/coretests/src/android/net/sntp/Duration64Test.java @@ -0,0 +1,268 @@ +/* + * 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. + */ +package android.net.sntp; + +import static android.net.sntp.Timestamp64.NANOS_PER_SECOND; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertTrue; + +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.time.Duration; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneOffset; + +@RunWith(AndroidJUnit4.class) +public class Duration64Test { + + @Test + public void testBetween_rangeChecks() { + long maxDuration64Seconds = Timestamp64.MAX_SECONDS_IN_ERA / 2; + + Timestamp64 zeroNoFrac = Timestamp64.fromComponents(0, 0); + assertEquals(Duration64.ZERO, Duration64.between(zeroNoFrac, zeroNoFrac)); + + { + Timestamp64 ceilNoFrac = Timestamp64.fromComponents(maxDuration64Seconds, 0); + assertEquals(Duration64.ZERO, Duration64.between(ceilNoFrac, ceilNoFrac)); + + long expectedNanos = maxDuration64Seconds * NANOS_PER_SECOND; + assertEquals(Duration.ofNanos(expectedNanos), + Duration64.between(zeroNoFrac, ceilNoFrac).toDuration()); + assertEquals(Duration.ofNanos(-expectedNanos), + Duration64.between(ceilNoFrac, zeroNoFrac).toDuration()); + } + + { + // This value is the largest fraction of a second representable. It is 1-(1/2^32)), and + // so numerically larger than 999_999_999 nanos. + int fractionBits = 0xFFFF_FFFF; + Timestamp64 ceilWithFrac = Timestamp64 + .fromComponents(maxDuration64Seconds, fractionBits); + assertEquals(Duration64.ZERO, Duration64.between(ceilWithFrac, ceilWithFrac)); + + long expectedNanos = maxDuration64Seconds * NANOS_PER_SECOND + 999_999_999; + assertEquals( + Duration.ofNanos(expectedNanos), + Duration64.between(zeroNoFrac, ceilWithFrac).toDuration()); + // The -1 nanos demonstrates asymmetry due to the way Duration64 has different + // precision / range of sub-second fractions. + assertEquals( + Duration.ofNanos(-expectedNanos - 1), + Duration64.between(ceilWithFrac, zeroNoFrac).toDuration()); + } + } + + @Test + public void testBetween_smallSecondsOnly() { + long expectedNanos = 5L * NANOS_PER_SECOND; + assertEquals(Duration.ofNanos(expectedNanos), + Duration64.between(Timestamp64.fromComponents(5, 0), + Timestamp64.fromComponents(10, 0)) + .toDuration()); + assertEquals(Duration.ofNanos(-expectedNanos), + Duration64.between(Timestamp64.fromComponents(10, 0), + Timestamp64.fromComponents(5, 0)) + .toDuration()); + } + + @Test + public void testBetween_smallSecondsAndFraction() { + // Choose a nanos values we know can be represented exactly with fixed point binary (1/2 + // second, 1/4 second, etc.). + { + long expectedNanos = 5L * NANOS_PER_SECOND + 500_000_000L; + int fractionHalfSecond = 0x8000_0000; + assertEquals(Duration.ofNanos(expectedNanos), + Duration64.between( + Timestamp64.fromComponents(5, 0), + Timestamp64.fromComponents(10, fractionHalfSecond)).toDuration()); + assertEquals(Duration.ofNanos(-expectedNanos), + Duration64.between( + Timestamp64.fromComponents(10, fractionHalfSecond), + Timestamp64.fromComponents(5, 0)).toDuration()); + } + + { + long expectedNanos = 5L * NANOS_PER_SECOND + 250_000_000L; + int fractionHalfSecond = 0x8000_0000; + int fractionQuarterSecond = 0x4000_0000; + + assertEquals(Duration.ofNanos(expectedNanos), + Duration64.between( + Timestamp64.fromComponents(5, fractionQuarterSecond), + Timestamp64.fromComponents(10, fractionHalfSecond)).toDuration()); + assertEquals(Duration.ofNanos(-expectedNanos), + Duration64.between( + Timestamp64.fromComponents(10, fractionHalfSecond), + Timestamp64.fromComponents(5, fractionQuarterSecond)).toDuration()); + } + + } + + @Test + public void testBetween_sameEra0() { + int arbitraryEra0Year = 2021; + Instant one = utcInstant(arbitraryEra0Year, 1, 1, 0, 0, 0, 500); + assertNtpEraOfInstant(one, 0); + + checkDuration64Behavior(one, one); + + Instant two = utcInstant(arbitraryEra0Year + 1, 1, 1, 0, 0, 0, 250); + assertNtpEraOfInstant(two, 0); + + checkDuration64Behavior(one, two); + checkDuration64Behavior(two, one); + } + + @Test + public void testBetween_sameEra1() { + int arbitraryEra1Year = 2037; + Instant one = utcInstant(arbitraryEra1Year, 1, 1, 0, 0, 0, 500); + assertNtpEraOfInstant(one, 1); + + checkDuration64Behavior(one, one); + + Instant two = utcInstant(arbitraryEra1Year + 1, 1, 1, 0, 0, 0, 250); + assertNtpEraOfInstant(two, 1); + + checkDuration64Behavior(one, two); + checkDuration64Behavior(two, one); + } + + /** + * Tests that two timestamps can originate from times in different eras, and the works + * calculation still works providing the two times aren't more than 68 years apart (half of the + * 136 years representable using an unsigned 32-bit seconds representation). + */ + @Test + public void testBetween_adjacentEras() { + int yearsSeparation = 68; + + // This year just needs to be < 68 years before the end of NTP timestamp era 0. + int arbitraryYearInEra0 = 2021; + + Instant one = utcInstant(arbitraryYearInEra0, 1, 1, 0, 0, 0, 500); + assertNtpEraOfInstant(one, 0); + + checkDuration64Behavior(one, one); + + Instant two = utcInstant(arbitraryYearInEra0 + yearsSeparation, 1, 1, 0, 0, 0, 250); + assertNtpEraOfInstant(two, 1); + + checkDuration64Behavior(one, two); + checkDuration64Behavior(two, one); + } + + /** + * This test confirms that duration calculations fail in the expected fashion if two + * Timestamp64s are more than 2^31 seconds apart. + * + * <p>The types / math specified by NTP for timestamps deliberately takes place in 64-bit signed + * arithmetic for the bits used to represent timestamps (32-bit unsigned integer seconds, + * 32-bits fixed point for fraction of seconds). Timestamps can therefore represent ~136 years + * of seconds. + * When subtracting one timestamp from another, we end up with a signed 32-bit seconds value. + * This means the max duration representable is ~68 years before numbers will over or underflow. + * i.e. the client and server are in the same or adjacent NTP eras and the difference in their + * clocks isn't more than ~68 years. >= ~68 years and things break down. + */ + @Test + public void testBetween_tooFarApart() { + int tooManyYearsSeparation = 68 + 1; + + Instant one = utcInstant(2021, 1, 1, 0, 0, 0, 500); + assertNtpEraOfInstant(one, 0); + Instant two = utcInstant(2021 + tooManyYearsSeparation, 1, 1, 0, 0, 0, 250); + assertNtpEraOfInstant(two, 1); + + checkDuration64OverflowBehavior(one, two); + checkDuration64OverflowBehavior(two, one); + } + + private static void checkDuration64Behavior(Instant one, Instant two) { + // This is the answer if we perform the arithmetic in a lossless fashion. + Duration expectedDuration = Duration.between(one, two); + Duration64 expectedDuration64 = Duration64.fromDuration(expectedDuration); + + // Sub-second precision is limited in Timestamp64, so we can lose 1ms. + assertEqualsOrSlightlyLessThan( + expectedDuration.toMillis(), expectedDuration64.toDuration().toMillis()); + + Timestamp64 one64 = Timestamp64.fromInstant(one); + Timestamp64 two64 = Timestamp64.fromInstant(two); + + // This is the answer if we perform the arithmetic in a lossy fashion. + Duration64 actualDuration64 = Duration64.between(one64, two64); + assertEquals(expectedDuration64.getSeconds(), actualDuration64.getSeconds()); + assertEqualsOrSlightlyLessThan(expectedDuration64.getNanos(), actualDuration64.getNanos()); + } + + private static void checkDuration64OverflowBehavior(Instant one, Instant two) { + // This is the answer if we perform the arithmetic in a lossless fashion. + Duration trueDuration = Duration.between(one, two); + + // Confirm the maths is expected to overflow / underflow. + assertTrue(trueDuration.getSeconds() > Integer.MAX_VALUE / 2 + || trueDuration.getSeconds() < Integer.MIN_VALUE / 2); + + // Now perform the arithmetic as specified for NTP: do subtraction using the 64-bit + // timestamp. + Timestamp64 one64 = Timestamp64.fromInstant(one); + Timestamp64 two64 = Timestamp64.fromInstant(two); + + Duration64 actualDuration64 = Duration64.between(one64, two64); + assertNotEquals(trueDuration.getSeconds(), actualDuration64.getSeconds()); + } + + /** + * Asserts the instant provided is in the specified NTP timestamp era. Used to confirm / + * document values picked for tests have the properties needed. + */ + private static void assertNtpEraOfInstant(Instant one, int ntpEra) { + long expectedSeconds = one.getEpochSecond(); + + // The conversion to Timestamp64 is lossy (it loses the era). We then supply the expected + // era. If the era was correct, we will end up with the value we started with (modulo nano + // precision loss). If the era is wrong, we won't. + Instant roundtrippedInstant = Timestamp64.fromInstant(one).toInstant(ntpEra); + + long actualSeconds = roundtrippedInstant.getEpochSecond(); + assertEquals(expectedSeconds, actualSeconds); + } + + /** + * Used to account for the fact that NTP types used 32-bit fixed point storage, so cannot store + * all values precisely. The value we get out will always be the value we put in, or one that is + * one unit smaller (due to truncation). + */ + private static void assertEqualsOrSlightlyLessThan(long expected, long actual) { + assertTrue("expected=" + expected + ", actual=" + actual, + expected == actual || expected == actual - 1); + } + + private static Instant utcInstant( + int year, int monthOfYear, int day, int hour, int minute, int second, int nanos) { + return LocalDateTime.of(year, monthOfYear, day, hour, minute, second, nanos) + .toInstant(ZoneOffset.UTC); + } +} diff --git a/core/tests/coretests/src/android/net/sntp/OWNERS b/core/tests/coretests/src/android/net/sntp/OWNERS new file mode 100644 index 000000000000..232c2ebe75e0 --- /dev/null +++ b/core/tests/coretests/src/android/net/sntp/OWNERS @@ -0,0 +1 @@ +include /core/java/android/net/sntp/OWNERS diff --git a/core/tests/coretests/src/android/net/sntp/PredictableRandom.java b/core/tests/coretests/src/android/net/sntp/PredictableRandom.java new file mode 100644 index 000000000000..bb2922bf8ce2 --- /dev/null +++ b/core/tests/coretests/src/android/net/sntp/PredictableRandom.java @@ -0,0 +1,34 @@ +/* + * 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. + */ +package android.net.sntp; + +import java.util.Random; + +class PredictableRandom extends Random { + private int[] mIntSequence = new int[] { 1 }; + private int mIntPos = 0; + + public void setIntSequence(int[] intSequence) { + this.mIntSequence = intSequence; + } + + @Override + public int nextInt() { + int value = mIntSequence[mIntPos++]; + mIntPos %= mIntSequence.length; + return value; + } +} diff --git a/core/tests/coretests/src/android/net/sntp/Timestamp64Test.java b/core/tests/coretests/src/android/net/sntp/Timestamp64Test.java new file mode 100644 index 000000000000..1b1c500c127f --- /dev/null +++ b/core/tests/coretests/src/android/net/sntp/Timestamp64Test.java @@ -0,0 +1,316 @@ +/* + * 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. + */ +package android.net.sntp; + +import static android.net.sntp.Timestamp64.NANOS_PER_SECOND; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.time.Instant; +import java.util.HashSet; +import java.util.Random; +import java.util.Set; + +@RunWith(AndroidJUnit4.class) +public class Timestamp64Test { + + @Test + public void testFromComponents() { + long minNtpEraSeconds = 0; + long maxNtpEraSeconds = 0xFFFFFFFFL; + + expectIllegalArgumentException(() -> Timestamp64.fromComponents(minNtpEraSeconds - 1, 0)); + expectIllegalArgumentException(() -> Timestamp64.fromComponents(maxNtpEraSeconds + 1, 0)); + + assertComponentCreation(minNtpEraSeconds, 0); + assertComponentCreation(maxNtpEraSeconds, 0); + assertComponentCreation(maxNtpEraSeconds, Integer.MIN_VALUE); + assertComponentCreation(maxNtpEraSeconds, Integer.MAX_VALUE); + } + + private static void assertComponentCreation(long ntpEraSeconds, int fractionBits) { + Timestamp64 value = Timestamp64.fromComponents(ntpEraSeconds, fractionBits); + assertEquals(ntpEraSeconds, value.getEraSeconds()); + assertEquals(fractionBits, value.getFractionBits()); + } + + @Test + public void testEqualsAndHashcode() { + assertEqualsAndHashcode(0, 0); + assertEqualsAndHashcode(1, 0); + assertEqualsAndHashcode(0, 1); + } + + private static void assertEqualsAndHashcode(int eraSeconds, int fractionBits) { + Timestamp64 one = Timestamp64.fromComponents(eraSeconds, fractionBits); + Timestamp64 two = Timestamp64.fromComponents(eraSeconds, fractionBits); + assertEquals(one, two); + assertEquals(one.hashCode(), two.hashCode()); + } + + @Test + public void testStringForm() { + expectIllegalArgumentException(() -> Timestamp64.fromString("")); + expectIllegalArgumentException(() -> Timestamp64.fromString(".")); + expectIllegalArgumentException(() -> Timestamp64.fromString("1234567812345678")); + expectIllegalArgumentException(() -> Timestamp64.fromString("12345678?12345678")); + expectIllegalArgumentException(() -> Timestamp64.fromString("12345678..12345678")); + expectIllegalArgumentException(() -> Timestamp64.fromString("1.12345678")); + expectIllegalArgumentException(() -> Timestamp64.fromString("12.12345678")); + expectIllegalArgumentException(() -> Timestamp64.fromString("123456.12345678")); + expectIllegalArgumentException(() -> Timestamp64.fromString("1234567.12345678")); + expectIllegalArgumentException(() -> Timestamp64.fromString("12345678.1")); + expectIllegalArgumentException(() -> Timestamp64.fromString("12345678.12")); + expectIllegalArgumentException(() -> Timestamp64.fromString("12345678.123456")); + expectIllegalArgumentException(() -> Timestamp64.fromString("12345678.1234567")); + expectIllegalArgumentException(() -> Timestamp64.fromString("X2345678.12345678")); + expectIllegalArgumentException(() -> Timestamp64.fromString("12345678.X2345678")); + + assertStringCreation("00000000.00000000", 0, 0); + assertStringCreation("00000001.00000001", 1, 1); + assertStringCreation("ffffffff.ffffffff", 0xFFFFFFFFL, 0xFFFFFFFF); + } + + private static void assertStringCreation( + String string, long expectedSeconds, int expectedFractionBits) { + Timestamp64 timestamp64 = Timestamp64.fromString(string); + assertEquals(string, timestamp64.toString()); + assertEquals(expectedSeconds, timestamp64.getEraSeconds()); + assertEquals(expectedFractionBits, timestamp64.getFractionBits()); + } + + @Test + public void testStringForm_lenientHexCasing() { + Timestamp64 mixedCaseValue = Timestamp64.fromString("AaBbCcDd.EeFf1234"); + assertEquals(0xAABBCCDDL, mixedCaseValue.getEraSeconds()); + assertEquals(0xEEFF1234, mixedCaseValue.getFractionBits()); + } + + @Test + public void testFromInstant_secondsHandling() { + final int era0 = 0; + final int eraNeg1 = -1; + final int eraNeg2 = -2; + final int era1 = 1; + + assertInstantCreationOnlySeconds(-Timestamp64.OFFSET_1900_TO_1970, 0, era0); + assertInstantCreationOnlySeconds( + -Timestamp64.OFFSET_1900_TO_1970 - Timestamp64.SECONDS_IN_ERA, 0, eraNeg1); + assertInstantCreationOnlySeconds( + -Timestamp64.OFFSET_1900_TO_1970 + Timestamp64.SECONDS_IN_ERA, 0, era1); + + assertInstantCreationOnlySeconds( + -Timestamp64.OFFSET_1900_TO_1970 - 1, Timestamp64.MAX_SECONDS_IN_ERA, -1); + assertInstantCreationOnlySeconds( + -Timestamp64.OFFSET_1900_TO_1970 - Timestamp64.SECONDS_IN_ERA - 1, + Timestamp64.MAX_SECONDS_IN_ERA, eraNeg2); + assertInstantCreationOnlySeconds( + -Timestamp64.OFFSET_1900_TO_1970 + Timestamp64.SECONDS_IN_ERA - 1, + Timestamp64.MAX_SECONDS_IN_ERA, era0); + + assertInstantCreationOnlySeconds(-Timestamp64.OFFSET_1900_TO_1970 + 1, 1, era0); + assertInstantCreationOnlySeconds( + -Timestamp64.OFFSET_1900_TO_1970 - Timestamp64.SECONDS_IN_ERA + 1, 1, eraNeg1); + assertInstantCreationOnlySeconds( + -Timestamp64.OFFSET_1900_TO_1970 + Timestamp64.SECONDS_IN_ERA + 1, 1, era1); + + assertInstantCreationOnlySeconds(0, Timestamp64.OFFSET_1900_TO_1970, era0); + assertInstantCreationOnlySeconds( + -Timestamp64.SECONDS_IN_ERA, Timestamp64.OFFSET_1900_TO_1970, eraNeg1); + assertInstantCreationOnlySeconds( + Timestamp64.SECONDS_IN_ERA, Timestamp64.OFFSET_1900_TO_1970, era1); + + assertInstantCreationOnlySeconds(1, Timestamp64.OFFSET_1900_TO_1970 + 1, era0); + assertInstantCreationOnlySeconds( + -Timestamp64.SECONDS_IN_ERA + 1, Timestamp64.OFFSET_1900_TO_1970 + 1, eraNeg1); + assertInstantCreationOnlySeconds( + Timestamp64.SECONDS_IN_ERA + 1, Timestamp64.OFFSET_1900_TO_1970 + 1, era1); + + assertInstantCreationOnlySeconds(-1, Timestamp64.OFFSET_1900_TO_1970 - 1, era0); + assertInstantCreationOnlySeconds( + -Timestamp64.SECONDS_IN_ERA - 1, Timestamp64.OFFSET_1900_TO_1970 - 1, eraNeg1); + assertInstantCreationOnlySeconds( + Timestamp64.SECONDS_IN_ERA - 1, Timestamp64.OFFSET_1900_TO_1970 - 1, era1); + } + + private static void assertInstantCreationOnlySeconds( + long epochSeconds, long expectedNtpEraSeconds, int ntpEra) { + int nanosOfSecond = 0; + Instant instant = Instant.ofEpochSecond(epochSeconds, nanosOfSecond); + Timestamp64 timestamp = Timestamp64.fromInstant(instant); + assertEquals(expectedNtpEraSeconds, timestamp.getEraSeconds()); + + int expectedFractionBits = 0; + assertEquals(expectedFractionBits, timestamp.getFractionBits()); + + // Confirm the Instant can be round-tripped if we know the era. Also assumes the nanos can + // be stored precisely; 0 can be. + Instant roundTrip = timestamp.toInstant(ntpEra); + assertEquals(instant, roundTrip); + } + + @Test + public void testFromInstant_fractionHandling() { + // Try some values we know can be represented exactly. + assertInstantCreationOnlyFractionExact(0x0, 0); + assertInstantCreationOnlyFractionExact(0x80000000, 500_000_000L); + assertInstantCreationOnlyFractionExact(0x40000000, 250_000_000L); + + // Test the limits of precision. + assertInstantCreationOnlyFractionExact(0x00000006, 1L); + assertInstantCreationOnlyFractionExact(0x00000005, 1L); + assertInstantCreationOnlyFractionExact(0x00000004, 0L); + assertInstantCreationOnlyFractionExact(0x00000002, 0L); + assertInstantCreationOnlyFractionExact(0x00000001, 0L); + + // Confirm nanosecond storage / precision is within 1ns. + final boolean exhaustive = false; + for (int i = 0; i < NANOS_PER_SECOND; i++) { + Instant instant = Instant.ofEpochSecond(0, i); + Instant roundTripped = Timestamp64.fromInstant(instant).toInstant(0); + assertNanosWithTruncationAllowed(i, roundTripped); + if (!exhaustive) { + i += 999_999; + } + } + } + + @SuppressWarnings("JavaInstantGetSecondsGetNano") + private static void assertInstantCreationOnlyFractionExact( + int fractionBits, long expectedNanos) { + Timestamp64 timestamp64 = Timestamp64.fromComponents(0, fractionBits); + + final int ntpEra = 0; + Instant instant = timestamp64.toInstant(ntpEra); + + assertEquals(expectedNanos, instant.getNano()); + } + + @SuppressWarnings("JavaInstantGetSecondsGetNano") + private static void assertNanosWithTruncationAllowed(long expectedNanos, Instant instant) { + // Allow for < 1ns difference due to truncation. + long actualNanos = instant.getNano(); + assertTrue("expectedNanos=" + expectedNanos + ", actualNanos=" + actualNanos, + actualNanos == expectedNanos || actualNanos == expectedNanos - 1); + } + + @SuppressWarnings("JavaInstantGetSecondsGetNano") + @Test + public void testMillisRandomizationConstant() { + // Mathematically, we can say that to represent 1000 different values, we need 10 binary + // digits (2^10 = 1024). The same is true whether we're dealing with integers or fractions. + // Unfortunately, for fractions those 1024 values do not correspond to discrete decimal + // values. Discrete millisecond values as fractions (e.g. 0.001 - 0.999) cannot be + // represented exactly except where the value can also be represented as some combination of + // powers of -2. When we convert back and forth, we truncate, so millisecond decimal + // fraction N represented as a binary fraction will always be equal to or lower than N. If + // we are truncating correctly it will never be as low as (N-0.001). N -> [N-0.001, N]. + + // We need to keep 10 bits to hold millis (inaccurately, since there are numbers that + // cannot be represented exactly), leaving us able to randomize the remaining 22 bits of the + // fraction part without significantly affecting the number represented. + assertEquals(22, Timestamp64.SUB_MILLIS_BITS_TO_RANDOMIZE); + + // Brute force proof that randomization logic will keep the timestamp within the range + // [N-0.001, N] where x is in milliseconds. + int smallFractionRandomizedLow = 0; + int smallFractionRandomizedHigh = 0b00000000_00111111_11111111_11111111; + int largeFractionRandomizedLow = 0b11111111_11000000_00000000_00000000; + int largeFractionRandomizedHigh = 0b11111111_11111111_11111111_11111111; + + long smallLowNanos = Timestamp64.fromComponents( + 0, smallFractionRandomizedLow).toInstant(0).getNano(); + long smallHighNanos = Timestamp64.fromComponents( + 0, smallFractionRandomizedHigh).toInstant(0).getNano(); + long smallDelta = smallHighNanos - smallLowNanos; + long millisInNanos = 1_000_000_000 / 1_000; + assertTrue(smallDelta >= 0 && smallDelta < millisInNanos); + + long largeLowNanos = Timestamp64.fromComponents( + 0, largeFractionRandomizedLow).toInstant(0).getNano(); + long largeHighNanos = Timestamp64.fromComponents( + 0, largeFractionRandomizedHigh).toInstant(0).getNano(); + long largeDelta = largeHighNanos - largeLowNanos; + assertTrue(largeDelta >= 0 && largeDelta < millisInNanos); + + PredictableRandom random = new PredictableRandom(); + random.setIntSequence(new int[] { 0xFFFF_FFFF }); + Timestamp64 zero = Timestamp64.fromComponents(0, 0); + Timestamp64 zeroWithFractionRandomized = zero.randomizeSubMillis(random); + assertEquals(zero.getEraSeconds(), zeroWithFractionRandomized.getEraSeconds()); + assertEquals(smallFractionRandomizedHigh, zeroWithFractionRandomized.getFractionBits()); + } + + @Test + public void testRandomizeLowestBits() { + Random random = new Random(1); + { + int fractionBits = 0; + expectIllegalArgumentException( + () -> Timestamp64.randomizeLowestBits(random, fractionBits, -1)); + expectIllegalArgumentException( + () -> Timestamp64.randomizeLowestBits(random, fractionBits, 0)); + expectIllegalArgumentException( + () -> Timestamp64.randomizeLowestBits(random, fractionBits, Integer.SIZE)); + expectIllegalArgumentException( + () -> Timestamp64.randomizeLowestBits(random, fractionBits, Integer.SIZE + 1)); + } + + // Check the behavior looks correct from a probabilistic point of view. + for (int input : new int[] { 0, 0xFFFFFFFF }) { + for (int bitCount = 1; bitCount < Integer.SIZE; bitCount++) { + int upperBitMask = 0xFFFFFFFF << bitCount; + int expectedUpperBits = input & upperBitMask; + + Set<Integer> values = new HashSet<>(); + values.add(input); + + int trials = 100; + for (int i = 0; i < trials; i++) { + int outputFractionBits = + Timestamp64.randomizeLowestBits(random, input, bitCount); + + // Record the output value for later analysis. + values.add(outputFractionBits); + + // Check upper bits did not change. + assertEquals(expectedUpperBits, outputFractionBits & upperBitMask); + } + + // It's possible to be more rigorous here, perhaps with a histogram. As bitCount + // rises, values.size() quickly trend towards the value of trials + 1. For now, this + // mostly just guards against a no-op implementation. + assertTrue(bitCount + ":" + values.size(), values.size() > 1); + } + } + } + + private static void expectIllegalArgumentException(Runnable r) { + try { + r.run(); + fail(); + } catch (IllegalArgumentException e) { + // Expected + } + } +} diff --git a/core/tests/coretests/src/android/os/BundleTest.java b/core/tests/coretests/src/android/os/BundleTest.java index ddd0070588ed..09f48403cf31 100644 --- a/core/tests/coretests/src/android/os/BundleTest.java +++ b/core/tests/coretests/src/android/os/BundleTest.java @@ -273,16 +273,21 @@ public class BundleTest { Parcelable p1 = new CustomParcelable(13, "Tiramisu"); Parcelable p2 = new CustomParcelable(13, "Tiramisu"); Bundle a = new Bundle(); - a.putParcelable("key", p1); + a.putParcelable("key1", p1); a.readFromParcel(getParcelledBundle(a)); a.setClassLoader(getClass().getClassLoader()); Bundle b = new Bundle(); - b.putParcelable("key", p2); + // Adding extra element so that the position of the elements of interest in their respective + // source parcels are different so we can cover that case of Parcel.compareData(). We'll + // remove the element later so the map is equal. + b.putString("key0", "string"); + b.putParcelable("key1", p2); b.readFromParcel(getParcelledBundle(b)); b.setClassLoader(getClass().getClassLoader()); - // 2 lazy values with identical parcels inside a.isEmpty(); b.isEmpty(); + b.remove("key0"); + // 2 lazy values with identical parcels inside assertTrue(Bundle.kindofEquals(a, b)); } diff --git a/core/tests/coretests/src/android/os/BytesMatcherTest.java b/core/tests/coretests/src/android/os/BytesMatcherTest.java deleted file mode 100644 index b28e3090edd0..000000000000 --- a/core/tests/coretests/src/android/os/BytesMatcherTest.java +++ /dev/null @@ -1,178 +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. - */ - -package android.os; - -import static com.android.internal.util.HexDump.hexStringToByteArray; - -import android.bluetooth.BluetoothUuid; -import android.net.MacAddress; - -import androidx.test.filters.SmallTest; - -import junit.framework.TestCase; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -@RunWith(JUnit4.class) -@SmallTest -public class BytesMatcherTest extends TestCase { - @Test - public void testEmpty() throws Exception { - BytesMatcher matcher = BytesMatcher.decode(""); - assertFalse(matcher.test(hexStringToByteArray("cafe"))); - assertFalse(matcher.test(hexStringToByteArray(""))); - } - - @Test - public void testExact() throws Exception { - BytesMatcher matcher = BytesMatcher.decode("+cafe"); - assertTrue(matcher.test(hexStringToByteArray("cafe"))); - assertFalse(matcher.test(hexStringToByteArray("beef"))); - assertFalse(matcher.test(hexStringToByteArray("ca"))); - assertFalse(matcher.test(hexStringToByteArray("cafe00"))); - } - - @Test - public void testMask() throws Exception { - BytesMatcher matcher = BytesMatcher.decode("+cafe/ff00"); - assertTrue(matcher.test(hexStringToByteArray("cafe"))); - assertTrue(matcher.test(hexStringToByteArray("ca88"))); - assertFalse(matcher.test(hexStringToByteArray("beef"))); - assertFalse(matcher.test(hexStringToByteArray("ca"))); - assertFalse(matcher.test(hexStringToByteArray("cafe00"))); - } - - @Test - public void testPrefix() throws Exception { - BytesMatcher matcher = BytesMatcher.decode("⊆cafe,⊆beef/ff00"); - assertTrue(matcher.test(hexStringToByteArray("cafe"))); - assertFalse(matcher.test(hexStringToByteArray("caff"))); - assertTrue(matcher.test(hexStringToByteArray("cafecafe"))); - assertFalse(matcher.test(hexStringToByteArray("ca"))); - assertTrue(matcher.test(hexStringToByteArray("beef"))); - assertTrue(matcher.test(hexStringToByteArray("beff"))); - assertTrue(matcher.test(hexStringToByteArray("beffbeff"))); - assertFalse(matcher.test(hexStringToByteArray("be"))); - } - - @Test - public void testMacAddress() throws Exception { - BytesMatcher matcher = BytesMatcher.decode("+cafe00112233/ffffff000000"); - assertTrue(matcher.testMacAddress( - MacAddress.fromString("ca:fe:00:00:00:00"))); - assertFalse(matcher.testMacAddress( - MacAddress.fromString("f0:0d:00:00:00:00"))); - } - - @Test - public void testBluetoothUuid() throws Exception { - BytesMatcher matcher = BytesMatcher.decode("+cafe/ff00"); - assertTrue(matcher.testBluetoothUuid( - BluetoothUuid.parseUuidFrom(hexStringToByteArray("cafe")))); - assertFalse(matcher.testBluetoothUuid( - BluetoothUuid.parseUuidFrom(hexStringToByteArray("beef")))); - } - - /** - * Verify that single matcher can be configured to match Bluetooth UUIDs of - * varying lengths. - */ - @Test - public void testBluetoothUuid_Mixed() throws Exception { - BytesMatcher matcher = BytesMatcher.decode("+aaaa/ff00,+bbbbbbbb/ffff0000"); - assertTrue(matcher.testBluetoothUuid( - BluetoothUuid.parseUuidFrom(hexStringToByteArray("aaaa")))); - assertFalse(matcher.testBluetoothUuid( - BluetoothUuid.parseUuidFrom(hexStringToByteArray("bbbb")))); - assertTrue(matcher.testBluetoothUuid( - BluetoothUuid.parseUuidFrom(hexStringToByteArray("bbbbbbbb")))); - assertFalse(matcher.testBluetoothUuid( - BluetoothUuid.parseUuidFrom(hexStringToByteArray("aaaaaaaa")))); - } - - @Test - public void testSerialize_Empty() throws Exception { - BytesMatcher matcher = new BytesMatcher(); - matcher = BytesMatcher.decode(BytesMatcher.encode(matcher)); - - // Also very empty and null values - BytesMatcher.decode(""); - BytesMatcher.decode(null); - } - - @Test - public void testSerialize_Exact() throws Exception { - BytesMatcher matcher = new BytesMatcher(); - matcher.addExactRejectRule(hexStringToByteArray("cafe00112233"), - hexStringToByteArray("ffffff000000")); - matcher.addExactRejectRule(hexStringToByteArray("beef00112233"), - null); - matcher.addExactAcceptRule(hexStringToByteArray("000000000000"), - hexStringToByteArray("000000000000")); - - assertFalse(matcher.test(hexStringToByteArray("cafe00ffffff"))); - assertFalse(matcher.test(hexStringToByteArray("beef00112233"))); - assertTrue(matcher.test(hexStringToByteArray("beef00ffffff"))); - - // Bounce through serialization pass and confirm it still works - matcher = BytesMatcher.decode(BytesMatcher.encode(matcher)); - - assertFalse(matcher.test(hexStringToByteArray("cafe00ffffff"))); - assertFalse(matcher.test(hexStringToByteArray("beef00112233"))); - assertTrue(matcher.test(hexStringToByteArray("beef00ffffff"))); - } - - @Test - public void testSerialize_Prefix() throws Exception { - BytesMatcher matcher = new BytesMatcher(); - matcher.addExactRejectRule(hexStringToByteArray("aa"), null); - matcher.addExactAcceptRule(hexStringToByteArray("bb"), null); - matcher.addPrefixAcceptRule(hexStringToByteArray("aa"), null); - matcher.addPrefixRejectRule(hexStringToByteArray("bb"), null); - - assertFalse(matcher.test(hexStringToByteArray("aa"))); - assertTrue(matcher.test(hexStringToByteArray("bb"))); - assertTrue(matcher.test(hexStringToByteArray("aaaa"))); - assertFalse(matcher.test(hexStringToByteArray("bbbb"))); - - // Bounce through serialization pass and confirm it still works - matcher = BytesMatcher.decode(BytesMatcher.encode(matcher)); - - assertFalse(matcher.test(hexStringToByteArray("aa"))); - assertTrue(matcher.test(hexStringToByteArray("bb"))); - assertTrue(matcher.test(hexStringToByteArray("aaaa"))); - assertFalse(matcher.test(hexStringToByteArray("bbbb"))); - } - - @Test - public void testOrdering_RejectFirst() throws Exception { - BytesMatcher matcher = BytesMatcher.decode("-ff/0f,+ff/f0"); - assertFalse(matcher.test(hexStringToByteArray("ff"))); - assertTrue(matcher.test(hexStringToByteArray("f0"))); - assertFalse(matcher.test(hexStringToByteArray("0f"))); - } - - @Test - public void testOrdering_AcceptFirst() throws Exception { - BytesMatcher matcher = BytesMatcher.decode("+ff/f0,-ff/0f"); - assertTrue(matcher.test(hexStringToByteArray("ff"))); - assertTrue(matcher.test(hexStringToByteArray("f0"))); - assertFalse(matcher.test(hexStringToByteArray("0f"))); - } -} diff --git a/core/tests/coretests/src/android/os/ParcelTest.java b/core/tests/coretests/src/android/os/ParcelTest.java index dcb3e2f23da8..fdd278b9c621 100644 --- a/core/tests/coretests/src/android/os/ParcelTest.java +++ b/core/tests/coretests/src/android/os/ParcelTest.java @@ -17,6 +17,9 @@ package android.os; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; import android.platform.test.annotations.Presubmit; @@ -110,4 +113,130 @@ public class ParcelTest { assertEquals(string, p.readString16()); } } + + @Test + public void testCompareDataInRange_whenSameData() { + Parcel pA = Parcel.obtain(); + int iA = pA.dataPosition(); + pA.writeInt(13); + pA.writeString("Tiramisu"); + int length = pA.dataPosition() - iA; + Parcel pB = Parcel.obtain(); + pB.writeString("Prefix"); + int iB = pB.dataPosition(); + pB.writeInt(13); + pB.writeString("Tiramisu"); + + assertTrue(Parcel.compareData(pA, iA, pB, iB, length)); + } + + @Test + public void testCompareDataInRange_whenSameDataWithBinder() { + Binder binder = new Binder(); + Parcel pA = Parcel.obtain(); + int iA = pA.dataPosition(); + pA.writeInt(13); + pA.writeStrongBinder(binder); + pA.writeString("Tiramisu"); + int length = pA.dataPosition() - iA; + Parcel pB = Parcel.obtain(); + pB.writeString("Prefix"); + int iB = pB.dataPosition(); + pB.writeInt(13); + pB.writeStrongBinder(binder); + pB.writeString("Tiramisu"); + + assertTrue(Parcel.compareData(pA, iA, pB, iB, length)); + } + + @Test + public void testCompareDataInRange_whenDifferentData() { + Parcel pA = Parcel.obtain(); + int iA = pA.dataPosition(); + pA.writeInt(13); + pA.writeString("Tiramisu"); + int length = pA.dataPosition() - iA; + Parcel pB = Parcel.obtain(); + int iB = pB.dataPosition(); + pB.writeString("Prefix"); + pB.writeInt(13); + pB.writeString("Tiramisu"); + + assertFalse(Parcel.compareData(pA, iA, pB, iB, length)); + } + + @Test + public void testCompareDataInRange_whenLimitOutOfBounds_throws() { + Parcel pA = Parcel.obtain(); + int iA = pA.dataPosition(); + pA.writeInt(12); + pA.writeString("Tiramisu"); + int length = pA.dataPosition() - iA; + Parcel pB = Parcel.obtain(); + pB.writeString("Prefix"); + int iB = pB.dataPosition(); + pB.writeInt(13); + pB.writeString("Tiramisu"); + pB.writeInt(-1); + + assertThrows(IllegalArgumentException.class, + () -> Parcel.compareData(pA, iA + length, pB, iB, 1)); + assertThrows(IllegalArgumentException.class, + () -> Parcel.compareData(pA, iA, pB, pB.dataSize(), 1)); + assertThrows(IllegalArgumentException.class, + () -> Parcel.compareData(pA, iA, pB, iB, length + 1)); + assertThrows(IllegalArgumentException.class, + () -> Parcel.compareData(pA, iA + length + 1, pB, iB, 0)); + assertThrows(IllegalArgumentException.class, + () -> Parcel.compareData(pA, iA, pB, iB + pB.dataSize() + 1, 0)); + } + + @Test + public void testCompareDataInRange_whenLengthZero() { + Parcel pA = Parcel.obtain(); + int iA = pA.dataPosition(); + pA.writeInt(12); + pA.writeString("Tiramisu"); + int length = pA.dataPosition() - iA; + Parcel pB = Parcel.obtain(); + pB.writeString("Prefix"); + int iB = pB.dataPosition(); + pB.writeInt(13); + pB.writeString("Tiramisu"); + + assertTrue(Parcel.compareData(pA, 0, pB, iB, 0)); + assertTrue(Parcel.compareData(pA, iA + length, pB, iB, 0)); + assertTrue(Parcel.compareData(pA, iA, pB, pB.dataSize(), 0)); + } + + @Test + public void testCompareDataInRange_whenNegativeLength_throws() { + Parcel pA = Parcel.obtain(); + int iA = pA.dataPosition(); + pA.writeInt(12); + pA.writeString("Tiramisu"); + Parcel pB = Parcel.obtain(); + pB.writeString("Prefix"); + int iB = pB.dataPosition(); + pB.writeInt(13); + pB.writeString("Tiramisu"); + + assertThrows(IllegalArgumentException.class, () -> Parcel.compareData(pA, iA, pB, iB, -1)); + } + + @Test + public void testCompareDataInRange_whenNegativeOffset_throws() { + Parcel pA = Parcel.obtain(); + int iA = pA.dataPosition(); + pA.writeInt(12); + pA.writeString("Tiramisu"); + Parcel pB = Parcel.obtain(); + pB.writeString("Prefix"); + int iB = pB.dataPosition(); + pB.writeInt(13); + pB.writeString("Tiramisu"); + + assertThrows(IllegalArgumentException.class, () -> Parcel.compareData(pA, -1, pB, iB, 0)); + assertThrows(IllegalArgumentException.class, () -> Parcel.compareData(pA, 0, pB, -1, 0)); + } } diff --git a/core/tests/coretests/src/android/service/timezone/OWNERS b/core/tests/coretests/src/android/service/timezone/OWNERS new file mode 100644 index 000000000000..811638805996 --- /dev/null +++ b/core/tests/coretests/src/android/service/timezone/OWNERS @@ -0,0 +1,2 @@ +# Bug component: 847766 +include /core/java/android/service/timezone/OWNERS diff --git a/core/tests/coretests/src/com/android/internal/content/res/OverlayConfigIterationRule.java b/core/tests/coretests/src/com/android/internal/content/res/OverlayConfigIterationRule.java index c50c818be716..e2c40d8b699b 100644 --- a/core/tests/coretests/src/com/android/internal/content/res/OverlayConfigIterationRule.java +++ b/core/tests/coretests/src/com/android/internal/content/res/OverlayConfigIterationRule.java @@ -28,6 +28,7 @@ import android.util.ArrayMap; import com.android.internal.content.om.OverlayConfig.PackageProvider; import com.android.internal.content.om.OverlayScanner; import com.android.internal.content.om.OverlayScanner.ParsedOverlayInfo; +import com.android.internal.util.function.TriConsumer; import org.junit.Assert; import org.junit.rules.TestRule; @@ -39,7 +40,6 @@ import org.mockito.invocation.InvocationOnMock; import java.io.File; import java.io.IOException; import java.util.Map; -import java.util.function.BiConsumer; import java.util.function.Supplier; /** @@ -73,7 +73,7 @@ public class OverlayConfigIterationRule implements TestRule { final File canonicalPath = new File(path.getCanonicalPath()); mOverlayStubResults.put(canonicalPath, new ParsedOverlayInfo( packageName, targetPackage, targetSdkVersion, isStatic, priority, - canonicalPath)); + canonicalPath, null)); } catch (IOException e) { Assert.fail("Failed to add overlay " + e); } @@ -135,8 +135,8 @@ public class OverlayConfigIterationRule implements TestRule { mIteration = Iteration.SYSTEM_SERVER; doAnswer((InvocationOnMock invocation) -> { final Object[] args = invocation.getArguments(); - final BiConsumer<ParsingPackageRead, Boolean> f = - (BiConsumer<ParsingPackageRead, Boolean>) args[0]; + final TriConsumer<ParsingPackageRead, Boolean, File> f = + (TriConsumer<ParsingPackageRead, Boolean, File>) args[0]; for (Map.Entry<File, ParsedOverlayInfo> overlay : mOverlayStubResults.entrySet()) { final ParsingPackageRead a = Mockito.mock(ParsingPackageRead.class); @@ -147,7 +147,8 @@ public class OverlayConfigIterationRule implements TestRule { when(a.isOverlayIsStatic()).thenReturn(info.isStatic); when(a.getOverlayPriority()).thenReturn(info.priority); when(a.getBaseApkPath()).thenReturn(info.path.getPath()); - f.accept(a, !info.path.getPath().contains("data/overlay")); + f.accept(a, !info.path.getPath().contains("data/overlay"), + /*preInstalledApexPath=*/null); } return null; }).when(mPkgProvider).forEachPackage(any()); diff --git a/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java index 5c8479406c03..d361da95a1b9 100644 --- a/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java +++ b/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java @@ -33,6 +33,8 @@ import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import java.util.ArrayList; + @RunWith(AndroidJUnit4.class) @SmallTest public class BluetoothPowerCalculatorTest { @@ -105,10 +107,10 @@ public class BluetoothPowerCalculatorTest { final BluetoothActivityEnergyInfo info = new BluetoothActivityEnergyInfo(1000, BluetoothActivityEnergyInfo.BT_STACK_STATE_STATE_ACTIVE, 7000, 5000, 0, reportedEnergyUc); - info.setUidTraffic(new UidTraffic[]{ - new UidTraffic(Process.BLUETOOTH_UID, 1000, 2000), - new UidTraffic(APP_UID, 3000, 4000) - }); + info.setUidTraffic(new ArrayList<UidTraffic>(){{ + add(new UidTraffic(Process.BLUETOOTH_UID, 1000, 2000)); + add(new UidTraffic(APP_UID, 3000, 4000)); + }}); mStatsRule.getBatteryStats().updateBluetoothStateLocked(info, consumedEnergyUc, 1000, 1000); } diff --git a/graphics/java/android/graphics/HardwareRenderer.java b/graphics/java/android/graphics/HardwareRenderer.java index c3b1cd74d29b..b61ae1259cf5 100644 --- a/graphics/java/android/graphics/HardwareRenderer.java +++ b/graphics/java/android/graphics/HardwareRenderer.java @@ -22,6 +22,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.app.Activity; import android.app.ActivityManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.pm.ActivityInfo; import android.content.res.Configuration; @@ -1075,6 +1076,53 @@ public class HardwareRenderer { ProcessInitializer.sInstance.setContext(context); } + /** + * Returns true if HardwareRender will produce output. + * + * This value is global to the process and affects all uses of HardwareRenderer, + * including + * those created by the system such as those used by the View tree when using hardware + * accelerated rendering. + * + * Default is true in all production environments, but may be false in testing-focused + * emulators or if {@link #setDrawingEnabled(boolean)} is used. + * + * Backported from android T. + * + * @hide + */ + @UnsupportedAppUsage + public static boolean isDrawingEnabled() { + return nIsDrawingEnabled(); + } + + /** + * Toggles whether or not HardwareRenderer will produce drawing output globally in the current + * process. + * + * This applies to all HardwareRenderer instances, including those created by the platform such + * as those used by the system for hardware accelerated View rendering. + * + * The capability to disable drawing output is intended for test environments, primarily + * headless ones. By setting this to false, tests that launch activities or interact with Views + * can be quicker with less RAM usage by skipping the final step of View drawing. All View + * lifecycle events will occur as normal, only the final step of rendering on the GPU to the + * display will be skipped. + * + * This can be toggled on and off at will, so screenshot tests can also run in this same + * environment by toggling drawing back on and forcing a frame to be drawn such as by calling + * view#invalidate(). Once drawn and the screenshot captured, this can then be turned back off. + * + * Backported from android T. + * + * @hide + */ + // TODO: Add link to androidx's Screenshot library for help with this + @UnsupportedAppUsage + public static void setDrawingEnabled(boolean drawingEnabled) { + nSetDrawingEnabled(drawingEnabled); + } + private static final class DestroyContextRunnable implements Runnable { private final long mNativeInstance; @@ -1393,4 +1441,8 @@ public class HardwareRenderer { private static native void nInitDisplayInfo(int width, int height, float refreshRate, int wideColorDataspace, long appVsyncOffsetNanos, long presentationDeadlineNanos); + + private static native void nSetDrawingEnabled(boolean drawingEnabled); + + private static native boolean nIsDrawingEnabled(); } diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp index b8fa55a18dac..c804418e8380 100644 --- a/libs/hwui/Properties.cpp +++ b/libs/hwui/Properties.cpp @@ -88,6 +88,8 @@ bool Properties::enableWebViewOverlays = false; StretchEffectBehavior Properties::stretchEffectBehavior = StretchEffectBehavior::ShaderHWUI; +DrawingEnabled Properties::drawingEnabled = DrawingEnabled::NotInitialized; + bool Properties::load() { bool prevDebugLayersUpdates = debugLayersUpdates; bool prevDebugOverdraw = debugOverdraw; @@ -141,6 +143,9 @@ bool Properties::load() { enableWebViewOverlays = base::GetBoolProperty(PROPERTY_WEBVIEW_OVERLAYS_ENABLED, false); + // call isDrawingEnabled to force loading of the property + isDrawingEnabled(); + return (prevDebugLayersUpdates != debugLayersUpdates) || (prevDebugOverdraw != debugOverdraw); } @@ -210,5 +215,19 @@ void Properties::overrideRenderPipelineType(RenderPipelineType type, bool inUnit sRenderPipelineType = type; } +void Properties::setDrawingEnabled(bool newDrawingEnabled) { + drawingEnabled = newDrawingEnabled ? DrawingEnabled::On : DrawingEnabled::Off; + enableRTAnimations = newDrawingEnabled; +} + +bool Properties::isDrawingEnabled() { + if (drawingEnabled == DrawingEnabled::NotInitialized) { + bool drawingEnabledProp = base::GetBoolProperty(PROPERTY_DRAWING_ENABLED, true); + drawingEnabled = drawingEnabledProp ? DrawingEnabled::On : DrawingEnabled::Off; + enableRTAnimations = drawingEnabledProp; + } + return drawingEnabled == DrawingEnabled::On; +} + } // namespace uirenderer } // namespace android diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h index 7df6e2c92247..7f9782bf8d20 100644 --- a/libs/hwui/Properties.h +++ b/libs/hwui/Properties.h @@ -187,6 +187,12 @@ enum DebugLevel { */ #define PROPERTY_WEBVIEW_OVERLAYS_ENABLED "debug.hwui.webview_overlays_enabled" +/** + * Property for globally GL drawing state. Can be overridden per process with + * setDrawingEnabled. + */ +#define PROPERTY_DRAWING_ENABLED "debug.hwui.drawing_enabled" + /////////////////////////////////////////////////////////////////////////////// // Misc /////////////////////////////////////////////////////////////////////////////// @@ -208,6 +214,8 @@ enum class StretchEffectBehavior { UniformScale // Uniform scale stretch everywhere }; +enum class DrawingEnabled { NotInitialized, On, Off }; + /** * Renderthread-only singleton which manages several static rendering properties. Most of these * are driven by system properties which are queried once at initialization, and again if init() @@ -301,6 +309,11 @@ public: stretchEffectBehavior = behavior; } + // Represents if drawing is enabled. Should only be Off in headless testing environments + static DrawingEnabled drawingEnabled; + static bool isDrawingEnabled(); + static void setDrawingEnabled(bool enable); + private: static StretchEffectBehavior stretchEffectBehavior; static ProfileType sProfileType; diff --git a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp index 54367b8334cb..9e56584ed582 100644 --- a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp +++ b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp @@ -817,6 +817,14 @@ static void android_view_ThreadedRenderer_initDisplayInfo(JNIEnv*, jclass, jint DeviceInfo::setPresentationDeadlineNanos(presentationDeadlineNanos); } +static void android_view_ThreadedRenderer_setDrawingEnabled(JNIEnv*, jclass, jboolean enabled) { + Properties::setDrawingEnabled(enabled); +} + +static jboolean android_view_ThreadedRenderer_isDrawingEnabled(JNIEnv*, jclass) { + return Properties::isDrawingEnabled(); +} + // ---------------------------------------------------------------------------- // HardwareRendererObserver // ---------------------------------------------------------------------------- @@ -953,6 +961,9 @@ static const JNINativeMethod gMethods[] = { {"preload", "()V", (void*)android_view_ThreadedRenderer_preload}, {"isWebViewOverlaysEnabled", "()Z", (void*)android_view_ThreadedRenderer_isWebViewOverlaysEnabled}, + {"nSetDrawingEnabled", "(Z)V", (void*)android_view_ThreadedRenderer_setDrawingEnabled}, + {"nIsDrawingEnabled", "()Z", (void*)android_view_ThreadedRenderer_isDrawingEnabled}, + }; static JavaVM* mJvm = nullptr; diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index 2f3a509831d1..bb0b1352c360 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -256,7 +256,7 @@ void CanvasContext::setStopped(bool stopped) { } void CanvasContext::allocateBuffers() { - if (mNativeSurface) { + if (mNativeSurface && Properties::isDrawingEnabled()) { ANativeWindow_tryAllocateBuffers(mNativeSurface->getNativeWindow()); } } @@ -480,7 +480,8 @@ nsecs_t CanvasContext::draw() { SkRect dirty; mDamageAccumulator.finish(&dirty); - if (dirty.isEmpty() && Properties::skipEmptyFrames && !surfaceRequiresRedraw()) { + if (!Properties::isDrawingEnabled() || + (dirty.isEmpty() && Properties::skipEmptyFrames && !surfaceRequiresRedraw())) { mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame); if (auto grContext = getGrContext()) { // Submit to ensure that any texture uploads complete and Skia can diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index 6dbfcc349d50..2fed4686f16e 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -90,9 +90,17 @@ public: * and false otherwise (e.g. cache limits have been exceeded). */ bool pinImages(std::vector<SkImage*>& mutableImages) { + if (!Properties::isDrawingEnabled()) { + return true; + } return mRenderPipeline->pinImages(mutableImages); } - bool pinImages(LsaVector<sk_sp<Bitmap>>& images) { return mRenderPipeline->pinImages(images); } + bool pinImages(LsaVector<sk_sp<Bitmap>>& images) { + if (!Properties::isDrawingEnabled()) { + return true; + } + return mRenderPipeline->pinImages(images); + } /** * Unpin any image that had be previously pinned to the GPU cache diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index c068963adc92..cf7039b9ed5c 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -3255,6 +3255,54 @@ public class AudioManager { } /** + * @hide + */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK) + public void setHfpEnabled(boolean enable) { + AudioSystem.setParameters("hfp_enable=" + enable); + } + + /** + * @hide + */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK) + public void setHfpVolume(int volume) { + AudioSystem.setParameters("hfp_volume=" + volume); + } + + /** + * @hide + */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK) + public void setHfpSamplingRate(int rate) { + AudioSystem.setParameters("hfp_set_sampling_rate=" + rate); + } + + /** + * @hide + */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK) + public void setBluetoothHeadsetProperties(@NonNull String name, boolean hasNrecEnabled, + boolean hasWbsEnabled) { + AudioSystem.setParameters("bt_headset_name=" + name + + ";bt_headset_nrec=" + (hasNrecEnabled ? "on" : "off") + + ";bt_wbs=" + (hasWbsEnabled ? "on" : "off")); + } + + /** + * @hide + */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK) + public void setA2dpSuspended(boolean enable) { + AudioSystem.setParameters("A2dpSuspended=" + enable); + } + + /** * Gets a variable number of parameter values from audio hardware. * * @param keys list of parameters @@ -5203,21 +5251,6 @@ public class AudioManager { } } - /** - * @hide - * Notifies AudioService that it is connected to an A2DP device that supports absolute volume, - * so that AudioService can send volume change events to the A2DP device, rather than handling - * them. - */ - public void avrcpSupportsAbsoluteVolume(String address, boolean support) { - final IAudioService service = getService(); - try { - service.avrcpSupportsAbsoluteVolume(address, support); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - /** * {@hide} */ diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index 71912800e0d7..dd44fdf1e8c4 100755 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -171,8 +171,6 @@ interface IAudioService { int getEncodedSurroundMode(int targetSdkVersion); - oneway void avrcpSupportsAbsoluteVolume(String address, boolean support); - void setSpeakerphoneOn(IBinder cb, boolean on); boolean isSpeakerphoneOn(); diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java index 49477b94cbe0..374cc7592faf 100644 --- a/media/java/android/media/MediaCodecInfo.java +++ b/media/java/android/media/MediaCodecInfo.java @@ -182,10 +182,15 @@ public final class MediaCodecInfo { public String mName; public int mValue; public boolean mDefault; + public boolean mInternal; public Feature(String name, int value, boolean def) { + this(name, value, def, false /* internal */); + } + public Feature(String name, int value, boolean def, boolean internal) { mName = name; mValue = value; mDefault = def; + mInternal = internal; } } @@ -579,6 +584,11 @@ public final class MediaCodecInfo { public static final String FEATURE_LowLatency = "low-latency"; /** + * Do not include in REGULAR_CODECS list in MediaCodecList. + */ + private static final String FEATURE_SpecialCodec = "special-codec"; + + /** * <b>video encoder only</b>: codec supports quantization parameter bounds. * @see MediaFormat#KEY_VIDEO_QP_MAX * @see MediaFormat#KEY_VIDEO_QP_MIN @@ -616,6 +626,8 @@ public final class MediaCodecInfo { new Feature(FEATURE_MultipleFrames, (1 << 5), false), new Feature(FEATURE_DynamicTimestamp, (1 << 6), false), new Feature(FEATURE_LowLatency, (1 << 7), true), + // feature to exclude codec from REGULAR codec list + new Feature(FEATURE_SpecialCodec, (1 << 30), false, true), }; private static final Feature[] encoderFeatures = { @@ -623,6 +635,8 @@ public final class MediaCodecInfo { new Feature(FEATURE_MultipleFrames, (1 << 1), false), new Feature(FEATURE_DynamicTimestamp, (1 << 2), false), new Feature(FEATURE_QpBounds, (1 << 3), false), + // feature to exclude codec from REGULAR codec list + new Feature(FEATURE_SpecialCodec, (1 << 30), false, true), }; /** @hide */ @@ -630,7 +644,9 @@ public final class MediaCodecInfo { Feature[] features = getValidFeatures(); String[] res = new String[features.length]; for (int i = 0; i < res.length; i++) { - res[i] = features[i].mName; + if (!features[i].mInternal) { + res[i] = features[i].mName; + } } return res; } @@ -778,6 +794,10 @@ public final class MediaCodecInfo { // check feature support for (Feature feat: getValidFeatures()) { + if (feat.mInternal) { + continue; + } + Integer yesNo = (Integer)map.get(MediaFormat.KEY_FEATURE_ + feat.mName); if (yesNo == null) { continue; @@ -1091,7 +1111,9 @@ public final class MediaCodecInfo { mFlagsRequired |= feat.mValue; } mFlagsSupported |= feat.mValue; - mDefaultFormat.setInteger(key, 1); + if (!feat.mInternal) { + mDefaultFormat.setInteger(key, 1); + } // TODO restrict features by mFlagsVerified once all codecs reliably verify them } } diff --git a/media/java/android/media/MediaRoute2Info.java b/media/java/android/media/MediaRoute2Info.java index 7e9d2d809fdd..9c9e83b0987d 100644 --- a/media/java/android/media/MediaRoute2Info.java +++ b/media/java/android/media/MediaRoute2Info.java @@ -106,7 +106,7 @@ public final class MediaRoute2Info implements Parcelable { @IntDef({ TYPE_UNKNOWN, TYPE_BUILTIN_SPEAKER, TYPE_WIRED_HEADSET, TYPE_WIRED_HEADPHONES, TYPE_BLUETOOTH_A2DP, TYPE_HDMI, TYPE_USB_DEVICE, - TYPE_USB_ACCESSORY, TYPE_DOCK, TYPE_USB_HEADSET, TYPE_HEARING_AID, + TYPE_USB_ACCESSORY, TYPE_DOCK, TYPE_USB_HEADSET, TYPE_HEARING_AID, TYPE_BLE_HEADSET, TYPE_REMOTE_TV, TYPE_REMOTE_SPEAKER, TYPE_GROUP}) @Retention(RetentionPolicy.SOURCE) public @interface Type {} @@ -202,6 +202,14 @@ public final class MediaRoute2Info implements Parcelable { public static final int TYPE_HEARING_AID = AudioDeviceInfo.TYPE_HEARING_AID; /** + * A route type describing a BLE HEADSET. + * + * @see #getType + * @hide + */ + public static final int TYPE_BLE_HEADSET = AudioDeviceInfo.TYPE_BLE_HEADSET; + + /** * A route type indicating the presentation of the media is happening on a TV. * * @see #getType diff --git a/media/java/android/media/PlayerBase.java b/media/java/android/media/PlayerBase.java index 86ed50bacb63..72ee00f03774 100644 --- a/media/java/android/media/PlayerBase.java +++ b/media/java/android/media/PlayerBase.java @@ -102,6 +102,13 @@ public abstract class PlayerBase { mState = AudioPlaybackConfiguration.PLAYER_STATE_IDLE; }; + /** @hide */ + public int getPlayerIId() { + synchronized (mLock) { + return mPlayerIId; + } + } + /** * Call from derived class when instantiation / initialization is successful */ diff --git a/media/jni/Android.bp b/media/jni/Android.bp index bc73f6ad1ad2..c775b6f7afc2 100644 --- a/media/jni/Android.bp +++ b/media/jni/Android.bp @@ -183,8 +183,8 @@ cc_library_shared { "libmedia", "libnativehelper", "libutils", - "tv_tuner_aidl_interface-ndk_platform", - "tv_tuner_resource_manager_aidl_interface-ndk_platform", + "tv_tuner_aidl_interface-ndk", + "tv_tuner_resource_manager_aidl_interface-ndk", ], static_libs: [ diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp index 2636ab227646..8dcdc989ec8f 100644 --- a/media/jni/android_media_MediaPlayer.cpp +++ b/media/jni/android_media_MediaPlayer.cpp @@ -953,7 +953,7 @@ android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_t Parcel* parcel = parcelForJavaObject(env, jAttributionSource); android::content::AttributionSourceState attributionSource; attributionSource.readFromParcel(parcel); - sp<MediaPlayer> mp = new MediaPlayer(attributionSource); + sp<MediaPlayer> mp = sp<MediaPlayer>::make(attributionSource); if (mp == NULL) { jniThrowException(env, "java/lang/RuntimeException", "Out of memory"); return; diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java index c1a0a9a92cc2..b4cafd8548f4 100644 --- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java +++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java @@ -93,9 +93,9 @@ public class CompanionDeviceActivity extends Activity { final DeviceFilterPair selectedDevice = getService().mDevicesFound.get(0); setTitle(Html.fromHtml(getString( R.string.confirmation_title, - getCallingAppName(), - profileName, - selectedDevice.getDisplayName()), 0)); + Html.escapeHtml(getCallingAppName()), + Html.escapeHtml(selectedDevice.getDisplayName())), 0)); + mPairButton = findViewById(R.id.button_pair); mPairButton.setOnClickListener(v -> onDeviceConfirmed(getService().mSelectedDevice)); getService().mSelectedDevice = selectedDevice; @@ -108,8 +108,8 @@ public class CompanionDeviceActivity extends Activity { mPairButton = findViewById(R.id.button_pair); mPairButton.setVisibility(View.GONE); setTitle(Html.fromHtml(getString(R.string.chooser_title, - profileName, - getCallingAppName()), 0)); + Html.escapeHtml(profileName), + Html.escapeHtml(getCallingAppName())), 0)); mDeviceListView = findViewById(R.id.device_list); mDevicesAdapter = new DevicesAdapter(); mDeviceListView.setAdapter(mDevicesAdapter); diff --git a/packages/PackageInstaller/OWNERS b/packages/PackageInstaller/OWNERS index c6331133367a..27368705c6b0 100644 --- a/packages/PackageInstaller/OWNERS +++ b/packages/PackageInstaller/OWNERS @@ -1,7 +1,5 @@ svetoslavganov@google.com -toddke@google.com -patb@google.com -suprabh@google.com +include /PACKAGE_MANAGER_OWNERS # For automotive related changes rogerxue@google.com diff --git a/packages/SettingsLib/res/drawable/ic_bt_le_audio.xml b/packages/SettingsLib/res/drawable/ic_bt_le_audio.xml new file mode 100644 index 000000000000..5b52a04e1cf6 --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_bt_le_audio.xml @@ -0,0 +1,31 @@ +<!-- + Copyright 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0" + android:tint="?android:attr/colorControlNormal" > + <path + android:pathData="M18.2,1L9.8,1C8.81,1 8,1.81 8,2.8v14.4c0,0.99 0.81,1.79 1.8,1.79l8.4,0.01c0.99,0 1.8,-0.81 1.8,-1.8L20,2.8c0,-0.99 -0.81,-1.8 -1.8,-1.8zM14,3c1.1,0 2,0.89 2,2s-0.9,2 -2,2 -2,-0.89 -2,-2 0.9,-2 2,-2zM14,16.5c-2.21,0 -4,-1.79 -4,-4s1.79,-4 4,-4 4,1.79 4,4 -1.79,4 -4,4z" + android:fillColor="#FFFFFFFF"/> + <path + android:pathData="M14,12.5m-2.5,0a2.5,2.5 0,1 1,5 0a2.5,2.5 0,1 1,-5 0" + android:fillColor="#FFFFFFFF"/> + <path + android:pathData="M6,5H4v16c0,1.1 0.89,2 2,2h10v-2H6V5z" + android:fillColor="#FFFFFFFF"/> +</vector> diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml index 6b840bd7901d..a56c49088b67 100644 --- a/packages/SettingsLib/res/values/strings.xml +++ b/packages/SettingsLib/res/values/strings.xml @@ -257,8 +257,12 @@ <!-- Bluetooth settings. The user-visible string that is used whenever referring to the Hearing Aid profile. --> <string name="bluetooth_profile_hearing_aid">Hearing Aids</string> + <!-- Bluetooth settings. The user-visible string that is used whenever referring to the LE_AUDIO profile. --> + <string name="bluetooth_profile_le_audio">LE_AUDIO</string> <!-- Bluetooth settings. Connection options screen. The summary for the Hearing Aid checkbox preference when Hearing Aid is connected. --> <string name="bluetooth_hearing_aid_profile_summary_connected">Connected to Hearing Aids</string> + <!-- Bluetooth settings. Connection options screen. The summary for the LE_AUDIO checkbox preference when LE_AUDIO is connected. --> + <string name="bluetooth_le_audio_profile_summary_connected">Connected to LE_AUDIO</string> <!-- Bluetooth settings. Connection options screen. The summary for the A2DP checkbox preference when A2DP is connected. --> <string name="bluetooth_a2dp_profile_summary_connected">Connected to media audio</string> @@ -299,6 +303,8 @@ <string name="bluetooth_hid_profile_summary_use_for">Use for input</string> <!-- Bluetooth settings. Connection options screen. The summary for the Hearing Aid checkbox preference that describes how checking it will set the Hearing Aid profile as preferred. --> <string name="bluetooth_hearing_aid_profile_summary_use_for">Use for Hearing Aids</string> + <!-- Bluetooth settings. Connection options screen. The summary for the LE_AUDIO checkbox preference that describes how checking it will set the LE_AUDIO profile as preferred. --> + <string name="bluetooth_le_audio_profile_summary_use_for">Use for LE_AUDIO</string> <!-- Button text for accepting an incoming pairing request. [CHAR LIMIT=20] --> <string name="bluetooth_pairing_accept">Pair</string> diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java index 875030949fe8..58d2185ea9e9 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java @@ -22,6 +22,7 @@ import android.bluetooth.BluetoothCsipSetCoordinator; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothHeadset; import android.bluetooth.BluetoothHearingAid; +import android.bluetooth.BluetoothLeAudio; import android.bluetooth.BluetoothProfile; import android.content.BroadcastReceiver; import android.content.Context; @@ -116,6 +117,8 @@ public class BluetoothEventManager { addHandler(BluetoothHeadset.ACTION_ACTIVE_DEVICE_CHANGED, new ActiveDeviceChangedHandler()); addHandler(BluetoothHearingAid.ACTION_ACTIVE_DEVICE_CHANGED, new ActiveDeviceChangedHandler()); + addHandler(BluetoothLeAudio.ACTION_LE_AUDIO_ACTIVE_DEVICE_CHANGED, + new ActiveDeviceChangedHandler()); // Headset state changed broadcasts addHandler(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED, @@ -127,9 +130,6 @@ public class BluetoothEventManager { addHandler(BluetoothDevice.ACTION_ACL_CONNECTED, new AclStateChangedHandler()); addHandler(BluetoothDevice.ACTION_ACL_DISCONNECTED, new AclStateChangedHandler()); - addHandler(BluetoothCsipSetCoordinator.ACTION_CSIS_SET_MEMBER_AVAILABLE, - new SetMemberAvailableHandler()); - registerAdapterIntentReceiver(); } @@ -455,6 +455,9 @@ public class BluetoothEventManager { bluetoothProfile = BluetoothProfile.HEADSET; } else if (Objects.equals(action, BluetoothHearingAid.ACTION_ACTIVE_DEVICE_CHANGED)) { bluetoothProfile = BluetoothProfile.HEARING_AID; + } else if (Objects.equals(action, + BluetoothLeAudio.ACTION_LE_AUDIO_ACTIVE_DEVICE_CHANGED)) { + bluetoothProfile = BluetoothProfile.LE_AUDIO; } else { Log.w(TAG, "ActiveDeviceChangedHandler: unknown action " + action); return; @@ -515,29 +518,4 @@ public class BluetoothEventManager { dispatchAudioModeChanged(); } } - - private class SetMemberAvailableHandler implements Handler { - @Override - public void onReceive(Context context, Intent intent, BluetoothDevice device) { - final String action = intent.getAction(); - if (device == null) { - Log.e(TAG, "SetMemberAvailableHandler: device is null"); - return; - } - - if (action == null) { - Log.e(TAG, "SetMemberAvailableHandler: action is null"); - return; - } - - final int groupId = intent.getIntExtra(BluetoothCsipSetCoordinator.EXTRA_CSIS_GROUP_ID, - BluetoothCsipSetCoordinator.GROUP_ID_INVALID); - if (groupId == BluetoothCsipSetCoordinator.GROUP_ID_INVALID) { - Log.e(TAG, "SetMemberAvailableHandler: Invalid group id"); - return; - } - - mDeviceManager.onSetMemberAppear(device, groupId); - } - } } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java index 243194188727..021ba2247e67 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java @@ -21,6 +21,7 @@ import android.bluetooth.BluetoothClass; import android.bluetooth.BluetoothCsipSetCoordinator; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothHearingAid; +import android.bluetooth.BluetoothLeAudio; import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothUuid; import android.content.Context; @@ -109,10 +110,12 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> private boolean mIsActiveDeviceA2dp = false; private boolean mIsActiveDeviceHeadset = false; private boolean mIsActiveDeviceHearingAid = false; + private boolean mIsActiveDeviceLeAudio = false; // Media profile connect state private boolean mIsA2dpProfileConnectedFail = false; private boolean mIsHeadsetProfileConnectedFail = false; private boolean mIsHearingAidProfileConnectedFail = false; + private boolean mIsLeAudioProfileConnectedFail = false; // Group second device for Hearing Aid private CachedBluetoothDevice mSubDevice; // Group member devices for the coordinated set @@ -133,6 +136,9 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> case BluetoothProfile.HEARING_AID: mIsHearingAidProfileConnectedFail = true; break; + case BluetoothProfile.LE_AUDIO: + mIsLeAudioProfileConnectedFail = true; + break; default: Log.w(TAG, "handleMessage(): unknown message : " + msg.what); break; @@ -266,6 +272,9 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> case BluetoothProfile.HEARING_AID: mIsHearingAidProfileConnectedFail = isFailed; break; + case BluetoothProfile.LE_AUDIO: + mIsLeAudioProfileConnectedFail = isFailed; + break; default: Log.w(TAG, "setProfileConnectedStatus(): unknown profile id : " + profileId); break; @@ -541,6 +550,13 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> result = true; } } + LeAudioProfile leAudioProfile = mProfileManager.getLeAudioProfile(); + if ((leAudioProfile != null) && isConnectedProfile(leAudioProfile)) { + if (leAudioProfile.setActiveDevice(getDevice())) { + Log.i(TAG, "OnPreferenceClickListener: LeAudio active device=" + this); + result = true; + } + } return result; } @@ -619,6 +635,10 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> changed = (mIsActiveDeviceHearingAid != isActive); mIsActiveDeviceHearingAid = isActive; break; + case BluetoothProfile.LE_AUDIO: + changed = (mIsActiveDeviceLeAudio != isActive); + mIsActiveDeviceLeAudio = isActive; + break; default: Log.w(TAG, "onActiveDeviceChanged: unknown profile " + bluetoothProfile + " isActive " + isActive); @@ -650,6 +670,8 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> return mIsActiveDeviceHeadset; case BluetoothProfile.HEARING_AID: return mIsActiveDeviceHearingAid; + case BluetoothProfile.LE_AUDIO: + return mIsActiveDeviceLeAudio; default: Log.w(TAG, "getActiveDevice: unknown profile " + bluetoothProfile); break; @@ -744,6 +766,10 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> if (hearingAidProfile != null) { mIsActiveDeviceHearingAid = hearingAidProfile.getActiveDevices().contains(mDevice); } + LeAudioProfile leAudio = mProfileManager.getLeAudioProfile(); + if (leAudio != null) { + mIsActiveDeviceLeAudio = leAudio.getActiveDevices().contains(mDevice); + } } /** @@ -984,6 +1010,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> boolean a2dpConnected = true; // A2DP is connected boolean hfpConnected = true; // HFP is connected boolean hearingAidConnected = true; // Hearing Aid is connected + boolean leAudioConnected = true; // LeAudio is connected int leftBattery = -1; int rightBattery = -1; @@ -1015,6 +1042,8 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> hfpConnected = false; } else if (profile instanceof HearingAidProfile) { hearingAidConnected = false; + } else if (profile instanceof LeAudioProfile) { + leAudioConnected = false; } } break; @@ -1057,7 +1086,8 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> // 1. Hearing Aid device active. // 2. Headset device active with in-calling state. // 3. A2DP device active without in-calling state. - if (a2dpConnected || hfpConnected || hearingAidConnected) { + // 4. Le Audio device active + if (a2dpConnected || hfpConnected || hearingAidConnected || leAudioConnected) { final boolean isOnCall = Utils.isAudioModeOngoingCall(mContext); if ((mIsActiveDeviceHearingAid) || (mIsActiveDeviceHeadset && isOnCall) @@ -1092,7 +1122,8 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> private boolean isProfileConnectedFail() { return mIsA2dpProfileConnectedFail || mIsHearingAidProfileConnectedFail - || (!isConnectedSapDevice() && mIsHeadsetProfileConnectedFail); + || (!isConnectedSapDevice() && mIsHeadsetProfileConnectedFail) + || mIsLeAudioProfileConnectedFail; } /** @@ -1103,6 +1134,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> boolean a2dpNotConnected = false; // A2DP is preferred but not connected boolean hfpNotConnected = false; // HFP is preferred but not connected boolean hearingAidNotConnected = false; // Hearing Aid is preferred but not connected + boolean leAudioNotConnected = false; // LeAudio is preferred but not connected synchronized (mProfileLock) { for (LocalBluetoothProfile profile : getProfiles()) { @@ -1128,6 +1160,8 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> hfpNotConnected = true; } else if (profile instanceof HearingAidProfile) { hearingAidNotConnected = true; + } else if (profile instanceof LeAudioProfile) { + leAudioNotConnected = true; } } break; @@ -1166,6 +1200,11 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> return mContext.getString(R.string.bluetooth_connected, activeDeviceString); } + if (!leAudioNotConnected && mIsActiveDeviceLeAudio) { + activeDeviceString = activeDeviceStringsArray[1]; + return mContext.getString(R.string.bluetooth_connected, activeDeviceString); + } + if (profileConnected) { if (a2dpNotConnected && hfpNotConnected) { if (batteryLevelPercentageString != null) { @@ -1235,6 +1274,15 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> BluetoothProfile.STATE_CONNECTED; } + /** + * @return {@code true} if {@code cachedBluetoothDevice} is LeAudio device + */ + public boolean isConnectedLeAudioDevice() { + LeAudioProfile leAudio = mProfileManager.getLeAudioProfile(); + return leAudio != null && leAudio.getConnectionStatus(mDevice) == + BluetoothProfile.STATE_CONNECTED; + } + private boolean isConnectedSapDevice() { SapProfile sapProfile = mProfileManager.getSapProfile(); return sapProfile != null && sapProfile.getConnectionStatus(mDevice) diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java index 1f75ae329f4a..b429fe6d4939 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java @@ -340,22 +340,24 @@ public class CachedBluetoothDeviceManager { /** * Called when we found a set member of a group. The function will check the {@code groupId} if - * it exists and if there is a ongoing pair, the device would be ignored. + * it exists and the bond state of the device is BOND_NOE, and if there isn't any ongoing pair + * , and then return {@code true} to pair the device automatically. * * @param device The found device * @param groupId The group id of the found device + * + * @return {@code true}, if the device should pair automatically; Otherwise, return + * {@code false}. */ - public synchronized void onSetMemberAppear(BluetoothDevice device, int groupId) { - Log.d(TAG, "onSetMemberAppear, groupId: " + groupId + " device: " + device.toString()); - - if (mOngoingSetMemberPair != null) { - Log.d(TAG, "Ongoing set memberPairing in process, drop it!"); - return; + public synchronized boolean shouldPairByCsip(BluetoothDevice device, int groupId) { + if (mOngoingSetMemberPair != null || device.getBondState() != BluetoothDevice.BOND_NONE + || !mCsipDeviceManager.isExistedGroupId(groupId)) { + return false; } - if (mCsipDeviceManager.onSetMemberAppear(device, groupId)) { - mOngoingSetMemberPair = device; - } + Log.d(TAG, "Bond " + device.getName() + " by CSIP"); + mOngoingSetMemberPair = device; + return true; } /** diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java index 347e14b91656..1d29966838d3 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java @@ -240,22 +240,15 @@ public class CsipDeviceManager { } /** - * Called when we found a set member of a group. The function will check bond state, and - * the {@code groupId} if it exists, and then create the bond. + * Check if the {@code groupId} is existed. * - * @param device The found device - * @param groupId The group id of the found device + * @param groupId The group id * - * @return {@code true}, if the we create bond with the device. Otherwise, return - * {@code false}. + * @return {@code true}, if we could find a device with this {@code groupId}; Otherwise, + * return {@code false}. */ - public boolean onSetMemberAppear(BluetoothDevice device, int groupId) { - if (device.getBondState() != BluetoothDevice.BOND_NONE) { - return false; - } - + public boolean isExistedGroupId(int groupId) { if (getCachedDevice(groupId) != null) { - device.createBond(BluetoothDevice.TRANSPORT_LE); return true; } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java new file mode 100644 index 000000000000..209507ac7088 --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java @@ -0,0 +1,264 @@ +/* Copyright 2021 HIMSA II K/S - www.himsa.com. Represented by EHIMA +- www.ehima.com +*/ + +/* 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.settingslib.bluetooth; + +import static android.bluetooth.BluetoothAdapter.ACTIVE_DEVICE_ALL; +import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED; +import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; + +import android.bluetooth.BluetoothLeAudio; +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothClass; +import android.bluetooth.BluetoothCodecConfig; +import android.bluetooth.BluetoothCodecStatus; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothProfile; +import android.bluetooth.BluetoothUuid; +import android.content.Context; +import android.os.Build; +import android.os.ParcelUuid; +import android.util.Log; + +import androidx.annotation.RequiresApi; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.settingslib.R; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class LeAudioProfile implements LocalBluetoothProfile { + private static final String TAG = "LeAudioProfile"; + private static boolean DEBUG = true; + + private Context mContext; + + private BluetoothLeAudio mService; + private boolean mIsProfileReady; + + private final CachedBluetoothDeviceManager mDeviceManager; + + static final String NAME = "LE_AUDIO"; + private final LocalBluetoothProfileManager mProfileManager; + private final BluetoothAdapter mBluetoothAdapter; + + // Order of this profile in device profiles list + private static final int ORDINAL = 1; + + // These callbacks run on the main thread. + private final class LeAudioServiceListener + implements BluetoothProfile.ServiceListener { + + @RequiresApi(Build.VERSION_CODES.S) + public void onServiceConnected(int profile, BluetoothProfile proxy) { + if (DEBUG) { + Log.d(TAG,"Bluetooth service connected"); + } + mService = (BluetoothLeAudio) proxy; + // We just bound to the service, so refresh the UI for any connected LeAudio devices. + List<BluetoothDevice> deviceList = mService.getConnectedDevices(); + while (!deviceList.isEmpty()) { + BluetoothDevice nextDevice = deviceList.remove(0); + CachedBluetoothDevice device = mDeviceManager.findDevice(nextDevice); + // we may add a new device here, but generally this should not happen + if (device == null) { + if (DEBUG) { + Log.d(TAG, "LeAudioProfile found new device: " + nextDevice); + } + device = mDeviceManager.addDevice(nextDevice); + } + device.onProfileStateChanged(LeAudioProfile.this, + BluetoothProfile.STATE_CONNECTED); + device.refresh(); + } + + mProfileManager.callServiceConnectedListeners(); + mIsProfileReady = true; + } + + public void onServiceDisconnected(int profile) { + if (DEBUG) { + Log.d(TAG,"Bluetooth service disconnected"); + } + mProfileManager.callServiceDisconnectedListeners(); + mIsProfileReady = false; + } + } + + public boolean isProfileReady() { + return mIsProfileReady; + } + + @Override + public int getProfileId() { + return BluetoothProfile.LE_AUDIO; + } + + LeAudioProfile(Context context, CachedBluetoothDeviceManager deviceManager, + LocalBluetoothProfileManager profileManager) { + mContext = context; + mDeviceManager = deviceManager; + mProfileManager = profileManager; + + mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); + mBluetoothAdapter.getProfileProxy( + context, new LeAudioServiceListener(), + BluetoothProfile.LE_AUDIO); + } + + public boolean accessProfileEnabled() { + return true; + } + + public boolean isAutoConnectable() { + return true; + } + + public List<BluetoothDevice> getConnectedDevices() { + if (mService == null) { + return new ArrayList<BluetoothDevice>(0); + } + return mService.getDevicesMatchingConnectionStates( + new int[] {BluetoothProfile.STATE_CONNECTED, + BluetoothProfile.STATE_CONNECTING, + BluetoothProfile.STATE_DISCONNECTING}); + } + + /* + * @hide + */ + public boolean connect(BluetoothDevice device) { + if (mService == null) { + return false; + } + return mService.connect(device); + } + + /* + * @hide + */ + public boolean disconnect(BluetoothDevice device) { + if (mService == null) { + return false; + } + return mService.disconnect(device); + } + + public int getConnectionStatus(BluetoothDevice device) { + if (mService == null) { + return BluetoothProfile.STATE_DISCONNECTED; + } + return mService.getConnectionState(device); + } + + public boolean setActiveDevice(BluetoothDevice device) { + if (mBluetoothAdapter == null) { + return false; + } + return device == null + ? mBluetoothAdapter.removeActiveDevice(ACTIVE_DEVICE_ALL) + : mBluetoothAdapter.setActiveDevice(device, ACTIVE_DEVICE_ALL); + } + + public List<BluetoothDevice> getActiveDevices() { + if (mService == null) { + return new ArrayList<>(); + } + return mService.getActiveDevices(); + } + + @Override + public boolean isEnabled(BluetoothDevice device) { + if (mService == null || device == null) { + return false; + } + return mService.getConnectionPolicy(device) > CONNECTION_POLICY_FORBIDDEN; + } + + @Override + public int getConnectionPolicy(BluetoothDevice device) { + if (mService == null || device == null) { + return CONNECTION_POLICY_FORBIDDEN; + } + return mService.getConnectionPolicy(device); + } + + @Override + public boolean setEnabled(BluetoothDevice device, boolean enabled) { + boolean isEnabled = false; + if (mService == null || device == null) { + return false; + } + if (enabled) { + if (mService.getConnectionPolicy(device) < CONNECTION_POLICY_ALLOWED) { + isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED); + } + } else { + isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN); + } + + return isEnabled; + } + + public String toString() { + return NAME; + } + + public int getOrdinal() { + return ORDINAL; + } + + public int getNameResource(BluetoothDevice device) { + return R.string.bluetooth_profile_le_audio; + } + + public int getSummaryResourceForDevice(BluetoothDevice device) { + int state = getConnectionStatus(device); + switch (state) { + case BluetoothProfile.STATE_DISCONNECTED: + return R.string.bluetooth_le_audio_profile_summary_use_for; + + case BluetoothProfile.STATE_CONNECTED: + return R.string.bluetooth_le_audio_profile_summary_connected; + + default: + return BluetoothUtils.getConnectionStateSummary(state); + } + } + + public int getDrawableResource(BluetoothClass btClass) { + return R.drawable.ic_bt_le_audio; + } + + @RequiresApi(Build.VERSION_CODES.S) + protected void finalize() { + if (DEBUG) { + Log.d(TAG, "finalize()"); + } + if (mService != null) { + try { + BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.LE_AUDIO, + mService); + mService = null; + }catch (Throwable t) { + Log.w(TAG, "Error cleaning up LeAudio proxy", t); + } + } + } +} diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java index bcb345584ff3..334792048105 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java @@ -24,6 +24,7 @@ import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothHeadset; import android.bluetooth.BluetoothHeadsetClient; import android.bluetooth.BluetoothHearingAid; +import android.bluetooth.BluetoothLeAudio; import android.bluetooth.BluetoothHidDevice; import android.bluetooth.BluetoothHidHost; import android.bluetooth.BluetoothMap; @@ -102,6 +103,7 @@ public class LocalBluetoothProfileManager { private PbapServerProfile mPbapProfile; private HearingAidProfile mHearingAidProfile; private CsipSetCoordinatorProfile mCsipSetCoordinatorProfile; + private LeAudioProfile mLeAudioProfile; private SapProfile mSapProfile; private VolumeControlProfile mVolumeControlProfile; @@ -232,6 +234,14 @@ public class LocalBluetoothProfileManager { // Note: no event handler for VCP, only for being connectable. mProfileNameMap.put(VolumeControlProfile.NAME, mVolumeControlProfile); } + if (mLeAudioProfile == null && supportedList.contains(BluetoothProfile.LE_AUDIO)) { + if (DEBUG) { + Log.d(TAG, "Adding local LE_AUDIO profile"); + } + mLeAudioProfile = new LeAudioProfile(mContext, mDeviceManager, this); + addProfile(mLeAudioProfile, LeAudioProfile.NAME, + BluetoothLeAudio.ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED); + } if (mCsipSetCoordinatorProfile == null && supportedList.contains(BluetoothProfile.CSIP_SET_COORDINATOR)) { if (DEBUG) { @@ -487,6 +497,10 @@ public class LocalBluetoothProfileManager { return mHearingAidProfile; } + public LeAudioProfile getLeAudioProfile() { + return mLeAudioProfile; + } + SapProfile getSapProfile() { return mSapProfile; } @@ -614,6 +628,11 @@ public class LocalBluetoothProfileManager { removedProfiles.remove(mHearingAidProfile); } + if (ArrayUtils.contains(uuids, BluetoothUuid.LE_AUDIO) && mLeAudioProfile != null) { + profiles.add(mLeAudioProfile); + removedProfiles.remove(mLeAudioProfile); + } + if (mSapProfile != null && ArrayUtils.contains(uuids, BluetoothUuid.SAP)) { profiles.add(mSapProfile); removedProfiles.remove(mSapProfile); diff --git a/packages/SettingsLib/src/com/android/settingslib/inputmethod/OWNERS b/packages/SettingsLib/src/com/android/settingslib/inputmethod/OWNERS index a0e28baee3f6..e3e28cbcd3f2 100644 --- a/packages/SettingsLib/src/com/android/settingslib/inputmethod/OWNERS +++ b/packages/SettingsLib/src/com/android/settingslib/inputmethod/OWNERS @@ -1,5 +1,3 @@ -# Default reviewers for this and subdirectories. -takaoka@google.com -yukawa@google.com +# Bug component: 34867 -# Emergency approvers in case the above are not available
\ No newline at end of file +include platform/frameworks/base:/services/core/java/com/android/server/inputmethod/OWNERS
\ No newline at end of file diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java index 3c43f4a637ba..54230c8ef7c0 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java @@ -21,6 +21,7 @@ import static android.media.MediaRoute2Info.TYPE_DOCK; import static android.media.MediaRoute2Info.TYPE_GROUP; import static android.media.MediaRoute2Info.TYPE_HDMI; import static android.media.MediaRoute2Info.TYPE_HEARING_AID; +import static android.media.MediaRoute2Info.TYPE_BLE_HEADSET; import static android.media.MediaRoute2Info.TYPE_REMOTE_SPEAKER; import static android.media.MediaRoute2Info.TYPE_REMOTE_TV; import static android.media.MediaRoute2Info.TYPE_UNKNOWN; @@ -481,6 +482,7 @@ public class InfoMediaManager extends MediaManager { break; case TYPE_HEARING_AID: case TYPE_BLUETOOTH_A2DP: + case TYPE_BLE_HEADSET: final BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(route.getAddress()); final CachedBluetoothDevice cachedDevice = diff --git a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java index 22001c9c925a..215e2a06e442 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java @@ -38,6 +38,7 @@ import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager; import com.android.settingslib.bluetooth.HearingAidProfile; import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.settingslib.bluetooth.LocalBluetoothProfile; +import com.android.settingslib.bluetooth.LeAudioProfile; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -440,6 +441,7 @@ public class LocalMediaManager implements BluetoothCallback { private boolean isActiveDevice(CachedBluetoothDevice device) { boolean isActiveDeviceA2dp = false; boolean isActiveDeviceHearingAid = false; + boolean isActiveLeAudio = false; final A2dpProfile a2dpProfile = mLocalBluetoothManager.getProfileManager().getA2dpProfile(); if (a2dpProfile != null) { isActiveDeviceA2dp = device.getDevice().equals(a2dpProfile.getActiveDevice()); @@ -453,7 +455,15 @@ public class LocalMediaManager implements BluetoothCallback { } } - return isActiveDeviceA2dp || isActiveDeviceHearingAid; + if (!isActiveDeviceA2dp && !isActiveDeviceHearingAid) { + final LeAudioProfile leAudioProfile = mLocalBluetoothManager.getProfileManager() + .getLeAudioProfile(); + if (leAudioProfile != null) { + isActiveLeAudio = leAudioProfile.getActiveDevices().contains(device.getDevice()); + } + } + + return isActiveDeviceA2dp || isActiveDeviceHearingAid || isActiveLeAudio; } private Collection<DeviceCallback> getCallbacks() { @@ -526,7 +536,7 @@ public class LocalMediaManager implements BluetoothCallback { if (cachedDevice != null) { if (cachedDevice.getBondState() == BluetoothDevice.BOND_BONDED && !cachedDevice.isConnected() - && isA2dpOrHearingAidDevice(cachedDevice)) { + && isMediaDevice(cachedDevice)) { deviceCount++; cachedBluetoothDeviceList.add(cachedDevice); if (deviceCount >= MAX_DISCONNECTED_DEVICE_NUM) { @@ -550,9 +560,10 @@ public class LocalMediaManager implements BluetoothCallback { return new ArrayList<>(mDisconnectedMediaDevices); } - private boolean isA2dpOrHearingAidDevice(CachedBluetoothDevice device) { + private boolean isMediaDevice(CachedBluetoothDevice device) { for (LocalBluetoothProfile profile : device.getConnectableProfiles()) { - if (profile instanceof A2dpProfile || profile instanceof HearingAidProfile) { + if (profile instanceof A2dpProfile || profile instanceof HearingAidProfile || + profile instanceof LeAudioProfile) { return true; } } diff --git a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java index f21c3598a23d..a49d7f60a479 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java @@ -29,6 +29,7 @@ import static android.media.MediaRoute2Info.TYPE_USB_DEVICE; import static android.media.MediaRoute2Info.TYPE_USB_HEADSET; import static android.media.MediaRoute2Info.TYPE_WIRED_HEADPHONES; import static android.media.MediaRoute2Info.TYPE_WIRED_HEADSET; +import static android.media.MediaRoute2Info.TYPE_BLE_HEADSET; import android.content.Context; import android.content.res.ColorStateList; @@ -122,6 +123,7 @@ public abstract class MediaDevice implements Comparable<MediaDevice> { break; case TYPE_HEARING_AID: case TYPE_BLUETOOTH_A2DP: + case TYPE_BLE_HEADSET: mType = MediaDeviceType.TYPE_BLUETOOTH_DEVICE; break; case TYPE_UNKNOWN: diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaDeviceTest.java index e887c45083c0..f50802a1702e 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaDeviceTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaDeviceTest.java @@ -52,6 +52,7 @@ public class BluetoothMediaDeviceTest { when(mDevice.isActiveDevice(BluetoothProfile.A2DP)).thenReturn(true); when(mDevice.isActiveDevice(BluetoothProfile.HEARING_AID)).thenReturn(true); + when(mDevice.isActiveDevice(BluetoothProfile.LE_AUDIO)).thenReturn(true); mBluetoothMediaDevice = new BluetoothMediaDevice(mContext, mDevice, null, null, null); } diff --git a/packages/SettingsProvider/OWNERS b/packages/SettingsProvider/OWNERS index 6c61d4b91d36..5ade9716c8cb 100644 --- a/packages/SettingsProvider/OWNERS +++ b/packages/SettingsProvider/OWNERS @@ -2,6 +2,4 @@ hackbod@android.com hackbod@google.com narayan@google.com svetoslavganov@google.com -schfan@google.com -toddke@google.com -patb@google.com +include /PACKAGE_MANAGER_OWNERS diff --git a/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java b/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java index 89786ee880ad..a617850ef0ae 100644 --- a/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java +++ b/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java @@ -139,7 +139,7 @@ public class NotificationPlayer implements OnCompletionListener, OnErrorListener + " with ducking", e); } player.start(); - if (DEBUG) { Log.d(mTag, "player.start"); } + if (DEBUG) { Log.d(mTag, "player.start piid:" + player.getPlayerIId()); } } catch (Exception e) { if (player != null) { player.release(); @@ -155,7 +155,13 @@ public class NotificationPlayer implements OnCompletionListener, OnErrorListener mPlayer = player; } if (mp != null) { - if (DEBUG) { Log.d(mTag, "mPlayer.release"); } + if (DEBUG) { + Log.d(mTag, "mPlayer.pause+release piid:" + player.getPlayerIId()); + } + mp.pause(); + try { + Thread.sleep(100); + } catch (InterruptedException ie) { } mp.release(); } this.notify(); @@ -244,6 +250,10 @@ public class NotificationPlayer implements OnCompletionListener, OnErrorListener try { mp.stop(); } catch (Exception e) { } + if (DEBUG) { + Log.i(mTag, "About to release MediaPlayer piid:" + + mp.getPlayerIId() + " due to notif cancelled"); + } mp.release(); synchronized(mQueueAudioFocusLock) { if (mAudioManagerWithAudioFocus != null) { @@ -284,7 +294,7 @@ public class NotificationPlayer implements OnCompletionListener, OnErrorListener public void onCompletion(MediaPlayer mp) { synchronized(mQueueAudioFocusLock) { if (mAudioManagerWithAudioFocus != null) { - if (DEBUG) Log.d(mTag, "onCompletion() abandonning AudioFocus"); + if (DEBUG) Log.d(mTag, "onCompletion() abandoning AudioFocus"); mAudioManagerWithAudioFocus.abandonAudioFocus(null); mAudioManagerWithAudioFocus = null; } else { @@ -310,6 +320,10 @@ public class NotificationPlayer implements OnCompletionListener, OnErrorListener } } if (mp != null) { + if (DEBUG) { + Log.i("NotificationPlayer", "About to release MediaPlayer piid:" + + mp.getPlayerIId() + " due to onCompletion"); + } mp.release(); } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java index 541ee2c4fe8f..4a75810f86db 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java @@ -51,6 +51,7 @@ import com.android.systemui.qs.external.TileServices; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.settings.UserTracker; import com.android.systemui.shared.plugins.PluginManager; +import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.statusbar.phone.AutoTileManager; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.phone.StatusBarIconController; @@ -95,6 +96,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D private final UiEventLogger mUiEventLogger; private final InstanceIdSequence mInstanceIdSequence; private final CustomTileStatePersister mCustomTileStatePersister; + private final FeatureFlags mFeatureFlags; private final List<Callback> mCallbacks = new ArrayList<>(); private AutoTileManager mAutoTiles; @@ -122,7 +124,8 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D UiEventLogger uiEventLogger, UserTracker userTracker, SecureSettings secureSettings, - CustomTileStatePersister customTileStatePersister + CustomTileStatePersister customTileStatePersister, + FeatureFlags featureFlags ) { mIconController = iconController; mContext = context; @@ -144,6 +147,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D mUserTracker = userTracker; mSecureSettings = secureSettings; mCustomTileStatePersister = customTileStatePersister; + mFeatureFlags = featureFlags; mainHandler.post(() -> { // This is technically a hack to avoid circular dependency of @@ -265,7 +269,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D if (newValue == null && UserManager.isDeviceInDemoMode(mContext)) { newValue = mContext.getResources().getString(R.string.quick_settings_tiles_retail_mode); } - final List<String> tileSpecs = loadTileSpecs(mContext, newValue); + final List<String> tileSpecs = loadTileSpecs(mContext, newValue, mFeatureFlags); int currentUser = mUserTracker.getUserId(); if (currentUser != mCurrentUser) { mUserContext = mUserTracker.getUserContext(); @@ -334,7 +338,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D if (newTiles.isEmpty() && !tileSpecs.isEmpty()) { // If we didn't manage to create any tiles, set it to empty (default) Log.d(TAG, "No valid tiles on tuning changed. Setting to default."); - changeTiles(currentSpecs, loadTileSpecs(mContext, "")); + changeTiles(currentSpecs, loadTileSpecs(mContext, "", mFeatureFlags)); } else { for (int i = 0; i < mCallbacks.size(); i++) { mCallbacks.get(i).onTilesChanged(); @@ -389,7 +393,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D private void changeTileSpecs(Predicate<List<String>> changeFunction) { final String setting = mSecureSettings.getStringForUser(TILES_SETTING, mCurrentUser); - final List<String> tileSpecs = loadTileSpecs(mContext, setting); + final List<String> tileSpecs = loadTileSpecs(mContext, setting, mFeatureFlags); if (changeFunction.test(tileSpecs)) { saveTilesToSettings(tileSpecs); } @@ -478,7 +482,8 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D throw new RuntimeException("Default factory didn't create view for " + tile.getTileSpec()); } - protected static List<String> loadTileSpecs(Context context, String tileList) { + protected static List<String> loadTileSpecs( + Context context, String tileList, FeatureFlags featureFlags) { final Resources res = context.getResources(); if (TextUtils.isEmpty(tileList)) { @@ -511,6 +516,21 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D } } } + if (featureFlags.isProviderModelSettingEnabled()) { + if (!tiles.contains("internet")) { + if (tiles.contains("wifi")) { + // Replace the WiFi with Internet, and remove the Cell + tiles.set(tiles.indexOf("wifi"), "internet"); + tiles.remove("cell"); + } else if (tiles.contains("cell")) { + // Replace the Cell with Internet + tiles.set(tiles.indexOf("cell"), "internet"); + } + } else { + tiles.remove("wifi"); + tiles.remove("cell"); + } + } return tiles; } diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java index 3c2f35b954ea..f2832b3d45ff 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java +++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java @@ -41,6 +41,7 @@ import com.android.systemui.qs.dagger.QSScope; import com.android.systemui.qs.external.CustomTile; import com.android.systemui.qs.tileimpl.QSTileImpl.DrawableIcon; import com.android.systemui.settings.UserTracker; +import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.util.leak.GarbageMonitor; import java.util.ArrayList; @@ -62,6 +63,7 @@ public class TileQueryHelper { private final Executor mBgExecutor; private final Context mContext; private final UserTracker mUserTracker; + private final FeatureFlags mFeatureFlags; private TileStateListener mListener; private boolean mFinished; @@ -71,12 +73,14 @@ public class TileQueryHelper { Context context, UserTracker userTracker, @Main Executor mainExecutor, - @Background Executor bgExecutor + @Background Executor bgExecutor, + FeatureFlags featureFlags ) { mContext = context; mMainExecutor = mainExecutor; mBgExecutor = bgExecutor; mUserTracker = userTracker; + mFeatureFlags = featureFlags; } public void setListener(TileStateListener listener) { @@ -117,6 +121,10 @@ public class TileQueryHelper { } final ArrayList<QSTile> tilesToAdd = new ArrayList<>(); + if (mFeatureFlags.isProviderModelSettingEnabled()) { + possibleTiles.remove("cell"); + possibleTiles.remove("wifi"); + } for (String spec : possibleTiles) { // Only add current and stock tiles that can be created from QSFactoryImpl. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java index 86c90c7bcb2e..9eb95c409009 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java @@ -16,7 +16,6 @@ package com.android.systemui.statusbar.notification.row; -import android.annotation.ColorInt; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; @@ -28,15 +27,12 @@ import com.android.systemui.statusbar.notification.stack.ExpandableViewState; import com.android.systemui.statusbar.notification.stack.ViewState; public class FooterView extends StackScrollerDecorView { - private final int mClearAllTopPadding; private FooterViewButton mDismissButton; private FooterViewButton mManageButton; private boolean mShowHistory; public FooterView(Context context, AttributeSet attrs) { super(context, attrs); - mClearAllTopPadding = context.getResources().getDimensionPixelSize( - R.dimen.clear_all_padding_top); } @Override @@ -55,11 +51,6 @@ public class FooterView extends StackScrollerDecorView { mManageButton = findViewById(R.id.manage_text); } - public void setTextColor(@ColorInt int color) { - mManageButton.setTextColor(color); - mDismissButton.setTextColor(color); - } - public void setManageButtonClickListener(OnClickListener listener) { mManageButton.setOnClickListener(listener); } @@ -95,21 +86,25 @@ public class FooterView extends StackScrollerDecorView { @Override protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); - int textColor = getResources().getColor(R.color.notif_pill_text); - Resources.Theme theme = getContext().getTheme(); - mDismissButton.setBackground( - getResources().getDrawable(R.drawable.notif_footer_btn_background, theme)); - mDismissButton.setTextColor(textColor); - mManageButton.setBackground( - getResources().getDrawable(R.drawable.notif_footer_btn_background, theme)); - mManageButton = findViewById(R.id.manage_text); + updateColors(); mDismissButton.setText(R.string.clear_all_notifications_text); - mManageButton.setTextColor(textColor); mDismissButton.setContentDescription( mContext.getString(R.string.accessibility_clear_all)); showHistory(mShowHistory); } + /** + * Update the text and background colors for the current color palette and night mode setting. + */ + public void updateColors() { + Resources.Theme theme = mContext.getTheme(); + int textColor = getResources().getColor(R.color.notif_pill_text, theme); + mDismissButton.setBackground(theme.getDrawable(R.drawable.notif_footer_btn_background)); + mDismissButton.setTextColor(textColor); + mManageButton.setBackground(theme.getDrawable(R.drawable.notif_footer_btn_background)); + mManageButton.setTextColor(textColor); + } + @Override public ExpandableViewState createExpandableViewState() { return new FooterViewState(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index 289c32f17b31..0660daab3720 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -4231,7 +4231,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable final @ColorInt int textColor = Utils.getColorAttrDefaultColor(mContext, android.R.attr.textColorPrimary); mSectionsManager.setHeaderForegroundColor(textColor); - mFooterView.setTextColor(textColor); + mFooterView.updateColors(); mEmptyShadeView.setTextColor(textColor); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java index 3ee3e55c749a..7f89b2629a6a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java @@ -139,7 +139,7 @@ public class QSFragmentTest extends SysuiBaseFragmentTest { () -> mock(AutoTileManager.class), mock(DumpManager.class), mock(BroadcastDispatcher.class), Optional.of(mock(StatusBar.class)), mock(QSLogger.class), mock(UiEventLogger.class), mock(UserTracker.class), - mock(SecureSettings.class), mock(CustomTileStatePersister.class)); + mock(SecureSettings.class), mock(CustomTileStatePersister.class), mFeatureFlags); qs.setHost(host); qs.setListening(true); diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java index 9e97f801be3e..4cbad5f15c5f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java @@ -63,6 +63,7 @@ import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.settings.UserTracker; import com.android.systemui.shared.plugins.PluginManager; +import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.statusbar.phone.AutoTileManager; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.phone.StatusBarIconController; @@ -124,6 +125,8 @@ public class QSTileHostTest extends SysuiTestCase { private SecureSettings mSecureSettings; @Mock private CustomTileStatePersister mCustomTileStatePersister; + @Mock + private FeatureFlags mFeatureFlags; private Handler mHandler; private TestableLooper mLooper; @@ -137,9 +140,9 @@ public class QSTileHostTest extends SysuiTestCase { mQSTileHost = new TestQSTileHost(mContext, mIconController, mDefaultFactory, mHandler, mLooper.getLooper(), mPluginManager, mTunerService, mAutoTiles, mDumpManager, mBroadcastDispatcher, mStatusBar, mQSLogger, mUiEventLogger, mUserTracker, - mSecureSettings, mCustomTileStatePersister); + mSecureSettings, mCustomTileStatePersister, mFeatureFlags); setUpTileFactory(); - + when(mFeatureFlags.isProviderModelSettingEnabled()).thenReturn(false); when(mSecureSettings.getStringForUser(eq(QSTileHost.TILES_SETTING), anyInt())) .thenReturn(""); } @@ -169,13 +172,13 @@ public class QSTileHostTest extends SysuiTestCase { @Test public void testLoadTileSpecs_emptySetting() { - List<String> tiles = QSTileHost.loadTileSpecs(mContext, ""); + List<String> tiles = QSTileHost.loadTileSpecs(mContext, "", mFeatureFlags); assertFalse(tiles.isEmpty()); } @Test public void testLoadTileSpecs_nullSetting() { - List<String> tiles = QSTileHost.loadTileSpecs(mContext, null); + List<String> tiles = QSTileHost.loadTileSpecs(mContext, null, mFeatureFlags); assertFalse(tiles.isEmpty()); } @@ -189,6 +192,55 @@ public class QSTileHostTest extends SysuiTestCase { } @Test + public void testRemoveWifiAndCellularWithoutInternet() { + when(mFeatureFlags.isProviderModelSettingEnabled()).thenReturn(true); + mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "wifi, spec1, cell, spec2"); + + assertEquals("internet", mQSTileHost.mTileSpecs.get(0)); + assertEquals("spec1", mQSTileHost.mTileSpecs.get(1)); + assertEquals("spec2", mQSTileHost.mTileSpecs.get(2)); + } + + @Test + public void testRemoveWifiAndCellularWithInternet() { + when(mFeatureFlags.isProviderModelSettingEnabled()).thenReturn(true); + mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "wifi, spec1, cell, spec2, internet"); + + assertEquals("spec1", mQSTileHost.mTileSpecs.get(0)); + assertEquals("spec2", mQSTileHost.mTileSpecs.get(1)); + assertEquals("internet", mQSTileHost.mTileSpecs.get(2)); + } + + @Test + public void testRemoveWifiWithoutInternet() { + when(mFeatureFlags.isProviderModelSettingEnabled()).thenReturn(true); + mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1, wifi, spec2"); + + assertEquals("spec1", mQSTileHost.mTileSpecs.get(0)); + assertEquals("internet", mQSTileHost.mTileSpecs.get(1)); + assertEquals("spec2", mQSTileHost.mTileSpecs.get(2)); + } + + @Test + public void testRemoveCellWithInternet() { + when(mFeatureFlags.isProviderModelSettingEnabled()).thenReturn(true); + mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1, spec2, cell, internet"); + + assertEquals("spec1", mQSTileHost.mTileSpecs.get(0)); + assertEquals("spec2", mQSTileHost.mTileSpecs.get(1)); + assertEquals("internet", mQSTileHost.mTileSpecs.get(2)); + } + + @Test + public void testNoWifiNoCellularNoInternet() { + when(mFeatureFlags.isProviderModelSettingEnabled()).thenReturn(true); + mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1,spec2"); + + assertEquals("spec1", mQSTileHost.mTileSpecs.get(0)); + assertEquals("spec2", mQSTileHost.mTileSpecs.get(1)); + } + + @Test public void testSpecWithInvalidDoesNotUseDefault() { mContext.getOrCreateTestableResources() .addOverride(R.string.quick_settings_tiles, "spec1,spec2"); @@ -321,7 +373,7 @@ public class QSTileHostTest extends SysuiTestCase { @Test public void testLoadTileSpec_repeated() { - List<String> specs = QSTileHost.loadTileSpecs(mContext, "spec1,spec1,spec2"); + List<String> specs = QSTileHost.loadTileSpecs(mContext, "spec1,spec1,spec2", mFeatureFlags); assertEquals(2, specs.size()); assertEquals("spec1", specs.get(0)); @@ -332,7 +384,7 @@ public class QSTileHostTest extends SysuiTestCase { public void testLoadTileSpec_repeatedInDefault() { mContext.getOrCreateTestableResources() .addOverride(R.string.quick_settings_tiles_default, "spec1,spec1"); - List<String> specs = QSTileHost.loadTileSpecs(mContext, "default"); + List<String> specs = QSTileHost.loadTileSpecs(mContext, "default", mFeatureFlags); // Remove spurious tiles, like dbg:mem specs.removeIf(spec -> !"spec1".equals(spec)); @@ -343,7 +395,7 @@ public class QSTileHostTest extends SysuiTestCase { public void testLoadTileSpec_repeatedDefaultAndSetting() { mContext.getOrCreateTestableResources() .addOverride(R.string.quick_settings_tiles_default, "spec1"); - List<String> specs = QSTileHost.loadTileSpecs(mContext, "default,spec1"); + List<String> specs = QSTileHost.loadTileSpecs(mContext, "default,spec1", mFeatureFlags); // Remove spurious tiles, like dbg:mem specs.removeIf(spec -> !"spec1".equals(spec)); @@ -371,11 +423,12 @@ public class QSTileHostTest extends SysuiTestCase { Provider<AutoTileManager> autoTiles, DumpManager dumpManager, BroadcastDispatcher broadcastDispatcher, StatusBar statusBar, QSLogger qsLogger, UiEventLogger uiEventLogger, UserTracker userTracker, - SecureSettings secureSettings, CustomTileStatePersister customTileStatePersister) { + SecureSettings secureSettings, CustomTileStatePersister customTileStatePersister, + FeatureFlags featureFlags) { super(context, iconController, defaultFactory, mainHandler, bgLooper, pluginManager, tunerService, autoTiles, dumpManager, broadcastDispatcher, Optional.of(statusBar), qsLogger, uiEventLogger, userTracker, secureSettings, - customTileStatePersister); + customTileStatePersister, featureFlags); } @Override diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java index 4efcc5c3fc73..c5b67091d197 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java @@ -58,6 +58,7 @@ import com.android.systemui.plugins.qs.QSIconView; import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.qs.QSTileHost; import com.android.systemui.settings.UserTracker; +import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.time.FakeSystemClock; @@ -108,6 +109,8 @@ public class TileQueryHelperTest extends SysuiTestCase { private PackageManager mPackageManager; @Mock private UserTracker mUserTracker; + @Mock + private FeatureFlags mFeatureFlags; @Captor private ArgumentCaptor<List<TileQueryHelper.TileInfo>> mCaptor; @@ -133,12 +136,12 @@ public class TileQueryHelperTest extends SysuiTestCase { } } ).when(mQSTileHost).createTile(anyString()); - + when(mFeatureFlags.isProviderModelSettingEnabled()).thenReturn(false); FakeSystemClock clock = new FakeSystemClock(); mMainExecutor = new FakeExecutor(clock); mBgExecutor = new FakeExecutor(clock); mTileQueryHelper = new TileQueryHelper( - mContext, mUserTracker, mMainExecutor, mBgExecutor); + mContext, mUserTracker, mMainExecutor, mBgExecutor, mFeatureFlags); mTileQueryHelper.setListener(mListener); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java index 2b1840462291..01fa222896d3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java @@ -48,6 +48,7 @@ import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSFactoryImpl; import com.android.systemui.settings.UserTracker; import com.android.systemui.shared.plugins.PluginManager; +import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.statusbar.phone.AutoTileManager; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.phone.StatusBarIconController; @@ -98,6 +99,8 @@ public class TileServicesTest extends SysuiTestCase { private UserTracker mUserTracker; @Mock private SecureSettings mSecureSettings; + @Mock + private FeatureFlags mFeatureFlags; @Before public void setUp() throws Exception { @@ -119,7 +122,8 @@ public class TileServicesTest extends SysuiTestCase { mUiEventLogger, mUserTracker, mSecureSettings, - mock(CustomTileStatePersister.class)); + mock(CustomTileStatePersister.class), + mFeatureFlags); mTileService = new TestTileServices(host, Looper.getMainLooper(), mBroadcastDispatcher, mUserTracker); } diff --git a/packages/services/PacProcessor/src/com/android/pacprocessor/PacService.java b/packages/services/PacProcessor/src/com/android/pacprocessor/PacService.java index 46bda06d0e04..27d4ea71dfc0 100644 --- a/packages/services/PacProcessor/src/com/android/pacprocessor/PacService.java +++ b/packages/services/PacProcessor/src/com/android/pacprocessor/PacService.java @@ -21,6 +21,7 @@ import android.os.Binder; import android.os.IBinder; import android.os.Process; import android.os.RemoteException; +import android.os.UserManager; import android.util.Log; import android.webkit.PacProcessor; @@ -33,16 +34,44 @@ import java.net.URL; public class PacService extends Service { private static final String TAG = "PacService"; - private Object mLock = new Object(); + private final Object mLock = new Object(); + // Webkit PacProcessor cannot be instantiated before the user is unlocked, so this field is + // initialized lazily. @GuardedBy("mLock") - private final PacProcessor mPacProcessor = PacProcessor.getInstance(); + private PacProcessor mPacProcessor; + + // Stores PAC script when setPacFile is called before mPacProcessor is available. In case the + // script was already fed to the PacProcessor, it should be null. + @GuardedBy("mLock") + private String mPendingScript; private ProxyServiceStub mStub = new ProxyServiceStub(); @Override public void onCreate() { super.onCreate(); + + synchronized (mLock) { + checkPacProcessorLocked(); + } + } + + /** + * Initializes PacProcessor if it hasn't been initialized yet and if the system user is + * unlocked, e.g. after the user has entered their PIN after a reboot. + * Returns whether PacProcessor is available. + */ + private boolean checkPacProcessorLocked() { + if (mPacProcessor != null) { + return true; + } + UserManager um = getSystemService(UserManager.class); + if (um.isUserUnlocked()) { + mPacProcessor = PacProcessor.getInstance(); + return true; + } + return false; } @Override @@ -74,7 +103,20 @@ public class PacService extends Service { } synchronized (mLock) { - return mPacProcessor.findProxyForUrl(url); + if (checkPacProcessorLocked()) { + // Apply pending script in case it was set before processor was ready. + if (mPendingScript != null) { + if (!mPacProcessor.setProxyScript(mPendingScript)) { + Log.e(TAG, "Unable to parse proxy script."); + } + mPendingScript = null; + } + return mPacProcessor.findProxyForUrl(url); + } else { + Log.e(TAG, "PacProcessor isn't ready during early boot," + + " request will be direct"); + return null; + } } } catch (MalformedURLException e) { throw new IllegalArgumentException("Invalid URL was passed"); @@ -88,8 +130,13 @@ public class PacService extends Service { throw new SecurityException(); } synchronized (mLock) { - if (!mPacProcessor.setProxyScript(script)) { - Log.e(TAG, "Unable to parse proxy script."); + if (checkPacProcessorLocked()) { + if (!mPacProcessor.setProxyScript(script)) { + Log.e(TAG, "Unable to parse proxy script."); + } + } else { + Log.d(TAG, "PAC processor isn't ready, saving script for later."); + mPendingScript = script; } } } diff --git a/rs/jni/Android.bp b/rs/jni/Android.bp new file mode 100644 index 000000000000..9a6fa8e8e423 --- /dev/null +++ b/rs/jni/Android.bp @@ -0,0 +1,54 @@ +// +// 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. +// + +package { + // See: http://go/android-license-faq + default_applicable_licenses: ["frameworks_base_license"], +} + +cc_library_shared { + name: "librs_jni", + + srcs: ["android_renderscript_RenderScript.cpp"], + + shared_libs: [ + "libandroid", + "libandroid_runtime", + "libandroidfw", + "libRS", + "libcutils", + "libhwui", + "liblog", + "libutils", + "libui", + "libgui", + "libjnigraphics", + ], + + header_libs: [ + "jni_headers", + "libbase_headers", + ], + + include_dirs: ["frameworks/rs"], + + cflags: [ + "-Wno-unused-parameter", + "-Wunused", + "-Wunreachable-code", + "-Wno-deprecated-declarations", + ], +} diff --git a/rs/jni/Android.mk b/rs/jni/Android.mk deleted file mode 100644 index 0caba421dca8..000000000000 --- a/rs/jni/Android.mk +++ /dev/null @@ -1,37 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - android_renderscript_RenderScript.cpp - -LOCAL_SHARED_LIBRARIES := \ - libandroid \ - libandroid_runtime \ - libandroidfw \ - libRS \ - libcutils \ - libhwui \ - liblog \ - libutils \ - libui \ - libgui \ - libjnigraphics - -LOCAL_HEADER_LIBRARIES := \ - jni_headers \ - libbase_headers - -LOCAL_C_INCLUDES += \ - frameworks/rs - -LOCAL_CFLAGS += -Wno-unused-parameter -LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code -Wno-deprecated-declarations - -LOCAL_MODULE:= librs_jni -LOCAL_LICENSE_KINDS:= SPDX-license-identifier-Apache-2.0 -LOCAL_LICENSE_CONDITIONS:= notice -LOCAL_NOTICE_FILE:= $(LOCAL_PATH)/../../NOTICE -LOCAL_MODULE_TAGS := optional -LOCAL_REQUIRED_MODULES := libRS - -include $(BUILD_SHARED_LIBRARY) diff --git a/services/companion/OWNERS b/services/companion/OWNERS new file mode 100644 index 000000000000..cb4cc56ca17b --- /dev/null +++ b/services/companion/OWNERS @@ -0,0 +1,4 @@ +evanxinchen@google.com +ewol@google.com +guojing@google.com +svetoslavganov@google.com
\ No newline at end of file diff --git a/services/core/java/android/content/pm/OWNERS b/services/core/java/android/content/pm/OWNERS index 5eed0b509688..39931407ec1f 100644 --- a/services/core/java/android/content/pm/OWNERS +++ b/services/core/java/android/content/pm/OWNERS @@ -1 +1 @@ -include /core/java/android/content/pm/OWNERS
\ No newline at end of file +include /PACKAGE_MANAGER_OWNERS
\ No newline at end of file diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java index 1e608f5c1240..0146aa82a217 100644 --- a/services/core/java/com/android/server/BatteryService.java +++ b/services/core/java/com/android/server/BatteryService.java @@ -81,8 +81,6 @@ import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayDeque; import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; import java.util.NoSuchElementException; import java.util.Objects; import java.util.concurrent.atomic.AtomicReference; @@ -1435,11 +1433,7 @@ public final class BatteryService extends SystemService { */ public static final class HealthServiceWrapper { private static final String TAG = "HealthServiceWrapper"; - public static final String INSTANCE_HEALTHD = "backup"; public static final String INSTANCE_VENDOR = "default"; - // All interesting instances, sorted by priority high -> low. - private static final List<String> sAllInstances = - Arrays.asList(INSTANCE_VENDOR, INSTANCE_HEALTHD); private final IServiceNotification mNotification = new Notification(); private final HandlerThread mHandlerThread = new HandlerThread("HealthServiceHwbinder"); @@ -1471,8 +1465,8 @@ public final class BatteryService extends SystemService { } /** - * Start monitoring registration of new IHealth services. Only instances that are in - * {@code sAllInstances} and in device / framework manifest are used. This function should + * Start monitoring registration of new IHealth services. Only instance + * {@link #INSTANCE_VENDOR} and in device / framework manifest are used. This function should * only be called once. * * mCallback.onRegistration() is called synchronously (aka in init thread) before @@ -1481,7 +1475,7 @@ public final class BatteryService extends SystemService { * @throws RemoteException transaction error when talking to IServiceManager * @throws NoSuchElementException if one of the following cases: * - No service manager; - * - none of {@code sAllInstances} are in manifests (i.e. not + * - {@link #INSTANCE_VENDOR} is not in manifests (i.e. not * available on this device), or none of these instances are available to current * process. * @throws NullPointerException when supplier is null @@ -1499,26 +1493,23 @@ public final class BatteryService extends SystemService { // Initialize mLastService and call callback for the first time (in init thread) IHealth newService = null; - for (String name : sAllInstances) { - traceBegin("HealthInitGetService_" + name); - try { - newService = healthSupplier.get(name); - } catch (NoSuchElementException ex) { - /* ignored, handled below */ - } finally { - traceEnd(); - } - if (newService != null) { - mInstanceName = name; - mLastService.set(newService); - break; - } + traceBegin("HealthInitGetService_" + INSTANCE_VENDOR); + try { + newService = healthSupplier.get(INSTANCE_VENDOR); + } catch (NoSuchElementException ex) { + /* ignored, handled below */ + } finally { + traceEnd(); + } + if (newService != null) { + mInstanceName = INSTANCE_VENDOR; + mLastService.set(newService); } if (mInstanceName == null || newService == null) { throw new NoSuchElementException(String.format( - "No IHealth service instance among %s is available. Perhaps no permission?", - sAllInstances.toString())); + "IHealth service instance %s isn't available. Perhaps no permission?", + INSTANCE_VENDOR)); } if (callback != null) { diff --git a/services/core/java/com/android/server/BootReceiver.java b/services/core/java/com/android/server/BootReceiver.java index fdba098e6b80..469f465d7c9a 100644 --- a/services/core/java/com/android/server/BootReceiver.java +++ b/services/core/java/com/android/server/BootReceiver.java @@ -476,7 +476,11 @@ public class BootReceiver extends BroadcastReceiver { */ public static void addTombstoneToDropBox(Context ctx, File tombstone, boolean proto) { final DropBoxManager db = ctx.getSystemService(DropBoxManager.class); - final String bootReason = SystemProperties.get("ro.boot.bootreason", null); + if (db == null) { + Slog.e(TAG, "Can't log tombstone: DropBoxManager not available"); + return; + } + HashMap<String, Long> timestamps = readTimestamps(); try { if (proto) { diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index d6ee95131ea9..aeb814327e66 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -58,13 +58,13 @@ import android.system.OsConstants; import android.text.TextUtils; import android.util.Log; import android.util.Range; -import android.util.Slog; import android.util.SparseArray; import android.util.SparseBooleanArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Preconditions; +import com.android.net.module.util.BinderUtils; import com.android.net.module.util.NetdUtils; import com.android.net.module.util.PermissionUtils; @@ -1056,9 +1056,9 @@ public class IpSecService extends IIpSecService.Stub { public void systemReady() { if (isNetdAlive()) { - Slog.d(TAG, "IpSecService is ready"); + Log.d(TAG, "IpSecService is ready"); } else { - Slog.wtf(TAG, "IpSecService not ready: failed to connect to NetD Native Service!"); + Log.wtf(TAG, "IpSecService not ready: failed to connect to NetD Native Service!"); } } @@ -1332,7 +1332,7 @@ public class IpSecService extends IIpSecService.Stub { final INetd netd = mSrvConfig.getNetdInstance(); netd.ipSecAddTunnelInterface(intfName, localAddr, remoteAddr, ikey, okey, resourceId); - Binder.withCleanCallingIdentity(() -> { + BinderUtils.withCleanCallingIdentity(() -> { NetdUtils.setInterfaceUp(netd, intfName); }); diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java index 3ea0ce173745..c7e906876526 100644 --- a/services/core/java/com/android/server/NetworkManagementService.java +++ b/services/core/java/com/android/server/NetworkManagementService.java @@ -59,9 +59,6 @@ import android.net.NetworkStats; import android.net.RouteInfo; import android.net.TetherStatsParcel; import android.net.UidRangeParcel; -import android.net.shared.NetdUtils; -import android.net.shared.RouteUtils; -import android.net.shared.RouteUtils.ModifyOperation; import android.net.util.NetdService; import android.os.BatteryStats; import android.os.Binder; @@ -88,6 +85,8 @@ import com.android.internal.app.IBatteryStats; import com.android.internal.util.DumpUtils; import com.android.internal.util.HexDump; import com.android.internal.util.Preconditions; +import com.android.net.module.util.NetdUtils; +import com.android.net.module.util.NetdUtils.ModifyOperation; import com.google.android.collect.Maps; @@ -831,13 +830,13 @@ public class NetworkManagementService extends INetworkManagementService.Stub { @Override public void addRoute(int netId, RouteInfo route) { NetworkStack.checkNetworkStackPermission(mContext); - RouteUtils.modifyRoute(mNetdService, ModifyOperation.ADD, netId, route); + NetdUtils.modifyRoute(mNetdService, ModifyOperation.ADD, netId, route); } @Override public void removeRoute(int netId, RouteInfo route) { NetworkStack.checkNetworkStackPermission(mContext); - RouteUtils.modifyRoute(mNetdService, ModifyOperation.REMOVE, netId, route); + NetdUtils.modifyRoute(mNetdService, ModifyOperation.REMOVE, netId, route); } private ArrayList<String> readRouteList(String filename) { @@ -1785,7 +1784,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub { public void addInterfaceToLocalNetwork(String iface, List<RouteInfo> routes) { modifyInterfaceInNetwork(MODIFY_OPERATION_ADD, INetd.LOCAL_NET_ID, iface); // modifyInterfaceInNetwork already check calling permission. - RouteUtils.addRoutesToLocalNetwork(mNetdService, iface, routes); + NetdUtils.addRoutesToLocalNetwork(mNetdService, iface, routes); } @Override @@ -1796,7 +1795,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub { @Override public int removeRoutesFromLocalNetwork(List<RouteInfo> routes) { NetworkStack.checkNetworkStackPermission(mContext); - return RouteUtils.removeRoutesFromLocalNetwork(mNetdService, routes); + return NetdUtils.removeRoutesFromLocalNetwork(mNetdService, routes); } @Override diff --git a/services/core/java/com/android/server/OWNERS b/services/core/java/com/android/server/OWNERS index 95dc66727730..b6413773046f 100644 --- a/services/core/java/com/android/server/OWNERS +++ b/services/core/java/com/android/server/OWNERS @@ -16,6 +16,9 @@ per-file SensorPrivacyService.java = file:platform/frameworks/native:/libs/senso # ServiceWatcher per-file ServiceWatcher.java = sooniln@google.com +# Health +per-file BatteryService.java = file:platform/hardware/interfaces:/health/aidl/OWNERS + per-file *Alarm* = file:/apex/jobscheduler/OWNERS per-file *AppOp* = file:/core/java/android/permission/OWNERS per-file *Battery* = file:/BATTERY_STATS_OWNERS diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index edf832f0fc22..c74270882260 100644 --- a/services/core/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java @@ -385,6 +385,10 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { private int[] mAllowedNetworkTypeReason; private long[] mAllowedNetworkTypeValue; + private static final List<LinkCapacityEstimate> INVALID_LCE_LIST = + new ArrayList<LinkCapacityEstimate>(Arrays.asList(new LinkCapacityEstimate( + LinkCapacityEstimate.LCE_TYPE_COMBINED, + LinkCapacityEstimate.INVALID, LinkCapacityEstimate.INVALID))); private List<List<LinkCapacityEstimate>> mLinkCapacityEstimateLists; /** @@ -719,7 +723,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mPhysicalChannelConfigs.add(i, new ArrayList<>()); mAllowedNetworkTypeReason[i] = -1; mAllowedNetworkTypeValue[i] = -1; - mLinkCapacityEstimateLists.add(i, new ArrayList<>()); + mLinkCapacityEstimateLists.add(i, INVALID_LCE_LIST); } } @@ -819,7 +823,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mPhysicalChannelConfigs.add(i, new ArrayList<>()); mAllowedNetworkTypeReason[i] = -1; mAllowedNetworkTypeValue[i] = -1; - mLinkCapacityEstimateLists.add(i, new ArrayList<>()); + mLinkCapacityEstimateLists.add(i, INVALID_LCE_LIST); } mAppOps = mContext.getSystemService(AppOpsManager.class); @@ -1025,7 +1029,6 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { return; } - int phoneId = getPhoneIdFromSubId(subId); synchronized (mRecords) { // register IBinder b = callback.asBinder(); @@ -1048,21 +1051,24 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { // Legacy applications pass SubscriptionManager.DEFAULT_SUB_ID, // force all illegal subId to SubscriptionManager.DEFAULT_SUB_ID if (!SubscriptionManager.isValidSubscriptionId(subId)) { + if (DBG) { + log("invalid subscription id, use default id"); + } r.subId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID; } else {//APP specify subID r.subId = subId; } - r.phoneId = phoneId; + r.phoneId = getPhoneIdFromSubId(r.subId); r.eventList = events; if (DBG) { - log("listen: Register r=" + r + " r.subId=" + r.subId + " phoneId=" + phoneId); + log("listen: Register r=" + r + " r.subId=" + r.subId + " r.phoneId=" + r.phoneId); } - if (notifyNow && validatePhoneId(phoneId)) { + if (notifyNow && validatePhoneId(r.phoneId)) { if (events.contains(TelephonyCallback.EVENT_SERVICE_STATE_CHANGED)){ try { - if (VDBG) log("listen: call onSSC state=" + mServiceState[phoneId]); - ServiceState rawSs = new ServiceState(mServiceState[phoneId]); + if (VDBG) log("listen: call onSSC state=" + mServiceState[r.phoneId]); + ServiceState rawSs = new ServiceState(mServiceState[r.phoneId]); if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) { r.callback.onServiceStateChanged(rawSs); } else if (checkCoarseLocationAccess(r, Build.VERSION_CODES.Q)) { @@ -1078,8 +1084,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } if (events.contains(TelephonyCallback.EVENT_SIGNAL_STRENGTH_CHANGED)) { try { - if (mSignalStrength[phoneId] != null) { - int gsmSignalStrength = mSignalStrength[phoneId] + if (mSignalStrength[r.phoneId] != null) { + int gsmSignalStrength = mSignalStrength[r.phoneId] .getGsmSignalStrength(); r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1 : gsmSignalStrength)); @@ -1092,7 +1098,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { TelephonyCallback.EVENT_MESSAGE_WAITING_INDICATOR_CHANGED)) { try { r.callback.onMessageWaitingIndicatorChanged( - mMessageWaiting[phoneId]); + mMessageWaiting[r.phoneId]); } catch (RemoteException ex) { remove(r.binder); } @@ -1101,7 +1107,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { TelephonyCallback.EVENT_CALL_FORWARDING_INDICATOR_CHANGED)) { try { r.callback.onCallForwardingIndicatorChanged( - mCallForwarding[phoneId]); + mCallForwarding[r.phoneId]); } catch (RemoteException ex) { remove(r.binder); } @@ -1109,11 +1115,11 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { if (validateEventAndUserLocked( r, TelephonyCallback.EVENT_CELL_LOCATION_CHANGED)) { try { - if (DBG_LOC) log("listen: mCellIdentity = " + mCellIdentity[phoneId]); + if (DBG_LOC) log("listen: mCellIdentity = " + mCellIdentity[r.phoneId]); if (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE) && checkFineLocationAccess(r, Build.VERSION_CODES.Q)) { // null will be translated to empty CellLocation object in client. - r.callback.onCellLocationChanged(mCellIdentity[phoneId]); + r.callback.onCellLocationChanged(mCellIdentity[r.phoneId]); } } catch (RemoteException ex) { remove(r.binder); @@ -1121,49 +1127,38 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } if (events.contains(TelephonyCallback.EVENT_LEGACY_CALL_STATE_CHANGED)) { try { - r.callback.onLegacyCallStateChanged(mCallState[phoneId], - getCallIncomingNumber(r, phoneId)); + r.callback.onLegacyCallStateChanged(mCallState[r.phoneId], + getCallIncomingNumber(r, r.phoneId)); } catch (RemoteException ex) { remove(r.binder); } } if (events.contains(TelephonyCallback.EVENT_CALL_STATE_CHANGED)) { try { - r.callback.onCallStateChanged(mCallState[phoneId]); + r.callback.onCallStateChanged(mCallState[r.phoneId]); } catch (RemoteException ex) { remove(r.binder); } } if (events.contains(TelephonyCallback.EVENT_DATA_CONNECTION_STATE_CHANGED)) { try { - r.callback.onDataConnectionStateChanged(mDataConnectionState[phoneId], - mDataConnectionNetworkType[phoneId]); + r.callback.onDataConnectionStateChanged(mDataConnectionState[r.phoneId], + mDataConnectionNetworkType[r.phoneId]); } catch (RemoteException ex) { remove(r.binder); } } if (events.contains(TelephonyCallback.EVENT_DATA_ACTIVITY_CHANGED)) { try { - r.callback.onDataActivity(mDataActivity[phoneId]); + r.callback.onDataActivity(mDataActivity[r.phoneId]); } catch (RemoteException ex) { remove(r.binder); } } if (events.contains(TelephonyCallback.EVENT_SIGNAL_STRENGTHS_CHANGED)) { try { - if (mSignalStrength[phoneId] != null) { - r.callback.onSignalStrengthsChanged(mSignalStrength[phoneId]); - } - } catch (RemoteException ex) { - remove(r.binder); - } - } - if (events.contains( - TelephonyCallback.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED)) { - updateReportSignalStrengthDecision(r.subId); - try { - if (mSignalStrength[phoneId] != null) { - r.callback.onSignalStrengthsChanged(mSignalStrength[phoneId]); + if (mSignalStrength[r.phoneId] != null) { + r.callback.onSignalStrengthsChanged(mSignalStrength[r.phoneId]); } } catch (RemoteException ex) { remove(r.binder); @@ -1172,11 +1167,13 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { if (validateEventAndUserLocked( r, TelephonyCallback.EVENT_CELL_INFO_CHANGED)) { try { - if (DBG_LOC) log("listen: mCellInfo[" + phoneId + "] = " - + mCellInfo.get(phoneId)); + if (DBG_LOC) { + log("listen: mCellInfo[" + r.phoneId + "] = " + + mCellInfo.get(r.phoneId)); + } if (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE) && checkFineLocationAccess(r, Build.VERSION_CODES.Q)) { - r.callback.onCellInfoChanged(mCellInfo.get(phoneId)); + r.callback.onCellInfoChanged(mCellInfo.get(r.phoneId)); } } catch (RemoteException ex) { remove(r.binder); @@ -1184,22 +1181,22 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } if (events.contains(TelephonyCallback.EVENT_PRECISE_CALL_STATE_CHANGED)) { try { - r.callback.onPreciseCallStateChanged(mPreciseCallState[phoneId]); + r.callback.onPreciseCallStateChanged(mPreciseCallState[r.phoneId]); } catch (RemoteException ex) { remove(r.binder); } } if (events.contains(TelephonyCallback.EVENT_CALL_DISCONNECT_CAUSE_CHANGED)) { try { - r.callback.onCallDisconnectCauseChanged(mCallDisconnectCause[phoneId], - mCallPreciseDisconnectCause[phoneId]); + r.callback.onCallDisconnectCauseChanged(mCallDisconnectCause[r.phoneId], + mCallPreciseDisconnectCause[r.phoneId]); } catch (RemoteException ex) { remove(r.binder); } } if (events.contains(TelephonyCallback.EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED)) { try { - r.callback.onImsCallDisconnectCauseChanged(mImsReasonInfo.get(phoneId)); + r.callback.onImsCallDisconnectCauseChanged(mImsReasonInfo.get(r.phoneId)); } catch (RemoteException ex) { remove(r.binder); } @@ -1208,7 +1205,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { TelephonyCallback.EVENT_PRECISE_DATA_CONNECTION_STATE_CHANGED)) { try { for (PreciseDataConnectionState pdcs - : mPreciseDataConnectionStates.get(phoneId).values()) { + : mPreciseDataConnectionStates.get(r.phoneId).values()) { r.callback.onPreciseDataConnectionStateChanged(pdcs); } } catch (RemoteException ex) { @@ -1225,29 +1222,29 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { if (events.contains(TelephonyCallback.EVENT_VOICE_ACTIVATION_STATE_CHANGED)) { try { r.callback.onVoiceActivationStateChanged( - mVoiceActivationState[phoneId]); + mVoiceActivationState[r.phoneId]); } catch (RemoteException ex) { remove(r.binder); } } if (events.contains(TelephonyCallback.EVENT_DATA_ACTIVATION_STATE_CHANGED)) { try { - r.callback.onDataActivationStateChanged(mDataActivationState[phoneId]); + r.callback.onDataActivationStateChanged(mDataActivationState[r.phoneId]); } catch (RemoteException ex) { remove(r.binder); } } if (events.contains(TelephonyCallback.EVENT_USER_MOBILE_DATA_STATE_CHANGED)) { try { - r.callback.onUserMobileDataStateChanged(mUserMobileDataState[phoneId]); + r.callback.onUserMobileDataStateChanged(mUserMobileDataState[r.phoneId]); } catch (RemoteException ex) { remove(r.binder); } } if (events.contains(TelephonyCallback.EVENT_DISPLAY_INFO_CHANGED)) { try { - if (mTelephonyDisplayInfos[phoneId] != null) { - r.callback.onDisplayInfoChanged(mTelephonyDisplayInfos[phoneId]); + if (mTelephonyDisplayInfos[r.phoneId] != null) { + r.callback.onDisplayInfoChanged(mTelephonyDisplayInfos[r.phoneId]); } } catch (RemoteException ex) { remove(r.binder); @@ -1284,20 +1281,20 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } if (events.contains(TelephonyCallback.EVENT_SRVCC_STATE_CHANGED)) { try { - r.callback.onSrvccStateChanged(mSrvccState[phoneId]); + r.callback.onSrvccStateChanged(mSrvccState[r.phoneId]); } catch (RemoteException ex) { remove(r.binder); } } if (events.contains(TelephonyCallback.EVENT_CALL_ATTRIBUTES_CHANGED)) { try { - r.callback.onCallAttributesChanged(mCallAttributes[phoneId]); + r.callback.onCallAttributesChanged(mCallAttributes[r.phoneId]); } catch (RemoteException ex) { remove(r.binder); } } if (events.contains(TelephonyCallback.EVENT_BARRING_INFO_CHANGED)) { - BarringInfo barringInfo = mBarringInfo.get(phoneId); + BarringInfo barringInfo = mBarringInfo.get(r.phoneId); BarringInfo biNoLocation = barringInfo != null ? barringInfo.createLocationInfoSanitizedCopy() : null; if (VDBG) log("listen: call onBarringInfoChanged=" + barringInfo); @@ -1315,8 +1312,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { r.callback.onPhysicalChannelConfigChanged( shouldSanitizeLocationForPhysicalChannelConfig(r) ? getLocationSanitizedConfigs( - mPhysicalChannelConfigs.get(phoneId)) - : mPhysicalChannelConfigs.get(phoneId)); + mPhysicalChannelConfigs.get(r.phoneId)) + : mPhysicalChannelConfigs.get(r.phoneId)); } catch (RemoteException ex) { remove(r.binder); } @@ -1325,7 +1322,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { TelephonyCallback.EVENT_DATA_ENABLED_CHANGED)) { try { r.callback.onDataEnabledChanged( - mIsDataEnabled[phoneId], mDataEnabledReason[phoneId]); + mIsDataEnabled[r.phoneId], mDataEnabledReason[r.phoneId]); } catch (RemoteException ex) { remove(r.binder); } @@ -1333,9 +1330,9 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { if (events.contains( TelephonyCallback.EVENT_LINK_CAPACITY_ESTIMATE_CHANGED)) { try { - if (mLinkCapacityEstimateLists.get(phoneId) != null) { + if (mLinkCapacityEstimateLists.get(r.phoneId) != null) { r.callback.onLinkCapacityEstimateChanged(mLinkCapacityEstimateLists - .get(phoneId)); + .get(r.phoneId)); } } catch (RemoteException ex) { remove(r.binder); @@ -1345,27 +1342,6 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } } - private void updateReportSignalStrengthDecision(int subscriptionId) { - synchronized (mRecords) { - TelephonyManager telephonyManager = (TelephonyManager) mContext - .getSystemService(Context.TELEPHONY_SERVICE); - for (Record r : mRecords) { - // If any of the system clients wants to always listen to signal strength, - // we need to set it on. - if (r.matchTelephonyCallbackEvent( - TelephonyCallback.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED)) { - telephonyManager.createForSubscriptionId(subscriptionId) - .setAlwaysReportSignalStrength(true); - return; - } - } - // If none of the system clients wants to always listen to signal strength, - // we need to set it off. - telephonyManager.createForSubscriptionId(subscriptionId) - .setAlwaysReportSignalStrength(false); - } - } - private String getCallIncomingNumber(Record record, int phoneId) { // Only reveal the incoming number if the record has read call log permission. return record.canReadCallLog() ? mCallIncomingNumber[phoneId] : ""; @@ -1449,14 +1425,6 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } mRecords.remove(i); - - // Every time a client that is registrating to always receive the signal - // strength is removed from registry records, we need to check if - // the signal strength decision needs to update on its slot. - if (r.matchTelephonyCallbackEvent( - TelephonyCallback.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED)) { - updateReportSignalStrengthDecision(r.subId); - } return; } } @@ -1577,7 +1545,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_SERVICE_STATE_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { ServiceState stateToSend; @@ -1639,7 +1607,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { if ((activationType == SIM_ACTIVATION_TYPE_VOICE) && r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_VOICE_ACTIVATION_STATE_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { if (DBG) { log("notifyVoiceActivationStateForPhoneId: callback.onVASC r=" + r + " subId=" + subId + " phoneId=" + phoneId @@ -1650,7 +1618,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { if ((activationType == SIM_ACTIVATION_TYPE_DATA) && r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_DATA_ACTIVATION_STATE_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { if (DBG) { log("notifyDataActivationStateForPhoneId: callback.onDASC r=" + r + " subId=" + subId + " phoneId=" + phoneId @@ -1688,11 +1656,9 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { log("notifySignalStrengthForPhoneId: r=" + r + " subId=" + subId + " phoneId=" + phoneId + " ss=" + signalStrength); } - if ((r.matchTelephonyCallbackEvent( + if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_SIGNAL_STRENGTHS_CHANGED) - || r.matchTelephonyCallbackEvent( - TelephonyCallback.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED)) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { if (DBG) { log("notifySignalStrengthForPhoneId: callback.onSsS r=" + r @@ -1706,7 +1672,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_SIGNAL_STRENGTH_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { int gsmSignalStrength = signalStrength.getGsmSignalStrength(); int ss = (gsmSignalStrength == 99 ? -1 : gsmSignalStrength); @@ -1753,7 +1719,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_CARRIER_NETWORK_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { r.callback.onCarrierNetworkChange(active); } catch (RemoteException ex) { @@ -1785,7 +1751,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (validateEventAndUserLocked( r, TelephonyCallback.EVENT_CELL_INFO_CHANGED) - && idMatch(r.subId, subId, phoneId) + && idMatch(r, subId, phoneId) && (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE) && checkFineLocationAccess(r, Build.VERSION_CODES.Q))) { try { @@ -1819,7 +1785,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_MESSAGE_WAITING_INDICATOR_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { r.callback.onMessageWaitingIndicatorChanged(mwi); } catch (RemoteException ex) { @@ -1846,7 +1812,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_USER_MOBILE_DATA_STATE_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { r.callback.onUserMobileDataStateChanged(state); } catch (RemoteException ex) { @@ -1885,7 +1851,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_DISPLAY_INFO_CHANGED) - && idMatchWithoutDefaultPhoneCheck(r.subId, subId)) { + && idMatch(r, subId, phoneId)) { try { if (!mConfigurationProvider.isDisplayInfoNrAdvancedSupported( r.callingPackage, Binder.getCallingUserHandle())) { @@ -1936,7 +1902,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_CALL_FORWARDING_INDICATOR_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { r.callback.onCallForwardingIndicatorChanged(cfi); } catch (RemoteException ex) { @@ -1965,7 +1931,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { // Notify by correct subId. if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_DATA_ACTIVITY_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { r.callback.onDataActivity(state); } catch (RemoteException ex) { @@ -2013,7 +1979,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_DATA_CONNECTION_STATE_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { if (DBG) { log("Notify data connection state changed on sub: " + subId); @@ -2038,7 +2004,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_PRECISE_DATA_CONNECTION_STATE_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { r.callback.onPreciseDataConnectionStateChanged(preciseState); } catch (RemoteException ex) { @@ -2085,7 +2051,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (validateEventAndUserLocked( r, TelephonyCallback.EVENT_CELL_LOCATION_CHANGED) - && idMatch(r.subId, subId, phoneId) + && idMatch(r, subId, phoneId) && (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE) && checkFineLocationAccess(r, Build.VERSION_CODES.Q))) { try { @@ -2139,7 +2105,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_PRECISE_CALL_STATE_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { r.callback.onPreciseCallStateChanged(mPreciseCallState[phoneId]); } catch (RemoteException ex) { @@ -2148,7 +2114,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } if (notifyCallAttributes && r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_CALL_ATTRIBUTES_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { r.callback.onCallAttributesChanged(mCallAttributes[phoneId]); } catch (RemoteException ex) { @@ -2173,7 +2139,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_CALL_DISCONNECT_CAUSE_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { r.callback.onCallDisconnectCauseChanged(mCallDisconnectCause[phoneId], mCallPreciseDisconnectCause[phoneId]); @@ -2198,7 +2164,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { if (DBG_LOC) { log("notifyImsCallDisconnectCause: mImsReasonInfo=" @@ -2230,7 +2196,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_SRVCC_STATE_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { if (DBG_LOC) { log("notifySrvccStateChanged: mSrvccState=" + state + " r=" + r); @@ -2259,7 +2225,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } if ((r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_OEM_HOOK_RAW)) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { r.callback.onOemHookRawEvent(rawData); } catch (RemoteException ex) { @@ -2339,7 +2305,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_RADIO_POWER_STATE_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { r.callback.onRadioPowerStateChanged(state); } catch (RemoteException ex) { @@ -2368,7 +2334,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_EMERGENCY_NUMBER_LIST_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { r.callback.onEmergencyNumberListChanged(mEmergencyNumberList); if (VDBG) { @@ -2455,7 +2421,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_CALL_ATTRIBUTES_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { r.callback.onCallAttributesChanged(mCallAttributes[phoneId]); } catch (RemoteException ex) { @@ -2486,7 +2452,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_REGISTRATION_FAILURE) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { r.callback.onRegistrationFailed( checkFineLocationAccess(r, Build.VERSION_CODES.BASE) @@ -2529,7 +2495,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_BARRING_INFO_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { if (DBG_LOC) { log("notifyBarringInfo: mBarringInfo=" @@ -2574,7 +2540,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { if (DBG_LOC) { log("notifyPhysicalChannelConfig: mPhysicalChannelConfigs=" @@ -2641,7 +2607,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_DATA_ENABLED_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { r.callback.onDataEnabledChanged(enabled, reason); } catch (RemoteException ex) { @@ -2676,7 +2642,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_ALLOWED_NETWORK_TYPE_LIST_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { if (VDBG) { log("notifyAllowedNetworkTypesChanged: reason= " + reason @@ -2718,7 +2684,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_LINK_CAPACITY_ESTIMATE_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { r.callback.onLinkCapacityEstimateChanged(linkCapacityEstimateList); } catch (RemoteException ex) { @@ -3111,11 +3077,6 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION, null); } - if ((events.contains(TelephonyCallback.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED))) { - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH, null); - } - if (isPrivilegedPhoneStatePermissionRequired(events)) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, null); @@ -3168,33 +3129,24 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } /** - * If the registrant specified a subId, then we should only notify it if subIds match. - * If the registrant registered with DEFAULT subId, we should notify only when the related subId - * is default subId (which could be INVALID if there's no default subId). + * Match the sub id or phone id of the event to the record * - * This should be the correct way to check record ID match. in idMatch the record's phoneId is - * speculated based on subId passed by the registrant so it's not a good reference. - * But to avoid triggering potential regression only replace idMatch with it when an issue with - * idMatch is reported. Eventually this should replace all instances of idMatch. + * We follow the rules below: + * 1) If sub id of the event is invalid, phone id should be used. + * 2) The event on default sub should be notified to the records + * which register the default sub id. + * 3) Sub id should be exactly matched for all other cases. */ - private boolean idMatchWithoutDefaultPhoneCheck(int subIdInRecord, int subIdToNotify) { - if (subIdInRecord == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { - return (subIdToNotify == mDefaultSubId); - } else { - return (subIdInRecord == subIdToNotify); - } - } - - boolean idMatch(int rSubId, int subId, int phoneId) { + boolean idMatch(Record r, int subId, int phoneId) { - if(subId < 0) { - // Invalid case, we need compare phoneId with default one. - return (mDefaultPhoneId == phoneId); + if (subId < 0) { + // Invalid case, we need compare phoneId. + return (r.phoneId == phoneId); } - if(rSubId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { + if (r.subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { return (subId == mDefaultSubId); } else { - return (rSubId == subId); + return (r.subId == subId); } } @@ -3285,9 +3237,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } } - if (events.contains(TelephonyCallback.EVENT_SIGNAL_STRENGTHS_CHANGED) - || events.contains( - TelephonyCallback.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED)) { + if (events.contains(TelephonyCallback.EVENT_SIGNAL_STRENGTHS_CHANGED)) { try { if (mSignalStrength[phoneId] != null) { SignalStrength signalStrength = mSignalStrength[phoneId]; diff --git a/services/core/java/com/android/server/VpnManagerService.java b/services/core/java/com/android/server/VpnManagerService.java index a03425c0bb75..b48e21e4e2c6 100644 --- a/services/core/java/com/android/server/VpnManagerService.java +++ b/services/core/java/com/android/server/VpnManagerService.java @@ -681,7 +681,7 @@ public class VpnManagerService extends IVpnManager.Stub { intentFilter = new IntentFilter(); intentFilter.addAction(LockdownVpnTracker.ACTION_LOCKDOWN_RESET); mUserAllContext.registerReceiver( - mIntentReceiver, intentFilter, NETWORK_STACK, mHandler); + mIntentReceiver, intentFilter, NETWORK_STACK, mHandler, Context.RECEIVER_EXPORTED); } private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java index 731f7fec466c..ab2147dff853 100644 --- a/services/core/java/com/android/server/accounts/AccountManagerService.java +++ b/services/core/java/com/android/server/accounts/AccountManagerService.java @@ -1834,6 +1834,11 @@ public class AccountManagerService + ", skipping since the account already exists"); return false; } + if (accounts.accountsDb.findAllDeAccounts().size() > 100) { + Log.w(TAG, "insertAccountIntoDatabase: " + account.toSafeString() + + ", skipping since more than 50 accounts on device exist"); + return false; + } long accountId = accounts.accountsDb.insertCeAccount(account, password); if (accountId < 0) { Log.w(TAG, "insertAccountIntoDatabase: " + account.toSafeString() diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index a2fec2753340..a29a49cb07d8 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -4906,7 +4906,9 @@ public final class ActiveServices { sr.setProcess(null, null, 0, null); sr.isolatedProc = null; sr.executeNesting = 0; - sr.forceClearTracker(); + synchronized (mAm.mProcessStats.mLock) { + sr.forceClearTracker(); + } if (mDestroyingServices.remove(sr)) { if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "killServices remove destroying " + sr); } @@ -5056,7 +5058,9 @@ public final class ActiveServices { i--; ServiceRecord sr = mDestroyingServices.get(i); if (sr.app == app) { - sr.forceClearTracker(); + synchronized (mAm.mProcessStats.mLock) { + sr.forceClearTracker(); + } mDestroyingServices.remove(i); if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "killServices remove destroying " + sr); } diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java index 503b3a93b31f..94bf62f8b9b7 100644 --- a/services/core/java/com/android/server/am/BroadcastQueue.java +++ b/services/core/java/com/android/server/am/BroadcastQueue.java @@ -1568,17 +1568,23 @@ public final class BroadcastQueue { perm = PackageManager.PERMISSION_DENIED; } - if (perm == PackageManager.PERMISSION_GRANTED) { - skip = true; - break; - } - int appOp = AppOpsManager.permissionToOpCode(excludedPermission); if (appOp != AppOpsManager.OP_NONE) { - if (mService.getAppOpsManager().checkOpNoThrow(appOp, + // When there is an app op associated with the permission, + // skip when both the permission and the app op are + // granted. + if ((perm == PackageManager.PERMISSION_GRANTED) && ( + mService.getAppOpsManager().checkOpNoThrow(appOp, info.activityInfo.applicationInfo.uid, info.activityInfo.packageName) - == AppOpsManager.MODE_ALLOWED) { + == AppOpsManager.MODE_ALLOWED)) { + skip = true; + break; + } + } else { + // When there is no app op associated with the permission, + // skip when permission is granted. + if (perm == PackageManager.PERMISSION_GRANTED) { skip = true; break; } diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java index 2f20efbf5730..3ccacd84a9f3 100644 --- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java +++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java @@ -87,6 +87,7 @@ public class SettingsToPropertiesMapper { DeviceConfig.NAMESPACE_LMKD_NATIVE, DeviceConfig.NAMESPACE_MEDIA_NATIVE, DeviceConfig.NAMESPACE_NETD_NATIVE, + DeviceConfig.NAMESPACE_NNAPI_NATIVE, DeviceConfig.NAMESPACE_PROFCOLLECT_NATIVE_BOOT, DeviceConfig.NAMESPACE_RUNTIME_NATIVE, DeviceConfig.NAMESPACE_RUNTIME_NATIVE_BOOT, diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java index 38f71bae3004..c383f5120407 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java +++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java @@ -22,6 +22,7 @@ import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothHeadset; import android.bluetooth.BluetoothHearingAid; import android.bluetooth.BluetoothProfile; +import android.bluetooth.BluetoothLeAudio; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; @@ -503,6 +504,18 @@ import java.util.concurrent.atomic.AtomicBoolean; } } + /*package*/ static final class BleVolumeInfo { + final int mIndex; + final int mMaxIndex; + final int mStreamType; + + BleVolumeInfo(int index, int maxIndex, int streamType) { + mIndex = index; + mMaxIndex = maxIndex; + mStreamType = streamType; + } + }; + /*package*/ static final class BtDeviceConnectionInfo { final @NonNull BluetoothDevice mDevice; final @AudioService.BtProfileConnectionState int mState; @@ -711,6 +724,11 @@ import java.util.concurrent.atomic.AtomicBoolean; sendIIMsgNoDelay(MSG_II_SET_HEARING_AID_VOLUME, SENDMSG_REPLACE, index, streamType); } + /*package*/ void postSetLeAudioVolumeIndex(int index, int maxIndex, int streamType) { + BleVolumeInfo info = new BleVolumeInfo(index, maxIndex, streamType); + sendLMsgNoDelay(MSG_II_SET_LE_AUDIO_OUT_VOLUME, SENDMSG_REPLACE, info); + } + /*package*/ void postSetModeOwnerPid(int pid, int mode) { sendIIMsgNoDelay(MSG_I_SET_MODE_OWNER_PID, SENDMSG_REPLACE, pid, mode); } @@ -851,6 +869,10 @@ import java.util.concurrent.atomic.AtomicBoolean; return mAudioService.getVssVolumeForDevice(streamType, device); } + /*package*/ int getMaxVssVolumeForStream(int streamType) { + return mAudioService.getMaxVssVolumeForStream(streamType); + } + /*package*/ int getDeviceForStream(int streamType) { return mAudioService.getDeviceForStream(streamType); } @@ -962,6 +984,10 @@ import java.util.concurrent.atomic.AtomicBoolean; sendMsgNoDelay(MSG_DISCONNECT_BT_HEARING_AID, SENDMSG_QUEUE); } + /*package*/ void postDisconnectLeAudio() { + sendMsgNoDelay(MSG_DISCONNECT_BT_LE_AUDIO, SENDMSG_QUEUE); + } + /*package*/ void postDisconnectHeadset() { sendMsgNoDelay(MSG_DISCONNECT_BT_HEADSET, SENDMSG_QUEUE); } @@ -983,6 +1009,11 @@ import java.util.concurrent.atomic.AtomicBoolean; hearingAidProfile); } + /*package*/ void postBtLeAudioProfileConnected(BluetoothLeAudio leAudioProfile) { + sendLMsgNoDelay(MSG_L_BT_SERVICE_CONNECTED_PROFILE_LE_AUDIO, SENDMSG_QUEUE, + leAudioProfile); + } + /*package*/ void postCommunicationRouteClientDied(CommunicationRouteClient client) { sendLMsgNoDelay(MSG_L_COMMUNICATION_ROUTE_CLIENT_DIED, SENDMSG_QUEUE, client); } @@ -1321,6 +1352,12 @@ import java.util.concurrent.atomic.AtomicBoolean; mBtHelper.setHearingAidVolume(msg.arg1, msg.arg2); } break; + case MSG_II_SET_LE_AUDIO_OUT_VOLUME: { + final BleVolumeInfo info = (BleVolumeInfo) msg.obj; + synchronized (mDeviceStateLock) { + mBtHelper.setLeAudioVolume(info.mIndex, info.mMaxIndex, info.mStreamType); + } + } break; case MSG_I_SET_AVRCP_ABSOLUTE_VOLUME: synchronized (mDeviceStateLock) { mBtHelper.setAvrcpAbsoluteVolumeIndex(msg.arg1); @@ -1384,6 +1421,11 @@ import java.util.concurrent.atomic.AtomicBoolean; } } break; + case MSG_DISCONNECT_BT_LE_AUDIO: + synchronized(mDeviceStateLock) { + mDeviceInventory.disconnectLeAudio(); + } + break; case MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP: synchronized (mDeviceStateLock) { mBtHelper.onA2dpProfileConnected((BluetoothA2dp) msg.obj); @@ -1399,6 +1441,12 @@ import java.util.concurrent.atomic.AtomicBoolean; mBtHelper.onHearingAidProfileConnected((BluetoothHearingAid) msg.obj); } break; + + case MSG_L_BT_SERVICE_CONNECTED_PROFILE_LE_AUDIO: + synchronized(mDeviceStateLock) { + mBtHelper.onLeAudioProfileConnected((BluetoothLeAudio) msg.obj); + } + break; case MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEADSET: synchronized (mSetModeLock) { synchronized (mDeviceStateLock) { @@ -1586,6 +1634,11 @@ import java.util.concurrent.atomic.AtomicBoolean; private static final int MSG_IL_SET_LE_AUDIO_IN_CONNECTION_STATE = 43; private static final int MSG_L_LE_AUDIO_DEVICE_OUT_CONNECTION_CHANGE_EXT = 44; private static final int MSG_L_LE_AUDIO_DEVICE_IN_CONNECTION_CHANGE_EXT = 45; + // process set volume for Le Audio, obj is BleVolumeInfo + private static final int MSG_II_SET_LE_AUDIO_OUT_VOLUME = 46; + + private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_LE_AUDIO = 47; + private static final int MSG_DISCONNECT_BT_LE_AUDIO = 48; private static boolean isMessageHandledUnderWakelock(int msgId) { switch(msgId) { @@ -1714,10 +1767,12 @@ import java.util.concurrent.atomic.AtomicBoolean; MESSAGES_MUTE_MUSIC = new HashSet<>(); MESSAGES_MUTE_MUSIC.add(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED); MESSAGES_MUTE_MUSIC.add(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED); + MESSAGES_MUTE_MUSIC.add(MSG_IL_SET_LE_AUDIO_OUT_CONNECTION_STATE); MESSAGES_MUTE_MUSIC.add(MSG_L_A2DP_DEVICE_CONFIG_CHANGE); MESSAGES_MUTE_MUSIC.add(MSG_L_A2DP_ACTIVE_DEVICE_CHANGE); MESSAGES_MUTE_MUSIC.add(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION); MESSAGES_MUTE_MUSIC.add(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION); + MESSAGES_MUTE_MUSIC.add(MSG_L_LE_AUDIO_DEVICE_OUT_CONNECTION_CHANGE_EXT); MESSAGES_MUTE_MUSIC.add(MSG_IIL_SET_FORCE_BT_A2DP_USE); MESSAGES_MUTE_MUSIC.add(MSG_REPORT_NEW_ROUTES_A2DP); } diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java index 64e620eeb8a0..6c3c736aeb93 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java +++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java @@ -887,6 +887,28 @@ public class AudioDeviceInventory { } } + /*package*/ void disconnectLeAudio() { + synchronized (mDevicesLock) { + final ArraySet<String> toRemove = new ArraySet<>(); + // Disconnect ALL DEVICE_OUT_BLE_HEADSET devices + mConnectedDevices.values().forEach(deviceInfo -> { + if (deviceInfo.mDeviceType == AudioSystem.DEVICE_OUT_BLE_HEADSET) { + toRemove.add(deviceInfo.mDeviceAddress); + } + }); + new MediaMetrics.Item(mMetricsId + "disconnectLeAudio") + .record(); + if (toRemove.size() > 0) { + final int delay = checkSendBecomingNoisyIntentInt( + AudioSystem.DEVICE_OUT_BLE_HEADSET, 0, AudioSystem.DEVICE_NONE); + toRemove.stream().forEach(deviceAddress -> + makeLeAudioDeviceUnavailable(deviceAddress, + AudioSystem.DEVICE_OUT_BLE_HEADSET) + ); + } + } + } + // must be called before removing the device from mConnectedDevices // musicDevice argument is used when not AudioSystem.DEVICE_NONE instead of querying // from AudioSystem @@ -1195,6 +1217,10 @@ public class AudioDeviceInventory { return; } + final int leAudioVolIndex = mDeviceBroker.getVssVolumeForDevice(streamType, + AudioSystem.DEVICE_OUT_BLE_HEADSET); + final int maxIndex = mDeviceBroker.getMaxVssVolumeForStream(streamType); + mDeviceBroker.postSetLeAudioVolumeIndex(leAudioVolIndex, maxIndex, streamType); mDeviceBroker.postApplyVolumeOnDevice(streamType, device, "makeLeAudioDeviceAvailable"); } @@ -1243,6 +1269,7 @@ public class AudioDeviceInventory { BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET); BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_LINE); BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_HEARING_AID); + BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_BLE_HEADSET); BECOMING_NOISY_INTENT_DEVICES_SET.addAll(AudioSystem.DEVICE_OUT_ALL_A2DP_SET); BECOMING_NOISY_INTENT_DEVICES_SET.addAll(AudioSystem.DEVICE_OUT_ALL_USB_SET); BECOMING_NOISY_INTENT_DEVICES_SET.addAll(AudioSystem.DEVICE_OUT_ALL_BLE_SET); diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index bf5f4c2d3d33..d75f21c4ef85 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -334,6 +334,10 @@ public class AudioService extends IAudioService.Stub return mStreamStates[stream].getIndex(device); } + /*package*/ int getMaxVssVolumeForStream(int stream) { + return mStreamStates[stream].getMaxIndex(); + } + private SettingsObserver mSettingsObserver; private AtomicInteger mMode = new AtomicInteger(AudioSystem.MODE_NORMAL); @@ -2952,6 +2956,16 @@ public class AudioService extends IAudioService.Stub mDeviceBroker.postSetAvrcpAbsoluteVolumeIndex(newIndex / 10); } + if (device == AudioSystem.DEVICE_OUT_BLE_HEADSET + && streamType == getBluetoothContextualVolumeStream()) { + if (DEBUG_VOL) { + Log.d(TAG, "adjustSreamVolume postSetLeAudioVolumeIndex index=" + + newIndex + " stream=" + streamType); + } + mDeviceBroker.postSetLeAudioVolumeIndex(newIndex, + mStreamStates[streamType].getMaxIndex(), streamType); + } + // Check if volume update should be send to Hearing Aid if (device == AudioSystem.DEVICE_OUT_HEARING_AID) { // only modify the hearing aid attenuation when the stream to modify matches @@ -3580,6 +3594,16 @@ public class AudioService extends IAudioService.Stub mDeviceBroker.postSetAvrcpAbsoluteVolumeIndex(index / 10); } + if (device == AudioSystem.DEVICE_OUT_BLE_HEADSET + && streamType == getBluetoothContextualVolumeStream()) { + if (DEBUG_VOL) { + Log.d(TAG, "adjustSreamVolume postSetLeAudioVolumeIndex index=" + + index + " stream=" + streamType); + } + mDeviceBroker.postSetLeAudioVolumeIndex(index, + mStreamStates[streamType].getMaxIndex(), streamType); + } + if (device == AudioSystem.DEVICE_OUT_HEARING_AID && streamType == getBluetoothContextualVolumeStream()) { Log.i(TAG, "setStreamVolume postSetHearingAidVolumeIndex index=" + index @@ -6112,6 +6136,11 @@ public class AudioService extends IAudioService.Stub if (pkgName == null) { pkgName = ""; } + if (device.getType() == AudioDeviceInfo.TYPE_BLUETOOTH_A2DP) { + avrcpSupportsAbsoluteVolume(device.getAddress(), + deviceVolumeBehavior == AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE); + return; + } int audioSystemDeviceOut = AudioDeviceInfo.convertDeviceTypeToInternalDevice( device.getType()); @@ -7768,7 +7797,7 @@ public class AudioService extends IAudioService.Stub } } - public void avrcpSupportsAbsoluteVolume(String address, boolean support) { + private void avrcpSupportsAbsoluteVolume(String address, boolean support) { // address is not used for now, but may be used when multiple a2dp devices are supported sVolumeLogger.log(new AudioEventLogger.StringEvent("avrcpSupportsAbsoluteVolume addr=" + address + " support=" + support)); diff --git a/services/core/java/com/android/server/audio/AudioServiceEvents.java b/services/core/java/com/android/server/audio/AudioServiceEvents.java index 0eb5a5d1fb48..3137fa5784d2 100644 --- a/services/core/java/com/android/server/audio/AudioServiceEvents.java +++ b/services/core/java/com/android/server/audio/AudioServiceEvents.java @@ -155,6 +155,7 @@ public class AudioServiceEvents { static final int VOL_MODE_CHANGE_HEARING_AID = 7; static final int VOL_SET_GROUP_VOL = 8; static final int VOL_MUTE_STREAM_INT = 9; + static final int VOL_SET_LE_AUDIO_VOL = 10; final int mOp; final int mStream; @@ -310,6 +311,13 @@ public class AudioServiceEvents { .set(MediaMetrics.Property.INDEX, mVal1) .record(); return; + case VOL_SET_LE_AUDIO_VOL: + new MediaMetrics.Item(mMetricsId) + .set(MediaMetrics.Property.EVENT, "setLeAudioVolume") + .set(MediaMetrics.Property.INDEX, mVal1) + .set(MediaMetrics.Property.MAX_INDEX, mVal2) + .record(); + return; case VOL_SET_AVRCP_VOL: new MediaMetrics.Item(mMetricsId) .set(MediaMetrics.Property.EVENT, "setAvrcpVolume") @@ -382,6 +390,11 @@ public class AudioServiceEvents { .append(" index:").append(mVal1) .append(" gain dB:").append(mVal2) .toString(); + case VOL_SET_LE_AUDIO_VOL: + return new StringBuilder("setLeAudioVolume:") + .append(" index:").append(mVal1) + .append(" gain dB:").append(mVal2) + .toString(); case VOL_SET_AVRCP_VOL: return new StringBuilder("setAvrcpVolume:") .append(" index:").append(mVal1) diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java index 52e8edff5ffa..c924fde23f9d 100644 --- a/services/core/java/com/android/server/audio/BtHelper.java +++ b/services/core/java/com/android/server/audio/BtHelper.java @@ -25,6 +25,7 @@ import android.bluetooth.BluetoothCodecStatus; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothHeadset; import android.bluetooth.BluetoothHearingAid; +import android.bluetooth.BluetoothLeAudio; import android.bluetooth.BluetoothProfile; import android.content.Intent; import android.media.AudioDeviceAttributes; @@ -63,6 +64,8 @@ public class BtHelper { private @Nullable BluetoothHearingAid mHearingAid; + private @Nullable BluetoothLeAudio mLeAudio; + // Reference to BluetoothA2dp to query for AbsoluteVolume. private @Nullable BluetoothA2dp mA2dp; @@ -106,6 +109,8 @@ public class BtHelper { private static final int SCO_MODE_MAX = 2; private static final int BT_HEARING_AID_GAIN_MIN = -128; + private static final int BT_LE_AUDIO_MIN_VOL = 0; + private static final int BT_LE_AUDIO_MAX_VOL = 255; /** * Returns a string representation of the scoAudioMode. @@ -235,6 +240,8 @@ public class BtHelper { mBluetoothProfileServiceListener, BluetoothProfile.A2DP); adapter.getProfileProxy(mDeviceBroker.getContext(), mBluetoothProfileServiceListener, BluetoothProfile.HEARING_AID); + adapter.getProfileProxy(mDeviceBroker.getContext(), + mBluetoothProfileServiceListener, BluetoothProfile.LE_AUDIO); } } @@ -389,6 +396,26 @@ public class BtHelper { return requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, SCO_MODE_VIRTUAL_CALL); } + /*package*/ synchronized void setLeAudioVolume(int index, int maxIndex, int streamType) { + if (mLeAudio == null) { + if (AudioService.DEBUG_VOL) { + Log.i(TAG, "setLeAudioVolume: null mLeAudio"); + } + return; + } + /* leaudio expect volume value in range 0 to 255 + */ + int volume = (index * (BT_LE_AUDIO_MAX_VOL - BT_LE_AUDIO_MIN_VOL)) / maxIndex ; + + if (AudioService.DEBUG_VOL) { + Log.i(TAG, "setLeAudioVolume: calling mLeAudio.setVolume idx=" + + index + " volume=" + volume); + } + AudioService.sVolumeLogger.log(new AudioServiceEvents.VolumeEvent( + AudioServiceEvents.VolumeEvent.VOL_SET_LE_AUDIO_VOL, index, maxIndex)); + mLeAudio.setVolume(volume); + } + /*package*/ synchronized void setHearingAidVolume(int index, int streamType) { if (mHearingAid == null) { if (AudioService.DEBUG_VOL) { @@ -428,6 +455,7 @@ public class BtHelper { mDeviceBroker.postDisconnectA2dpSink(); mDeviceBroker.postDisconnectHeadset(); mDeviceBroker.postDisconnectHearingAid(); + mDeviceBroker.postDisconnectLeAudio(); } // @GuardedBy("AudioDeviceBroker.mSetModeLock") @@ -488,6 +516,23 @@ public class BtHelper { /*eventSource*/ "mBluetoothProfileServiceListener"); } + /*package*/ synchronized void onLeAudioProfileConnected(BluetoothLeAudio leAudio) { + mLeAudio = leAudio; + final List<BluetoothDevice> deviceList = mLeAudio.getConnectedDevices(); + if (deviceList.isEmpty()) { + return; + } + + final BluetoothDevice btDevice = deviceList.get(0); + final @BluetoothProfile.BtProfileState int state = + mLeAudio.getConnectionState(btDevice); + mDeviceBroker.postBluetoothLeAudioOutDeviceConnectionState( + btDevice, state, + /*suppressNoisyIntent*/ false, + /*musicDevice android.media.AudioSystem.DEVICE_NONE,*/ + /*eventSource*/ "mBluetoothProfileServiceListener"); + } + // @GuardedBy("AudioDeviceBroker.mSetModeLock") @GuardedBy("AudioDeviceBroker.mDeviceStateLock") /*package*/ synchronized void onHeadsetProfileConnected(BluetoothHeadset headset) { @@ -655,6 +700,13 @@ public class BtHelper { mDeviceBroker.postBtHearingAidProfileConnected( (BluetoothHearingAid) proxy); break; + + case BluetoothProfile.LE_AUDIO: + AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent( + "BT profile service: connecting LE_AUDIO profile")); + mDeviceBroker.postBtLeAudioProfileConnected( + (BluetoothLeAudio) proxy); + break; default: break; } @@ -677,6 +729,9 @@ public class BtHelper { case BluetoothProfile.HEARING_AID: mDeviceBroker.postDisconnectHearingAid(); break; + case BluetoothProfile.LE_AUDIO: + mDeviceBroker.postDisconnectLeAudio(); + break; default: break; @@ -899,6 +954,7 @@ public class BtHelper { pw.println(prefix + "mScoAudioState: " + scoAudioStateToString(mScoAudioState)); pw.println(prefix + "mScoAudioMode: " + scoAudioModeToString(mScoAudioMode)); pw.println("\n" + prefix + "mHearingAid: " + mHearingAid); + pw.println("\n" + prefix + "mLeAudio: " + mLeAudio); pw.println(prefix + "mA2dp: " + mA2dp); pw.println(prefix + "mAvrcpAbsVolSupported: " + mAvrcpAbsVolSupported); } diff --git a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java index 091e6c4adf4d..a56a8ea993f0 100644 --- a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java +++ b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java @@ -227,7 +227,7 @@ public class MultipathPolicyTracker { subscriberId = tele.getSubscriberId(); mNetworkTemplate = new NetworkTemplate( NetworkTemplate.MATCH_MOBILE, subscriberId, new String[] { subscriberId }, - null, NetworkStats.METERED_ALL, NetworkStats.ROAMING_ALL, + null, NetworkStats.METERED_YES, NetworkStats.ROAMING_ALL, NetworkStats.DEFAULT_NETWORK_NO, NETWORK_TYPE_ALL, OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_EXACT); mUsageCallback = new UsageCallback() { diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index 565c9ae2142c..bf4ef4879c9a 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -126,6 +126,7 @@ import com.android.server.net.BaseNetworkObserver; import libcore.io.IoUtils; import java.io.File; +import java.io.FileDescriptor; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -195,6 +196,7 @@ public class Vpn { private final Context mContext; private final ConnectivityManager mConnectivityManager; + private final AppOpsManager mAppOpsManager; // The context is for specific user which is created from mUserId private final Context mUserIdContext; @VisibleForTesting final Dependencies mDeps; @@ -407,6 +409,46 @@ public class Vpn { public boolean isInterfacePresent(final Vpn vpn, final String iface) { return vpn.jniCheck(iface) != 0; } + + /** + * @see ParcelFileDescriptor#adoptFd(int) + */ + public ParcelFileDescriptor adoptFd(Vpn vpn, int mtu) { + return ParcelFileDescriptor.adoptFd(jniCreate(vpn, mtu)); + } + + /** + * Call native method to create the VPN interface and return the FileDescriptor of /dev/tun. + */ + public int jniCreate(Vpn vpn, int mtu) { + return vpn.jniCreate(mtu); + } + + /** + * Call native method to get the interface name of VPN. + */ + public String jniGetName(Vpn vpn, int fd) { + return vpn.jniGetName(fd); + } + + /** + * Call native method to set the VPN addresses and return the number of addresses. + */ + public int jniSetAddresses(Vpn vpn, String interfaze, String addresses) { + return vpn.jniSetAddresses(interfaze, addresses); + } + + /** + * @see IoUtils#setBlocking(FileDescriptor, boolean) + */ + public void setBlocking(FileDescriptor fd, boolean blocking) { + try { + IoUtils.setBlocking(fd, blocking); + } catch (IOException e) { + throw new IllegalStateException( + "Cannot set tunnel's fd as blocking=" + blocking, e); + } + } } public Vpn(Looper looper, Context context, INetworkManagementService netService, INetd netd, @@ -431,6 +473,7 @@ public class Vpn { mVpnProfileStore = vpnProfileStore; mContext = context; mConnectivityManager = mContext.getSystemService(ConnectivityManager.class); + mAppOpsManager = mContext.getSystemService(AppOpsManager.class); mUserIdContext = context.createContextAsUser(UserHandle.of(userId), 0 /* flags */); mDeps = deps; mNms = netService; @@ -826,7 +869,6 @@ public class Vpn { VpnProfile profile = getVpnProfilePrivileged(alwaysOnPackage); if (profile != null) { startVpnProfilePrivileged(profile, alwaysOnPackage); - // If the above startVpnProfilePrivileged() call returns, the Ikev2VpnProfile was // correctly parsed, and the VPN has started running in a different thread. The only // other possibility is that the above call threw an exception, which will be @@ -974,9 +1016,15 @@ public class Vpn { } catch (Exception e) { // ignore } + mAppOpsManager.finishOp( + AppOpsManager.OPSTR_ESTABLISH_VPN_SERVICE, mOwnerUID, mPackage, null); mContext.unbindService(mConnection); cleanupVpnStateLocked(); } else if (mVpnRunner != null) { + if (!VpnConfig.LEGACY_VPN.equals(mPackage)) { + mAppOpsManager.finishOp( + AppOpsManager.OPSTR_ESTABLISH_VPN_MANAGER, mOwnerUID, mPackage, null); + } // cleanupVpnStateLocked() is called from mVpnRunner.exit() mVpnRunner.exit(); } @@ -1041,10 +1089,8 @@ public class Vpn { return false; } - final AppOpsManager appOpMgr = - (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE); for (final String appOpStr : toChange) { - appOpMgr.setMode( + mAppOpsManager.setMode( appOpStr, uid, packageName, @@ -1270,6 +1316,9 @@ public class Vpn { capsBuilder.addCapability(NET_CAPABILITY_NOT_METERED); } + capsBuilder.setUnderlyingNetworks((mConfig.underlyingNetworks != null) + ? Arrays.asList(mConfig.underlyingNetworks) : null); + mNetworkCapabilities = capsBuilder.build(); mNetworkAgent = new NetworkAgent(mContext, mLooper, NETWORKTYPE /* logtag */, mNetworkCapabilities, lp, @@ -1290,8 +1339,6 @@ public class Vpn { } finally { Binder.restoreCallingIdentity(token); } - mNetworkAgent.setUnderlyingNetworks((mConfig.underlyingNetworks != null) - ? Arrays.asList(mConfig.underlyingNetworks) : null); updateState(DetailedState.CONNECTED, "agentConnect"); } @@ -1365,9 +1412,9 @@ public class Vpn { Set<Range<Integer>> oldUsers = mNetworkCapabilities.getUids(); // Configure the interface. Abort if any of these steps fails. - ParcelFileDescriptor tun = ParcelFileDescriptor.adoptFd(jniCreate(config.mtu)); + final ParcelFileDescriptor tun = mDeps.adoptFd(this, config.mtu); try { - String interfaze = jniGetName(tun.getFd()); + final String interfaze = mDeps.jniGetName(this, tun.getFd()); // TEMP use the old jni calls until there is support for netd address setting StringBuilder builder = new StringBuilder(); @@ -1375,7 +1422,7 @@ public class Vpn { builder.append(" "); builder.append(address); } - if (jniSetAddresses(interfaze, builder.toString()) < 1) { + if (mDeps.jniSetAddresses(this, interfaze, builder.toString()) < 1) { throw new IllegalArgumentException("At least one address must be specified"); } Connection connection = new Connection(); @@ -1421,11 +1468,11 @@ public class Vpn { jniReset(oldInterface); } - try { - IoUtils.setBlocking(tun.getFileDescriptor(), config.blocking); - } catch (IOException e) { - throw new IllegalStateException( - "Cannot set tunnel's fd as blocking=" + config.blocking, e); + mDeps.setBlocking(tun.getFileDescriptor(), config.blocking); + // Record that the VPN connection is established by an app which uses VpnService API. + if (oldNetworkAgent != mNetworkAgent) { + mAppOpsManager.startOp( + AppOpsManager.OPSTR_ESTABLISH_VPN_SERVICE, mOwnerUID, mPackage, null, null); } } catch (RuntimeException e) { IoUtils.closeQuietly(tun); @@ -1780,9 +1827,17 @@ public class Vpn { synchronized (Vpn.this) { if (interfaze.equals(mInterface) && jniCheck(interfaze) == 0) { if (mConnection != null) { + mAppOpsManager.finishOp( + AppOpsManager.OPSTR_ESTABLISH_VPN_SERVICE, mOwnerUID, mPackage, + null); mContext.unbindService(mConnection); cleanupVpnStateLocked(); } else if (mVpnRunner != null) { + if (!VpnConfig.LEGACY_VPN.equals(mPackage)) { + mAppOpsManager.finishOp( + AppOpsManager.OPSTR_ESTABLISH_VPN_MANAGER, mOwnerUID, mPackage, + null); + } // cleanupVpnStateLocked() is called from mVpnRunner.exit() mVpnRunner.exit(); } @@ -3253,8 +3308,7 @@ public class Vpn { * * @param packageName the package name of the app provisioning this profile */ - public synchronized void startVpnProfile( - @NonNull String packageName) { + public synchronized void startVpnProfile(@NonNull String packageName) { requireNonNull(packageName, "No package name provided"); enforceNotRestrictedUser(); @@ -3317,6 +3371,13 @@ public class Vpn { Log.d(TAG, "Unknown VPN profile type: " + profile.type); break; } + + // Record that the VPN connection is established by an app which uses VpnManager API. + if (!VpnConfig.LEGACY_VPN.equals(packageName)) { + mAppOpsManager.startOp( + AppOpsManager.OPSTR_ESTABLISH_VPN_MANAGER, mOwnerUID, mPackage, null, + null); + } } catch (GeneralSecurityException e) { // Reset mConfig mConfig = null; diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java index d66d7ee99f2e..329a69634f71 100644 --- a/services/core/java/com/android/server/display/DisplayModeDirector.java +++ b/services/core/java/com/android/server/display/DisplayModeDirector.java @@ -512,7 +512,10 @@ public class DisplayModeDirector { */ public void setShouldAlwaysRespectAppRequestedMode(boolean enabled) { synchronized (mLock) { - mAlwaysRespectAppRequest = enabled; + if (mAlwaysRespectAppRequest != enabled) { + mAlwaysRespectAppRequest = enabled; + notifyDesiredDisplayModeSpecsChangedLocked(); + } } } diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java index a2cb78d27a57..c27293c3cc09 100755 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java @@ -209,6 +209,12 @@ abstract class HdmiCecLocalDevice { void init() { assertRunOnServiceThread(); mPreferredAddress = getPreferredAddress(); + if (mHandler.hasMessages(MSG_DISABLE_DEVICE_TIMEOUT)) { + // Remove and trigger the queued message for clearing all actions when going to standby. + // This is necessary because the device may wake up before the message is triggered. + mHandler.removeMessages(MSG_DISABLE_DEVICE_TIMEOUT); + handleDisableDeviceTimeout(); + } mPendingActionClearedCallback = null; } diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java index e5a8a17df525..a571dc06db97 100644 --- a/services/core/java/com/android/server/hdmi/HdmiControlService.java +++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java @@ -3131,7 +3131,7 @@ public class HdmiControlService extends SystemService { Slog.v(TAG, "On standby-action cleared:" + device.mDeviceType); devices.remove(device); if (devices.isEmpty()) { - onStandbyCompleted(standbyAction); + onPendingActionsCleared(standbyAction); // We will not clear local devices here, since some OEM/SOC will keep passing // the received packets until the application processor enters to the sleep // actually. @@ -3193,10 +3193,17 @@ public class HdmiControlService extends SystemService { mHdmiCecNetwork.clearLocalDevices(); } + /** + * Normally called after all devices have cleared their pending actions, to execute the final + * phase of the standby flow. + * + * This can also be called during wakeup, when pending actions are cleared after failing to be + * cleared during standby. In this case, it does not execute the standby flow. + */ @ServiceThreadOnly - private void onStandbyCompleted(int standbyAction) { + private void onPendingActionsCleared(int standbyAction) { assertRunOnServiceThread(); - Slog.v(TAG, "onStandbyCompleted"); + Slog.v(TAG, "onPendingActionsCleared"); if (!mPowerStatusController.isPowerStatusTransientToStandby()) { return; diff --git a/services/core/java/com/android/server/health/OWNERS b/services/core/java/com/android/server/health/OWNERS new file mode 100644 index 000000000000..81522fcaa09f --- /dev/null +++ b/services/core/java/com/android/server/health/OWNERS @@ -0,0 +1 @@ +file:platform/hardware/interfaces:/health/aidl/OWNERS diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index dc955337fdbc..3e52f5e07e62 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -2582,14 +2582,12 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } if (mCurToken != null) { - try { - if (DEBUG) { - Slog.v(TAG, "Removing window token: " + mCurToken + " for display: " - + mCurTokenDisplayId); - } - mIWindowManager.removeWindowToken(mCurToken, mCurTokenDisplayId); - } catch (RemoteException e) { + if (DEBUG) { + Slog.v(TAG, "Removing window token: " + mCurToken + " for display: " + + mCurTokenDisplayId); } + mWindowManagerInternal.removeWindowToken(mCurToken, false /* removeWindows */, + false /* animateExit */, mCurTokenDisplayId); // Set IME window status as invisible when unbind current method. mImeWindowVis = 0; mBackDisposition = InputMethodService.BACK_DISPOSITION_DEFAULT; diff --git a/services/core/java/com/android/server/inputmethod/OWNERS b/services/core/java/com/android/server/inputmethod/OWNERS index c09ade9e075f..00cd700541c0 100644 --- a/services/core/java/com/android/server/inputmethod/OWNERS +++ b/services/core/java/com/android/server/inputmethod/OWNERS @@ -5,3 +5,4 @@ yukawa@google.com tarandeep@google.com lumark@google.com roosa@google.com +wilsonwu@google.com diff --git a/services/core/java/com/android/server/media/BluetoothRouteProvider.java b/services/core/java/com/android/server/media/BluetoothRouteProvider.java index 7afa81aa047d..73de0f814325 100644 --- a/services/core/java/com/android/server/media/BluetoothRouteProvider.java +++ b/services/core/java/com/android/server/media/BluetoothRouteProvider.java @@ -26,6 +26,7 @@ import android.bluetooth.BluetoothA2dp; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothHearingAid; +import android.bluetooth.BluetoothLeAudio; import android.bluetooth.BluetoothProfile; import android.content.BroadcastReceiver; import android.content.Context; @@ -56,6 +57,7 @@ class BluetoothRouteProvider { private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); private static final String HEARING_AID_ROUTE_ID_PREFIX = "HEARING_AID_"; + private static final String LE_AUDIO_ROUTE_ID_PREFIX = "LE_AUDIO_"; @SuppressWarnings("WeakerAccess") /* synthetic access */ // Maps hardware address to BluetoothRouteInfo @@ -66,6 +68,8 @@ class BluetoothRouteProvider { BluetoothA2dp mA2dpProfile; @SuppressWarnings("WeakerAccess") /* synthetic access */ BluetoothHearingAid mHearingAidProfile; + @SuppressWarnings("WeakerAccess") /* synthetic access */ + BluetoothLeAudio mLeAudioProfile; // Route type -> volume map private final SparseIntArray mVolumeMap = new SparseIntArray(); @@ -108,6 +112,7 @@ class BluetoothRouteProvider { public void start(UserHandle user) { mBluetoothAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.A2DP); mBluetoothAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.HEARING_AID); + mBluetoothAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.LE_AUDIO); // Bluetooth on/off broadcasts addEventReceiver(BluetoothAdapter.ACTION_STATE_CHANGED, new AdapterStateChangedReceiver()); @@ -119,6 +124,10 @@ class BluetoothRouteProvider { deviceStateChangedReceiver); addEventReceiver(BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED, deviceStateChangedReceiver); + addEventReceiver(BluetoothLeAudio.ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED, + deviceStateChangedReceiver); + addEventReceiver(BluetoothLeAudio.ACTION_LE_AUDIO_ACTIVE_DEVICE_CHANGED, + deviceStateChangedReceiver); mContext.registerReceiverAsUser(mBroadcastReceiver, user, mIntentFilter, null, null); @@ -240,6 +249,8 @@ class BluetoothRouteProvider { | AudioManager.DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES | AudioManager.DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER)) != 0) { routeType = MediaRoute2Info.TYPE_BLUETOOTH_A2DP; + } else if ((devices & (AudioManager.DEVICE_OUT_BLE_HEADSET)) != 0) { + routeType = MediaRoute2Info.TYPE_BLE_HEADSET; } else { return false; } @@ -288,6 +299,12 @@ class BluetoothRouteProvider { routeId = HEARING_AID_ROUTE_ID_PREFIX + mHearingAidProfile.getHiSyncId(device); type = MediaRoute2Info.TYPE_HEARING_AID; } + if (mLeAudioProfile != null + && mLeAudioProfile.getConnectedDevices().contains(device)) { + newBtRoute.connectedProfiles.put(BluetoothProfile.LE_AUDIO, true); + routeId = LE_AUDIO_ROUTE_ID_PREFIX + mLeAudioProfile.getGroupId(device); + type = MediaRoute2Info.TYPE_BLE_HEADSET; + } // Current volume will be set when connected. newBtRoute.route = new MediaRoute2Info.Builder(routeId, deviceName) @@ -358,11 +375,7 @@ class BluetoothRouteProvider { } } - private void addActiveHearingAidDevices(BluetoothDevice device) { - if (DEBUG) { - Log.d(TAG, "Setting active hearing aid devices. device=" + device); - } - + private void addActiveDevices(BluetoothDevice device) { // Let the given device be the first active device BluetoothRouteInfo activeBtRoute = mBluetoothRoutes.get(device.getAddress()); addActiveRoute(activeBtRoute); @@ -376,6 +389,21 @@ class BluetoothRouteProvider { } } } + private void addActiveHearingAidDevices(BluetoothDevice device) { + if (DEBUG) { + Log.d(TAG, "Setting active hearing aid devices. device=" + device); + } + + addActiveDevices(device); + } + + private void addActiveLeAudioDevices(BluetoothDevice device) { + if (DEBUG) { + Log.d(TAG, "Setting active le audio devices. device=" + device); + } + + addActiveDevices(device); + } interface BluetoothRoutesUpdatedListener { void onBluetoothRoutesUpdated(@NonNull List<MediaRoute2Info> routes); @@ -392,6 +420,11 @@ class BluetoothRouteProvider { if (connectedProfiles.get(BluetoothProfile.HEARING_AID, false)) { return MediaRoute2Info.TYPE_HEARING_AID; } + + if (connectedProfiles.get(BluetoothProfile.LE_AUDIO, false)) { + return MediaRoute2Info.TYPE_BLE_HEADSET; + } + return MediaRoute2Info.TYPE_BLUETOOTH_A2DP; } } @@ -410,6 +443,10 @@ class BluetoothRouteProvider { mHearingAidProfile = (BluetoothHearingAid) proxy; activeDevices = mHearingAidProfile.getActiveDevices(); break; + case BluetoothProfile.LE_AUDIO: + mLeAudioProfile = (BluetoothLeAudio) proxy; + activeDevices = mLeAudioProfile.getActiveDevices(); + break; default: return; } @@ -434,6 +471,9 @@ class BluetoothRouteProvider { case BluetoothProfile.HEARING_AID: mHearingAidProfile = null; break; + case BluetoothProfile.LE_AUDIO: + mLeAudioProfile = null; + break; default: return; } @@ -490,12 +530,22 @@ class BluetoothRouteProvider { } notifyBluetoothRoutesUpdated(); break; + case BluetoothLeAudio.ACTION_LE_AUDIO_ACTIVE_DEVICE_CHANGED: + clearActiveRoutesWithType(MediaRoute2Info.TYPE_BLE_HEADSET); + if (device != null) { + addActiveLeAudioDevices(device); + } + notifyBluetoothRoutesUpdated(); + break; case BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED: handleConnectionStateChanged(BluetoothProfile.A2DP, intent, device); break; case BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED: handleConnectionStateChanged(BluetoothProfile.HEARING_AID, intent, device); break; + case BluetoothLeAudio.ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED: + handleConnectionStateChanged(BluetoothProfile.LE_AUDIO, intent, device); + break; } } diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index 84be7f5809e6..20687c6764db 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -4073,7 +4073,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { if (hasRestrictedModeAccess(uid)) { uidBlockedState.allowedReasons |= ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS; } else { - uidBlockedState.allowedReasons &= ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS; + uidBlockedState.allowedReasons &= ~ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS; } uidBlockedState.updateEffectiveBlockedReasons(); if (oldEffectiveBlockedReasons != uidBlockedState.effectiveBlockedReasons) { diff --git a/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java b/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java index 3019439a430b..5643873bef4d 100644 --- a/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java +++ b/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java @@ -215,7 +215,7 @@ public class DefaultCrossProfileIntentFiltersUtils { private static final DefaultCrossProfileIntentFilter RECOGNIZE_SPEECH = new DefaultCrossProfileIntentFilter.Builder( DefaultCrossProfileIntentFilter.Direction.TO_PARENT, - /* flags= */0, + /* flags= */ ONLY_IF_NO_MATCH_FOUND, /* letsPersonalDataIntoProfile= */ false) .addAction(ACTION_RECOGNIZE_SPEECH) .addCategory(Intent.CATEGORY_DEFAULT) diff --git a/services/core/java/com/android/server/pm/OWNERS b/services/core/java/com/android/server/pm/OWNERS index 3233819b543f..1bdc9f3cf850 100644 --- a/services/core/java/com/android/server/pm/OWNERS +++ b/services/core/java/com/android/server/pm/OWNERS @@ -3,27 +3,25 @@ hackbod@google.com jsharkey@android.com jsharkey@google.com narayan@google.com -patb@google.com svetoslavganov@android.com svetoslavganov@google.com -toddke@android.com -toddke@google.com +include /PACKAGE_MANAGER_OWNERS # apex support per-file ApexManager.java = dariofreni@google.com, ioffe@google.com, olilan@google.com per-file StagingManager.java = dariofreni@google.com, ioffe@google.com, olilan@google.com # dex -per-file AbstractStatsBase.java = calin@google.com, ngeoffray@google.com -per-file BackgroundDexOptService.java = calin@google.com, ngeoffray@google.com -per-file CompilerStats.java = calin@google.com, ngeoffray@google.com -per-file DynamicCodeLoggingService.java = alanstokes@google.com, calin@google.com, ngeoffray@google.com -per-file InstructionSets.java = calin@google.com, ngeoffray@google.com -per-file OtaDexoptService.java = calin@google.com, ngeoffray@google.com -per-file OtaDexoptShellCommand.java = calin@google.com, ngeoffray@google.com -per-file PackageDexOptimizer.java = calin@google.com, ngeoffray@google.com -per-file PackageManagerServiceCompilerMapping.java = calin@google.com, ngeoffray@google.com -per-file PackageUsage.java = calin@google.com, ngeoffray@google.com +per-file AbstractStatsBase.java = file:dex/OWNERS +per-file BackgroundDexOptService.java = file:dex/OWNERS +per-file CompilerStats.java = file:dex/OWNERS +per-file DynamicCodeLoggingService.java = file:dex/OWNERS +per-file InstructionSets.java = file:dex/OWNERS +per-file OtaDexoptService.java = file:dex/OWNERS +per-file OtaDexoptShellCommand.java = file:dex/OWNERS +per-file PackageDexOptimizer.java = file:dex/OWNERS +per-file PackageManagerServiceCompilerMapping.java = file:dex/OWNERS +per-file PackageUsage.java = file:dex/OWNERS # multi user / cross profile per-file CrossProfileAppsServiceImpl.java = omakoto@google.com, yamasani@google.com diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index f6acad0194c1..827dfc0caa16 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -7337,9 +7337,16 @@ public class PackageManagerService extends IPackageManager.Stub // Parse overlay configuration files to set default enable state, mutability, and // priority of system overlays. + final ArrayMap<String, File> apkInApexPreInstalledPaths = new ArrayMap<>(); + for (ApexManager.ActiveApexInfo apexInfo : mApexManager.getActiveApexInfos()) { + for (String packageName : mApexManager.getApksInApex(apexInfo.apexModuleName)) { + apkInApexPreInstalledPaths.put(packageName, apexInfo.preInstalledApexPath); + } + } mOverlayConfig = OverlayConfig.initializeSystemInstance( consumer -> mPmInternal.forEachPackage( - pkg -> consumer.accept(pkg, pkg.isSystem()))); + pkg -> consumer.accept(pkg, pkg.isSystem(), + apkInApexPreInstalledPaths.get(pkg.getPackageName())))); // Prune any system packages that no longer exist. final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<>(); diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java index c2c35b736eb7..08a72151aa37 100644 --- a/services/core/java/com/android/server/pm/StagingManager.java +++ b/services/core/java/com/android/server/pm/StagingManager.java @@ -1255,6 +1255,9 @@ public class StagingManager { info.diskImagePath = ai.modulePath; info.versionCode = ai.versionCode; info.versionName = ai.versionName; + info.hasBootClassPathJars = ai.hasBootClassPathJars; + info.hasDex2OatBootClassPathJars = ai.hasDex2OatBootClassPathJars; + info.hasSystemServerClassPathJars = ai.hasSystemServerClassPathJars; return info; } } diff --git a/services/core/java/com/android/server/pm/dex/OWNERS b/services/core/java/com/android/server/pm/dex/OWNERS index 5a4431ee8c89..052a4ca52afd 100644 --- a/services/core/java/com/android/server/pm/dex/OWNERS +++ b/services/core/java/com/android/server/pm/dex/OWNERS @@ -1,2 +1,3 @@ -calin@google.com +alanstokes@google.com +jiakaiz@google.com ngeoffray@google.com diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java index dab980a9e4b2..7bea01820a03 100644 --- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java +++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java @@ -213,6 +213,7 @@ final class DefaultPermissionGrantPolicy { NEARBY_DEVICES_PERMISSIONS.add(Manifest.permission.BLUETOOTH_CONNECT); NEARBY_DEVICES_PERMISSIONS.add(Manifest.permission.BLUETOOTH_SCAN); NEARBY_DEVICES_PERMISSIONS.add(Manifest.permission.UWB_RANGING); + NEARBY_DEVICES_PERMISSIONS.add(Manifest.permission.NEARBY_WIFI_DEVICES); } private static final int MSG_READ_DEFAULT_PERMISSION_EXCEPTIONS = 1; diff --git a/services/core/java/com/android/server/pm/permission/OWNERS b/services/core/java/com/android/server/pm/permission/OWNERS index 8c1a90c13513..fc0ee23c4859 100644 --- a/services/core/java/com/android/server/pm/permission/OWNERS +++ b/services/core/java/com/android/server/pm/permission/OWNERS @@ -1,7 +1,3 @@ include platform/frameworks/base:/core/java/android/permission/OWNERS -per-file DefaultPermissionGrantPolicy.java = hackbod@android.com -per-file DefaultPermissionGrantPolicy.java = jsharkey@android.com -per-file DefaultPermissionGrantPolicy.java = toddke@google.com -per-file DefaultPermissionGrantPolicy.java = yamasani@google.com -per-file DefaultPermissionGrantPolicy.java = patb@google.com +per-file DefaultPermissionGrantPolicy.java = file:platform/frameworks/base:/core/java/android/permission/DEFAULT_PERMISSION_GRANT_POLICY_OWNERS diff --git a/services/core/java/com/android/server/pm/permission/Permission.java b/services/core/java/com/android/server/pm/permission/Permission.java index cda48063e914..94e551a11dae 100644 --- a/services/core/java/com/android/server/pm/permission/Permission.java +++ b/services/core/java/com/android/server/pm/permission/Permission.java @@ -480,9 +480,10 @@ public final class Permission { r.append("DUP:"); r.append(permissionInfo.name); } - if (permission.isRuntime() && (ownerChanged || wasNonRuntime)) { - // If this is a runtime permission and the owner has changed, or this wasn't a runtime - // permission, then permission state should be cleaned up + if ((permission.isInternal() && ownerChanged) + || (permission.isRuntime() && (ownerChanged || wasNonRuntime))) { + // If this is an internal/runtime permission and the owner has changed, or this wasn't a + // runtime permission, then permission state should be cleaned up. permission.mDefinitionChanged = true; } if (PackageManagerService.DEBUG_PACKAGE_SCANNING && r != null) { diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java index 1133faabcf69..7b12709e4efd 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -1643,7 +1643,8 @@ public class PermissionManagerService extends IPermissionManager.Stub { isRolePermission = permission.isRole(); } final boolean mayRevokeRolePermission = isRolePermission - && mayManageRolePermission(callingUid); + // Allow ourselves to revoke role permissions due to definition changes. + && (callingUid == Process.myUid() || mayManageRolePermission(callingUid)); final boolean isRuntimePermission; synchronized (mLock) { @@ -2321,11 +2322,13 @@ public class PermissionManagerService extends IPermissionManager.Stub { for (int permNum = 0; permNum < numPermissions; permNum++) { final String permName = permissionsToRevoke.get(permNum); + final boolean isInternalPermission; synchronized (mLock) { final Permission bp = mRegistry.getPermission(permName); - if (bp == null || !bp.isRuntime()) { + if (bp == null || !(bp.isInternal() || bp.isRuntime())) { continue; } + isInternalPermission = bp.isInternal(); } mPackageManagerInt.forEachPackage(pkg -> { final String packageName = pkg.getPackageName(); @@ -2345,12 +2348,18 @@ public class PermissionManagerService extends IPermissionManager.Stub { if (permissionState == PackageManager.PERMISSION_GRANTED && (flags & flagMask) == 0) { final int uid = UserHandle.getUid(userId, appId); - EventLog.writeEvent(0x534e4554, "154505240", uid, - "Revoking permission " + permName + " from package " - + packageName + " due to definition change"); - EventLog.writeEvent(0x534e4554, "168319670", uid, - "Revoking permission " + permName + " from package " - + packageName + " due to definition change"); + if (isInternalPermission) { + EventLog.writeEvent(0x534e4554, "195338390", uid, + "Revoking permission " + permName + " from package " + + packageName + " due to definition change"); + } else { + EventLog.writeEvent(0x534e4554, "154505240", uid, + "Revoking permission " + permName + " from package " + + packageName + " due to definition change"); + EventLog.writeEvent(0x534e4554, "168319670", uid, + "Revoking permission " + permName + " from package " + + packageName + " due to definition change"); + } Slog.e(TAG, "Revoking permission " + permName + " from package " + packageName + " due to definition change"); try { diff --git a/services/core/java/com/android/server/security/OWNERS b/services/core/java/com/android/server/security/OWNERS index e6f5826557b5..5c2d5badfeee 100644 --- a/services/core/java/com/android/server/security/OWNERS +++ b/services/core/java/com/android/server/security/OWNERS @@ -1,3 +1,4 @@ # Bug component: 36824 +per-file *AttestationVerification* = file:/core/java/android/security/attestationverification/OWNERS per-file FileIntegrityService.java = victorhsieh@google.com diff --git a/services/core/java/com/android/server/soundtrigger_middleware/ConversionUtil.java b/services/core/java/com/android/server/soundtrigger_middleware/ConversionUtil.java index 6366280e1762..7ffff935128f 100644 --- a/services/core/java/com/android/server/soundtrigger_middleware/ConversionUtil.java +++ b/services/core/java/com/android/server/soundtrigger_middleware/ConversionUtil.java @@ -429,15 +429,7 @@ class ConversionUtil { private static @NonNull HidlMemory parcelFileDescriptorToHidlMemory(@Nullable ParcelFileDescriptor data, int dataSize) { if (dataSize > 0) { - // Extract a dup of the underlying FileDescriptor out of data. - FileDescriptor fd = new FileDescriptor(); - try { - ParcelFileDescriptor dup = data.dup(); - fd.setInt$(dup.detachFd()); - return HidlMemoryUtil.fileDescriptorToHidlMemory(fd, dataSize); - } catch (IOException e) { - throw new RuntimeException(e); - } + return HidlMemoryUtil.fileDescriptorToHidlMemory(data.getFileDescriptor(), dataSize); } else { return HidlMemoryUtil.fileDescriptorToHidlMemory(null, 0); } diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java index 61770ea1c1c2..68b760a1be34 100644 --- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java +++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java @@ -29,6 +29,7 @@ import static android.net.NetworkIdentity.OEM_PAID; import static android.net.NetworkIdentity.OEM_PRIVATE; import static android.net.NetworkStats.DEFAULT_NETWORK_ALL; import static android.net.NetworkStats.METERED_ALL; +import static android.net.NetworkStats.METERED_YES; import static android.net.NetworkStats.ROAMING_ALL; import static android.net.NetworkTemplate.MATCH_ETHERNET; import static android.net.NetworkTemplate.MATCH_MOBILE_WILDCARD; @@ -1340,7 +1341,7 @@ public class StatsPullAtomService extends SystemService { @Nullable private NetworkStats getUidNetworkStatsSnapshotForTransport(int transport) { final NetworkTemplate template = (transport == TRANSPORT_CELLULAR) ? NetworkTemplate.buildTemplateMobileWithRatType( - /*subscriptionId=*/null, NETWORK_TYPE_ALL) + /*subscriptionId=*/null, NETWORK_TYPE_ALL, METERED_YES) : NetworkTemplate.buildTemplateWifiWildcard(); return getUidNetworkStatsSnapshotForTemplate(template, /*includeTags=*/false); } @@ -1380,7 +1381,8 @@ public class StatsPullAtomService extends SystemService { final List<NetworkStatsExt> ret = new ArrayList<>(); for (final int ratType : getAllCollapsedRatTypes()) { final NetworkTemplate template = - buildTemplateMobileWithRatType(subInfo.subscriberId, ratType); + buildTemplateMobileWithRatType(subInfo.subscriberId, ratType, + METERED_YES); final NetworkStats stats = getUidNetworkStatsSnapshotForTemplate(template, /*includeTags=*/false); if (stats != null) { @@ -1601,7 +1603,7 @@ public class StatsPullAtomService extends SystemService { int pullBluetoothBytesTransferLocked(int atomTag, List<StatsEvent> pulledData) { BluetoothActivityEnergyInfo info = fetchBluetoothData(); - if (info == null || info.getUidTraffic() == null) { + if (info == null) { return StatsManager.PULL_SKIP; } for (UidTraffic traffic : info.getUidTraffic()) { @@ -2059,7 +2061,7 @@ public class StatsPullAtomService extends SystemService { if (info == null) { return StatsManager.PULL_SKIP; } - pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, info.getTimeStamp(), + pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, info.getTimestampMillis(), info.getBluetoothStackState(), info.getControllerTxTimeMillis(), info.getControllerRxTimeMillis(), info.getControllerIdleTimeMillis(), info.getControllerEnergyUsed())); diff --git a/services/core/java/com/android/server/timedetector/OWNERS b/services/core/java/com/android/server/timedetector/OWNERS index 8f8089717e3b..67fc9d66d69d 100644 --- a/services/core/java/com/android/server/timedetector/OWNERS +++ b/services/core/java/com/android/server/timedetector/OWNERS @@ -1,3 +1,3 @@ # Bug component: 847766 -mingaleev@google.com -include /core/java/android/app/timedetector/OWNERS +# This code is maintained by the same OWNERS as timezonedetector. +include /services/core/java/com/android/server/timezonedetector/OWNERS diff --git a/services/core/java/com/android/server/timezone/OWNERS b/services/core/java/com/android/server/timezone/OWNERS index 8f8089717e3b..2d365747473a 100644 --- a/services/core/java/com/android/server/timezone/OWNERS +++ b/services/core/java/com/android/server/timezone/OWNERS @@ -1,3 +1,2 @@ -# Bug component: 847766 -mingaleev@google.com -include /core/java/android/app/timedetector/OWNERS +# Bug component: 24949 +include platform/libcore:/OWNERS diff --git a/services/core/java/com/android/server/timezonedetector/OWNERS b/services/core/java/com/android/server/timezonedetector/OWNERS index 8f8089717e3b..029324246c91 100644 --- a/services/core/java/com/android/server/timezonedetector/OWNERS +++ b/services/core/java/com/android/server/timezonedetector/OWNERS @@ -1,3 +1,7 @@ # Bug component: 847766 +# This is the main list for platform time / time zone detection maintainers, for this dir and +# ultimately referenced by other OWNERS files for components maintained by the same team. +nfuller@google.com +jmorace@google.com mingaleev@google.com -include /core/java/android/app/timedetector/OWNERS +narayan@google.com diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java index 92e0845012de..f57a852fe8c5 100755 --- a/services/core/java/com/android/server/tv/TvInputHardwareManager.java +++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java @@ -1075,17 +1075,22 @@ class TvInputHardwareManager implements TvInputHal.Callback { } if (shouldRecreateAudioPatch) { mCommittedVolume = volume; - if (mAudioPatch != null) { - mAudioManager.releaseAudioPatch(mAudioPatch); - } - mAudioManager.createAudioPatch( + // only recreate if something was updated or audioPath is null + if (mAudioPatch == null || sinkUpdated ||sourceUpdated ) { + if (mAudioPatch != null) { + mAudioManager.releaseAudioPatch(mAudioPatch); + audioPatchArray[0] = null; + } + mAudioManager.createAudioPatch( audioPatchArray, new AudioPortConfig[] { sourceConfig }, sinkConfigs.toArray(new AudioPortConfig[sinkConfigs.size()])); - mAudioPatch = audioPatchArray[0]; - if (sourceGainConfig != null) { - mAudioManager.setAudioPortGain(mAudioSource, sourceGainConfig); + mAudioPatch = audioPatchArray[0]; } + } + + if (sourceGainConfig != null) { + mAudioManager.setAudioPortGain(mAudioSource, sourceGainConfig); } } diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java index 36a854e5374c..28947083854b 100755 --- a/services/core/java/com/android/server/tv/TvInputManagerService.java +++ b/services/core/java/com/android/server/tv/TvInputManagerService.java @@ -2304,10 +2304,9 @@ public final class TvInputManagerService extends SystemService { public void requestChannelBrowsable(Uri channelUri, int userId) throws RemoteException { final String callingPackageName = getCallingPackageName(); + final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), + Binder.getCallingUid(), userId, "requestChannelBrowsable"); final long identity = Binder.clearCallingIdentity(); - final int callingUid = Binder.getCallingUid(); - final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid, - userId, "requestChannelBrowsable"); try { Intent intent = new Intent(TvContract.ACTION_CHANNEL_BROWSABLE_REQUESTED); List<ResolveInfo> list = getContext().getPackageManager() diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java index 7dec4e785f5c..239a916fc5fc 100644 --- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java +++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java @@ -1663,8 +1663,6 @@ public class VcnGatewayConnection extends StateMachine { } /* validationStatusCallback */); agent.register(); - agent.setUnderlyingNetworks( - mUnderlying == null ? null : Collections.singletonList(mUnderlying.network)); agent.markConnected(); return agent; @@ -2039,6 +2037,7 @@ public class VcnGatewayConnection extends StateMachine { "Unknown transport type or missing TransportInfo/NetworkSpecifier for" + " non-null underlying network"); } + builder.setUnderlyingNetworks(List.of(underlying.network)); } else { Slog.wtf( TAG, diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 308df2f4e9a0..d1f21778177d 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -140,6 +140,7 @@ import static com.android.server.wm.ActivityRecordProto.IS_ANIMATING; import static com.android.server.wm.ActivityRecordProto.IS_WAITING_FOR_TRANSITION_START; import static com.android.server.wm.ActivityRecordProto.LAST_ALL_DRAWN; import static com.android.server.wm.ActivityRecordProto.LAST_SURFACE_SHOWING; +import static com.android.server.wm.ActivityRecordProto.MIN_ASPECT_RATIO; import static com.android.server.wm.ActivityRecordProto.NAME; import static com.android.server.wm.ActivityRecordProto.NUM_DRAWN_WINDOWS; import static com.android.server.wm.ActivityRecordProto.NUM_INTERESTING_WINDOWS; @@ -656,6 +657,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A boolean mLastImeShown; /** + * When set to true, the IME insets will be frozen until the next app becomes IME input target. + * @see InsetsPolicy#adjustVisibilityForIme + */ + boolean mImeInsetsFrozenUntilStartInput; + + /** * A flag to determine if this AR is in the process of closing or entering PIP. This is needed * to help AR know that the app is in the process of closing but hasn't yet started closing on * the WM side. @@ -1343,13 +1350,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } final Task rootTask = getRootTask(); - // If we reparent, make sure to remove ourselves from the old animation registry. - if (mAnimatingActivityRegistry != null) { - mAnimatingActivityRegistry.notifyFinished(this); - } - mAnimatingActivityRegistry = rootTask != null - ? rootTask.getAnimatingActivityRegistry() - : null; + updateAnimatingActivityRegistry(); if (task == mLastParentBeforePip) { // Activity's reparented back from pip, clear the links once established @@ -1363,6 +1364,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } if (newTask != null && isState(RESUMED)) { newTask.setResumedActivity(this, "onParentChanged"); + mImeInsetsFrozenUntilStartInput = false; } if (rootTask != null && rootTask.topRunningActivity() == this) { @@ -1373,6 +1375,20 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } } + void updateAnimatingActivityRegistry() { + final Task rootTask = getRootTask(); + final AnimatingActivityRegistry registry = rootTask != null + ? rootTask.getAnimatingActivityRegistry() + : null; + + // If we reparent, make sure to remove ourselves from the old animation registry. + if (mAnimatingActivityRegistry != null && mAnimatingActivityRegistry != registry) { + mAnimatingActivityRegistry.notifyFinished(this); + } + + mAnimatingActivityRegistry = registry; + } + /** * Sets {@link #mLastParentBeforePip} to the current parent Task, it's caller's job to ensure * {@link #getTask()} is set before this is called. @@ -4759,6 +4775,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A && imeInputTarget.getWindow().mActivityRecord == this && mDisplayContent.mInputMethodWindow != null && mDisplayContent.mInputMethodWindow.isVisible(); + mImeInsetsFrozenUntilStartInput = true; } final DisplayContent displayContent = getDisplayContent(); @@ -5877,6 +5894,14 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // closing activity having to wait until idle timeout to be stopped or destroyed if the // next activity won't report idle (e.g. repeated view animation). mTaskSupervisor.scheduleProcessStoppingAndFinishingActivitiesIfNeeded(); + + // If the activity is visible, but no windows are eligible to start input, unfreeze + // to avoid permanently frozen IME insets. + if (mImeInsetsFrozenUntilStartInput && getWindow( + win -> WindowManager.LayoutParams.mayUseInputMethod(win.mAttrs.flags)) + == null) { + mImeInsetsFrozenUntilStartInput = false; + } } } @@ -7792,6 +7817,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } } + @Override + void onResize() { + // Reset freezing IME insets flag when the activity resized. + mImeInsetsFrozenUntilStartInput = false; + super.onResize(); + } + /** Returns true if the configuration is compatible with this activity. */ boolean isConfigurationCompatible(Configuration config) { final int orientation = getRequestedOrientation(); @@ -8641,6 +8673,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } proto.write(PIP_AUTO_ENTER_ENABLED, pictureInPictureArgs.isAutoEnterEnabled()); proto.write(IN_SIZE_COMPAT_MODE, inSizeCompatMode()); + proto.write(MIN_ASPECT_RATIO, info.getMinAspectRatio()); } @Override diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index dbc1116ad389..9335846e7805 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -1165,10 +1165,10 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } } - WindowToken removeWindowToken(IBinder binder) { + WindowToken removeWindowToken(IBinder binder, boolean animateExit) { final WindowToken token = mTokenMap.remove(binder); if (token != null && token.asActivityRecord() == null) { - token.setExiting(); + token.setExiting(animateExit); } return token; } @@ -1252,7 +1252,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } void removeAppToken(IBinder binder) { - final WindowToken token = removeWindowToken(binder); + final WindowToken token = removeWindowToken(binder, true /* animateExit */); if (token == null) { Slog.w(TAG_WM, "removeAppToken: Attempted to remove non-existing token: " + binder); return; @@ -3971,6 +3971,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp void updateImeInputAndControlTarget(WindowState target) { if (mImeInputTarget != target) { ProtoLog.i(WM_DEBUG_IME, "setInputMethodInputTarget %s", target); + if (target != null && target.mActivityRecord != null) { + target.mActivityRecord.mImeInsetsFrozenUntilStartInput = false; + } setImeInputTarget(target); updateImeControlTarget(); } diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java index f2f192686ad5..a8e1c1cda72b 100644 --- a/services/core/java/com/android/server/wm/InsetsPolicy.java +++ b/services/core/java/com/android/server/wm/InsetsPolicy.java @@ -211,7 +211,7 @@ class InsetsPolicy { InsetsState getInsetsForWindow(WindowState target) { final InsetsState originalState = mStateController.getInsetsForWindow(target); final InsetsState state = adjustVisibilityForTransientTypes(originalState); - return target.mIsImWindow ? adjustVisibilityForIme(state, state == originalState) : state; + return adjustVisibilityForIme(target, state, state == originalState); } /** @@ -241,16 +241,37 @@ class InsetsPolicy { return state; } - // Navigation bar insets is always visible to IME. - private static InsetsState adjustVisibilityForIme(InsetsState originalState, + private InsetsState adjustVisibilityForIme(WindowState w, InsetsState originalState, boolean copyState) { - final InsetsSource originalNavSource = originalState.peekSource(ITYPE_NAVIGATION_BAR); - if (originalNavSource != null && !originalNavSource.isVisible()) { - final InsetsState state = copyState ? new InsetsState(originalState) : originalState; - final InsetsSource navSource = new InsetsSource(originalNavSource); - navSource.setVisible(true); - state.addSource(navSource); - return state; + if (w.mIsImWindow) { + // Navigation bar insets is always visible to IME. + final InsetsSource originalNavSource = originalState.peekSource(ITYPE_NAVIGATION_BAR); + if (originalNavSource != null && !originalNavSource.isVisible()) { + final InsetsState state = copyState ? new InsetsState(originalState) + : originalState; + final InsetsSource navSource = new InsetsSource(originalNavSource); + navSource.setVisible(true); + state.addSource(navSource); + return state; + } + } else if (w.mActivityRecord != null && w.mActivityRecord.mImeInsetsFrozenUntilStartInput) { + // During switching tasks with gestural navigation, if the IME is attached to + // one app window on that time, even the next app window is behind the IME window, + // conceptually the window should not receive the IME insets if the next window is + // not eligible IME requester and ready to show IME on top of it. + final boolean shouldImeAttachedToApp = mDisplayContent.shouldImeAttachedToApp(); + final InsetsSource originalImeSource = originalState.peekSource(ITYPE_IME); + + if (shouldImeAttachedToApp && originalImeSource != null) { + final boolean imeVisibility = + w.mActivityRecord.mLastImeShown || w.getRequestedVisibility(ITYPE_IME); + final InsetsState state = copyState ? new InsetsState(originalState) + : originalState; + final InsetsSource imeSource = new InsetsSource(originalImeSource); + imeSource.setVisible(imeVisibility); + state.addSource(imeSource); + return state; + } } return originalState; } diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 516be553d5f8..963485554b5e 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -1464,6 +1464,9 @@ class Task extends WindowContainer<WindowContainer> { adjustBoundsForDisplayChangeIfNeeded(getDisplayContent()); mRootWindowContainer.updateUIDsPresentOnDisplay(); + + // Ensure all animations are finished at same time in split-screen mode. + forAllActivities(ActivityRecord::updateAnimatingActivityRegistry); } void cleanUpActivityReferences(ActivityRecord r) { diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java index e74371036619..a518222c3bde 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotController.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java @@ -118,6 +118,11 @@ class TaskSnapshotController { */ private final boolean mIsRunningOnWear; + /** + * Flag indicating if device configuration has disabled app snapshots. + */ + private final boolean mConfigDisableTaskSnapshots; + TaskSnapshotController(WindowManagerService service) { mService = service; mPersister = new TaskSnapshotPersister(mService, Environment::getDataSystemCeDirectory); @@ -131,6 +136,8 @@ class TaskSnapshotController { PackageManager.FEATURE_WATCH); mHighResTaskSnapshotScale = mService.mContext.getResources().getFloat( com.android.internal.R.dimen.config_highResTaskSnapshotScale); + mConfigDisableTaskSnapshots = mService.mContext.getResources().getBoolean( + com.android.internal.R.bool.config_disableTaskSnapshots); } void systemReady() { @@ -488,7 +495,8 @@ class TaskSnapshotController { } boolean shouldDisableSnapshots() { - return mIsRunningOnWear || mIsRunningOnTv || mIsRunningOnIoT; + return mIsRunningOnWear || mIsRunningOnTv || mIsRunningOnIoT + || mConfigDisableTaskSnapshots; } /** diff --git a/services/core/java/com/android/server/wm/WallpaperWindowToken.java b/services/core/java/com/android/server/wm/WallpaperWindowToken.java index 194f48f57cc4..b54e8b7a7b4e 100644 --- a/services/core/java/com/android/server/wm/WallpaperWindowToken.java +++ b/services/core/java/com/android/server/wm/WallpaperWindowToken.java @@ -66,8 +66,8 @@ class WallpaperWindowToken extends WindowToken { } @Override - void setExiting() { - super.setExiting(); + void setExiting(boolean animateExit) { + super.setExiting(animateExit); mDisplayContent.mWallpaperController.removeWallpaperToken(this); } diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java index 47087cfbd147..4fac05c349c5 100644 --- a/services/core/java/com/android/server/wm/WindowManagerInternal.java +++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java @@ -445,8 +445,21 @@ public abstract class WindowManagerInternal { * @param removeWindows Whether to also remove the windows associated with the token. * @param displayId The display to remove the token from. */ + public final void removeWindowToken(android.os.IBinder token, boolean removeWindows, + int displayId) { + removeWindowToken(token, removeWindows, true /* animateExit */, displayId); + } + + /** + * Removes a window token. + * + * @param token The toke to remove. + * @param removeWindows Whether to also remove the windows associated with the token. + * @param animateExit Whether to play the windows exit animation after the token removal. + * @param displayId The display to remove the token from. + */ public abstract void removeWindowToken(android.os.IBinder token, boolean removeWindows, - int displayId); + boolean animateExit, int displayId); /** * Registers a listener to be notified about app transition events. diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 1ec9187d7a76..9caef70f6b51 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -2816,6 +2816,31 @@ public class WindowManagerService extends IWindowManager.Stub } + void removeWindowToken(IBinder binder, boolean removeWindows, boolean animateExit, + int displayId) { + synchronized (mGlobalLock) { + final DisplayContent dc = mRoot.getDisplayContent(displayId); + + if (dc == null) { + ProtoLog.w(WM_ERROR, "removeWindowToken: Attempted to remove token: %s" + + " for non-exiting displayId=%d", binder, displayId); + return; + } + final WindowToken token = dc.removeWindowToken(binder, animateExit); + if (token == null) { + ProtoLog.w(WM_ERROR, + "removeWindowToken: Attempted to remove non-existing token: %s", + binder); + return; + } + + if (removeWindows) { + token.removeAllWindowsIfPossible(); + } + dc.getInputMonitor().updateInputWindowsLw(true /* force */); + } + } + @Override public void removeWindowToken(IBinder binder, int displayId) { if (!checkCallingPermission(MANAGE_APP_TOKENS, "removeWindowToken()")) { @@ -2823,23 +2848,7 @@ public class WindowManagerService extends IWindowManager.Stub } final long origId = Binder.clearCallingIdentity(); try { - synchronized (mGlobalLock) { - final DisplayContent dc = mRoot.getDisplayContent(displayId); - - if (dc == null) { - ProtoLog.w(WM_ERROR, "removeWindowToken: Attempted to remove token: %s" - + " for non-exiting displayId=%d", binder, displayId); - return; - } - final WindowToken token = dc.removeWindowToken(binder); - if (token == null) { - ProtoLog.w(WM_ERROR, - "removeWindowToken: Attempted to remove non-existing token: %s", - binder); - return; - } - dc.getInputMonitor().updateInputWindowsLw(true /*force*/); - } + removeWindowToken(binder, false /* removeWindows */, true /* animateExit */, displayId); } finally { Binder.restoreCallingIdentity(origId); } @@ -7536,28 +7545,10 @@ public class WindowManagerService extends IWindowManager.Stub } @Override - public void removeWindowToken(IBinder binder, boolean removeWindows, int displayId) { - synchronized (mGlobalLock) { - if (removeWindows) { - final DisplayContent dc = mRoot.getDisplayContent(displayId); - if (dc == null) { - ProtoLog.w(WM_ERROR, "removeWindowToken: Attempted to remove token: %s" - + " for non-exiting displayId=%d", binder, displayId); - return; - } - - final WindowToken token = dc.removeWindowToken(binder); - if (token == null) { - ProtoLog.w(WM_ERROR, - "removeWindowToken: Attempted to remove non-existing token: %s", - binder); - return; - } - - token.removeAllWindowsIfPossible(); - } - WindowManagerService.this.removeWindowToken(binder, displayId); - } + public void removeWindowToken(IBinder binder, boolean removeWindows, boolean animateExit, + int displayId) { + WindowManagerService.this.removeWindowToken(binder, removeWindows, animateExit, + displayId); } @Override diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java index 5540cc567ed2..4857fb3faa76 100644 --- a/services/core/java/com/android/server/wm/WindowProcessController.java +++ b/services/core/java/com/android/server/wm/WindowProcessController.java @@ -1547,7 +1547,9 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio // activity as it could lead to incorrect display metrics. For ex, IME services // expect their config to match the config of the display with the IME window // showing. + // If the configuration has been overridden by previous activity, empty it. mIsActivityConfigOverrideAllowed = false; + unregisterActivityConfigurationListener(); break; default: break; diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index c3fc99554bcc..5e042efa2f11 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -2180,11 +2180,18 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } } - boolean onSetAppExiting() { + boolean onSetAppExiting(boolean animateExit) { final DisplayContent displayContent = getDisplayContent(); boolean changed = false; - if (isVisibleNow()) { + if (!animateExit) { + // Hide the window permanently if no window exist animation is performed, so we can + // avoid the window surface becoming visible again unexpectedly during the next + // relayout. + mPermanentlyHidden = true; + hide(false /* doAnimation */, false /* requestAnim */); + } + if (isVisibleNow() && animateExit) { mWinAnimator.applyAnimationLocked(TRANSIT_EXIT, false); if (mWmService.mAccessibilityController != null) { mWmService.mAccessibilityController.onWindowTransition(this, TRANSIT_EXIT); @@ -2197,7 +2204,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP for (int i = mChildren.size() - 1; i >= 0; --i) { final WindowState c = mChildren.get(i); - changed |= c.onSetAppExiting(); + changed |= c.onSetAppExiting(animateExit); } return changed; diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java index fbfa400ba852..3cbc67c004cd 100644 --- a/services/core/java/com/android/server/wm/WindowToken.java +++ b/services/core/java/com/android/server/wm/WindowToken.java @@ -24,6 +24,7 @@ import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_MOVEMENT; +import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION; import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN; import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS; import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION; @@ -232,7 +233,7 @@ class WindowToken extends WindowContainer<WindowState> { } } - void setExiting() { + void setExiting(boolean animateExit) { if (isEmpty()) { super.removeImmediately(); return; @@ -247,11 +248,12 @@ class WindowToken extends WindowContainer<WindowState> { final int count = mChildren.size(); boolean changed = false; - final boolean delayed = isAnimating(TRANSITION | PARENTS | CHILDREN); + final boolean delayed = isAnimating(TRANSITION | PARENTS) + || (isAnimating(CHILDREN, ANIMATION_TYPE_WINDOW_ANIMATION) && animateExit); for (int i = 0; i < count; i++) { final WindowState win = mChildren.get(i); - changed |= win.onSetAppExiting(); + changed |= win.onSetAppExiting(animateExit); } final ActivityRecord app = asActivityRecord(); @@ -353,7 +355,7 @@ class WindowToken extends WindowContainer<WindowState> { @Override void removeImmediately() { if (mDisplayContent != null) { - mDisplayContent.removeWindowToken(token); + mDisplayContent.removeWindowToken(token, true /* animateExit */); } // Needs to occur after the token is removed from the display above to avoid attempt at // duplicate removal of this window container from it's parent. diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp index 2722b8d04370..710a304545af 100644 --- a/services/core/jni/Android.bp +++ b/services/core/jni/Android.bp @@ -165,7 +165,7 @@ cc_defaults { "android.hardware.power@1.1", "android.hardware.power-V2-cpp", "android.hardware.power.stats@1.0", - "android.hardware.power.stats-V1-ndk_platform", + "android.hardware.power.stats-V1-ndk", "android.hardware.thermal@1.0", "android.hardware.tv.input@1.0", "android.hardware.vibrator-V2-cpp", @@ -178,7 +178,7 @@ cc_defaults { "android.frameworks.schedulerservice@1.0", "android.frameworks.sensorservice@1.0", "android.frameworks.stats@1.0", - "android.frameworks.stats-V1-ndk_platform", + "android.frameworks.stats-V1-ndk", "android.system.suspend.control-V1-cpp", "android.system.suspend.control.internal-cpp", "android.system.suspend-V1-ndk", diff --git a/services/core/jni/com_android_server_power_PowerManagerService.cpp b/services/core/jni/com_android_server_power_PowerManagerService.cpp index 7fea547459bc..fe86ff1ef7ef 100644 --- a/services/core/jni/com_android_server_power_PowerManagerService.cpp +++ b/services/core/jni/com_android_server_power_PowerManagerService.cpp @@ -178,9 +178,10 @@ sp<system::suspend::internal::ISuspendControlServiceInternal> getSuspendControlI void enableAutoSuspend() { static bool enabled = false; if (!enabled) { + static sp<IBinder> autosuspendClientToken = new BBinder(); sp<system::suspend::internal::ISuspendControlServiceInternal> suspendControl = getSuspendControlInternal(); - suspendControl->enableAutosuspend(&enabled); + suspendControl->enableAutosuspend(autosuspendClientToken, &enabled); } { diff --git a/services/java/com/android/server/SystemConfigService.java b/services/java/com/android/server/SystemConfigService.java index 3a9b2dca3921..cb52e5f72d5f 100644 --- a/services/java/com/android/server/SystemConfigService.java +++ b/services/java/com/android/server/SystemConfigService.java @@ -19,6 +19,7 @@ import static java.util.stream.Collectors.toList; import static java.util.stream.Collectors.toMap; import android.Manifest; +import android.content.ComponentName; import android.content.Context; import android.os.ISystemConfig; import android.util.ArrayMap; @@ -87,14 +88,14 @@ public class SystemConfigService extends SystemService { } @Override - public List<String> getEnabledComponentOverrides(String packageName) { + public List<ComponentName> getEnabledComponentOverrides(String packageName) { ArrayMap<String, Boolean> systemComponents = SystemConfig.getInstance() .getComponentsEnabledStates(packageName); - List<String> enabledComponent = new ArrayList<>(); + List<ComponentName> enabledComponent = new ArrayList<>(); if (systemComponents != null) { for (Map.Entry<String, Boolean> entry : systemComponents.entrySet()) { if (Boolean.TRUE.equals(entry.getValue())) { - enabledComponent.add(entry.getKey()); + enabledComponent.add(new ComponentName(packageName, entry.getKey())); } } } diff --git a/services/net/Android.bp b/services/net/Android.bp index 09a831e2b8c4..0c3f1dd3589d 100644 --- a/services/net/Android.bp +++ b/services/net/Android.bp @@ -41,6 +41,7 @@ java_library { sdk_version: "module_current", min_sdk_version: "30", libs: [ + "framework-annotations-lib", "unsupportedappusage", "framework-wifi-util-lib", "framework-connectivity", diff --git a/services/tests/PackageManagerServiceTests/OWNERS b/services/tests/PackageManagerServiceTests/OWNERS index 182dfe8fca9e..86ae5818e91c 100644 --- a/services/tests/PackageManagerServiceTests/OWNERS +++ b/services/tests/PackageManagerServiceTests/OWNERS @@ -1,3 +1 @@ -chiuwinson@google.com -patb@google.com -toddke@google.com +include /PACKAGE_MANAGER_OWNERS diff --git a/services/tests/servicestests/src/com/android/server/BatteryServiceTest.java b/services/tests/servicestests/src/com/android/server/BatteryServiceTest.java index cb12ba7d7679..a2ecbc30ec64 100644 --- a/services/tests/servicestests/src/com/android/server/BatteryServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/BatteryServiceTest.java @@ -47,7 +47,6 @@ public class BatteryServiceTest extends AndroidTestCase { @Mock BatteryService.HealthServiceWrapper.IHealthSupplier mHealthServiceSupplier; BatteryService.HealthServiceWrapper mWrapper; - private static final String HEALTHD = BatteryService.HealthServiceWrapper.INSTANCE_HEALTHD; private static final String VENDOR = BatteryService.HealthServiceWrapper.INSTANCE_VENDOR; @Override @@ -117,7 +116,7 @@ public class BatteryServiceTest extends AndroidTestCase { @SmallTest public void testWrapPreferVendor() throws Exception { - initForInstances(VENDOR, HEALTHD); + initForInstances(VENDOR); mWrapper.init(mCallback, mManagerSupplier, mHealthServiceSupplier); waitHandlerThreadFinish(); verify(mCallback, times(1)).onRegistration(same(null), same(mMockedHal), eq(VENDOR)); @@ -126,16 +125,6 @@ public class BatteryServiceTest extends AndroidTestCase { } @SmallTest - public void testUseHealthd() throws Exception { - initForInstances(HEALTHD); - mWrapper.init(mCallback, mManagerSupplier, mHealthServiceSupplier); - waitHandlerThreadFinish(); - verify(mCallback, times(1)).onRegistration(same(null), same(mMockedHal), eq(HEALTHD)); - verify(mCallback, never()).onRegistration(same(mMockedHal), same(mMockedHal), anyString()); - verify(mCallback, times(1)).onRegistration(same(mMockedHal), same(mMockedHal2), eq(HEALTHD)); - } - - @SmallTest public void testNoService() throws Exception { initForInstances("unrelated"); try { diff --git a/services/tests/servicestests/src/com/android/server/OWNERS b/services/tests/servicestests/src/com/android/server/OWNERS index f1402ead3866..6a7d298514c5 100644 --- a/services/tests/servicestests/src/com/android/server/OWNERS +++ b/services/tests/servicestests/src/com/android/server/OWNERS @@ -3,4 +3,5 @@ per-file *AppOp* = file:/core/java/android/permission/OWNERS per-file *Bluetooth* = file:/core/java/android/bluetooth/OWNERS per-file *Gnss* = file:/services/core/java/com/android/server/location/OWNERS per-file *Network* = file:/services/core/java/com/android/server/net/OWNERS +per-file BatteryServiceTest.java = file:platform/hardware/interfaces:/health/aidl/OWNERS per-file GestureLauncherServiceTest.java = file:platform/packages/apps/EmergencyInfo:/OWNERS diff --git a/services/tests/servicestests/src/com/android/server/timedetector/OWNERS b/services/tests/servicestests/src/com/android/server/timedetector/OWNERS index 8f8089717e3b..a0f46e172da6 100644 --- a/services/tests/servicestests/src/com/android/server/timedetector/OWNERS +++ b/services/tests/servicestests/src/com/android/server/timedetector/OWNERS @@ -1,3 +1,2 @@ # Bug component: 847766 -mingaleev@google.com -include /core/java/android/app/timedetector/OWNERS +include /services/core/java/com/android/server/timedetector/OWNERS diff --git a/services/tests/servicestests/src/com/android/server/timezone/OWNERS b/services/tests/servicestests/src/com/android/server/timezone/OWNERS index 8f8089717e3b..61652604ee9f 100644 --- a/services/tests/servicestests/src/com/android/server/timezone/OWNERS +++ b/services/tests/servicestests/src/com/android/server/timezone/OWNERS @@ -1,3 +1,2 @@ -# Bug component: 847766 -mingaleev@google.com -include /core/java/android/app/timedetector/OWNERS +# Bug component: 24949 +include /services/core/java/com/android/server/timezone/OWNERS diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/OWNERS b/services/tests/servicestests/src/com/android/server/timezonedetector/OWNERS index 8f8089717e3b..a6ff1ba8a8cb 100644 --- a/services/tests/servicestests/src/com/android/server/timezonedetector/OWNERS +++ b/services/tests/servicestests/src/com/android/server/timezonedetector/OWNERS @@ -1,3 +1,2 @@ # Bug component: 847766 -mingaleev@google.com -include /core/java/android/app/timedetector/OWNERS +include /services/core/java/com/android/server/timezonedetector/OWNERS diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java index 293e862a6b74..6f04f176afd8 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -39,6 +39,7 @@ import static android.os.Process.NOBODY_UID; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW; +import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD; import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; @@ -2816,6 +2817,73 @@ public class ActivityRecordTests extends WindowTestsBase { assertFalse(activity.mDisplayContent.mClosingApps.contains(activity)); } + @Test + public void testImeInsetsFrozenFlag_resetWhenReparented() { + final ActivityRecord activity = createActivityWithTask(); + final WindowState app = createWindow(null, TYPE_APPLICATION, activity, "app"); + final WindowState imeWindow = createWindow(null, TYPE_APPLICATION, "imeWindow"); + final Task newTask = new TaskBuilder(mSupervisor).build(); + makeWindowVisible(app, imeWindow); + mDisplayContent.mInputMethodWindow = imeWindow; + mDisplayContent.setImeLayeringTarget(app); + mDisplayContent.setImeInputTarget(app); + + // Simulate app is closing and expect the last IME is shown and IME insets is frozen. + app.mActivityRecord.commitVisibility(false, false); + assertTrue(app.mActivityRecord.mLastImeShown); + assertTrue(app.mActivityRecord.mImeInsetsFrozenUntilStartInput); + + // Expect IME insets frozen state will reset when the activity is reparent to the new task. + activity.setState(RESUMED, "test"); + activity.reparent(newTask, 0 /* top */, "test"); + assertFalse(app.mActivityRecord.mImeInsetsFrozenUntilStartInput); + } + + @UseTestDisplay(addWindows = W_INPUT_METHOD) + @Test + public void testImeInsetsFrozenFlag_resetWhenResized() { + final WindowState app = createWindow(null, TYPE_APPLICATION, "app"); + makeWindowVisibleAndDrawn(app, mImeWindow); + mDisplayContent.setImeLayeringTarget(app); + mDisplayContent.setImeInputTarget(app); + + // Simulate app is closing and expect the last IME is shown and IME insets is frozen. + app.mActivityRecord.commitVisibility(false, false); + assertTrue(app.mActivityRecord.mLastImeShown); + assertTrue(app.mActivityRecord.mImeInsetsFrozenUntilStartInput); + + // Expect IME insets frozen state will reset when the activity is reparent to the new task. + app.mActivityRecord.onResize(); + assertFalse(app.mActivityRecord.mImeInsetsFrozenUntilStartInput); + } + + @UseTestDisplay(addWindows = W_INPUT_METHOD) + @Test + public void testImeInsetsFrozenFlag_resetWhenNoImeFocusableInActivity() { + final WindowState app = createWindow(null, TYPE_APPLICATION, "app"); + makeWindowVisibleAndDrawn(app, mImeWindow); + mDisplayContent.setImeLayeringTarget(app); + mDisplayContent.setImeInputTarget(app); + + // Simulate app is closing and expect the last IME is shown and IME insets is frozen. + app.mActivityRecord.commitVisibility(false, false); + app.mActivityRecord.onWindowsGone(); + + assertTrue(app.mActivityRecord.mLastImeShown); + assertTrue(app.mActivityRecord.mImeInsetsFrozenUntilStartInput); + + // Expect IME insets frozen state will reset when the activity has no IME focusable window. + app.mActivityRecord.forAllWindowsUnchecked(w -> { + w.mAttrs.flags |= FLAG_ALT_FOCUSABLE_IM; + return true; + }, true); + + app.mActivityRecord.commitVisibility(true, false); + app.mActivityRecord.onWindowsVisible(); + + assertFalse(app.mActivityRecord.mImeInsetsFrozenUntilStartInput); + } + private void assertHasStartingWindow(ActivityRecord atoken) { assertNotNull(atoken.mStartingSurface); assertNotNull(atoken.mStartingData); diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java index a8e17534e6ed..8e7ba4bc3293 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java +++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java @@ -258,6 +258,7 @@ public class SystemServicesTestRule implements TestRule { final ActivityManagerInternal amInternal = mAmService.mInternal; spyOn(amInternal); doNothing().when(amInternal).trimApplications(); + doNothing().when(amInternal).scheduleAppGcs(); doNothing().when(amInternal).updateCpuStats(); doNothing().when(amInternal).updateOomAdj(); doNothing().when(amInternal).updateBatteryStats(any(), anyInt(), anyInt(), anyBoolean()); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java index 92b670ed9699..d88ac256be5c 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java @@ -891,6 +891,40 @@ public class WindowStateTests extends WindowTestsBase { assertTrue(mAppWindow.getInsetsState().getSourceOrDefaultVisibility(ITYPE_NAVIGATION_BAR)); } + @Test + public void testAdjustImeInsetsVisibilityWhenSwitchingApps() { + final WindowState app = createWindow(null, TYPE_APPLICATION, "app"); + final WindowState app2 = createWindow(null, TYPE_APPLICATION, "app2"); + final WindowState imeWindow = createWindow(null, TYPE_APPLICATION, "imeWindow"); + spyOn(imeWindow); + doReturn(true).when(imeWindow).isVisible(); + mDisplayContent.mInputMethodWindow = imeWindow; + + final InsetsStateController controller = mDisplayContent.getInsetsStateController(); + controller.getImeSourceProvider().setWindow(imeWindow, null, null); + + // Simulate app requests IME with updating all windows Insets State when IME is above app. + mDisplayContent.setImeLayeringTarget(app); + mDisplayContent.setImeInputTarget(app); + assertTrue(mDisplayContent.shouldImeAttachedToApp()); + controller.getImeSourceProvider().scheduleShowImePostLayout(app); + controller.getImeSourceProvider().getSource().setVisible(true); + controller.updateAboveInsetsState(imeWindow, false); + + // Expect all app windows behind IME can receive IME insets visible. + assertTrue(app.getInsetsState().getSource(ITYPE_IME).isVisible()); + assertTrue(app2.getInsetsState().getSource(ITYPE_IME).isVisible()); + + // Simulate app plays closing transition to app2. + app.mActivityRecord.commitVisibility(false, false); + assertTrue(app.mActivityRecord.mLastImeShown); + assertTrue(app.mActivityRecord.mImeInsetsFrozenUntilStartInput); + + // Verify the IME insets is visible on app, but not for app2 during app task switching. + assertTrue(app.getInsetsState().getSource(ITYPE_IME).isVisible()); + assertFalse(app2.getInsetsState().getSource(ITYPE_IME).isVisible()); + } + @UseTestDisplay(addWindows = { W_ACTIVITY }) @Test public void testUpdateImeControlTargetWhenLeavingMultiWindow() { diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java index d048f1842aa3..589f9134f227 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java @@ -24,6 +24,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; import static android.view.WindowManager.LayoutParams.TYPE_TOAST; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; +import static com.android.server.policy.WindowManagerPolicy.TRANSIT_EXIT; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -44,6 +45,7 @@ import androidx.test.filters.SmallTest; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mockito; import java.util.function.BiFunction; @@ -126,7 +128,7 @@ public class WindowTokenTests extends WindowTestsBase { final WindowState window1 = createWindow(null, TYPE_TOAST, token, "window1"); final WindowState window2 = createWindow(null, TYPE_TOAST, token, "window2"); - mDisplayContent.removeWindowToken(token.token); + mDisplayContent.removeWindowToken(token.token, true /* animateExit */); // Verify that the token is no longer mapped on the display assertNull(mDisplayContent.getWindowToken(token.token)); // Verify that the token is still attached to its parent @@ -261,4 +263,29 @@ public class WindowTokenTests extends WindowTestsBase { assertNotNull(app.getFrozenInsetsState()); assertNull(mDisplayContent.mInputMethodWindow.getFrozenInsetsState()); } + + @Test + public void testRemoveWindowToken_noAnimateExitWhenSet() { + final TestWindowToken token = createTestWindowToken(0, mDisplayContent); + final WindowState win = createWindow(null, TYPE_APPLICATION, token, "win"); + makeWindowVisible(win); + assertTrue(win.isOnScreen()); + spyOn(win); + spyOn(win.mWinAnimator); + spyOn(win.mToken); + + // Invoking removeWindowToken with setting no window exit animation and not remove window + // immediately. verify the window will hide without applying exit animation. + mWm.removeWindowToken(win.mToken.token, false /* removeWindows */, false /* animateExit */, + mDisplayContent.mDisplayId); + verify(win).onSetAppExiting(Mockito.eq(false) /* animateExit */); + verify(win).hide(false /* doAnimation */, false /* requestAnim */); + assertFalse(win.isOnScreen()); + verify(win.mWinAnimator, Mockito.never()).applyAnimationLocked(TRANSIT_EXIT, false); + assertTrue(win.mToken.hasChild()); + + // Even though the window is being removed afterwards, it won't apply exit animation. + win.removeIfPossible(); + verify(win.mWinAnimator, Mockito.never()).applyAnimationLocked(TRANSIT_EXIT, false); + } } diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java index 7f24c365237d..1579aaf9a571 100644 --- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java +++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java @@ -765,6 +765,8 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser // send a sticky broadcast containing USB accessory handshake information Intent intent = new Intent(UsbManager.ACTION_USB_ACCESSORY_HANDSHAKE) + .addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND + | Intent.FLAG_RECEIVER_FOREGROUND) .putExtra(UsbManager.EXTRA_ACCESSORY_UEVENT_TIME, mAccessoryConnectionStartTime) .putExtra(UsbManager.EXTRA_ACCESSORY_STRING_COUNT, diff --git a/startop/OWNERS b/startop/OWNERS index 2d1eb38952ed..11d5ad0f000a 100644 --- a/startop/OWNERS +++ b/startop/OWNERS @@ -1,7 +1,2 @@ -# mailing list: startop-eng@google.com -calin@google.com -chriswailes@google.com -eholk@google.com -iam@google.com -mathieuc@google.com -yawanng@google.com +include platform/art:/OWNERS +keunyoung@google.com diff --git a/telephony/java/android/telephony/BarringInfo.java b/telephony/java/android/telephony/BarringInfo.java index e9698adc0356..0aa4b5805cd6 100644 --- a/telephony/java/android/telephony/BarringInfo.java +++ b/telephony/java/android/telephony/BarringInfo.java @@ -28,7 +28,6 @@ import android.util.SparseArray; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import java.util.List; import java.util.Objects; /** @@ -269,42 +268,6 @@ public final class BarringInfo implements Parcelable { mBarringServiceInfos = barringServiceInfos; } - /** @hide */ - public static BarringInfo create( - @NonNull android.hardware.radio.V1_5.CellIdentity halBarringCellId, - @NonNull List<android.hardware.radio.V1_5.BarringInfo> halBarringInfos) { - CellIdentity ci = CellIdentity.create(halBarringCellId); - SparseArray<BarringServiceInfo> serviceInfos = new SparseArray<>(); - - for (android.hardware.radio.V1_5.BarringInfo halBarringInfo : halBarringInfos) { - if (halBarringInfo.barringType - == android.hardware.radio.V1_5.BarringInfo.BarringType.CONDITIONAL) { - if (halBarringInfo.barringTypeSpecificInfo.getDiscriminator() - != android.hardware.radio.V1_5.BarringInfo.BarringTypeSpecificInfo - .hidl_discriminator.conditional) { - // this is an error case where the barring info is conditional but the - // conditional barring fields weren't included - continue; - } - android.hardware.radio.V1_5.BarringInfo.BarringTypeSpecificInfo - .Conditional conditionalInfo = - halBarringInfo.barringTypeSpecificInfo.conditional(); - serviceInfos.put( - halBarringInfo.serviceType, new BarringServiceInfo( - halBarringInfo.barringType, // will always be CONDITIONAL here - conditionalInfo.isBarred, - conditionalInfo.factor, - conditionalInfo.timeSeconds)); - } else { - // Barring type is either NONE or UNCONDITIONAL - serviceInfos.put( - halBarringInfo.serviceType, new BarringServiceInfo( - halBarringInfo.barringType, false, 0, 0)); - } - } - return new BarringInfo(ci, serviceInfos); - } - /** * Get the BarringServiceInfo for a specified service. * diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 73e6c76fe214..d11c66702d99 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -1879,6 +1879,20 @@ public class CarrierConfigManager { "lte_plus_threshold_bandwidth_khz_int"; /** + * The combined channel bandwidth threshold (non-inclusive) in KHz required to display the + * NR advanced (i.e. 5G+) data icon. It is 0 by default, meaning minimum bandwidth check is + * not enabled. Other factors like bands or frequency can also determine whether the NR + * advanced data icon is shown or not. + * + * @see #KEY_ADDITIONAL_NR_ADVANCED_BANDS_INT_ARRAY + * @see #KEY_NR_ADVANCED_CAPABLE_PCO_ID_INT + * + * @hide + */ + public static final String KEY_NR_ADVANCED_THRESHOLD_BANDWIDTH_KHZ_INT = + "nr_advanced_threshold_bandwidth_khz_int"; + + /** * The string is used to filter redundant string from PLMN Network Name that's supplied by * specific carrier. * @@ -3543,6 +3557,17 @@ public class CarrierConfigManager { "nr_advanced_capable_pco_id_int"; /** + * Enabled NR advanced (i.e. 5G+) icon while roaming. The default value is {@code true}, meaming + * the same NR advanced logic used for home network will be used for roaming network as well. + * Set this to {@code false} will disable NR advanced icon while the device is roaming, + * regardless meeting NR advanced criteria or not. + * + * @hide + */ + public static final String KEY_ENABLE_NR_ADVANCED_WHILE_ROAMING_BOOL = + "enable_nr_advanced_for_roaming_bool"; + + /** * This configuration allows the framework to use user data communication to detect Idle state, * and this is used on the 5G icon. * @@ -5560,6 +5585,7 @@ public class CarrierConfigManager { sDefaults.putString(KEY_SHOW_CARRIER_DATA_ICON_PATTERN_STRING, ""); sDefaults.putBoolean(KEY_HIDE_LTE_PLUS_DATA_ICON_BOOL, true); sDefaults.putInt(KEY_LTE_PLUS_THRESHOLD_BANDWIDTH_KHZ_INT, 20000); + sDefaults.putInt(KEY_NR_ADVANCED_THRESHOLD_BANDWIDTH_KHZ_INT, 0); sDefaults.putIntArray(KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY, new int[]{CARRIER_NR_AVAILABILITY_NSA, CARRIER_NR_AVAILABILITY_SA}); sDefaults.putBoolean(KEY_LTE_ENABLED_BOOL, true); @@ -5655,6 +5681,7 @@ public class CarrierConfigManager { sDefaults.putLong(KEY_5G_WATCHDOG_TIME_MS_LONG, 3600000); sDefaults.putIntArray(KEY_ADDITIONAL_NR_ADVANCED_BANDS_INT_ARRAY, new int[0]); sDefaults.putInt(KEY_NR_ADVANCED_CAPABLE_PCO_ID_INT, 0); + sDefaults.putBoolean(KEY_ENABLE_NR_ADVANCED_WHILE_ROAMING_BOOL, true); sDefaults.putBoolean(KEY_LTE_ENDC_USING_USER_DATA_FOR_RRC_DETECTION_BOOL, false); sDefaults.putBoolean(KEY_UNMETERED_NR_NSA_BOOL, false); sDefaults.putBoolean(KEY_UNMETERED_NR_NSA_MMWAVE_BOOL, false); diff --git a/telephony/java/android/telephony/CellConfigLte.java b/telephony/java/android/telephony/CellConfigLte.java index 4b57d71d84ba..3e4e244a3dc6 100644 --- a/telephony/java/android/telephony/CellConfigLte.java +++ b/telephony/java/android/telephony/CellConfigLte.java @@ -34,11 +34,6 @@ public class CellConfigLte implements Parcelable { } /** @hide */ - public CellConfigLte(android.hardware.radio.V1_4.CellConfigLte cellConfig) { - mIsEndcAvailable = cellConfig.isEndcAvailable; - } - - /** @hide */ public CellConfigLte(boolean isEndcAvailable) { mIsEndcAvailable = isEndcAvailable; } diff --git a/telephony/java/android/telephony/CellIdentity.java b/telephony/java/android/telephony/CellIdentity.java index 15147da925b8..06cfd6718664 100644 --- a/telephony/java/android/telephony/CellIdentity.java +++ b/telephony/java/android/telephony/CellIdentity.java @@ -20,7 +20,6 @@ import android.annotation.CallSuper; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; -import android.hardware.radio.V1_0.CellInfoType; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; @@ -359,104 +358,4 @@ public abstract class CellIdentity implements Parcelable { return true; } - - /** @hide */ - public static CellIdentity create(android.hardware.radio.V1_0.CellIdentity cellIdentity) { - if (cellIdentity == null) return null; - switch(cellIdentity.cellInfoType) { - case CellInfoType.GSM: { - if (cellIdentity.cellIdentityGsm.size() == 1) { - return new CellIdentityGsm(cellIdentity.cellIdentityGsm.get(0)); - } - break; - } - case CellInfoType.WCDMA: { - if (cellIdentity.cellIdentityWcdma.size() == 1) { - return new CellIdentityWcdma(cellIdentity.cellIdentityWcdma.get(0)); - } - break; - } - case CellInfoType.TD_SCDMA: { - if (cellIdentity.cellIdentityTdscdma.size() == 1) { - return new CellIdentityTdscdma(cellIdentity.cellIdentityTdscdma.get(0)); - } - break; - } - case CellInfoType.LTE: { - if (cellIdentity.cellIdentityLte.size() == 1) { - return new CellIdentityLte(cellIdentity.cellIdentityLte.get(0)); - } - break; - } - case CellInfoType.CDMA: { - if (cellIdentity.cellIdentityCdma.size() == 1) { - return new CellIdentityCdma(cellIdentity.cellIdentityCdma.get(0)); - } - break; - } - case CellInfoType.NONE: break; - default: break; - } - return null; - } - - /** @hide */ - public static CellIdentity create(android.hardware.radio.V1_2.CellIdentity cellIdentity) { - if (cellIdentity == null) return null; - switch(cellIdentity.cellInfoType) { - case CellInfoType.GSM: { - if (cellIdentity.cellIdentityGsm.size() == 1) { - return new CellIdentityGsm(cellIdentity.cellIdentityGsm.get(0)); - } - break; - } - case CellInfoType.WCDMA: { - if (cellIdentity.cellIdentityWcdma.size() == 1) { - return new CellIdentityWcdma(cellIdentity.cellIdentityWcdma.get(0)); - } - break; - } - case CellInfoType.TD_SCDMA: { - if (cellIdentity.cellIdentityTdscdma.size() == 1) { - return new CellIdentityTdscdma(cellIdentity.cellIdentityTdscdma.get(0)); - } - break; - } - case CellInfoType.LTE: { - if (cellIdentity.cellIdentityLte.size() == 1) { - return new CellIdentityLte(cellIdentity.cellIdentityLte.get(0)); - } - break; - } - case CellInfoType.CDMA: { - if (cellIdentity.cellIdentityCdma.size() == 1) { - return new CellIdentityCdma(cellIdentity.cellIdentityCdma.get(0)); - } - break; - } - case CellInfoType.NONE: break; - default: break; - } - return null; - } - - /** @hide */ - public static CellIdentity create(android.hardware.radio.V1_5.CellIdentity ci) { - if (ci == null) return null; - switch (ci.getDiscriminator()) { - case android.hardware.radio.V1_5.CellIdentity.hidl_discriminator.gsm: - return new CellIdentityGsm(ci.gsm()); - case android.hardware.radio.V1_5.CellIdentity.hidl_discriminator.cdma: - return new CellIdentityCdma(ci.cdma()); - case android.hardware.radio.V1_5.CellIdentity.hidl_discriminator.lte: - return new CellIdentityLte(ci.lte()); - case android.hardware.radio.V1_5.CellIdentity.hidl_discriminator.wcdma: - return new CellIdentityWcdma(ci.wcdma()); - case android.hardware.radio.V1_5.CellIdentity.hidl_discriminator.tdscdma: - return new CellIdentityTdscdma(ci.tdscdma()); - case android.hardware.radio.V1_5.CellIdentity.hidl_discriminator.nr: - return new CellIdentityNr(ci.nr()); - default: return null; - } - } } diff --git a/telephony/java/android/telephony/CellIdentityCdma.java b/telephony/java/android/telephony/CellIdentityCdma.java index 58a01e9d01af..ba3a192074bc 100644 --- a/telephony/java/android/telephony/CellIdentityCdma.java +++ b/telephony/java/android/telephony/CellIdentityCdma.java @@ -112,17 +112,6 @@ public final class CellIdentityCdma extends CellIdentity { updateGlobalCellId(); } - /** @hide */ - public CellIdentityCdma(@NonNull android.hardware.radio.V1_0.CellIdentityCdma cid) { - this(cid.networkId, cid.systemId, cid.baseStationId, cid.longitude, cid.latitude, "", ""); - } - - /** @hide */ - public CellIdentityCdma(@NonNull android.hardware.radio.V1_2.CellIdentityCdma cid) { - this(cid.base.networkId, cid.base.systemId, cid.base.baseStationId, cid.base.longitude, - cid.base.latitude, cid.operatorNames.alphaLong, cid.operatorNames.alphaShort); - } - private CellIdentityCdma(@NonNull CellIdentityCdma cid) { this(cid.mNetworkId, cid.mSystemId, cid.mBasestationId, cid.mLongitude, cid.mLatitude, cid.mAlphaLong, cid.mAlphaShort); diff --git a/telephony/java/android/telephony/CellIdentityGsm.java b/telephony/java/android/telephony/CellIdentityGsm.java index a3bec339794b..2516a79546f8 100644 --- a/telephony/java/android/telephony/CellIdentityGsm.java +++ b/telephony/java/android/telephony/CellIdentityGsm.java @@ -101,30 +101,6 @@ public final class CellIdentityGsm extends CellIdentity { updateGlobalCellId(); } - /** @hide */ - public CellIdentityGsm(@NonNull android.hardware.radio.V1_0.CellIdentityGsm cid) { - this(cid.lac, cid.cid, cid.arfcn, - cid.bsic == (byte) 0xFF ? CellInfo.UNAVAILABLE : cid.bsic, - cid.mcc, cid.mnc, "", "", new ArraySet<>()); - } - - /** @hide */ - public CellIdentityGsm(@NonNull android.hardware.radio.V1_2.CellIdentityGsm cid) { - this(cid.base.lac, cid.base.cid, cid.base.arfcn, - cid.base.bsic == (byte) 0xFF ? CellInfo.UNAVAILABLE : cid.base.bsic, cid.base.mcc, - cid.base.mnc, cid.operatorNames.alphaLong, cid.operatorNames.alphaShort, - new ArraySet<>()); - } - - /** @hide */ - public CellIdentityGsm(@NonNull android.hardware.radio.V1_5.CellIdentityGsm cid) { - this(cid.base.base.lac, cid.base.base.cid, cid.base.base.arfcn, - cid.base.base.bsic == (byte) 0xFF ? CellInfo.UNAVAILABLE - : cid.base.base.bsic, cid.base.base.mcc, - cid.base.base.mnc, cid.base.operatorNames.alphaLong, - cid.base.operatorNames.alphaShort, cid.additionalPlmns); - } - private CellIdentityGsm(@NonNull CellIdentityGsm cid) { this(cid.mLac, cid.mCid, cid.mArfcn, cid.mBsic, cid.mMccStr, cid.mMncStr, cid.mAlphaLong, cid.mAlphaShort, cid.mAdditionalPlmns); diff --git a/telephony/java/android/telephony/CellIdentityLte.java b/telephony/java/android/telephony/CellIdentityLte.java index bd92d00a0321..4db00cf258e5 100644 --- a/telephony/java/android/telephony/CellIdentityLte.java +++ b/telephony/java/android/telephony/CellIdentityLte.java @@ -136,31 +136,6 @@ public final class CellIdentityLte extends CellIdentity { updateGlobalCellId(); } - /** @hide */ - public CellIdentityLte(@NonNull android.hardware.radio.V1_0.CellIdentityLte cid) { - this(cid.ci, cid.pci, cid.tac, cid.earfcn, new int[] {}, - CellInfo.UNAVAILABLE, cid.mcc, cid.mnc, "", "", new ArraySet<>(), null); - } - - /** @hide */ - public CellIdentityLte(@NonNull android.hardware.radio.V1_2.CellIdentityLte cid) { - this(cid.base.ci, cid.base.pci, cid.base.tac, cid.base.earfcn, new int[] {}, - cid.bandwidth, cid.base.mcc, cid.base.mnc, cid.operatorNames.alphaLong, - cid.operatorNames.alphaShort, new ArraySet<>(), null); - } - - /** @hide */ - public CellIdentityLte(@NonNull android.hardware.radio.V1_5.CellIdentityLte cid) { - this(cid.base.base.ci, cid.base.base.pci, cid.base.base.tac, cid.base.base.earfcn, - cid.bands.stream().mapToInt(Integer::intValue).toArray(), cid.base.bandwidth, - cid.base.base.mcc, cid.base.base.mnc, cid.base.operatorNames.alphaLong, - cid.base.operatorNames.alphaShort, cid.additionalPlmns, - cid.optionalCsgInfo.getDiscriminator() - == android.hardware.radio.V1_5.OptionalCsgInfo.hidl_discriminator.csgInfo - ? new ClosedSubscriberGroupInfo(cid.optionalCsgInfo.csgInfo()) - : null); - } - private CellIdentityLte(@NonNull CellIdentityLte cid) { this(cid.mCi, cid.mPci, cid.mTac, cid.mEarfcn, cid.mBands, cid.mBandwidth, cid.mMccStr, cid.mMncStr, cid.mAlphaLong, cid.mAlphaShort, cid.mAdditionalPlmns, cid.mCsgInfo); diff --git a/telephony/java/android/telephony/CellIdentityNr.java b/telephony/java/android/telephony/CellIdentityNr.java index 4f5052151af5..6aeb482fb236 100644 --- a/telephony/java/android/telephony/CellIdentityNr.java +++ b/telephony/java/android/telephony/CellIdentityNr.java @@ -65,7 +65,6 @@ public final class CellIdentityNr extends CellIdentity { } /** - * * @param pci Physical Cell Id in range [0, 1007]. * @param tac 24-bit Tracking Area Code. * @param nrArfcn NR Absolute Radio Frequency Channel Number, in range [0, 3279165]. @@ -100,21 +99,6 @@ public final class CellIdentityNr extends CellIdentity { } /** @hide */ - public CellIdentityNr(@NonNull android.hardware.radio.V1_4.CellIdentityNr cid) { - this(cid.pci, cid.tac, cid.nrarfcn, new int[] {}, cid.mcc, cid.mnc, cid.nci, - cid.operatorNames.alphaLong, cid.operatorNames.alphaShort, - new ArraySet<>()); - } - - /** @hide */ - public CellIdentityNr(@NonNull android.hardware.radio.V1_5.CellIdentityNr cid) { - this(cid.base.pci, cid.base.tac, cid.base.nrarfcn, - cid.bands.stream().mapToInt(Integer::intValue).toArray(), cid.base.mcc, - cid.base.mnc, cid.base.nci, cid.base.operatorNames.alphaLong, - cid.base.operatorNames.alphaShort, cid.additionalPlmns); - } - - /** @hide */ @Override public @NonNull CellIdentityNr sanitizeLocationInfo() { return new CellIdentityNr(CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, mNrArfcn, diff --git a/telephony/java/android/telephony/CellIdentityTdscdma.java b/telephony/java/android/telephony/CellIdentityTdscdma.java index ec07d5494849..13d93737f751 100644 --- a/telephony/java/android/telephony/CellIdentityTdscdma.java +++ b/telephony/java/android/telephony/CellIdentityTdscdma.java @@ -113,31 +113,6 @@ public final class CellIdentityTdscdma extends CellIdentity { } /** @hide */ - public CellIdentityTdscdma(@NonNull android.hardware.radio.V1_0.CellIdentityTdscdma cid) { - this(cid.mcc, cid.mnc, cid.lac, cid.cid, cid.cpid, CellInfo.UNAVAILABLE, "", "", - Collections.emptyList(), null); - } - - /** @hide */ - public CellIdentityTdscdma(@NonNull android.hardware.radio.V1_2.CellIdentityTdscdma cid) { - this(cid.base.mcc, cid.base.mnc, cid.base.lac, cid.base.cid, cid.base.cpid, - cid.uarfcn, cid.operatorNames.alphaLong, cid.operatorNames.alphaShort, - Collections.emptyList(), null); - } - - /** @hide */ - public CellIdentityTdscdma(@NonNull android.hardware.radio.V1_5.CellIdentityTdscdma cid) { - this(cid.base.base.mcc, cid.base.base.mnc, cid.base.base.lac, cid.base.base.cid, - cid.base.base.cpid, cid.base.uarfcn, cid.base.operatorNames.alphaLong, - cid.base.operatorNames.alphaShort, - cid.additionalPlmns, - cid.optionalCsgInfo.getDiscriminator() - == android.hardware.radio.V1_5.OptionalCsgInfo.hidl_discriminator.csgInfo - ? new ClosedSubscriberGroupInfo(cid.optionalCsgInfo.csgInfo()) - : null); - } - - /** @hide */ @Override public @NonNull CellIdentityTdscdma sanitizeLocationInfo() { return new CellIdentityTdscdma(mMccStr, mMncStr, CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, diff --git a/telephony/java/android/telephony/CellIdentityWcdma.java b/telephony/java/android/telephony/CellIdentityWcdma.java index b04a51d238c1..9b463da14f16 100644 --- a/telephony/java/android/telephony/CellIdentityWcdma.java +++ b/telephony/java/android/telephony/CellIdentityWcdma.java @@ -107,30 +107,6 @@ public final class CellIdentityWcdma extends CellIdentity { updateGlobalCellId(); } - /** @hide */ - public CellIdentityWcdma(@NonNull android.hardware.radio.V1_0.CellIdentityWcdma cid) { - this(cid.lac, cid.cid, cid.psc, cid.uarfcn, cid.mcc, cid.mnc, "", "", - new ArraySet<>(), null); - } - - /** @hide */ - public CellIdentityWcdma(@NonNull android.hardware.radio.V1_2.CellIdentityWcdma cid) { - this(cid.base.lac, cid.base.cid, cid.base.psc, cid.base.uarfcn, - cid.base.mcc, cid.base.mnc, cid.operatorNames.alphaLong, - cid.operatorNames.alphaShort, new ArraySet<>(), null); - } - - /** @hide */ - public CellIdentityWcdma(@NonNull android.hardware.radio.V1_5.CellIdentityWcdma cid) { - this(cid.base.base.lac, cid.base.base.cid, cid.base.base.psc, cid.base.base.uarfcn, - cid.base.base.mcc, cid.base.base.mnc, cid.base.operatorNames.alphaLong, - cid.base.operatorNames.alphaShort, cid.additionalPlmns, - cid.optionalCsgInfo.getDiscriminator() - == android.hardware.radio.V1_5.OptionalCsgInfo.hidl_discriminator.csgInfo - ? new ClosedSubscriberGroupInfo(cid.optionalCsgInfo.csgInfo()) - : null); - } - private CellIdentityWcdma(@NonNull CellIdentityWcdma cid) { this(cid.mLac, cid.mCid, cid.mPsc, cid.mUarfcn, cid.mMccStr, cid.mMncStr, cid.mAlphaLong, cid.mAlphaShort, cid.mAdditionalPlmns, cid.mCsgInfo); diff --git a/telephony/java/android/telephony/CellInfo.java b/telephony/java/android/telephony/CellInfo.java index 189a4b898886..2b2df24bb268 100644 --- a/telephony/java/android/telephony/CellInfo.java +++ b/telephony/java/android/telephony/CellInfo.java @@ -20,7 +20,6 @@ import android.annotation.ElapsedRealtimeLong; import android.annotation.IntDef; import android.annotation.NonNull; import android.compat.annotation.UnsupportedAppUsage; -import android.hardware.radio.V1_4.CellInfo.Info; import android.os.Parcel; import android.os.Parcelable; @@ -150,6 +149,13 @@ public abstract class CellInfo implements Parcelable { private long mTimeStamp; /** @hide */ + protected CellInfo(int cellConnectionStatus, boolean registered, long timestamp) { + mCellConnectionStatus = cellConnectionStatus; + mRegistered = registered; + mTimeStamp = timestamp; + } + + /** @hide */ protected CellInfo() { this.mRegistered = false; this.mTimeStamp = Long.MAX_VALUE; @@ -321,131 +327,4 @@ public abstract class CellInfo implements Parcelable { return new CellInfo[size]; } }; - - /** @hide */ - protected CellInfo(android.hardware.radio.V1_0.CellInfo ci) { - this.mRegistered = ci.registered; - this.mTimeStamp = ci.timeStamp; - this.mCellConnectionStatus = CONNECTION_UNKNOWN; - } - - /** @hide */ - protected CellInfo(android.hardware.radio.V1_2.CellInfo ci) { - this.mRegistered = ci.registered; - this.mTimeStamp = ci.timeStamp; - this.mCellConnectionStatus = ci.connectionStatus; - } - - /** @hide */ - protected CellInfo(android.hardware.radio.V1_4.CellInfo ci, long timeStamp) { - this.mRegistered = ci.isRegistered; - this.mTimeStamp = timeStamp; - this.mCellConnectionStatus = ci.connectionStatus; - } - - /** @hide */ - protected CellInfo(android.hardware.radio.V1_5.CellInfo ci, long timeStamp) { - this.mRegistered = ci.registered; - this.mTimeStamp = timeStamp; - this.mCellConnectionStatus = ci.connectionStatus; - } - - /** @hide */ - protected CellInfo(android.hardware.radio.V1_6.CellInfo ci, long timeStamp) { - this.mRegistered = ci.registered; - this.mTimeStamp = timeStamp; - this.mCellConnectionStatus = ci.connectionStatus; - } - - /** @hide */ - public static CellInfo create(android.hardware.radio.V1_0.CellInfo ci) { - if (ci == null) return null; - switch(ci.cellInfoType) { - case android.hardware.radio.V1_0.CellInfoType.GSM: return new CellInfoGsm(ci); - case android.hardware.radio.V1_0.CellInfoType.CDMA: return new CellInfoCdma(ci); - case android.hardware.radio.V1_0.CellInfoType.LTE: return new CellInfoLte(ci); - case android.hardware.radio.V1_0.CellInfoType.WCDMA: return new CellInfoWcdma(ci); - case android.hardware.radio.V1_0.CellInfoType.TD_SCDMA: return new CellInfoTdscdma(ci); - default: return null; - } - } - - /** @hide */ - public static CellInfo create(android.hardware.radio.V1_2.CellInfo ci) { - if (ci == null) return null; - switch(ci.cellInfoType) { - case android.hardware.radio.V1_0.CellInfoType.GSM: return new CellInfoGsm(ci); - case android.hardware.radio.V1_0.CellInfoType.CDMA: return new CellInfoCdma(ci); - case android.hardware.radio.V1_0.CellInfoType.LTE: return new CellInfoLte(ci); - case android.hardware.radio.V1_0.CellInfoType.WCDMA: return new CellInfoWcdma(ci); - case android.hardware.radio.V1_0.CellInfoType.TD_SCDMA: return new CellInfoTdscdma(ci); - default: return null; - } - } - - /** @hide */ - public static CellInfo create(android.hardware.radio.V1_4.CellInfo ci, long timeStamp) { - if (ci == null) return null; - switch (ci.info.getDiscriminator()) { - case Info.hidl_discriminator.gsm: return new CellInfoGsm(ci, timeStamp); - case Info.hidl_discriminator.cdma: return new CellInfoCdma(ci, timeStamp); - case Info.hidl_discriminator.lte: return new CellInfoLte(ci, timeStamp); - case Info.hidl_discriminator.wcdma: return new CellInfoWcdma(ci, timeStamp); - case Info.hidl_discriminator.tdscdma: return new CellInfoTdscdma(ci, timeStamp); - case Info.hidl_discriminator.nr: return new CellInfoNr(ci, timeStamp); - default: return null; - } - } - - /** @hide */ - public static CellInfo create(android.hardware.radio.V1_5.CellInfo ci, long timeStamp) { - if (ci == null) return null; - switch (ci.ratSpecificInfo.getDiscriminator()) { - case android.hardware.radio.V1_5.CellInfo - .CellInfoRatSpecificInfo.hidl_discriminator.gsm: - return new CellInfoGsm(ci, timeStamp); - case android.hardware.radio.V1_5.CellInfo - .CellInfoRatSpecificInfo.hidl_discriminator.cdma: - return new CellInfoCdma(ci, timeStamp); - case android.hardware.radio.V1_5.CellInfo - .CellInfoRatSpecificInfo.hidl_discriminator.lte: - return new CellInfoLte(ci, timeStamp); - case android.hardware.radio.V1_5.CellInfo - .CellInfoRatSpecificInfo.hidl_discriminator.wcdma: - return new CellInfoWcdma(ci, timeStamp); - case android.hardware.radio.V1_5.CellInfo - .CellInfoRatSpecificInfo.hidl_discriminator.tdscdma: - return new CellInfoTdscdma(ci, timeStamp); - case android.hardware.radio.V1_5.CellInfo - .CellInfoRatSpecificInfo.hidl_discriminator.nr: - return new CellInfoNr(ci, timeStamp); - default: return null; - } - } - - /** @hide */ - public static CellInfo create(android.hardware.radio.V1_6.CellInfo ci, long timeStamp) { - if (ci == null) return null; - switch (ci.ratSpecificInfo.getDiscriminator()) { - case android.hardware.radio.V1_6.CellInfo - .CellInfoRatSpecificInfo.hidl_discriminator.gsm: - return new CellInfoGsm(ci, timeStamp); - case android.hardware.radio.V1_6.CellInfo - .CellInfoRatSpecificInfo.hidl_discriminator.cdma: - return new CellInfoCdma(ci, timeStamp); - case android.hardware.radio.V1_6.CellInfo - .CellInfoRatSpecificInfo.hidl_discriminator.lte: - return new CellInfoLte(ci, timeStamp); - case android.hardware.radio.V1_6.CellInfo - .CellInfoRatSpecificInfo.hidl_discriminator.wcdma: - return new CellInfoWcdma(ci, timeStamp); - case android.hardware.radio.V1_6.CellInfo - .CellInfoRatSpecificInfo.hidl_discriminator.tdscdma: - return new CellInfoTdscdma(ci, timeStamp); - case android.hardware.radio.V1_6.CellInfo - .CellInfoRatSpecificInfo.hidl_discriminator.nr: - return new CellInfoNr(ci, timeStamp); - default: return null; - } - } } diff --git a/telephony/java/android/telephony/CellInfoCdma.java b/telephony/java/android/telephony/CellInfoCdma.java index dbb30d29eb87..aa8cff52bcaf 100644 --- a/telephony/java/android/telephony/CellInfoCdma.java +++ b/telephony/java/android/telephony/CellInfoCdma.java @@ -52,48 +52,11 @@ public final class CellInfoCdma extends CellInfo implements Parcelable { } /** @hide */ - public CellInfoCdma(android.hardware.radio.V1_0.CellInfo ci) { - super(ci); - final android.hardware.radio.V1_0.CellInfoCdma cic = ci.cdma.get(0); - mCellIdentityCdma = new CellIdentityCdma(cic.cellIdentityCdma); - mCellSignalStrengthCdma = - new CellSignalStrengthCdma(cic.signalStrengthCdma, cic.signalStrengthEvdo); - } - - /** @hide */ - public CellInfoCdma(android.hardware.radio.V1_2.CellInfo ci) { - super(ci); - final android.hardware.radio.V1_2.CellInfoCdma cic = ci.cdma.get(0); - mCellIdentityCdma = new CellIdentityCdma(cic.cellIdentityCdma); - mCellSignalStrengthCdma = - new CellSignalStrengthCdma(cic.signalStrengthCdma, cic.signalStrengthEvdo); - } - - /** @hide */ - public CellInfoCdma(android.hardware.radio.V1_4.CellInfo ci, long timeStamp) { - super(ci, timeStamp); - final android.hardware.radio.V1_2.CellInfoCdma cic = ci.info.cdma(); - mCellIdentityCdma = new CellIdentityCdma(cic.cellIdentityCdma); - mCellSignalStrengthCdma = - new CellSignalStrengthCdma(cic.signalStrengthCdma, cic.signalStrengthEvdo); - } - - /** @hide */ - public CellInfoCdma(android.hardware.radio.V1_5.CellInfo ci, long timeStamp) { - super(ci, timeStamp); - final android.hardware.radio.V1_2.CellInfoCdma cic = ci.ratSpecificInfo.cdma(); - mCellIdentityCdma = new CellIdentityCdma(cic.cellIdentityCdma); - mCellSignalStrengthCdma = - new CellSignalStrengthCdma(cic.signalStrengthCdma, cic.signalStrengthEvdo); - } - - /** @hide */ - public CellInfoCdma(android.hardware.radio.V1_6.CellInfo ci, long timeStamp) { - super(ci, timeStamp); - final android.hardware.radio.V1_2.CellInfoCdma cic = ci.ratSpecificInfo.cdma(); - mCellIdentityCdma = new CellIdentityCdma(cic.cellIdentityCdma); - mCellSignalStrengthCdma = - new CellSignalStrengthCdma(cic.signalStrengthCdma, cic.signalStrengthEvdo); + public CellInfoCdma(int connectionStatus, boolean registered, long timeStamp, + CellIdentityCdma cellIdentityCdma, CellSignalStrengthCdma cellSignalStrengthCdma) { + super(connectionStatus, registered, timeStamp); + mCellIdentityCdma = cellIdentityCdma; + mCellSignalStrengthCdma = cellSignalStrengthCdma; } /** diff --git a/telephony/java/android/telephony/CellInfoGsm.java b/telephony/java/android/telephony/CellInfoGsm.java index e1d996e87fcf..76e825bf426c 100644 --- a/telephony/java/android/telephony/CellInfoGsm.java +++ b/telephony/java/android/telephony/CellInfoGsm.java @@ -51,43 +51,11 @@ public final class CellInfoGsm extends CellInfo implements Parcelable { } /** @hide */ - public CellInfoGsm(android.hardware.radio.V1_0.CellInfo ci) { - super(ci); - final android.hardware.radio.V1_0.CellInfoGsm cig = ci.gsm.get(0); - mCellIdentityGsm = new CellIdentityGsm(cig.cellIdentityGsm); - mCellSignalStrengthGsm = new CellSignalStrengthGsm(cig.signalStrengthGsm); - } - - /** @hide */ - public CellInfoGsm(android.hardware.radio.V1_2.CellInfo ci) { - super(ci); - final android.hardware.radio.V1_2.CellInfoGsm cig = ci.gsm.get(0); - mCellIdentityGsm = new CellIdentityGsm(cig.cellIdentityGsm); - mCellSignalStrengthGsm = new CellSignalStrengthGsm(cig.signalStrengthGsm); - } - - /** @hide */ - public CellInfoGsm(android.hardware.radio.V1_4.CellInfo ci, long timeStamp) { - super(ci, timeStamp); - final android.hardware.radio.V1_2.CellInfoGsm cig = ci.info.gsm(); - mCellIdentityGsm = new CellIdentityGsm(cig.cellIdentityGsm); - mCellSignalStrengthGsm = new CellSignalStrengthGsm(cig.signalStrengthGsm); - } - - /** @hide */ - public CellInfoGsm(android.hardware.radio.V1_5.CellInfo ci, long timeStamp) { - super(ci, timeStamp); - final android.hardware.radio.V1_5.CellInfoGsm cig = ci.ratSpecificInfo.gsm(); - mCellIdentityGsm = new CellIdentityGsm(cig.cellIdentityGsm); - mCellSignalStrengthGsm = new CellSignalStrengthGsm(cig.signalStrengthGsm); - } - - /** @hide */ - public CellInfoGsm(android.hardware.radio.V1_6.CellInfo ci, long timeStamp) { - super(ci, timeStamp); - final android.hardware.radio.V1_5.CellInfoGsm cig = ci.ratSpecificInfo.gsm(); - mCellIdentityGsm = new CellIdentityGsm(cig.cellIdentityGsm); - mCellSignalStrengthGsm = new CellSignalStrengthGsm(cig.signalStrengthGsm); + public CellInfoGsm(int cellConnectionStatus, boolean registered, long timeStamp, + CellIdentityGsm cellIdentityGsm, CellSignalStrengthGsm cellSignalStrengthGsm) { + super(cellConnectionStatus, registered, timeStamp); + mCellIdentityGsm = cellIdentityGsm; + mCellSignalStrengthGsm = cellSignalStrengthGsm; } /** diff --git a/telephony/java/android/telephony/CellInfoLte.java b/telephony/java/android/telephony/CellInfoLte.java index 39b320afdac9..2d176d52c05c 100644 --- a/telephony/java/android/telephony/CellInfoLte.java +++ b/telephony/java/android/telephony/CellInfoLte.java @@ -56,48 +56,13 @@ public final class CellInfoLte extends CellInfo implements Parcelable { } /** @hide */ - public CellInfoLte(android.hardware.radio.V1_0.CellInfo ci) { - super(ci); - final android.hardware.radio.V1_0.CellInfoLte cil = ci.lte.get(0); - mCellIdentityLte = new CellIdentityLte(cil.cellIdentityLte); - mCellSignalStrengthLte = new CellSignalStrengthLte(cil.signalStrengthLte); - mCellConfig = new CellConfigLte(); - } - - /** @hide */ - public CellInfoLte(android.hardware.radio.V1_2.CellInfo ci) { - super(ci); - final android.hardware.radio.V1_2.CellInfoLte cil = ci.lte.get(0); - mCellIdentityLte = new CellIdentityLte(cil.cellIdentityLte); - mCellSignalStrengthLte = new CellSignalStrengthLte(cil.signalStrengthLte); - mCellConfig = new CellConfigLte(); - } - - /** @hide */ - public CellInfoLte(android.hardware.radio.V1_4.CellInfo ci, long timeStamp) { - super(ci, timeStamp); - final android.hardware.radio.V1_4.CellInfoLte cil = ci.info.lte(); - mCellIdentityLte = new CellIdentityLte(cil.base.cellIdentityLte); - mCellSignalStrengthLte = new CellSignalStrengthLte(cil.base.signalStrengthLte); - mCellConfig = new CellConfigLte(cil.cellConfig); - } - - /** @hide */ - public CellInfoLte(android.hardware.radio.V1_5.CellInfo ci, long timeStamp) { - super(ci, timeStamp); - final android.hardware.radio.V1_5.CellInfoLte cil = ci.ratSpecificInfo.lte(); - mCellIdentityLte = new CellIdentityLte(cil.cellIdentityLte); - mCellSignalStrengthLte = new CellSignalStrengthLte(cil.signalStrengthLte); - mCellConfig = new CellConfigLte(); - } - - /** @hide */ - public CellInfoLte(android.hardware.radio.V1_6.CellInfo ci, long timeStamp) { - super(ci, timeStamp); - final android.hardware.radio.V1_6.CellInfoLte cil = ci.ratSpecificInfo.lte(); - mCellIdentityLte = new CellIdentityLte(cil.cellIdentityLte); - mCellSignalStrengthLte = new CellSignalStrengthLte(cil.signalStrengthLte); - mCellConfig = new CellConfigLte(); + public CellInfoLte(int connectionStatus, boolean registered, long timeStamp, + CellIdentityLte cellIdentityLte, CellSignalStrengthLte cellSignalStrengthLte, + CellConfigLte cellConfig) { + super(connectionStatus, registered, timeStamp); + mCellIdentityLte = cellIdentityLte; + mCellSignalStrengthLte = cellSignalStrengthLte; + mCellConfig = cellConfig; } /** diff --git a/telephony/java/android/telephony/CellInfoNr.java b/telephony/java/android/telephony/CellInfoNr.java index 12e6a38bfdc0..37fac24ab5e7 100644 --- a/telephony/java/android/telephony/CellInfoNr.java +++ b/telephony/java/android/telephony/CellInfoNr.java @@ -53,27 +53,11 @@ public final class CellInfoNr extends CellInfo { } /** @hide */ - public CellInfoNr(android.hardware.radio.V1_4.CellInfo ci, long timeStamp) { - super(ci, timeStamp); - final android.hardware.radio.V1_4.CellInfoNr cil = ci.info.nr(); - mCellIdentity = new CellIdentityNr(cil.cellidentity); - mCellSignalStrength = new CellSignalStrengthNr(cil.signalStrength); - } - - /** @hide */ - public CellInfoNr(android.hardware.radio.V1_5.CellInfo ci, long timeStamp) { - super(ci, timeStamp); - final android.hardware.radio.V1_5.CellInfoNr cil = ci.ratSpecificInfo.nr(); - mCellIdentity = new CellIdentityNr(cil.cellIdentityNr); - mCellSignalStrength = new CellSignalStrengthNr(cil.signalStrengthNr); - } - - /** @hide */ - public CellInfoNr(android.hardware.radio.V1_6.CellInfo ci, long timeStamp) { - super(ci, timeStamp); - final android.hardware.radio.V1_6.CellInfoNr cil = ci.ratSpecificInfo.nr(); - mCellIdentity = new CellIdentityNr(cil.cellIdentityNr); - mCellSignalStrength = new CellSignalStrengthNr(cil.signalStrengthNr); + public CellInfoNr(int connectionStatus, boolean registered, long timeStamp, + CellIdentityNr cellIdentityNr, CellSignalStrengthNr cellSignalStrengthNr) { + super(connectionStatus, registered, timeStamp); + mCellIdentity = cellIdentityNr; + mCellSignalStrength = cellSignalStrengthNr; } /** diff --git a/telephony/java/android/telephony/CellInfoTdscdma.java b/telephony/java/android/telephony/CellInfoTdscdma.java index 994b317a47fd..d8db4295f374 100644 --- a/telephony/java/android/telephony/CellInfoTdscdma.java +++ b/telephony/java/android/telephony/CellInfoTdscdma.java @@ -54,43 +54,12 @@ public final class CellInfoTdscdma extends CellInfo implements Parcelable { } /** @hide */ - public CellInfoTdscdma(android.hardware.radio.V1_0.CellInfo ci) { - super(ci); - final android.hardware.radio.V1_0.CellInfoTdscdma cit = ci.tdscdma.get(0); - mCellIdentityTdscdma = new CellIdentityTdscdma(cit.cellIdentityTdscdma); - mCellSignalStrengthTdscdma = new CellSignalStrengthTdscdma(cit.signalStrengthTdscdma); - } - - /** @hide */ - public CellInfoTdscdma(android.hardware.radio.V1_2.CellInfo ci) { - super(ci); - final android.hardware.radio.V1_2.CellInfoTdscdma cit = ci.tdscdma.get(0); - mCellIdentityTdscdma = new CellIdentityTdscdma(cit.cellIdentityTdscdma); - mCellSignalStrengthTdscdma = new CellSignalStrengthTdscdma(cit.signalStrengthTdscdma); - } - - /** @hide */ - public CellInfoTdscdma(android.hardware.radio.V1_4.CellInfo ci, long timeStamp) { - super(ci, timeStamp); - final android.hardware.radio.V1_2.CellInfoTdscdma cit = ci.info.tdscdma(); - mCellIdentityTdscdma = new CellIdentityTdscdma(cit.cellIdentityTdscdma); - mCellSignalStrengthTdscdma = new CellSignalStrengthTdscdma(cit.signalStrengthTdscdma); - } - - /** @hide */ - public CellInfoTdscdma(android.hardware.radio.V1_5.CellInfo ci, long timeStamp) { - super(ci, timeStamp); - final android.hardware.radio.V1_5.CellInfoTdscdma cit = ci.ratSpecificInfo.tdscdma(); - mCellIdentityTdscdma = new CellIdentityTdscdma(cit.cellIdentityTdscdma); - mCellSignalStrengthTdscdma = new CellSignalStrengthTdscdma(cit.signalStrengthTdscdma); - } - - /** @hide */ - public CellInfoTdscdma(android.hardware.radio.V1_6.CellInfo ci, long timeStamp) { - super(ci, timeStamp); - final android.hardware.radio.V1_5.CellInfoTdscdma cit = ci.ratSpecificInfo.tdscdma(); - mCellIdentityTdscdma = new CellIdentityTdscdma(cit.cellIdentityTdscdma); - mCellSignalStrengthTdscdma = new CellSignalStrengthTdscdma(cit.signalStrengthTdscdma); + public CellInfoTdscdma(int connectionStatus, boolean registered, long timeStamp, + CellIdentityTdscdma cellIdentityTdscdma, + CellSignalStrengthTdscdma cellSignalStrengthTdscdma) { + super(connectionStatus, registered, timeStamp); + mCellIdentityTdscdma = cellIdentityTdscdma; + mCellSignalStrengthTdscdma = cellSignalStrengthTdscdma; } /** diff --git a/telephony/java/android/telephony/CellInfoWcdma.java b/telephony/java/android/telephony/CellInfoWcdma.java index 62ac0b8ae04e..dc8e1fed1392 100644 --- a/telephony/java/android/telephony/CellInfoWcdma.java +++ b/telephony/java/android/telephony/CellInfoWcdma.java @@ -49,43 +49,11 @@ public final class CellInfoWcdma extends CellInfo implements Parcelable { } /** @hide */ - public CellInfoWcdma(android.hardware.radio.V1_0.CellInfo ci) { - super(ci); - final android.hardware.radio.V1_0.CellInfoWcdma ciw = ci.wcdma.get(0); - mCellIdentityWcdma = new CellIdentityWcdma(ciw.cellIdentityWcdma); - mCellSignalStrengthWcdma = new CellSignalStrengthWcdma(ciw.signalStrengthWcdma); - } - - /** @hide */ - public CellInfoWcdma(android.hardware.radio.V1_2.CellInfo ci) { - super(ci); - final android.hardware.radio.V1_2.CellInfoWcdma ciw = ci.wcdma.get(0); - mCellIdentityWcdma = new CellIdentityWcdma(ciw.cellIdentityWcdma); - mCellSignalStrengthWcdma = new CellSignalStrengthWcdma(ciw.signalStrengthWcdma); - } - - /** @hide */ - public CellInfoWcdma(android.hardware.radio.V1_4.CellInfo ci, long timeStamp) { - super(ci, timeStamp); - final android.hardware.radio.V1_2.CellInfoWcdma ciw = ci.info.wcdma(); - mCellIdentityWcdma = new CellIdentityWcdma(ciw.cellIdentityWcdma); - mCellSignalStrengthWcdma = new CellSignalStrengthWcdma(ciw.signalStrengthWcdma); - } - - /** @hide */ - public CellInfoWcdma(android.hardware.radio.V1_5.CellInfo ci, long timeStamp) { - super(ci, timeStamp); - final android.hardware.radio.V1_5.CellInfoWcdma ciw = ci.ratSpecificInfo.wcdma(); - mCellIdentityWcdma = new CellIdentityWcdma(ciw.cellIdentityWcdma); - mCellSignalStrengthWcdma = new CellSignalStrengthWcdma(ciw.signalStrengthWcdma); - } - - /** @hide */ - public CellInfoWcdma(android.hardware.radio.V1_6.CellInfo ci, long timeStamp) { - super(ci, timeStamp); - final android.hardware.radio.V1_5.CellInfoWcdma ciw = ci.ratSpecificInfo.wcdma(); - mCellIdentityWcdma = new CellIdentityWcdma(ciw.cellIdentityWcdma); - mCellSignalStrengthWcdma = new CellSignalStrengthWcdma(ciw.signalStrengthWcdma); + public CellInfoWcdma(int connectionStatus, boolean registered, long timeStamp, + CellIdentityWcdma cellIdentityWcdma, CellSignalStrengthWcdma cellSignalStrengthWcdma) { + super(connectionStatus, registered, timeStamp); + mCellIdentityWcdma = cellIdentityWcdma; + mCellSignalStrengthWcdma = cellSignalStrengthWcdma; } /** diff --git a/telephony/java/android/telephony/CellSignalStrength.java b/telephony/java/android/telephony/CellSignalStrength.java index e0896570d3ed..9727ab7d23e2 100644 --- a/telephony/java/android/telephony/CellSignalStrength.java +++ b/telephony/java/android/telephony/CellSignalStrength.java @@ -108,7 +108,7 @@ public abstract class CellSignalStrength { // Range for RSSI in ASU (0-31, 99) as defined in TS 27.007 8.69 /** @hide */ - protected static final int getRssiDbmFromAsu(int asu) { + public static final int getRssiDbmFromAsu(int asu) { if (asu > 31 || asu < 0) return CellInfo.UNAVAILABLE; return -113 + (2 * asu); } @@ -122,7 +122,7 @@ public abstract class CellSignalStrength { // Range for RSCP in ASU (0-96, 255) as defined in TS 27.007 8.69 /** @hide */ - protected static final int getRscpDbmFromAsu(int asu) { + public static final int getRscpDbmFromAsu(int asu) { if (asu > 96 || asu < 0) return CellInfo.UNAVAILABLE; return asu - 120; } @@ -136,7 +136,7 @@ public abstract class CellSignalStrength { // Range for SNR in ASU (0-49, 255) as defined in TS 27.007 8.69 /** @hide */ - protected static final int getEcNoDbFromAsu(int asu) { + public static final int getEcNoDbFromAsu(int asu) { if (asu > 49 || asu < 0) return CellInfo.UNAVAILABLE; return -24 + (asu / 2); } diff --git a/telephony/java/android/telephony/CellSignalStrengthCdma.java b/telephony/java/android/telephony/CellSignalStrengthCdma.java index d00049c1ebe5..5298e67bdf80 100644 --- a/telephony/java/android/telephony/CellSignalStrengthCdma.java +++ b/telephony/java/android/telephony/CellSignalStrengthCdma.java @@ -78,13 +78,6 @@ public final class CellSignalStrengthCdma extends CellSignalStrength implements } /** @hide */ - public CellSignalStrengthCdma(android.hardware.radio.V1_0.CdmaSignalStrength cdma, - android.hardware.radio.V1_0.EvdoSignalStrength evdo) { - // Convert from HAL values as part of construction. - this(-cdma.dbm, -cdma.ecio, -evdo.dbm, -evdo.ecio, evdo.signalNoiseRatio); - } - - /** @hide */ public CellSignalStrengthCdma(CellSignalStrengthCdma s) { copyFrom(s); } diff --git a/telephony/java/android/telephony/CellSignalStrengthGsm.java b/telephony/java/android/telephony/CellSignalStrengthGsm.java index 51e1ebc63cf2..7b780843061b 100644 --- a/telephony/java/android/telephony/CellSignalStrengthGsm.java +++ b/telephony/java/android/telephony/CellSignalStrengthGsm.java @@ -67,16 +67,6 @@ public final class CellSignalStrengthGsm extends CellSignalStrength implements P } /** @hide */ - public CellSignalStrengthGsm(android.hardware.radio.V1_0.GsmSignalStrength gsm) { - // Convert from HAL values as part of construction. - this(getRssiDbmFromAsu(gsm.signalStrength), gsm.bitErrorRate, gsm.timingAdvance); - - if (mRssi == CellInfo.UNAVAILABLE) { - setDefaultValues(); - } - } - - /** @hide */ public CellSignalStrengthGsm(CellSignalStrengthGsm s) { copyFrom(s); } diff --git a/telephony/java/android/telephony/CellSignalStrengthLte.java b/telephony/java/android/telephony/CellSignalStrengthLte.java index 9211482fc067..e8633dd4b7bd 100644 --- a/telephony/java/android/telephony/CellSignalStrengthLte.java +++ b/telephony/java/android/telephony/CellSignalStrengthLte.java @@ -166,25 +166,6 @@ public final class CellSignalStrengthLte extends CellSignalStrength implements P } /** @hide */ - public CellSignalStrengthLte(android.hardware.radio.V1_0.LteSignalStrength lte) { - // Convert from HAL values as part of construction. - this(convertRssiAsuToDBm(lte.signalStrength), - lte.rsrp != CellInfo.UNAVAILABLE ? -lte.rsrp : lte.rsrp, - lte.rsrq != CellInfo.UNAVAILABLE ? -lte.rsrq : lte.rsrq, - convertRssnrUnitFromTenDbToDB(lte.rssnr), lte.cqi, lte.timingAdvance); - } - - /** @hide */ - public CellSignalStrengthLte(android.hardware.radio.V1_6.LteSignalStrength lte) { - // Convert from HAL values as part of construction. - this(convertRssiAsuToDBm(lte.base.signalStrength), - lte.base.rsrp != CellInfo.UNAVAILABLE ? -lte.base.rsrp : lte.base.rsrp, - lte.base.rsrq != CellInfo.UNAVAILABLE ? -lte.base.rsrq : lte.base.rsrq, - convertRssnrUnitFromTenDbToDB(lte.base.rssnr), lte.cqiTableIndex, lte.base.cqi, - lte.base.timingAdvance); - } - - /** @hide */ public CellSignalStrengthLte(CellSignalStrengthLte s) { copyFrom(s); } @@ -617,11 +598,13 @@ public final class CellSignalStrengthLte extends CellSignalStrength implements P Rlog.w(LOG_TAG, s); } - private static int convertRssnrUnitFromTenDbToDB(int rssnr) { + /** @hide */ + public static int convertRssnrUnitFromTenDbToDB(int rssnr) { return rssnr / 10; } - private static int convertRssiAsuToDBm(int rssiAsu) { + /** @hide */ + public static int convertRssiAsuToDBm(int rssiAsu) { if (rssiAsu == SIGNAL_STRENGTH_LTE_RSSI_ASU_UNKNOWN) { return CellInfo.UNAVAILABLE; } diff --git a/telephony/java/android/telephony/CellSignalStrengthNr.java b/telephony/java/android/telephony/CellSignalStrengthNr.java index 6ada32e1a86d..cd22abddd3a7 100644 --- a/telephony/java/android/telephony/CellSignalStrengthNr.java +++ b/telephony/java/android/telephony/CellSignalStrengthNr.java @@ -202,29 +202,12 @@ public final class CellSignalStrengthNr extends CellSignalStrength implements Pa } /** - * @hide - * @param ss signal strength from modem. - */ - public CellSignalStrengthNr(android.hardware.radio.V1_4.NrSignalStrength ss) { - this(flip(ss.csiRsrp), flip(ss.csiRsrq), ss.csiSinr, flip(ss.ssRsrp), flip(ss.ssRsrq), - ss.ssSinr); - } - - /** - * @hide - * @param ss signal strength from modem. - */ - public CellSignalStrengthNr(android.hardware.radio.V1_6.NrSignalStrength ss) { - this(flip(ss.base.csiRsrp), flip(ss.base.csiRsrq), ss.base.csiSinr, ss.csiCqiTableIndex, - ss.csiCqiReport, flip(ss.base.ssRsrp), flip(ss.base.ssRsrq), ss.base.ssSinr); - } - - /** * Flip sign cell strength value when taking in the value from hal * @param val cell strength value * @return flipped value + * @hide */ - private static int flip(int val) { + public static int flip(int val) { return val != CellInfo.UNAVAILABLE ? -val : val; } diff --git a/telephony/java/android/telephony/CellSignalStrengthTdscdma.java b/telephony/java/android/telephony/CellSignalStrengthTdscdma.java index e96f200280b6..8a7c70ec5ea9 100644 --- a/telephony/java/android/telephony/CellSignalStrengthTdscdma.java +++ b/telephony/java/android/telephony/CellSignalStrengthTdscdma.java @@ -75,28 +75,6 @@ public final class CellSignalStrengthTdscdma extends CellSignalStrength implemen } /** @hide */ - public CellSignalStrengthTdscdma(android.hardware.radio.V1_0.TdScdmaSignalStrength tdscdma) { - // Convert from HAL values as part of construction. - this(CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, - tdscdma.rscp != CellInfo.UNAVAILABLE ? -tdscdma.rscp : tdscdma.rscp); - - if (mRssi == CellInfo.UNAVAILABLE && mRscp == CellInfo.UNAVAILABLE) { - setDefaultValues(); - } - } - - /** @hide */ - public CellSignalStrengthTdscdma(android.hardware.radio.V1_2.TdscdmaSignalStrength tdscdma) { - // Convert from HAL values as part of construction. - this(getRssiDbmFromAsu(tdscdma.signalStrength), - tdscdma.bitErrorRate, getRscpDbmFromAsu(tdscdma.rscp)); - - if (mRssi == CellInfo.UNAVAILABLE && mRscp == CellInfo.UNAVAILABLE) { - setDefaultValues(); - } - } - - /** @hide */ public CellSignalStrengthTdscdma(CellSignalStrengthTdscdma s) { copyFrom(s); } diff --git a/telephony/java/android/telephony/CellSignalStrengthWcdma.java b/telephony/java/android/telephony/CellSignalStrengthWcdma.java index 8b14b7490679..f30440d95158 100644 --- a/telephony/java/android/telephony/CellSignalStrengthWcdma.java +++ b/telephony/java/android/telephony/CellSignalStrengthWcdma.java @@ -95,30 +95,6 @@ public final class CellSignalStrengthWcdma extends CellSignalStrength implements } /** @hide */ - public CellSignalStrengthWcdma(android.hardware.radio.V1_0.WcdmaSignalStrength wcdma) { - // Convert from HAL values as part of construction. - this(getRssiDbmFromAsu(wcdma.signalStrength), wcdma.bitErrorRate, - CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE); - - if (mRssi == CellInfo.UNAVAILABLE && mRscp == CellInfo.UNAVAILABLE) { - setDefaultValues(); - } - } - - /** @hide */ - public CellSignalStrengthWcdma(android.hardware.radio.V1_2.WcdmaSignalStrength wcdma) { - // Convert from HAL values as part of construction. - this(getRssiDbmFromAsu(wcdma.base.signalStrength), - wcdma.base.bitErrorRate, - getRscpDbmFromAsu(wcdma.rscp), - getEcNoDbFromAsu(wcdma.ecno)); - - if (mRssi == CellInfo.UNAVAILABLE && mRscp == CellInfo.UNAVAILABLE) { - setDefaultValues(); - } - } - - /** @hide */ public CellSignalStrengthWcdma(CellSignalStrengthWcdma s) { copyFrom(s); } diff --git a/telephony/java/android/telephony/ClosedSubscriberGroupInfo.java b/telephony/java/android/telephony/ClosedSubscriberGroupInfo.java index e9262725d232..bf418ab38648 100644 --- a/telephony/java/android/telephony/ClosedSubscriberGroupInfo.java +++ b/telephony/java/android/telephony/ClosedSubscriberGroupInfo.java @@ -44,12 +44,6 @@ public final class ClosedSubscriberGroupInfo implements Parcelable { mCsgIdentity = csgIdentity; } - /** @hide */ - public ClosedSubscriberGroupInfo( - @NonNull android.hardware.radio.V1_5.ClosedSubscriberGroupInfo csgInfo) { - this(csgInfo.csgIndication, csgInfo.homeNodebName, csgInfo.csgIdentity); - } - /** * Indicates whether the cell is restricted to only CSG members. * diff --git a/telephony/java/android/telephony/PhysicalChannelConfig.java b/telephony/java/android/telephony/PhysicalChannelConfig.java index d250088c2f10..95448c7807cc 100644 --- a/telephony/java/android/telephony/PhysicalChannelConfig.java +++ b/telephony/java/android/telephony/PhysicalChannelConfig.java @@ -242,6 +242,11 @@ public final class PhysicalChannelConfig implements Parcelable { } /** + * The physical cell ID which differentiates cells using the same radio channel. + * + * In GERAN, this value is the BSIC. The range is [0-63]. + * Reference: 3GPP TS 3.03 section 4.2.2. + * * In UTRAN, this value is primary scrambling code. The range is [0, 511]. * Reference: 3GPP TS 25.213 section 5.2.2. * diff --git a/telephony/java/android/telephony/SignalStrength.java b/telephony/java/android/telephony/SignalStrength.java index b317c5557108..b7bc46736e18 100644 --- a/telephony/java/android/telephony/SignalStrength.java +++ b/telephony/java/android/telephony/SignalStrength.java @@ -144,64 +144,6 @@ public class SignalStrength implements Parcelable { mTimestampMillis = SystemClock.elapsedRealtime(); } - /** - * Constructor for Radio HAL V1.0 - * - * @hide - */ - public SignalStrength(android.hardware.radio.V1_0.SignalStrength signalStrength) { - this(new CellSignalStrengthCdma(signalStrength.cdma, signalStrength.evdo), - new CellSignalStrengthGsm(signalStrength.gw), - new CellSignalStrengthWcdma(), - new CellSignalStrengthTdscdma(signalStrength.tdScdma), - new CellSignalStrengthLte(signalStrength.lte), - new CellSignalStrengthNr()); - } - - /** - * Constructor for Radio HAL V1.2 - * - * @hide - */ - public SignalStrength(android.hardware.radio.V1_2.SignalStrength signalStrength) { - this(new CellSignalStrengthCdma(signalStrength.cdma, signalStrength.evdo), - new CellSignalStrengthGsm(signalStrength.gsm), - new CellSignalStrengthWcdma(signalStrength.wcdma), - new CellSignalStrengthTdscdma(signalStrength.tdScdma), - new CellSignalStrengthLte(signalStrength.lte), - new CellSignalStrengthNr()); - } - - /** - * Constructor for Radio HAL V1.4. - * - * @param signalStrength signal strength reported from modem. - * @hide - */ - public SignalStrength(android.hardware.radio.V1_4.SignalStrength signalStrength) { - this(new CellSignalStrengthCdma(signalStrength.cdma, signalStrength.evdo), - new CellSignalStrengthGsm(signalStrength.gsm), - new CellSignalStrengthWcdma(signalStrength.wcdma), - new CellSignalStrengthTdscdma(signalStrength.tdscdma), - new CellSignalStrengthLte(signalStrength.lte), - new CellSignalStrengthNr(signalStrength.nr)); - } - - /** - * Constructor for Radio HAL V1.6. - * - * @param signalStrength signal strength reported from modem. - * @hide - */ - public SignalStrength(android.hardware.radio.V1_6.SignalStrength signalStrength) { - this(new CellSignalStrengthCdma(signalStrength.cdma, signalStrength.evdo), - new CellSignalStrengthGsm(signalStrength.gsm), - new CellSignalStrengthWcdma(signalStrength.wcdma), - new CellSignalStrengthTdscdma(signalStrength.tdscdma), - new CellSignalStrengthLte(signalStrength.lte), - new CellSignalStrengthNr(signalStrength.nr)); - } - private CellSignalStrength getPrimary() { // This behavior is intended to replicate the legacy behavior of getLevel() by prioritizing // newer faster RATs for default/for display purposes. diff --git a/telephony/java/android/telephony/SignalStrengthUpdateRequest.java b/telephony/java/android/telephony/SignalStrengthUpdateRequest.java index 41e24ddb3fa6..2ff4ac5e30d3 100644 --- a/telephony/java/android/telephony/SignalStrengthUpdateRequest.java +++ b/telephony/java/android/telephony/SignalStrengthUpdateRequest.java @@ -17,6 +17,8 @@ package android.telephony; import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.RequiresPermission; import android.os.Binder; import android.os.IBinder; import android.os.Parcel; @@ -66,10 +68,15 @@ public final class SignalStrengthUpdateRequest implements Parcelable { private final IBinder mLiveToken; private SignalStrengthUpdateRequest( - @NonNull List<SignalThresholdInfo> signalThresholdInfos, + @Nullable List<SignalThresholdInfo> signalThresholdInfos, boolean isReportingRequestedWhileIdle, boolean isSystemThresholdReportingRequestedWhileIdle) { - validate(signalThresholdInfos); + // System app (like Bluetooth) can specify the request to report system thresholds while + // device is idle (with permission protection). In this case, the request doesn't need to + // provide a non-empty list of SignalThresholdInfo which is only asked for public apps. + if (!isSystemThresholdReportingRequestedWhileIdle) { + validate(signalThresholdInfos); + } mSignalThresholdInfos = signalThresholdInfos; mIsReportingRequestedWhileIdle = isReportingRequestedWhileIdle; @@ -128,13 +135,15 @@ public final class SignalStrengthUpdateRequest implements Parcelable { /** * Set the builder object if require reporting on the system thresholds when device is idle. * - * This can only used by the system caller. + * <p>This can only used by the system caller. Requires permission + * {@link android.Manifest.permission#LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH}. * * @param isSystemThresholdReportingRequestedWhileIdle true if request reporting on the * system thresholds when device is idle * @return the builder to facilitate the chaining * @hide */ + @RequiresPermission(android.Manifest.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH) public @NonNull Builder setSystemThresholdReportingRequestedWhileIdle( boolean isSystemThresholdReportingRequestedWhileIdle) { mIsSystemThresholdReportingRequestedWhileIdle = diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 255a61266ebf..122f96df4ae6 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -2945,7 +2945,12 @@ public class TelephonyManager { * currently in use on the device for data transmission. * * If this object has been created with {@link #createForSubscriptionId}, applies to the given - * subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()} + * subId. Otherwise, applies to {@link SubscriptionManager#getActiveDataSubscriptionId()}. + * + * Note: Before {@link SubscriptionManager#getActiveDataSubscriptionId()} was introduced in API + * level 30, it was applied to {@link SubscriptionManager#getDefaultDataSubscriptionId()} which + * may be different now from {@link SubscriptionManager#getActiveDataSubscriptionId()}, e.g. + * when opportunistic network is providing cellular internet connection to the user. * * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}). @@ -12420,26 +12425,6 @@ public class TelephonyManager { } /** - * Enable or disable signal strength changes from radio will always be reported in any - * condition (e.g. screen is off). This is only allowed for System caller. - * - * @param isEnabled {@code true} for enabling; {@code false} for disabling. - * @hide - */ - @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) - public void setAlwaysReportSignalStrength(boolean isEnabled) { - try { - ITelephony telephony = getITelephony(); - if (telephony != null) { - telephony.setAlwaysReportSignalStrength(getSubId(), isEnabled); - } - } catch (RemoteException ex) { - Log.e(TAG, "setAlwaysReportSignalStrength RemoteException", ex); - ex.rethrowAsRuntimeException(); - } - } - - /** * Get the most recently available signal strength information. * * Get the most recent SignalStrength information reported by the modem. Due diff --git a/telephony/java/android/telephony/TelephonyScanManager.java b/telephony/java/android/telephony/TelephonyScanManager.java index e890acb36b48..9572154ec773 100644 --- a/telephony/java/android/telephony/TelephonyScanManager.java +++ b/telephony/java/android/telephony/TelephonyScanManager.java @@ -36,6 +36,7 @@ import com.android.telephony.Rlog; import java.util.Arrays; import java.util.List; +import java.util.Objects; import java.util.concurrent.Executor; /** @@ -152,16 +153,9 @@ public final class TelephonyScanManager { throw new RuntimeException( "Failed to find NetworkScanInfo with id " + message.arg2); } - NetworkScanCallback callback = nsi.mCallback; - Executor executor = nsi.mExecutor; - if (callback == null) { - throw new RuntimeException( - "Failed to find NetworkScanCallback with id " + message.arg2); - } - if (executor == null) { - throw new RuntimeException( - "Failed to find Executor with id " + message.arg2); - } + + final NetworkScanCallback callback = nsi.mCallback; + final Executor executor = nsi.mExecutor; switch (message.what) { case CALLBACK_RESTRICTED_SCAN_RESULTS: @@ -246,17 +240,24 @@ public final class TelephonyScanManager { NetworkScanRequest request, Executor executor, NetworkScanCallback callback, String callingPackage, @Nullable String callingFeatureId) { try { + Objects.requireNonNull(request, "Request was null"); + Objects.requireNonNull(callback, "Callback was null"); + Objects.requireNonNull(executor, "Executor was null"); final ITelephony telephony = getITelephony(); if (telephony == null) return null; - int scanId = telephony.requestNetworkScan( - subId, request, mMessenger, new Binder(), callingPackage, - callingFeatureId); - if (scanId == INVALID_SCAN_ID) { - Rlog.e(TAG, "Failed to initiate network scan"); - return null; - } + // The lock must be taken before calling requestNetworkScan because the resulting + // scanId can be invoked asynchronously on another thread at any time after + // requestNetworkScan invoked, leaving a critical section between that call and adding + // the record to the ScanInfo cache. synchronized (mScanInfo) { + int scanId = telephony.requestNetworkScan( + subId, request, mMessenger, new Binder(), callingPackage, + callingFeatureId); + if (scanId == INVALID_SCAN_ID) { + Rlog.e(TAG, "Failed to initiate network scan"); + return null; + } // We link to death whenever a scan is started to ensure that we are linked // at the point that phone process death might matter. // We never unlink because: diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java index be1502ad49f2..1ef04be8f242 100644 --- a/telephony/java/android/telephony/data/ApnSetting.java +++ b/telephony/java/android/telephony/data/ApnSetting.java @@ -147,7 +147,12 @@ public class ApnSetting implements Parcelable { } // Possible values for authentication types. - /** No authentication type. */ + /** + * Authentication type is unknown. + * @hide + */ + public static final int AUTH_TYPE_UNKNOWN = -1; + /** Authentication is not required. */ public static final int AUTH_TYPE_NONE = 0; /** Authentication type for PAP. */ public static final int AUTH_TYPE_PAP = 1; @@ -357,6 +362,7 @@ public class ApnSetting implements Parcelable { /** @hide */ @IntDef(prefix = { "AUTH_TYPE_" }, value = { + AUTH_TYPE_UNKNOWN, AUTH_TYPE_NONE, AUTH_TYPE_PAP, AUTH_TYPE_CHAP, @@ -498,7 +504,8 @@ public class ApnSetting implements Parcelable { private final String mOperatorNumeric; private final int mProtocol; private final int mRoamingProtocol; - private final int mMtu; + private final int mMtuV4; + private final int mMtuV6; private final boolean mCarrierEnabled; @@ -522,13 +529,25 @@ public class ApnSetting implements Parcelable { private final int mSkip464Xlat; /** - * Returns the MTU size of the mobile interface to which the APN connected. + * Returns the MTU size of the IPv4 mobile interface to which the APN connected. Note this value + * is used only if MTU size is not provided in {@link DataCallResponse}. * * @return the MTU size of the APN * @hide */ - public int getMtu() { - return mMtu; + public int getMtuV4() { + return mMtuV4; + } + + /** + * Returns the MTU size of the IPv6 mobile interface to which the APN connected. Note this value + * is used only if MTU size is not provided in {@link DataCallResponse}. + * + * @return the MTU size of the APN + * @hide + */ + public int getMtuV6() { + return mMtuV6; } /** @@ -879,13 +898,18 @@ public class ApnSetting implements Parcelable { this.mMmsProxyPort = builder.mMmsProxyPort; this.mUser = builder.mUser; this.mPassword = builder.mPassword; - this.mAuthType = builder.mAuthType; + this.mAuthType = (builder.mAuthType != AUTH_TYPE_UNKNOWN) + ? builder.mAuthType + : TextUtils.isEmpty(builder.mUser) + ? AUTH_TYPE_NONE + : AUTH_TYPE_PAP_OR_CHAP; this.mApnTypeBitmask = builder.mApnTypeBitmask; this.mId = builder.mId; this.mOperatorNumeric = builder.mOperatorNumeric; this.mProtocol = builder.mProtocol; this.mRoamingProtocol = builder.mRoamingProtocol; - this.mMtu = builder.mMtu; + this.mMtuV4 = builder.mMtuV4; + this.mMtuV6 = builder.mMtuV6; this.mCarrierEnabled = builder.mCarrierEnabled; this.mNetworkTypeBitmask = builder.mNetworkTypeBitmask; this.mProfileId = builder.mProfileId; @@ -903,66 +927,6 @@ public class ApnSetting implements Parcelable { /** * @hide */ - public static ApnSetting makeApnSetting(int id, String operatorNumeric, String entryName, - String apnName, String proxyAddress, int proxyPort, Uri mmsc, - String mmsProxyAddress, int mmsProxyPort, String user, String password, - int authType, int mApnTypeBitmask, int protocol, int roamingProtocol, - boolean carrierEnabled, int networkTypeBitmask, int profileId, - boolean modemCognitive, int maxConns, int waitTime, int maxConnsTime, int mtu, - int mvnoType, String mvnoMatchData, int apnSetId, int carrierId, int skip464xlat) { - return new Builder() - .setId(id) - .setOperatorNumeric(operatorNumeric) - .setEntryName(entryName) - .setApnName(apnName) - .setProxyAddress(proxyAddress) - .setProxyPort(proxyPort) - .setMmsc(mmsc) - .setMmsProxyAddress(mmsProxyAddress) - .setMmsProxyPort(mmsProxyPort) - .setUser(user) - .setPassword(password) - .setAuthType(authType) - .setApnTypeBitmask(mApnTypeBitmask) - .setProtocol(protocol) - .setRoamingProtocol(roamingProtocol) - .setCarrierEnabled(carrierEnabled) - .setNetworkTypeBitmask(networkTypeBitmask) - .setProfileId(profileId) - .setModemCognitive(modemCognitive) - .setMaxConns(maxConns) - .setWaitTime(waitTime) - .setMaxConnsTime(maxConnsTime) - .setMtu(mtu) - .setMvnoType(mvnoType) - .setMvnoMatchData(mvnoMatchData) - .setApnSetId(apnSetId) - .setCarrierId(carrierId) - .setSkip464Xlat(skip464xlat) - .buildWithoutCheck(); - } - - /** - * @hide - */ - public static ApnSetting makeApnSetting(int id, String operatorNumeric, String entryName, - String apnName, String proxyAddress, int proxyPort, Uri mmsc, - String mmsProxyAddress, int mmsProxyPort, String user, String password, - int authType, int mApnTypeBitmask, int protocol, int roamingProtocol, - boolean carrierEnabled, int networkTypeBitmask, int profileId, boolean modemCognitive, - int maxConns, int waitTime, int maxConnsTime, int mtu, int mvnoType, - String mvnoMatchData) { - return makeApnSetting(id, operatorNumeric, entryName, apnName, proxyAddress, proxyPort, - mmsc, mmsProxyAddress, mmsProxyPort, user, password, authType, mApnTypeBitmask, - protocol, roamingProtocol, carrierEnabled, networkTypeBitmask, profileId, - modemCognitive, maxConns, waitTime, maxConnsTime, mtu, mvnoType, mvnoMatchData, - Carriers.NO_APN_SET_ID, TelephonyManager.UNKNOWN_CARRIER_ID, - Carriers.SKIP_464XLAT_DEFAULT); - } - - /** - * @hide - */ public static ApnSetting makeApnSetting(Cursor cursor) { final int apnTypesBitmask = getApnTypesBitmaskFromString( cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.TYPE))); @@ -975,272 +939,99 @@ public class ApnSetting implements Parcelable { ServiceState.convertBearerBitmaskToNetworkTypeBitmask(bearerBitmask); } - return makeApnSetting( - cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID)), - cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NUMERIC)), - cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NAME)), - cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.APN)), - cursor.getString( - cursor.getColumnIndexOrThrow(Telephony.Carriers.PROXY)), - portFromString(cursor.getString( - cursor.getColumnIndexOrThrow(Telephony.Carriers.PORT))), - UriFromString(cursor.getString( - cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSC))), - cursor.getString( - cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPROXY)), - portFromString(cursor.getString( - cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPORT))), - cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.USER)), - cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PASSWORD)), - cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.AUTH_TYPE)), - apnTypesBitmask, - getProtocolIntFromString( - cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROTOCOL))), - getProtocolIntFromString( - cursor.getString(cursor.getColumnIndexOrThrow( - Telephony.Carriers.ROAMING_PROTOCOL))), - cursor.getInt(cursor.getColumnIndexOrThrow( - Telephony.Carriers.CARRIER_ENABLED)) == 1, - networkTypeBitmask, - cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROFILE_ID)), - cursor.getInt(cursor.getColumnIndexOrThrow( - Telephony.Carriers.MODEM_PERSIST)) == 1, - cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MAX_CONNECTIONS)), - cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.WAIT_TIME_RETRY)), - cursor.getInt(cursor.getColumnIndexOrThrow( - Telephony.Carriers.TIME_LIMIT_FOR_MAX_CONNECTIONS)), - cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MTU)), - getMvnoTypeIntFromString( - cursor.getString(cursor.getColumnIndexOrThrow( - Telephony.Carriers.MVNO_TYPE))), - cursor.getString(cursor.getColumnIndexOrThrow( - Telephony.Carriers.MVNO_MATCH_DATA)), - cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.APN_SET_ID)), - cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.CARRIER_ID)), - cursor.getInt(cursor.getColumnIndexOrThrow(Carriers.SKIP_464XLAT))); + return new Builder() + .setId(cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID))) + .setOperatorNumeric(cursor.getString( + cursor.getColumnIndexOrThrow(Telephony.Carriers.NUMERIC))) + .setEntryName(cursor.getString( + cursor.getColumnIndexOrThrow(Telephony.Carriers.NAME))) + .setApnName(cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.APN))) + .setProxyAddress(cursor.getString( + cursor.getColumnIndexOrThrow(Telephony.Carriers.PROXY))) + .setProxyPort(portFromString(cursor.getString( + cursor.getColumnIndexOrThrow(Telephony.Carriers.PORT)))) + .setMmsc(UriFromString(cursor.getString( + cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSC)))) + .setMmsProxyAddress(cursor.getString( + cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPROXY))) + .setMmsProxyPort(portFromString(cursor.getString( + cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPORT)))) + .setUser(cursor.getString( + cursor.getColumnIndexOrThrow(Telephony.Carriers.USER))) + .setPassword(cursor.getString( + cursor.getColumnIndexOrThrow(Telephony.Carriers.PASSWORD))) + .setAuthType(cursor.getInt( + cursor.getColumnIndexOrThrow(Telephony.Carriers.AUTH_TYPE))) + .setApnTypeBitmask(apnTypesBitmask) + .setProtocol(getProtocolIntFromString( + cursor.getString( + cursor.getColumnIndexOrThrow(Telephony.Carriers.PROTOCOL)))) + .setRoamingProtocol(getProtocolIntFromString( + cursor.getString(cursor.getColumnIndexOrThrow( + Telephony.Carriers.ROAMING_PROTOCOL)))) + .setCarrierEnabled(cursor.getInt(cursor.getColumnIndexOrThrow( + Telephony.Carriers.CARRIER_ENABLED)) == 1) + .setNetworkTypeBitmask(networkTypeBitmask) + .setProfileId(cursor.getInt( + cursor.getColumnIndexOrThrow(Telephony.Carriers.PROFILE_ID))) + .setModemCognitive(cursor.getInt(cursor.getColumnIndexOrThrow( + Telephony.Carriers.MODEM_PERSIST)) == 1) + .setMaxConns(cursor.getInt( + cursor.getColumnIndexOrThrow(Telephony.Carriers.MAX_CONNECTIONS))) + .setWaitTime(cursor.getInt( + cursor.getColumnIndexOrThrow(Telephony.Carriers.WAIT_TIME_RETRY))) + .setMaxConnsTime(cursor.getInt(cursor.getColumnIndexOrThrow( + Telephony.Carriers.TIME_LIMIT_FOR_MAX_CONNECTIONS))) + .setMtuV4(cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MTU))) + .setMtuV6(UNSET_MTU) // TODO: Add corresponding support in telephony provider + .setMvnoType(getMvnoTypeIntFromString( + cursor.getString(cursor.getColumnIndexOrThrow( + Telephony.Carriers.MVNO_TYPE)))) + .setMvnoMatchData(cursor.getString(cursor.getColumnIndexOrThrow( + Telephony.Carriers.MVNO_MATCH_DATA))) + .setApnSetId(cursor.getInt( + cursor.getColumnIndexOrThrow(Telephony.Carriers.APN_SET_ID))) + .setCarrierId(cursor.getInt( + cursor.getColumnIndexOrThrow(Telephony.Carriers.CARRIER_ID))) + .setSkip464Xlat(cursor.getInt(cursor.getColumnIndexOrThrow(Carriers.SKIP_464XLAT))) + .buildWithoutCheck(); } /** * @hide */ public static ApnSetting makeApnSetting(ApnSetting apn) { - return makeApnSetting(apn.mId, apn.mOperatorNumeric, apn.mEntryName, apn.mApnName, - apn.mProxyAddress, apn.mProxyPort, apn.mMmsc, apn.mMmsProxyAddress, - apn.mMmsProxyPort, apn.mUser, apn.mPassword, apn.mAuthType, apn.mApnTypeBitmask, - apn.mProtocol, apn.mRoamingProtocol, apn.mCarrierEnabled, apn.mNetworkTypeBitmask, - apn.mProfileId, apn.mPersistent, apn.mMaxConns, apn.mWaitTime, - apn.mMaxConnsTime, apn.mMtu, apn.mMvnoType, apn.mMvnoMatchData, apn.mApnSetId, - apn.mCarrierId, apn.mSkip464Xlat); - } - - /** - * Creates an ApnSetting object from a string. - * - * @param data the string to read. - * - * The string must be in one of two formats (newlines added for clarity, - * spaces are optional): - * - * v1 format: - * <carrier>, <apn>, <proxy>, <port>, <user>, <password>, <server>, - * <mmsc>, <mmsproxy>, <mmsport>, <mcc>, <mnc>, <authtype>, - * <type>[| <type>...], - * - * v2 format: - * [ApnSettingV2] <carrier>, <apn>, <proxy>, <port>, <user>, <password>, <server>, - * <mmsc>, <mmsproxy>, <mmsport>, <mcc>, <mnc>, <authtype>, - * <type>[| <type>...], <protocol>, <roaming_protocol>, <carrierEnabled>, <bearerBitmask>, - * - * v3 format: - * [ApnSettingV3] <carrier>, <apn>, <proxy>, <port>, <user>, <password>, <server>, - * <mmsc>, <mmsproxy>, <mmsport>, <mcc>, <mnc>, <authtype>, - * <type>[| <type>...], <protocol>, <roaming_protocol>, <carrierEnabled>, <bearerBitmask>, - * <profileId>, <modemCognitive>, <maxConns>, <waitTime>, <maxConnsTime>, <mtu>, - * <mvnoType>, <mvnoMatchData> - * - * v4 format: - * [ApnSettingV4] <carrier>, <apn>, <proxy>, <port>, <user>, <password>, <server>, - * <mmsc>, <mmsproxy>, <mmsport>, <mcc>, <mnc>, <authtype>, - * <type>[| <type>...], <protocol>, <roaming_protocol>, <carrierEnabled>, <bearerBitmask>, - * <profileId>, <modemCognitive>, <maxConns>, <waitTime>, <maxConnsTime>, <mtu>, - * <mvnoType>, <mvnoMatchData>, <networkTypeBitmask> - * - * v5 format: - * [ApnSettingV5] <carrier>, <apn>, <proxy>, <port>, <user>, <password>, <server>, - * <mmsc>, <mmsproxy>, <mmsport>, <mcc>, <mnc>, <authtype>, - * <type>[| <type>...], <protocol>, <roaming_protocol>, <carrierEnabled>, <bearerBitmask>, - * <profileId>, <modemCognitive>, <maxConns>, <waitTime>, <maxConnsTime>, <mtu>, - * <mvnoType>, <mvnoMatchData>, <networkTypeBitmask>, <apnSetId> - * - * v6 format: - * [ApnSettingV6] <carrier>, <apn>, <proxy>, <port>, <user>, <password>, <server>, - * <mmsc>, <mmsproxy>, <mmsport>, <mcc>, <mnc>, <authtype>, - * <type>[| <type>...], <protocol>, <roaming_protocol>, <carrierEnabled>, <bearerBitmask>, - * <profileId>, <modemCognitive>, <maxConns>, <waitTime>, <maxConnsTime>, <mtu>, - * <mvnoType>, <mvnoMatchData>, <networkTypeBitmask>, <apnSetId>, <carrierId> - * - * v7 format: - * [ApnSettingV7] <carrier>, <apn>, <proxy>, <port>, <user>, <password>, <server>, - * <mmsc>, <mmsproxy>, <mmsport>, <mcc>, <mnc>, <authtype>, - * <type>[| <type>...], <protocol>, <roaming_protocol>, <carrierEnabled>, <bearerBitmask>, - * <profileId>, <modemCognitive>, <maxConns>, <waitTime>, <maxConnsTime>, <mtu>, - * <mvnoType>, <mvnoMatchData>, <networkTypeBitmask>, <apnSetId>, <carrierId>, <skip464xlat> - * - * Note that the strings generated by {@link #toString()} do not contain the username - * and password and thus cannot be read by this method. - * - * This method may return {@code null} if the input string is invalid. - * - * @hide - */ - public static ApnSetting fromString(String data) { - if (data == null) return null; - - int version; - // matches() operates on the whole string, so append .* to the regex. - if (data.matches(V7_FORMAT_REGEX + ".*")) { - version = 7; - data = data.replaceFirst(V7_FORMAT_REGEX, ""); - } else if (data.matches(V6_FORMAT_REGEX + ".*")) { - version = 6; - data = data.replaceFirst(V6_FORMAT_REGEX, ""); - } else if (data.matches(V5_FORMAT_REGEX + ".*")) { - version = 5; - data = data.replaceFirst(V5_FORMAT_REGEX, ""); - } else if (data.matches(V4_FORMAT_REGEX + ".*")) { - version = 4; - data = data.replaceFirst(V4_FORMAT_REGEX, ""); - } else if (data.matches(V3_FORMAT_REGEX + ".*")) { - version = 3; - data = data.replaceFirst(V3_FORMAT_REGEX, ""); - } else if (data.matches(V2_FORMAT_REGEX + ".*")) { - version = 2; - data = data.replaceFirst(V2_FORMAT_REGEX, ""); - } else { - version = 1; - } - - String[] a = data.split("\\s*,\\s*", -1); - if (a.length < 14) { - return null; - } - - int authType; - try { - authType = Integer.parseInt(a[12]); - } catch (NumberFormatException e) { - authType = 0; - } - - String[] typeArray; - String protocol, roamingProtocol; - boolean carrierEnabled; - int bearerBitmask = 0; - int networkTypeBitmask = 0; - int profileId = 0; - boolean modemCognitive = false; - int maxConns = 0; - int waitTime = 0; - int maxConnsTime = 0; - int mtu = UNSET_MTU; - String mvnoType = ""; - String mvnoMatchData = ""; - int apnSetId = Carriers.NO_APN_SET_ID; - int carrierId = TelephonyManager.UNKNOWN_CARRIER_ID; - int skip464xlat = Carriers.SKIP_464XLAT_DEFAULT; - if (version == 1) { - typeArray = new String[a.length - 13]; - System.arraycopy(a, 13, typeArray, 0, a.length - 13); - protocol = PROTOCOL_INT_MAP.get(PROTOCOL_IP); - roamingProtocol = PROTOCOL_INT_MAP.get(PROTOCOL_IP); - carrierEnabled = true; - } else { - if (a.length < 18) { - return null; - } - typeArray = a[13].split("\\s*\\|\\s*"); - protocol = a[14]; - roamingProtocol = a[15]; - carrierEnabled = Boolean.parseBoolean(a[16]); - - bearerBitmask = ServiceState.getBitmaskFromString(a[17]); - - if (a.length > 22) { - modemCognitive = Boolean.parseBoolean(a[19]); - try { - profileId = Integer.parseInt(a[18]); - maxConns = Integer.parseInt(a[20]); - waitTime = Integer.parseInt(a[21]); - maxConnsTime = Integer.parseInt(a[22]); - } catch (NumberFormatException e) { - } - } - if (a.length > 23) { - try { - mtu = Integer.parseInt(a[23]); - } catch (NumberFormatException e) { - } - } - if (a.length > 25) { - mvnoType = a[24]; - mvnoMatchData = a[25]; - } - if (a.length > 26) { - networkTypeBitmask = ServiceState.getBitmaskFromString(a[26]); - } - if (a.length > 27) { - apnSetId = Integer.parseInt(a[27]); - } - if (a.length > 28) { - carrierId = Integer.parseInt(a[28]); - } - if (a.length > 29) { - try { - skip464xlat = Integer.parseInt(a[29]); - } catch (NumberFormatException e) { - } - } - } - - // If both bearerBitmask and networkTypeBitmask were specified, bearerBitmask would be - // ignored. - if (networkTypeBitmask == 0) { - networkTypeBitmask = - ServiceState.convertBearerBitmaskToNetworkTypeBitmask(bearerBitmask); - } - return makeApnSetting(-1, a[10] + a[11], a[0], a[1], a[2], - portFromString(a[3]), UriFromString(a[7]), a[8], - portFromString(a[9]), a[4], a[5], authType, - getApnTypesBitmaskFromString(TextUtils.join(",", typeArray)), - getProtocolIntFromString(protocol), getProtocolIntFromString(roamingProtocol), - carrierEnabled, networkTypeBitmask, profileId, modemCognitive, maxConns, waitTime, - maxConnsTime, mtu, getMvnoTypeIntFromString(mvnoType), mvnoMatchData, apnSetId, - carrierId, skip464xlat); - } - - /** - * Creates an array of ApnSetting objects from a string. - * - * @param data the string to read. - * - * Builds on top of the same format used by fromString, but allows for multiple entries - * separated by ";". - * - * @hide - */ - public static List<ApnSetting> arrayFromString(String data) { - List<ApnSetting> retVal = new ArrayList<ApnSetting>(); - if (TextUtils.isEmpty(data)) { - return retVal; - } - String[] apnStrings = data.split("\\s*;\\s*"); - for (String apnString : apnStrings) { - ApnSetting apn = fromString(apnString); - if (apn != null) { - retVal.add(apn); - } - } - return retVal; + return new Builder() + .setId(apn.mId) + .setOperatorNumeric(apn.mOperatorNumeric) + .setEntryName(apn.mEntryName) + .setApnName(apn.mApnName) + .setProxyAddress(apn.mProxyAddress) + .setProxyPort(apn.mProxyPort) + .setMmsc(apn.mMmsc) + .setMmsProxyAddress(apn.mMmsProxyAddress) + .setMmsProxyPort(apn.mMmsProxyPort) + .setUser(apn.mUser) + .setPassword(apn.mPassword) + .setAuthType(apn.mAuthType) + .setApnTypeBitmask(apn.mApnTypeBitmask) + .setProtocol(apn.mProtocol) + .setRoamingProtocol(apn.mRoamingProtocol) + .setCarrierEnabled(apn.mCarrierEnabled) + .setNetworkTypeBitmask(apn.mNetworkTypeBitmask) + .setProfileId(apn.mProfileId) + .setModemCognitive(apn.mPersistent) + .setMaxConns(apn.mMaxConns) + .setWaitTime(apn.mWaitTime) + .setMaxConnsTime(apn.mMaxConnsTime) + .setMtuV4(apn.mMtuV4) + .setMtuV6(apn.mMtuV6) + .setMvnoType(apn.mMvnoType) + .setMvnoMatchData(apn.mMvnoMatchData) + .setApnSetId(apn.mApnSetId) + .setCarrierId(apn.mCarrierId) + .setSkip464Xlat(apn.mSkip464Xlat) + .buildWithoutCheck(); } /** @@ -1251,7 +1042,7 @@ public class ApnSetting implements Parcelable { */ public String toString() { StringBuilder sb = new StringBuilder(); - sb.append("[ApnSettingV7] ") + sb.append("[ApnSetting] ") .append(mEntryName) .append(", ").append(mId) .append(", ").append(mOperatorNumeric) @@ -1272,7 +1063,8 @@ public class ApnSetting implements Parcelable { sb.append(", ").append(mMaxConns); sb.append(", ").append(mWaitTime); sb.append(", ").append(mMaxConnsTime); - sb.append(", ").append(mMtu); + sb.append(", ").append(mMtuV4); + sb.append(", ").append(mMtuV6); sb.append(", ").append(MVNO_TYPE_INT_MAP.get(mMvnoType)); sb.append(", ").append(mMvnoMatchData); sb.append(", ").append(mPermanentFailed); @@ -1343,9 +1135,9 @@ public class ApnSetting implements Parcelable { public int hashCode() { return Objects.hash(mApnName, mProxyAddress, mProxyPort, mMmsc, mMmsProxyAddress, mMmsProxyPort, mUser, mPassword, mAuthType, mApnTypeBitmask, mId, mOperatorNumeric, - mProtocol, mRoamingProtocol, mMtu, mCarrierEnabled, mNetworkTypeBitmask, mProfileId, - mPersistent, mMaxConns, mWaitTime, mMaxConnsTime, mMvnoType, mMvnoMatchData, - mApnSetId, mCarrierId, mSkip464Xlat); + mProtocol, mRoamingProtocol, mMtuV4, mMtuV6, mCarrierEnabled, mNetworkTypeBitmask, + mProfileId, mPersistent, mMaxConns, mWaitTime, mMaxConnsTime, mMvnoType, + mMvnoMatchData, mApnSetId, mCarrierId, mSkip464Xlat); } @Override @@ -1357,33 +1149,34 @@ public class ApnSetting implements Parcelable { ApnSetting other = (ApnSetting) o; return mEntryName.equals(other.mEntryName) - && Objects.equals(mId, other.mId) - && Objects.equals(mOperatorNumeric, other.mOperatorNumeric) - && Objects.equals(mApnName, other.mApnName) - && Objects.equals(mProxyAddress, other.mProxyAddress) - && Objects.equals(mMmsc, other.mMmsc) - && Objects.equals(mMmsProxyAddress, other.mMmsProxyAddress) - && Objects.equals(mMmsProxyPort, other.mMmsProxyPort) - && Objects.equals(mProxyPort, other.mProxyPort) - && Objects.equals(mUser, other.mUser) - && Objects.equals(mPassword, other.mPassword) - && Objects.equals(mAuthType, other.mAuthType) - && Objects.equals(mApnTypeBitmask, other.mApnTypeBitmask) - && Objects.equals(mProtocol, other.mProtocol) - && Objects.equals(mRoamingProtocol, other.mRoamingProtocol) - && Objects.equals(mCarrierEnabled, other.mCarrierEnabled) - && Objects.equals(mProfileId, other.mProfileId) - && Objects.equals(mPersistent, other.mPersistent) - && Objects.equals(mMaxConns, other.mMaxConns) - && Objects.equals(mWaitTime, other.mWaitTime) - && Objects.equals(mMaxConnsTime, other.mMaxConnsTime) - && Objects.equals(mMtu, other.mMtu) - && Objects.equals(mMvnoType, other.mMvnoType) - && Objects.equals(mMvnoMatchData, other.mMvnoMatchData) - && Objects.equals(mNetworkTypeBitmask, other.mNetworkTypeBitmask) - && Objects.equals(mApnSetId, other.mApnSetId) - && Objects.equals(mCarrierId, other.mCarrierId) - && Objects.equals(mSkip464Xlat, other.mSkip464Xlat); + && Objects.equals(mId, other.mId) + && Objects.equals(mOperatorNumeric, other.mOperatorNumeric) + && Objects.equals(mApnName, other.mApnName) + && Objects.equals(mProxyAddress, other.mProxyAddress) + && Objects.equals(mMmsc, other.mMmsc) + && Objects.equals(mMmsProxyAddress, other.mMmsProxyAddress) + && Objects.equals(mMmsProxyPort, other.mMmsProxyPort) + && Objects.equals(mProxyPort, other.mProxyPort) + && Objects.equals(mUser, other.mUser) + && Objects.equals(mPassword, other.mPassword) + && Objects.equals(mAuthType, other.mAuthType) + && Objects.equals(mApnTypeBitmask, other.mApnTypeBitmask) + && Objects.equals(mProtocol, other.mProtocol) + && Objects.equals(mRoamingProtocol, other.mRoamingProtocol) + && Objects.equals(mCarrierEnabled, other.mCarrierEnabled) + && Objects.equals(mProfileId, other.mProfileId) + && Objects.equals(mPersistent, other.mPersistent) + && Objects.equals(mMaxConns, other.mMaxConns) + && Objects.equals(mWaitTime, other.mWaitTime) + && Objects.equals(mMaxConnsTime, other.mMaxConnsTime) + && Objects.equals(mMtuV4, other.mMtuV4) + && Objects.equals(mMtuV6, other.mMtuV6) + && Objects.equals(mMvnoType, other.mMvnoType) + && Objects.equals(mMvnoMatchData, other.mMvnoMatchData) + && Objects.equals(mNetworkTypeBitmask, other.mNetworkTypeBitmask) + && Objects.equals(mApnSetId, other.mApnSetId) + && Objects.equals(mCarrierId, other.mCarrierId) + && Objects.equals(mSkip464Xlat, other.mSkip464Xlat); } /** @@ -1406,31 +1199,32 @@ public class ApnSetting implements Parcelable { ApnSetting other = (ApnSetting) o; return mEntryName.equals(other.mEntryName) - && Objects.equals(mOperatorNumeric, other.mOperatorNumeric) - && Objects.equals(mApnName, other.mApnName) - && Objects.equals(mProxyAddress, other.mProxyAddress) - && Objects.equals(mMmsc, other.mMmsc) - && Objects.equals(mMmsProxyAddress, other.mMmsProxyAddress) - && Objects.equals(mMmsProxyPort, other.mMmsProxyPort) - && Objects.equals(mProxyPort, other.mProxyPort) - && Objects.equals(mUser, other.mUser) - && Objects.equals(mPassword, other.mPassword) - && Objects.equals(mAuthType, other.mAuthType) - && Objects.equals(mApnTypeBitmask, other.mApnTypeBitmask) - && (isDataRoaming || Objects.equals(mProtocol, other.mProtocol)) - && (!isDataRoaming || Objects.equals(mRoamingProtocol, other.mRoamingProtocol)) - && Objects.equals(mCarrierEnabled, other.mCarrierEnabled) - && Objects.equals(mProfileId, other.mProfileId) - && Objects.equals(mPersistent, other.mPersistent) - && Objects.equals(mMaxConns, other.mMaxConns) - && Objects.equals(mWaitTime, other.mWaitTime) - && Objects.equals(mMaxConnsTime, other.mMaxConnsTime) - && Objects.equals(mMtu, other.mMtu) - && Objects.equals(mMvnoType, other.mMvnoType) - && Objects.equals(mMvnoMatchData, other.mMvnoMatchData) - && Objects.equals(mApnSetId, other.mApnSetId) - && Objects.equals(mCarrierId, other.mCarrierId) - && Objects.equals(mSkip464Xlat, other.mSkip464Xlat); + && Objects.equals(mOperatorNumeric, other.mOperatorNumeric) + && Objects.equals(mApnName, other.mApnName) + && Objects.equals(mProxyAddress, other.mProxyAddress) + && Objects.equals(mMmsc, other.mMmsc) + && Objects.equals(mMmsProxyAddress, other.mMmsProxyAddress) + && Objects.equals(mMmsProxyPort, other.mMmsProxyPort) + && Objects.equals(mProxyPort, other.mProxyPort) + && Objects.equals(mUser, other.mUser) + && Objects.equals(mPassword, other.mPassword) + && Objects.equals(mAuthType, other.mAuthType) + && Objects.equals(mApnTypeBitmask, other.mApnTypeBitmask) + && (isDataRoaming || Objects.equals(mProtocol, other.mProtocol)) + && (!isDataRoaming || Objects.equals(mRoamingProtocol, other.mRoamingProtocol)) + && Objects.equals(mCarrierEnabled, other.mCarrierEnabled) + && Objects.equals(mProfileId, other.mProfileId) + && Objects.equals(mPersistent, other.mPersistent) + && Objects.equals(mMaxConns, other.mMaxConns) + && Objects.equals(mWaitTime, other.mWaitTime) + && Objects.equals(mMaxConnsTime, other.mMaxConnsTime) + && Objects.equals(mMtuV4, other.mMtuV4) + && Objects.equals(mMtuV6, other.mMtuV6) + && Objects.equals(mMvnoType, other.mMvnoType) + && Objects.equals(mMvnoMatchData, other.mMvnoMatchData) + && Objects.equals(mApnSetId, other.mApnSetId) + && Objects.equals(mCarrierId, other.mCarrierId) + && Objects.equals(mSkip464Xlat, other.mSkip464Xlat); } /** @@ -1732,7 +1526,7 @@ public class ApnSetting implements Parcelable { dest.writeString(mApnName); dest.writeString(mProxyAddress); dest.writeInt(mProxyPort); - dest.writeValue(mMmsc); + dest.writeParcelable(mMmsc, flags); dest.writeString(mMmsProxyAddress); dest.writeInt(mMmsProxyPort); dest.writeString(mUser); @@ -1742,40 +1536,53 @@ public class ApnSetting implements Parcelable { dest.writeInt(mProtocol); dest.writeInt(mRoamingProtocol); dest.writeBoolean(mCarrierEnabled); - dest.writeInt(mMvnoType); dest.writeInt(mNetworkTypeBitmask); + dest.writeInt(mProfileId); + dest.writeBoolean(mPersistent); + dest.writeInt(mMaxConns); + dest.writeInt(mWaitTime); + dest.writeInt(mMaxConnsTime); + dest.writeInt(mMtuV4); + dest.writeInt(mMtuV6); + dest.writeInt(mMvnoType); + dest.writeString(mMvnoMatchData); dest.writeInt(mApnSetId); dest.writeInt(mCarrierId); dest.writeInt(mSkip464Xlat); } private static ApnSetting readFromParcel(Parcel in) { - final int id = in.readInt(); - final String operatorNumeric = in.readString(); - final String entryName = in.readString(); - final String apnName = in.readString(); - final String proxy = in.readString(); - final int port = in.readInt(); - final Uri mmsc = (Uri) in.readValue(Uri.class.getClassLoader()); - final String mmsProxy = in.readString(); - final int mmsPort = in.readInt(); - final String user = in.readString(); - final String password = in.readString(); - final int authType = in.readInt(); - final int apnTypesBitmask = in.readInt(); - final int protocol = in.readInt(); - final int roamingProtocol = in.readInt(); - final boolean carrierEnabled = in.readBoolean(); - final int mvnoType = in.readInt(); - final int networkTypeBitmask = in.readInt(); - final int apnSetId = in.readInt(); - final int carrierId = in.readInt(); - final int skip464xlat = in.readInt(); - - return makeApnSetting(id, operatorNumeric, entryName, apnName, - proxy, port, mmsc, mmsProxy, mmsPort, user, password, authType, apnTypesBitmask, - protocol, roamingProtocol, carrierEnabled, networkTypeBitmask, 0, false, - 0, 0, 0, 0, mvnoType, null, apnSetId, carrierId, skip464xlat); + return new Builder() + .setId(in.readInt()) + .setOperatorNumeric(in.readString()) + .setEntryName(in.readString()) + .setApnName(in.readString()) + .setProxyAddress(in.readString()) + .setProxyPort(in.readInt()) + .setMmsc(in.readParcelable(Uri.class.getClassLoader())) + .setMmsProxyAddress(in.readString()) + .setMmsProxyPort(in.readInt()) + .setUser(in.readString()) + .setPassword(in.readString()) + .setAuthType(in.readInt()) + .setApnTypeBitmask(in.readInt()) + .setProtocol(in.readInt()) + .setRoamingProtocol(in.readInt()) + .setCarrierEnabled(in.readBoolean()) + .setNetworkTypeBitmask(in.readInt()) + .setProfileId(in.readInt()) + .setModemCognitive(in.readBoolean()) + .setMaxConns(in.readInt()) + .setWaitTime(in.readInt()) + .setMaxConnsTime(in.readInt()) + .setMtuV4(in.readInt()) + .setMtuV6(in.readInt()) + .setMvnoType(in.readInt()) + .setMvnoMatchData(in.readString()) + .setApnSetId(in.readInt()) + .setCarrierId(in.readInt()) + .setSkip464Xlat(in.readInt()) + .buildWithoutCheck(); } public static final @android.annotation.NonNull Parcelable.Creator<ApnSetting> CREATOR = @@ -1834,13 +1641,14 @@ public class ApnSetting implements Parcelable { private int mMmsProxyPort = UNSPECIFIED_INT; private String mUser; private String mPassword; - private int mAuthType; + private int mAuthType = AUTH_TYPE_UNKNOWN; private int mApnTypeBitmask; private int mId; private String mOperatorNumeric; private int mProtocol = UNSPECIFIED_INT; private int mRoamingProtocol = UNSPECIFIED_INT; - private int mMtu; + private int mMtuV4; + private int mMtuV6; private int mNetworkTypeBitmask; private boolean mCarrierEnabled; private int mProfileId; @@ -1863,20 +1671,34 @@ public class ApnSetting implements Parcelable { * Sets the unique database id for this entry. * * @param id the unique database id to set for this entry + * @hide */ - private Builder setId(int id) { + public Builder setId(int id) { this.mId = id; return this; } /** - * Set the MTU size of the mobile interface to which the APN connected. + * Set the MTU size of the IPv4 mobile interface to which the APN connected. Note this value + * is used only if MTU size is not provided in {@link DataCallResponse}. + * + * @param mtuV4 the MTU size to set for the APN + * @hide + */ + public Builder setMtuV4(int mtuV4) { + this.mMtuV4 = mtuV4; + return this; + } + + /** + * Set the MTU size of the IPv6 mobile interface to which the APN connected. Note this value + * is used only if MTU size is not provided in {@link DataCallResponse}. * - * @param mtu the MTU size to set for the APN + * @param mtuV6 the MTU size to set for the APN * @hide */ - public Builder setMtu(int mtu) { - this.mMtu = mtu; + public Builder setMtuV6(int mtuV6) { + this.mMtuV6 = mtuV6; return this; } @@ -2237,7 +2059,8 @@ public class ApnSetting implements Parcelable { | TYPE_FOTA | TYPE_IMS | TYPE_CBS | TYPE_IA | TYPE_EMERGENCY | TYPE_MCX | TYPE_XCAP | TYPE_VSIM | TYPE_BIP | TYPE_ENTERPRISE)) == 0 || TextUtils.isEmpty(mApnName) || TextUtils.isEmpty(mEntryName)) { - return null; + throw new IllegalArgumentException("mApName=" + mApnName + ", mEntryName=" + + mEntryName + ", mApnTypeBitmask=" + mApnTypeBitmask); } return new ApnSetting(this); } diff --git a/telephony/java/android/telephony/data/DataProfile.java b/telephony/java/android/telephony/data/DataProfile.java index f2a124901bc4..93903d2658cd 100644 --- a/telephony/java/android/telephony/data/DataProfile.java +++ b/telephony/java/android/telephony/data/DataProfile.java @@ -25,13 +25,11 @@ import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; import android.telephony.Annotation.ApnType; +import android.telephony.TelephonyManager; import android.telephony.TelephonyManager.NetworkTypeBitMask; import android.telephony.data.ApnSetting.AuthType; import android.text.TextUtils; -import com.android.internal.telephony.RILConstants; -import com.android.internal.telephony.util.TelephonyUtils; - import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Objects; @@ -62,152 +60,141 @@ public final class DataProfile implements Parcelable { /** 3GPP2 type data profile */ public static final int TYPE_3GPP2 = 2; - private final int mProfileId; - - private final String mApn; - - @ProtocolType - private final int mProtocolType; - - @AuthType - private final int mAuthType; - - private final String mUserName; - - private final String mPassword; - - @Type - private final int mType; - - private final int mMaxConnectionsTime; - - private final int mMaxConnections; - - private final int mWaitTime; - - private final boolean mEnabled; - - @ApnType - private final int mSupportedApnTypesBitmask; - - @ProtocolType - private final int mRoamingProtocolType; - - @NetworkTypeBitMask - private final int mBearerBitmask; + private final @Type int mType; - private final int mMtuV4; + private final @Nullable ApnSetting mApnSetting; - private final int mMtuV6; - - private final boolean mPersistent; + private final @Nullable TrafficDescriptor mTrafficDescriptor; private final boolean mPreferred; - /** @hide */ - private DataProfile(int profileId, String apn, @ProtocolType int protocolType, int authType, - String userName, String password, int type, int maxConnectionsTime, - int maxConnections, int waitTime, boolean enabled, - @ApnType int supportedApnTypesBitmask, @ProtocolType int roamingProtocolType, - @NetworkTypeBitMask int bearerBitmask, int mtuV4, int mtuV6, boolean persistent, - boolean preferred) { - this.mProfileId = profileId; - this.mApn = apn; - this.mProtocolType = protocolType; - if (authType == -1) { - authType = TextUtils.isEmpty(userName) ? RILConstants.SETUP_DATA_AUTH_NONE - : RILConstants.SETUP_DATA_AUTH_PAP_CHAP; - } - this.mAuthType = authType; - this.mUserName = userName; - this.mPassword = password; - this.mType = type; - this.mMaxConnectionsTime = maxConnectionsTime; - this.mMaxConnections = maxConnections; - this.mWaitTime = waitTime; - this.mEnabled = enabled; - this.mSupportedApnTypesBitmask = supportedApnTypesBitmask; - this.mRoamingProtocolType = roamingProtocolType; - this.mBearerBitmask = bearerBitmask; - this.mMtuV4 = mtuV4; - this.mMtuV6 = mtuV6; - this.mPersistent = persistent; - this.mPreferred = preferred; + private DataProfile(@NonNull Builder builder) { + mApnSetting = builder.mApnSetting; + mTrafficDescriptor = builder.mTrafficDescriptor; + mPreferred = builder.mPreferred; + + if (builder.mType != -1) { + mType = builder.mType; + } else if (mApnSetting != null) { + int networkTypes = mApnSetting.getNetworkTypeBitmask(); + + if (networkTypes == 0) { + mType = DataProfile.TYPE_COMMON; + } else if ((networkTypes & TelephonyManager.NETWORK_STANDARDS_FAMILY_BITMASK_3GPP2) + == networkTypes) { + mType = DataProfile.TYPE_3GPP2; + } else if ((networkTypes & TelephonyManager.NETWORK_STANDARDS_FAMILY_BITMASK_3GPP) + == networkTypes) { + mType = DataProfile.TYPE_3GPP; + } else { + mType = DataProfile.TYPE_COMMON; + } + } else { + mType = DataProfile.TYPE_COMMON; + } } private DataProfile(Parcel source) { - mProfileId = source.readInt(); - mApn = source.readString(); - mProtocolType = source.readInt(); - mAuthType = source.readInt(); - mUserName = source.readString(); - mPassword = source.readString(); mType = source.readInt(); - mMaxConnectionsTime = source.readInt(); - mMaxConnections = source.readInt(); - mWaitTime = source.readInt(); - mEnabled = source.readBoolean(); - mSupportedApnTypesBitmask = source.readInt(); - mRoamingProtocolType = source.readInt(); - mBearerBitmask = source.readInt(); - mMtuV4 = source.readInt(); - mMtuV6 = source.readInt(); - mPersistent = source.readBoolean(); + mApnSetting = source.readParcelable(ApnSetting.class.getClassLoader()); + mTrafficDescriptor = source.readParcelable(TrafficDescriptor.class.getClassLoader()); mPreferred = source.readBoolean(); } /** * @return Id of the data profile. */ - public int getProfileId() { return mProfileId; } + public int getProfileId() { + if (mApnSetting != null) { + return mApnSetting.getProfileId(); + } + return 0; + } /** * @return The APN (Access Point Name) to establish data connection. This is a string * specifically defined by the carrier. */ @NonNull - public String getApn() { return mApn; } + public String getApn() { + if (mApnSetting != null) { + return TextUtils.emptyIfNull(mApnSetting.getApnName()); + } + return ""; + } /** * @return The connection protocol defined in 3GPP TS 27.007 section 10.1.1. */ - public @ProtocolType int getProtocolType() { return mProtocolType; } + public @ProtocolType int getProtocolType() { + if (mApnSetting != null) { + return mApnSetting.getProtocol(); + } + return ApnSetting.PROTOCOL_IP; + } /** * @return The authentication protocol used for this PDP context. */ - public @AuthType int getAuthType() { return mAuthType; } + public @AuthType int getAuthType() { + if (mApnSetting != null) { + return mApnSetting.getAuthType(); + } + return ApnSetting.AUTH_TYPE_NONE; + } /** * @return The username for APN. Can be null. */ @Nullable - public String getUserName() { return mUserName; } + public String getUserName() { + if (mApnSetting != null) { + return mApnSetting.getUser(); + } + return null; + } /** * @return The password for APN. Can be null. */ @Nullable - public String getPassword() { return mPassword; } + public String getPassword() { + if (mApnSetting != null) { + return mApnSetting.getPassword(); + } + return null; + } /** * @return The profile type. */ - public @Type int getType() { return mType; } + public @Type int getType() { + return mType; + } /** * @return The period in seconds to limit the maximum connections. * * @hide */ - public int getMaxConnectionsTime() { return mMaxConnectionsTime; } + public int getMaxConnectionsTime() { + if (mApnSetting != null) { + return mApnSetting.getMaxConnsTime(); + } + return 0; + } /** * @return The maximum connections allowed. * * @hide */ - public int getMaxConnections() { return mMaxConnections; } + public int getMaxConnections() { + if (mApnSetting != null) { + return mApnSetting.getMaxConns(); + } + return 0; + } /** * @return The required wait time in seconds after a successful UE initiated disconnect of a @@ -216,57 +203,117 @@ public final class DataProfile implements Parcelable { * * @hide */ - public int getWaitTime() { return mWaitTime; } + public int getWaitTime() { + if (mApnSetting != null) { + return mApnSetting.getWaitTime(); + } + return 0; + } /** * @return True if the profile is enabled. */ - public boolean isEnabled() { return mEnabled; } + public boolean isEnabled() { + if (mApnSetting != null) { + return mApnSetting.isEnabled(); + } + return false; + } /** * @return The supported APN types bitmask. */ - public @ApnType int getSupportedApnTypesBitmask() { return mSupportedApnTypesBitmask; } + public @ApnType int getSupportedApnTypesBitmask() { + if (mApnSetting != null) { + return mApnSetting.getApnTypeBitmask(); + } + return ApnSetting.TYPE_NONE; + } /** * @return The connection protocol on roaming network defined in 3GPP TS 27.007 section 10.1.1. */ - public @ProtocolType int getRoamingProtocolType() { return mRoamingProtocolType; } + public @ProtocolType int getRoamingProtocolType() { + if (mApnSetting != null) { + return mApnSetting.getRoamingProtocol(); + } + return ApnSetting.PROTOCOL_IP; + } /** * @return The bearer bitmask indicating the applicable networks for this data profile. */ - public @NetworkTypeBitMask int getBearerBitmask() { return mBearerBitmask; } + public @NetworkTypeBitMask int getBearerBitmask() { + if (mApnSetting != null) { + return mApnSetting.getNetworkTypeBitmask(); + } + return (int) TelephonyManager.NETWORK_TYPE_BITMASK_UNKNOWN; + } /** * @return The maximum transmission unit (MTU) size in bytes. * @deprecated use {@link #getMtuV4} or {@link #getMtuV6} instead. */ @Deprecated - public int getMtu() { return mMtuV4; } + public int getMtu() { + return getMtuV4(); + } /** * This replaces the deprecated method getMtu. * @return The maximum transmission unit (MTU) size in bytes, for IPv4. */ - public int getMtuV4() { return mMtuV4; } + public int getMtuV4() { + if (mApnSetting != null) { + return mApnSetting.getMtuV4(); + } + return 0; + } /** * @return The maximum transmission unit (MTU) size in bytes, for IPv6. */ - public int getMtuV6() { return mMtuV6; } + public int getMtuV6() { + if (mApnSetting != null) { + return mApnSetting.getMtuV6(); + } + return 0; + } /** * @return {@code true} if modem must persist this data profile. */ - public boolean isPersistent() { return mPersistent; } + public boolean isPersistent() { + if (mApnSetting != null) { + return mApnSetting.isPersistent(); + } + return false; + } /** * @return {@code true} if this data profile was used to bring up the last default * (i.e internet) data connection successfully, or the one chosen by the user in Settings' * APN editor. For one carrier there can be only one profiled preferred. */ - public boolean isPreferred() { return mPreferred; } + public boolean isPreferred() { + return mPreferred; + } + + /** + * @return The APN setting + * @hide TODO: Remove before T is released. + */ + public @Nullable ApnSetting getApnSetting() { + return mApnSetting; + } + + /** + * @return The traffic descriptor + * @hide TODO: Remove before T is released. + */ + public @Nullable TrafficDescriptor getTrafficDescriptor() { + return mTrafficDescriptor; + } @Override public int describeContents() { @@ -276,34 +323,15 @@ public final class DataProfile implements Parcelable { @NonNull @Override public String toString() { - return "DataProfile=" + mProfileId + "/" + mProtocolType + "/" + mAuthType - + "/" + (TelephonyUtils.IS_USER ? "***/***/***" : - (mApn + "/" + mUserName + "/" + mPassword)) + "/" + mType + "/" - + mMaxConnectionsTime + "/" + mMaxConnections + "/" - + mWaitTime + "/" + mEnabled + "/" + mSupportedApnTypesBitmask + "/" - + mRoamingProtocolType + "/" + mBearerBitmask + "/" + mMtuV4 + "/" + mMtuV6 + "/" - + mPersistent + "/" + mPreferred; + return "DataProfile=" + mApnSetting + ", " + mTrafficDescriptor + ", preferred=" + + mPreferred; } @Override public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(mProfileId); - dest.writeString(mApn); - dest.writeInt(mProtocolType); - dest.writeInt(mAuthType); - dest.writeString(mUserName); - dest.writeString(mPassword); dest.writeInt(mType); - dest.writeInt(mMaxConnectionsTime); - dest.writeInt(mMaxConnections); - dest.writeInt(mWaitTime); - dest.writeBoolean(mEnabled); - dest.writeInt(mSupportedApnTypesBitmask); - dest.writeInt(mRoamingProtocolType); - dest.writeInt(mBearerBitmask); - dest.writeInt(mMtuV4); - dest.writeInt(mMtuV6); - dest.writeBoolean(mPersistent); + dest.writeParcelable(mApnSetting, flags); + dest.writeParcelable(mTrafficDescriptor, flags); dest.writeBoolean(mPreferred); } @@ -321,36 +349,18 @@ public final class DataProfile implements Parcelable { }; @Override - public boolean equals(@Nullable Object o) { + public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; DataProfile that = (DataProfile) o; - return mProfileId == that.mProfileId - && mProtocolType == that.mProtocolType - && mAuthType == that.mAuthType - && mType == that.mType - && mMaxConnectionsTime == that.mMaxConnectionsTime - && mMaxConnections == that.mMaxConnections - && mWaitTime == that.mWaitTime - && mEnabled == that.mEnabled - && mSupportedApnTypesBitmask == that.mSupportedApnTypesBitmask - && mRoamingProtocolType == that.mRoamingProtocolType - && mBearerBitmask == that.mBearerBitmask - && mMtuV4 == that.mMtuV4 - && mMtuV6 == that.mMtuV6 - && mPersistent == that.mPersistent - && mPreferred == that.mPreferred - && Objects.equals(mApn, that.mApn) - && Objects.equals(mUserName, that.mUserName) - && Objects.equals(mPassword, that.mPassword); + return mType == that.mType + && Objects.equals(mApnSetting, that.mApnSetting) + && Objects.equals(mTrafficDescriptor, that.mTrafficDescriptor); } @Override public int hashCode() { - return Objects.hash(mProfileId, mApn, mProtocolType, mAuthType, mUserName, mPassword, mType, - mMaxConnectionsTime, mMaxConnections, mWaitTime, mEnabled, - mSupportedApnTypesBitmask, mRoamingProtocolType, mBearerBitmask, mMtuV4, mMtuV6, - mPersistent, mPreferred); + return Objects.hash(mType, mApnSetting, mTrafficDescriptor); } /** @@ -383,13 +393,7 @@ public final class DataProfile implements Parcelable { private String mPassword; @Type - private int mType; - - private int mMaxConnectionsTime; - - private int mMaxConnections; - - private int mWaitTime; + private int mType = -1; private boolean mEnabled; @@ -410,6 +414,10 @@ public final class DataProfile implements Parcelable { private boolean mPreferred; + private ApnSetting mApnSetting; + + private TrafficDescriptor mTrafficDescriptor; + /** * Default constructor for Builder. */ @@ -496,48 +504,6 @@ public final class DataProfile implements Parcelable { } /** - * Set the period in seconds to limit the maximum connections. - * - * @param maxConnectionsTime The profile type - * @return The same instance of the builder. - * - * @hide - */ - public @NonNull Builder setMaxConnectionsTime(int maxConnectionsTime) { - mMaxConnectionsTime = maxConnectionsTime; - return this; - } - - /** - * Set the maximum connections allowed. - * - * @param maxConnections The maximum connections allowed. - * @return The same instance of the builder. - * - * @hide - */ - public @NonNull Builder setMaxConnections(int maxConnections) { - mMaxConnections = maxConnections; - return this; - } - - /** - * Set the period in seconds to limit the maximum connections. - * - * @param waitTime The required wait time in seconds after a successful UE initiated - * disconnect of a given PDN connection before the device can send a new PDN connection - * request for that given PDN. - * - * @return The same instance of the builder. - * - * @hide - */ - public @NonNull Builder setWaitTime(int waitTime) { - mWaitTime = waitTime; - return this; - } - - /** * Enable the data profile * * @param isEnabled {@code true} to enable the data profile, otherwise disable. @@ -587,8 +553,9 @@ public final class DataProfile implements Parcelable { * * @param mtu The maximum transmission unit (MTU) size in bytes. * @return The same instance of the builder. - * @deprecated use {@link #setMtuV4} or {@link #setMtuV6} instead. + * @deprecated use {@link #setApnSetting(ApnSetting)} instead. */ + @Deprecated public @NonNull Builder setMtu(int mtu) { mMtuV4 = mMtuV6 = mtu; return this; @@ -631,7 +598,7 @@ public final class DataProfile implements Parcelable { } /** - * Set data profile as persistent/non-persistent + * Set data profile as persistent/non-persistent. * * @param isPersistent {@code true} if this data profile was used to bring up the last * default (i.e internet) data connection successfully. @@ -643,15 +610,63 @@ public final class DataProfile implements Parcelable { } /** + * Set APN setting. + * + * @param apnSetting APN setting + * @return The same instance of the builder + * + * @hide // TODO: Remove before T is released. + */ + public @NonNull Builder setApnSetting(@NonNull ApnSetting apnSetting) { + mApnSetting = apnSetting; + return this; + } + + /** + * Set traffic descriptor. + * + * @param trafficDescriptor Traffic descriptor + * @return The same instance of the builder + * + * @hide // TODO: Remove before T is released. + */ + public @NonNull Builder setTrafficDescriptor(@NonNull TrafficDescriptor trafficDescriptor) { + mTrafficDescriptor = trafficDescriptor; + return this; + } + + /** * Build the DataProfile object * * @return The data profile object */ public @NonNull DataProfile build() { - return new DataProfile(mProfileId, mApn, mProtocolType, mAuthType, mUserName, mPassword, - mType, mMaxConnectionsTime, mMaxConnections, mWaitTime, mEnabled, - mSupportedApnTypesBitmask, mRoamingProtocolType, mBearerBitmask, mMtuV4, mMtuV6, - mPersistent, mPreferred); + if (mApnSetting == null && mApn != null) { + // This is for backwards compatibility. + mApnSetting = new ApnSetting.Builder() + .setEntryName(mApn) + .setApnName(mApn) + .setApnTypeBitmask(mSupportedApnTypesBitmask) + .setAuthType(mAuthType) + .setCarrierEnabled(mEnabled) + .setModemCognitive(mPersistent) + .setMtuV4(mMtuV4) + .setMtuV6(mMtuV6) + .setNetworkTypeBitmask(mBearerBitmask) + .setProfileId(mProfileId) + .setPassword(mPassword) + .setProtocol(mProtocolType) + .setRoamingProtocol(mRoamingProtocolType) + .setUser(mUserName) + .build(); + } + + if (mApnSetting == null && mTrafficDescriptor == null) { + throw new IllegalArgumentException("APN setting and traffic descriptor can't be " + + "both null."); + } + + return new DataProfile(this); } } } diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index 63732b5ee444..232a5d881722 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -1002,11 +1002,6 @@ interface ITelephony { boolean isManualNetworkSelectionAllowed(int subId); /** - * Enable or disable always reporting signal strength changes from radio. - */ - void setAlwaysReportSignalStrength(int subId, boolean isEnable); - - /** * Get P-CSCF address from PCO after data connection is established or modified. * @param apnType the apnType, "ims" for IMS APN, "emergency" for EMERGENCY APN * @param callingPackage The package making the call. diff --git a/telephony/java/com/android/internal/telephony/uicc/IccUtils.java b/telephony/java/com/android/internal/telephony/uicc/IccUtils.java index ec1204042260..5b44dba49929 100644 --- a/telephony/java/com/android/internal/telephony/uicc/IccUtils.java +++ b/telephony/java/com/android/internal/telephony/uicc/IccUtils.java @@ -43,6 +43,10 @@ public class IccUtils { @VisibleForTesting static final int FPLMN_BYTE_SIZE = 3; + // ICCID used for tests by some OEMs + // TODO(b/159354974): Replace the constant here with UiccPortInfo.ICCID_REDACTED once ready + private static final String TEST_ICCID = "FFFFFFFFFFFFFFFFFFFF"; + // A table mapping from a number to a hex character for fast encoding hex strings. private static final char[] HEX_CHARS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' @@ -923,6 +927,9 @@ public class IccUtils { * Strip all the trailing 'F' characters of a string, e.g., an ICCID. */ public static String stripTrailingFs(String s) { + if (TEST_ICCID.equals(s)) { + return s; + } return s == null ? null : s.replaceAll("(?i)f*$", ""); } diff --git a/tests/DynamicCodeLoggerIntegrationTests/Android.bp b/tests/DynamicCodeLoggerIntegrationTests/Android.bp new file mode 100644 index 000000000000..448d46fe5e4e --- /dev/null +++ b/tests/DynamicCodeLoggerIntegrationTests/Android.bp @@ -0,0 +1,60 @@ +// +// Copyright 2017 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package { + default_applicable_licenses: ["frameworks_base_license"], +} + +java_test_helper_library { + name: "DynamicCodeLoggerTestLibrary", + srcs: ["src/com/android/dcl/**/*.java"], + +} + +cc_library_shared { + name: "DynamicCodeLoggerNativeTestLibrary", + srcs: ["src/cpp/com_android_dcl_Jni.cpp"], + header_libs: ["jni_headers"], + sdk_version: "28", + stl: "c++_static", +} + +cc_binary { + name: "DynamicCodeLoggerNativeExecutable", + srcs: ["src/cpp/test_executable.cpp"], +} + +android_test { + name: "DynamicCodeLoggerIntegrationTests", + + sdk_version: "current", + test_suites: ["device-tests"], + certificate: "shared", + srcs: ["src/com/android/server/pm/**/*.java"], + + static_libs: [ + "androidx.test.rules", + "truth-prebuilt", + ], + + compile_multilib: "both", + jni_libs: ["DynamicCodeLoggerNativeTestLibrary"], + + java_resources: [ + ":DynamicCodeLoggerTestLibrary", + ":DynamicCodeLoggerNativeExecutable", + ], +} diff --git a/tests/DynamicCodeLoggerIntegrationTests/Android.mk b/tests/DynamicCodeLoggerIntegrationTests/Android.mk deleted file mode 100644 index dab83046c28f..000000000000 --- a/tests/DynamicCodeLoggerIntegrationTests/Android.mk +++ /dev/null @@ -1,95 +0,0 @@ -# -# Copyright 2017 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -LOCAL_PATH:= $(call my-dir) - -# Build a tiny library that the test app can dynamically load - -include $(CLEAR_VARS) - -LOCAL_MODULE_TAGS := tests -LOCAL_MODULE := DynamicCodeLoggerTestLibrary -LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0 -LOCAL_LICENSE_CONDITIONS := notice -LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../NOTICE -LOCAL_SRC_FILES := $(call all-java-files-under, src/com/android/dcl) - -include $(BUILD_JAVA_LIBRARY) - -dynamiccodeloggertest_jar := $(LOCAL_BUILT_MODULE) - - -# Also build a native library that the test app can dynamically load - -include $(CLEAR_VARS) - -LOCAL_MODULE_TAGS := tests -LOCAL_MODULE := DynamicCodeLoggerNativeTestLibrary -LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0 -LOCAL_LICENSE_CONDITIONS := notice -LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../NOTICE -LOCAL_SRC_FILES := src/cpp/com_android_dcl_Jni.cpp -LOCAL_HEADER_LIBRARIES := jni_headers -LOCAL_SDK_VERSION := 28 -LOCAL_NDK_STL_VARIANT := c++_static - -include $(BUILD_SHARED_LIBRARY) - -# And a standalone native executable that we can exec. - -include $(CLEAR_VARS) - -LOCAL_MODULE_TAGS := tests -LOCAL_MODULE := DynamicCodeLoggerNativeExecutable -LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0 -LOCAL_LICENSE_CONDITIONS := notice -LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../NOTICE -LOCAL_SRC_FILES := src/cpp/test_executable.cpp - -include $(BUILD_EXECUTABLE) - -dynamiccodeloggertest_executable := $(LOCAL_BUILT_MODULE) - -# Build the test app itself - -include $(CLEAR_VARS) - -LOCAL_MODULE_TAGS := tests -LOCAL_PACKAGE_NAME := DynamicCodeLoggerIntegrationTests -LOCAL_SDK_VERSION := current -LOCAL_COMPATIBILITY_SUITE := device-tests -LOCAL_CERTIFICATE := shared -LOCAL_SRC_FILES := $(call all-java-files-under, src/com/android/server/pm) - -LOCAL_STATIC_JAVA_LIBRARIES := \ - androidx.test.rules \ - truth-prebuilt \ - -# Include both versions of the .so if we have 2 arch -LOCAL_MULTILIB := both -LOCAL_JNI_SHARED_LIBRARIES := \ - DynamicCodeLoggerNativeTestLibrary \ - -# This gets us the javalib.jar built by DynamicCodeLoggerTestLibrary above as well as the various -# native binaries. -LOCAL_JAVA_RESOURCE_FILES := \ - $(dynamiccodeloggertest_jar) \ - $(dynamiccodeloggertest_executable) \ - -LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0 -LOCAL_LICENSE_CONDITIONS := notice -LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../NOTICE -include $(BUILD_PACKAGE) diff --git a/tests/DynamicCodeLoggerIntegrationTests/OWNERS b/tests/DynamicCodeLoggerIntegrationTests/OWNERS new file mode 100644 index 000000000000..d9eb1413cb1e --- /dev/null +++ b/tests/DynamicCodeLoggerIntegrationTests/OWNERS @@ -0,0 +1 @@ +file:/services/core/java/com/android/server/pm/dex/OWNERS diff --git a/tests/DynamicCodeLoggerIntegrationTests/src/com/android/server/pm/dex/DynamicCodeLoggerIntegrationTests.java b/tests/DynamicCodeLoggerIntegrationTests/src/com/android/server/pm/dex/DynamicCodeLoggerIntegrationTests.java index 883c172e4990..5430dee5ca31 100644 --- a/tests/DynamicCodeLoggerIntegrationTests/src/com/android/server/pm/dex/DynamicCodeLoggerIntegrationTests.java +++ b/tests/DynamicCodeLoggerIntegrationTests/src/com/android/server/pm/dex/DynamicCodeLoggerIntegrationTests.java @@ -114,7 +114,8 @@ public final class DynamicCodeLoggerIntegrationTests { // Obtained via "echo -n copied.jar | sha256sum" String expectedNameHash = "1B6C71DB26F36582867432CCA12FB6A517470C9F9AABE9198DD4C5C030D6DC0C"; - String expectedContentHash = copyAndHashResource("/javalib.jar", privateCopyFile); + String expectedContentHash = copyAndHashResource( + "/DynamicCodeLoggerTestLibrary.jar", privateCopyFile); // Feed the jar to a class loader and make sure it contains what we expect. ClassLoader parentClassLoader = sContext.getClass().getClassLoader(); @@ -135,7 +136,8 @@ public final class DynamicCodeLoggerIntegrationTests { File privateCopyFile = privateFile("copied2.jar"); String expectedNameHash = "202158B6A3169D78F1722487205A6B036B3F2F5653FDCFB4E74710611AC7EB93"; - String expectedContentHash = copyAndHashResource("/javalib.jar", privateCopyFile); + String expectedContentHash = copyAndHashResource( + "/DynamicCodeLoggerTestLibrary.jar", privateCopyFile); // This time make sure an unknown class loader is an ancestor of the class loader we use. ClassLoader knownClassLoader = sContext.getClass().getClassLoader(); diff --git a/tests/LockTaskTests/Android.bp b/tests/LockTaskTests/Android.bp new file mode 100644 index 000000000000..dce681ead4b0 --- /dev/null +++ b/tests/LockTaskTests/Android.bp @@ -0,0 +1,32 @@ +// 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. + +package { + default_applicable_licenses: ["frameworks_base_license"], +} + +android_app { + name: "LockTaskTests", + + privileged: true, + + sdk_version: "current", + certificate: "platform", + + srcs: [ + "src/**/I*.aidl", + "src/**/*.java", + ], + +} diff --git a/tests/LockTaskTests/Android.mk b/tests/LockTaskTests/Android.mk deleted file mode 100644 index 5406ee19041b..000000000000 --- a/tests/LockTaskTests/Android.mk +++ /dev/null @@ -1,19 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_PATH := $(PRODUCT_OUT)/system/priv-app - -LOCAL_PACKAGE_NAME := LockTaskTests -LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0 -LOCAL_LICENSE_CONDITIONS := notice -LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../NOTICE -LOCAL_SDK_VERSION := current -LOCAL_CERTIFICATE := platform - -LOCAL_SRC_FILES := $(call all-Iaidl-files-under, src) $(call all-java-files-under, src) - -include $(BUILD_PACKAGE) - -# Use the following include to make our test apk. -include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/tests/SharedLibraryLoadingTest/Android.bp b/tests/SharedLibraryLoadingTest/Android.bp new file mode 100644 index 000000000000..088278d6ee89 --- /dev/null +++ b/tests/SharedLibraryLoadingTest/Android.bp @@ -0,0 +1,37 @@ +// 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. + +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + +java_test_host { + name: "SharedLibraryLoadingTests", + libs: [ + "tradefed", + "junit", + ], + test_suites: ["general-tests"], + data: [ + ":SharedLibraryLoadingTests_StandardSharedLibrary", + ":SharedLibraryLoadingTests_SharedLibraryLoadedAfter", + ":SharedLibraryLoadingTests_SharedLibraryClientTests", + ":SharedLibraryLoadingTests_Overlay", + ], +} diff --git a/tests/SharedLibraryLoadingTest/AndroidTest.xml b/tests/SharedLibraryLoadingTest/AndroidTest.xml new file mode 100644 index 000000000000..947453d07bd9 --- /dev/null +++ b/tests/SharedLibraryLoadingTest/AndroidTest.xml @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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. + --> + +<configuration description="Host-driven test module config for SharedLibraryHostTests"> + <option name="test-tag" value="SharedLibraryLoadingTests" /> + <option name="test-suite-tag" value="apct" /> + <option name="test-suite-tag" value="apct-instrumentation" /> + + <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" /> + <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher"> + <option name="cleanup" value="false" /> + <option name="remount-system" value="true" /> + <option name="push" + value="SharedLibraryLoadingTests_StandardSharedLibrary.apk->/product/app/SharedLibraryLoadingTests_StandardSharedLibrary.apk" /> + <option name="push" + value="SharedLibraryLoadingTests_SharedLibraryLoadedAfter.apk->/product/app/SharedLibraryLoadingTests_SharedLibraryLoadedAfter.apk" /> + <option name="push" + value="SharedLibraryLoadingTests_Overlay.apk->/product/overlay/SharedLibraryLoadingTests_Overlay.apk" /> + </target_preparer> + + <target_preparer class="com.android.tradefed.targetprep.RebootTargetPreparer" /> + + <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup"> + <option name="cleanup-apks" value="true" /> + <option name="test-file-name" value="SharedLibraryLoadingTests_SharedLibraryClientTests.apk" /> + </target_preparer> + + <test class="com.android.tradefed.testtype.AndroidJUnitTest"> + <option name="package" value="com.android.sharedlibloadingtest.client" /> + </test> +</configuration>
\ No newline at end of file diff --git a/tests/SharedLibraryLoadingTest/OWNERS b/tests/SharedLibraryLoadingTest/OWNERS new file mode 100644 index 000000000000..d7b4569b6bc0 --- /dev/null +++ b/tests/SharedLibraryLoadingTest/OWNERS @@ -0,0 +1,2 @@ +stenning@google.com + diff --git a/tests/SharedLibraryLoadingTest/test-apps/Overlay/Android.bp b/tests/SharedLibraryLoadingTest/test-apps/Overlay/Android.bp new file mode 100644 index 000000000000..b2f4e8925b58 --- /dev/null +++ b/tests/SharedLibraryLoadingTest/test-apps/Overlay/Android.bp @@ -0,0 +1,29 @@ +// 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. + +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + +android_test_helper_app { + name: "SharedLibraryLoadingTests_Overlay", + platform_apis: true, + certificate: "platform", + aaptflags: ["--no-resource-removal"], +} diff --git a/tests/SharedLibraryLoadingTest/test-apps/Overlay/AndroidManifest.xml b/tests/SharedLibraryLoadingTest/test-apps/Overlay/AndroidManifest.xml new file mode 100644 index 000000000000..ae2784ca0904 --- /dev/null +++ b/tests/SharedLibraryLoadingTest/test-apps/Overlay/AndroidManifest.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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. + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.sharedlibloadingtest.overlay"> + <application android:hasCode="false" /> + <overlay android:targetPackage="android" + android:isStatic="true" + android:priority="1"/> +</manifest>
\ No newline at end of file diff --git a/tests/SharedLibraryLoadingTest/test-apps/Overlay/res/values/config.xml b/tests/SharedLibraryLoadingTest/test-apps/Overlay/res/values/config.xml new file mode 100644 index 000000000000..15da3dbafd84 --- /dev/null +++ b/tests/SharedLibraryLoadingTest/test-apps/Overlay/res/values/config.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* + * Copyright (C) 2020 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources> + <string-array name="config_sharedLibrariesLoadedAfterApp" translatable="false"> + <item>com.android.sharedlibloadingtest.shared_library_after</item> + </string-array> +</resources>
\ No newline at end of file diff --git a/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryClientTests/Android.bp b/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryClientTests/Android.bp new file mode 100644 index 000000000000..0d204979cb92 --- /dev/null +++ b/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryClientTests/Android.bp @@ -0,0 +1,35 @@ +// 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. + +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +android_test_helper_app { + name: "SharedLibraryLoadingTests_SharedLibraryClientTests", + srcs: ["**/*.java"], + resource_dirs: ["res"], + libs: [ + "SharedLibraryLoadingTests_StandardSharedLibrary", + "SharedLibraryLoadingTests_SharedLibraryLoadedAfter", + "android.test.base", + ], + static_libs: [ + "androidx.test.ext.junit", + "androidx.test.rules", + "androidx.test.core", + "testng", + ], + platform_apis: true, +} diff --git a/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryClientTests/AndroidManifest.xml b/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryClientTests/AndroidManifest.xml new file mode 100644 index 000000000000..e3a9b9bca78a --- /dev/null +++ b/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryClientTests/AndroidManifest.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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. + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.sharedlibloadingtest.client"> + <application> + <uses-library android:name="android.test.runner" /> + <uses-library android:name="com.android.sharedlibloadingtest.shared_library"/> + <uses-library android:name="com.android.sharedlibloadingtest.shared_library_after"/> + </application> + + <instrumentation + android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="com.android.sharedlibloadingtest.client" /> +</manifest>
\ No newline at end of file diff --git a/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryClientTests/res/values/values.xml b/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryClientTests/res/values/values.xml new file mode 100644 index 000000000000..5e0544eb8696 --- /dev/null +++ b/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryClientTests/res/values/values.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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. + --> + +<resources> + <string name="identical_resource_key">client value</string> +</resources>
\ No newline at end of file diff --git a/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryClientTests/src/com/android/sharedlibloadingtest/ClientClass.java b/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryClientTests/src/com/android/sharedlibloadingtest/ClientClass.java new file mode 100644 index 000000000000..e48fb833bd76 --- /dev/null +++ b/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryClientTests/src/com/android/sharedlibloadingtest/ClientClass.java @@ -0,0 +1,24 @@ +/* + * 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. + */ + +package com.android.sharedlibloadingtest; + +public class ClientClass { + @Override + public String toString() { + return "Client Code"; + } +} diff --git a/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryClientTests/src/com/android/sharedlibloadingtest/DuplicateClassA.java b/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryClientTests/src/com/android/sharedlibloadingtest/DuplicateClassA.java new file mode 100644 index 000000000000..4c771557e119 --- /dev/null +++ b/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryClientTests/src/com/android/sharedlibloadingtest/DuplicateClassA.java @@ -0,0 +1,24 @@ +/* + * 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. + */ + +package com.android.sharedlibloadingtest; + +public class DuplicateClassA { + @Override + public String toString() { + return "Client's Version"; + } +} diff --git a/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryClientTests/src/com/android/sharedlibloadingtest/DuplicateClassB.java b/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryClientTests/src/com/android/sharedlibloadingtest/DuplicateClassB.java new file mode 100644 index 000000000000..86aa6a1a0901 --- /dev/null +++ b/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryClientTests/src/com/android/sharedlibloadingtest/DuplicateClassB.java @@ -0,0 +1,24 @@ +/* + * 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. + */ + +package com.android.sharedlibloadingtest; + +public class DuplicateClassB { + @Override + public String toString() { + return "Client's Version B"; + } +} diff --git a/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryClientTests/src/com/android/sharedlibloadingtest/client/SharedLibraryLoadingOrderTest.java b/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryClientTests/src/com/android/sharedlibloadingtest/client/SharedLibraryLoadingOrderTest.java new file mode 100644 index 000000000000..43bcb1ad7d27 --- /dev/null +++ b/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryClientTests/src/com/android/sharedlibloadingtest/client/SharedLibraryLoadingOrderTest.java @@ -0,0 +1,90 @@ +/* + * 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. + */ + +package com.android.sharedlibloadingtest.client; + +import static org.testng.Assert.assertEquals; + +import android.content.Context; +import android.content.res.Resources; + +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import com.android.internal.util.Preconditions; +import com.android.sharedlibloadingtest.ClientClass; +import com.android.sharedlibloadingtest.DuplicateClassA; +import com.android.sharedlibloadingtest.DuplicateClassB; +import com.android.sharedlibloadingtest.SharedClassAfter; +import com.android.sharedlibloadingtest.StdSharedClass; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.Collections; +import java.util.HashSet; + +@RunWith(AndroidJUnit4.class) +public class SharedLibraryLoadingOrderTest { + + @Test + public void testLoadingOfStdShareLibsShouldBeFirst() { + Preconditions.checkArgument(!getLibsLoadedAfter() + .contains("com.android.sharedlibloadingtest.shared_library")); + DuplicateClassA clazz = new DuplicateClassA(); + assertEquals(clazz.toString(), "Standard Shared Lib's Version"); + + StdSharedClass stdSharedClass = new StdSharedClass(); + assertEquals(stdSharedClass.toString(), "Nothing Special Lib"); + + ClientClass clientCode = new ClientClass(); + assertEquals(clientCode.toString(), "Client Code"); + } + + @Test + public void testLoadingOfShareLibsIsAfter() { + Preconditions.checkArgument(getLibsLoadedAfter() + .contains("com.android.sharedlibloadingtest.shared_library_after")); + DuplicateClassB clazz = new DuplicateClassB(); + assertEquals(clazz.toString(), "Client's Version B"); + + SharedClassAfter stdSharedClass = new SharedClassAfter(); + assertEquals(stdSharedClass.toString(), "Also Nothing Special"); + + ClientClass clientCode = new ClientClass(); + assertEquals(clientCode.toString(), "Client Code"); + } + + @Test + public void testLoadingOfResource() { + // aapt compiler gives each lib their own namespace so this test just confirming + // the resources can be loaded from the same context object + Context context = ApplicationProvider.getApplicationContext(); + String clientString = context.getResources().getString(R.string.identical_resource_key); + assertEquals(clientString, "client value"); + assertEquals(StdSharedClass.getResString(context), "std lib value"); + assertEquals(SharedClassAfter.getResString(context), "loaded after value"); + + } + + private HashSet<String> getLibsLoadedAfter() { + Resources systemR = Resources.getSystem(); + HashSet<String> libsToLoadAfter = new HashSet<>(); + Collections.addAll(libsToLoadAfter, systemR.getStringArray( + com.android.internal.R.array.config_sharedLibrariesLoadedAfterApp)); + return libsToLoadAfter; + } +} diff --git a/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryLoadedAfter/Android.bp b/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryLoadedAfter/Android.bp new file mode 100644 index 000000000000..db9b3edfe6a2 --- /dev/null +++ b/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryLoadedAfter/Android.bp @@ -0,0 +1,30 @@ +// 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. + +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + +android_test_helper_app { + name: "SharedLibraryLoadingTests_SharedLibraryLoadedAfter", + srcs: ["**/*.java"], + resource_dirs: ["res"], + sdk_version: "current", + aaptflags: ["--shared-lib"], +} diff --git a/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryLoadedAfter/AndroidManifest.xml b/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryLoadedAfter/AndroidManifest.xml new file mode 100644 index 000000000000..efedfcfeb515 --- /dev/null +++ b/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryLoadedAfter/AndroidManifest.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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. + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.sharedlibloadingtest.shared_library_after"> + <application> + <library android:name="com.android.sharedlibloadingtest.shared_library_after" /> + </application> +</manifest>
\ No newline at end of file diff --git a/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryLoadedAfter/res/values/values.xml b/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryLoadedAfter/res/values/values.xml new file mode 100644 index 000000000000..4525944b060c --- /dev/null +++ b/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryLoadedAfter/res/values/values.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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. + --> + +<resources> + <string name="identical_resource_key">loaded after value</string> +</resources>
\ No newline at end of file diff --git a/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryLoadedAfter/src/com/android/sharedlibloadingtest/DuplicateClassB.java b/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryLoadedAfter/src/com/android/sharedlibloadingtest/DuplicateClassB.java new file mode 100644 index 000000000000..1e1f5aab5993 --- /dev/null +++ b/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryLoadedAfter/src/com/android/sharedlibloadingtest/DuplicateClassB.java @@ -0,0 +1,24 @@ +/* + * 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. + */ + +package com.android.sharedlibloadingtest; + +public class DuplicateClassB { + @Override + public String toString() { + return "Loaded After Shared Lib's Version"; + } +} diff --git a/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryLoadedAfter/src/com/android/sharedlibloadingtest/SharedClassAfter.java b/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryLoadedAfter/src/com/android/sharedlibloadingtest/SharedClassAfter.java new file mode 100644 index 000000000000..9e5b40fc38d8 --- /dev/null +++ b/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryLoadedAfter/src/com/android/sharedlibloadingtest/SharedClassAfter.java @@ -0,0 +1,32 @@ +/* + * 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. + */ + +package com.android.sharedlibloadingtest; + +import android.content.Context; + +import com.android.sharedlibloadingtest.shared_library_after.R; + +public class SharedClassAfter { + @Override + public String toString() { + return "Also Nothing Special"; + } + + public static String getResString(Context context) { + return context.getResources().getString(R.string.identical_resource_key); + } +} diff --git a/tests/SharedLibraryLoadingTest/test-apps/StandardSharedLibrary/Android.bp b/tests/SharedLibraryLoadingTest/test-apps/StandardSharedLibrary/Android.bp new file mode 100644 index 000000000000..50456b0439c2 --- /dev/null +++ b/tests/SharedLibraryLoadingTest/test-apps/StandardSharedLibrary/Android.bp @@ -0,0 +1,30 @@ +// 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. + +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + +android_test_helper_app { + name: "SharedLibraryLoadingTests_StandardSharedLibrary", + srcs: ["**/*.java"], + resource_dirs: ["res"], + sdk_version: "current", + aaptflags: ["--shared-lib"], +} diff --git a/tests/SharedLibraryLoadingTest/test-apps/StandardSharedLibrary/AndroidManifest.xml b/tests/SharedLibraryLoadingTest/test-apps/StandardSharedLibrary/AndroidManifest.xml new file mode 100644 index 000000000000..f1a079feb316 --- /dev/null +++ b/tests/SharedLibraryLoadingTest/test-apps/StandardSharedLibrary/AndroidManifest.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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. + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.sharedlibloadingtest.shared_library"> + <application> + <library android:name="com.android.sharedlibloadingtest.shared_library" /> + </application> +</manifest>
\ No newline at end of file diff --git a/tests/SharedLibraryLoadingTest/test-apps/StandardSharedLibrary/res/values/values.xml b/tests/SharedLibraryLoadingTest/test-apps/StandardSharedLibrary/res/values/values.xml new file mode 100644 index 000000000000..941351aaea62 --- /dev/null +++ b/tests/SharedLibraryLoadingTest/test-apps/StandardSharedLibrary/res/values/values.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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. + --> + +<resources> + <string name="identical_resource_key">std lib value</string> +</resources>
\ No newline at end of file diff --git a/tests/SharedLibraryLoadingTest/test-apps/StandardSharedLibrary/src/com/android/sharedlibloadingtest/DuplicateClassA.java b/tests/SharedLibraryLoadingTest/test-apps/StandardSharedLibrary/src/com/android/sharedlibloadingtest/DuplicateClassA.java new file mode 100644 index 000000000000..a3874aa3ad96 --- /dev/null +++ b/tests/SharedLibraryLoadingTest/test-apps/StandardSharedLibrary/src/com/android/sharedlibloadingtest/DuplicateClassA.java @@ -0,0 +1,24 @@ +/* + * 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. + */ + +package com.android.sharedlibloadingtest; + +public class DuplicateClassA { + @Override + public String toString() { + return "Standard Shared Lib's Version"; + } +} diff --git a/tests/SharedLibraryLoadingTest/test-apps/StandardSharedLibrary/src/com/android/sharedlibloadingtest/StdSharedClass.java b/tests/SharedLibraryLoadingTest/test-apps/StandardSharedLibrary/src/com/android/sharedlibloadingtest/StdSharedClass.java new file mode 100644 index 000000000000..429d65ca2439 --- /dev/null +++ b/tests/SharedLibraryLoadingTest/test-apps/StandardSharedLibrary/src/com/android/sharedlibloadingtest/StdSharedClass.java @@ -0,0 +1,32 @@ +/* + * 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. + */ + +package com.android.sharedlibloadingtest; + +import android.content.Context; + +import com.android.sharedlibloadingtest.shared_library.R; + +public class StdSharedClass { + @Override + public String toString() { + return "Nothing Special Lib"; + } + + public static String getResString(Context context) { + return context.getResources().getString(R.string.identical_resource_key); + } +} diff --git a/tests/StagedInstallTest/Android.bp b/tests/StagedInstallTest/Android.bp index 7a564fcaa99e..a5852b52ff19 100644 --- a/tests/StagedInstallTest/Android.bp +++ b/tests/StagedInstallTest/Android.bp @@ -31,6 +31,7 @@ android_test_helper_app { ], test_suites: ["general-tests"], java_resources: [ + ":apex.apexd_test_classpath", ":com.android.apex.apkrollback.test_v2", ":StagedInstallTestApexV2", ":StagedInstallTestApexV2_WrongSha", @@ -54,6 +55,7 @@ java_test_host { "cts-install-lib-host", ], data: [ + ":apex.apexd_test", ":com.android.apex.apkrollback.test_v1", ":StagedInstallTestApexV2", ":StagedInstallTestApexV2_WrongSha", diff --git a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java index c610641932df..f0ab63eb41b5 100644 --- a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java +++ b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java @@ -74,6 +74,11 @@ public class StagedInstallInternalTest { "ApexV2", SHIM_APEX_PACKAGE_NAME, 2, /* isApex= */ true, "com.android.apex.cts.shim.v2.apex"); + private static final String TEST_APEX_PACKAGE_NAME = "com.android.apex.test_package"; + private static final TestApp TEST_APEX_CLASSPATH = new TestApp("TestApex", + TEST_APEX_PACKAGE_NAME, 1, /*isApex=*/true, + "apex.apexd_test_classpath.apex"); + private File mTestStateFile = new File( InstrumentationRegistry.getInstrumentation().getContext().getFilesDir(), "stagedinstall_state"); @@ -439,11 +444,13 @@ public class StagedInstallInternalTest { StagedApexInfo result = getPackageManagerNative().getStagedApexInfo("not found"); assertThat(result).isNull(); // Stage an apex - int sessionId = Install.single(APEX_V2).setStaged().commit(); + int sessionId = Install.single(TEST_APEX_CLASSPATH).setStaged().commit(); waitForSessionReady(sessionId); // Query proper module name - result = getPackageManagerNative().getStagedApexInfo(SHIM_APEX_PACKAGE_NAME); - assertThat(result.moduleName).isEqualTo(SHIM_APEX_PACKAGE_NAME); + result = getPackageManagerNative().getStagedApexInfo(TEST_APEX_PACKAGE_NAME); + assertThat(result.moduleName).isEqualTo(TEST_APEX_PACKAGE_NAME); + assertThat(result.hasBootClassPathJars).isTrue(); + assertThat(result.hasSystemServerClassPathJars).isTrue(); InstallUtils.openPackageInstallerSession(sessionId).abandon(); } diff --git a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java index 31021031b47a..cd0078363c4b 100644 --- a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java +++ b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java @@ -61,6 +61,7 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test { private static final String APEX_WRONG_SHA = "com.android.apex.cts.shim.v2_wrong_sha.apex"; private static final String APK_A = "TestAppAv1.apk"; private static final String APK_IN_APEX_TESTAPEX_NAME = "com.android.apex.apkrollback.test"; + private static final String APEXD_TEST_APEX = "apex.apexd_test.apex"; private static final String TEST_VENDOR_APEX_ALLOW_LIST = "/vendor/etc/sysconfig/test-vendor-apex-allow-list.xml"; @@ -480,16 +481,29 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test { @Test public void testGetStagedModuleNames() throws Exception { + assumeTrue("Device does not support updating APEX", + mHostUtils.isApexUpdateSupported()); + runPhase("testGetStagedModuleNames"); } @Test + @LargeTest public void testGetStagedApexInfo() throws Exception { + assumeTrue("Device does not support updating APEX", + mHostUtils.isApexUpdateSupported()); + + pushTestApex(APEXD_TEST_APEX); + getDevice().reboot(); + runPhase("testGetStagedApexInfo"); } @Test public void testStagedApexObserver() throws Exception { + assumeTrue("Device does not support updating APEX", + mHostUtils.isApexUpdateSupported()); + runPhase("testStagedApexObserver"); } diff --git a/tests/notification/src/com/android/frameworks/tests/notification/NotificationTests.java b/tests/notification/src/com/android/frameworks/tests/notification/NotificationTests.java index 7cda977d2115..5d639f6f6266 100644 --- a/tests/notification/src/com/android/frameworks/tests/notification/NotificationTests.java +++ b/tests/notification/src/com/android/frameworks/tests/notification/NotificationTests.java @@ -409,10 +409,10 @@ public class NotificationTests extends AndroidTestCase { sleepIfYouCan(500); L("Parceling notifications..."); - // we want to be able to use this test on older OSes that do not have getBlobAshmemSize - Method getBlobAshmemSize = null; + // we want to be able to use this test on older OSes that do not have getOpenAshmemSize + Method getOpenAshmemSize = null; try { - getBlobAshmemSize = Parcel.class.getMethod("getBlobAshmemSize"); + getOpenAshmemSize = Parcel.class.getMethod("getOpenAshmemSize"); } catch (NoSuchMethodException ex) { } for (int i=0; i<mNotifications.size(); i++) { @@ -424,8 +424,8 @@ public class NotificationTests extends AndroidTestCase { time = SystemClock.currentThreadTimeMillis() - time; L(" %s: write parcel=%dms size=%d ashmem=%s", summarize(n), time, p.dataPosition(), - (getBlobAshmemSize != null) - ? getBlobAshmemSize.invoke(p) + (getOpenAshmemSize != null) + ? getOpenAshmemSize.invoke(p) : "???"); p.setDataPosition(0); } diff --git a/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java b/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java index f3851130c68a..3b201f9d20dd 100644 --- a/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java +++ b/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java @@ -135,11 +135,12 @@ public class IkeSessionParamsUtilsTest { } @Test - public void testEncodeRecodeParamsWithIkeOptions() throws Exception { + public void testEncodeDecodeParamsWithIkeOptions() throws Exception { final IkeSessionParams params = createBuilderMinimum() .addIkeOption(IkeSessionParams.IKE_OPTION_ACCEPT_ANY_REMOTE_ID) .addIkeOption(IkeSessionParams.IKE_OPTION_MOBIKE) + .addIkeOption(IkeSessionParams.IKE_OPTION_INITIAL_CONTACT) .build(); verifyPersistableBundleEncodeDecodeIsLossless(params); } diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index c9a8947ab5ef..937f9dc60a72 100644 --- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -297,8 +297,6 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection any(), any()); verify(mNetworkAgent).register(); - verify(mNetworkAgent) - .setUnderlyingNetworks(eq(singletonList(TEST_UNDERLYING_NETWORK_RECORD_1.network))); verify(mNetworkAgent).markConnected(); verify(mIpSecSvc) @@ -313,6 +311,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection final NetworkCapabilities nc = ncCaptor.getValue(); assertTrue(nc.hasTransport(TRANSPORT_CELLULAR)); assertFalse(nc.hasTransport(TRANSPORT_WIFI)); + assertEquals(List.of(TEST_UNDERLYING_NETWORK_RECORD_1.network), nc.getUnderlyingNetworks()); for (int cap : mConfig.getAllExposedCapabilities()) { assertTrue(nc.hasCapability(cap)); } diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java index a7001713533c..5253c3e9b77c 100644 --- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java +++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java @@ -61,6 +61,7 @@ import org.junit.runner.RunWith; import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.UUID; @@ -116,8 +117,9 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { capBuilder.setLinkUpstreamBandwidthKbps(TEST_UPSTREAM_BANDWIDTH); capBuilder.setLinkDownstreamBandwidthKbps(TEST_DOWNSTREAM_BANDWIDTH); capBuilder.setAdministratorUids(new int[] {TEST_UID}); + final Network underlyingNetwork = mock(Network.class, CALLS_REAL_METHODS); UnderlyingNetworkRecord record = new UnderlyingNetworkRecord( - mock(Network.class, CALLS_REAL_METHODS), + underlyingNetwork, capBuilder.build(), new LinkProperties(), false); final NetworkCapabilities vcnCaps = VcnGatewayConnection.buildNetworkCapabilities( @@ -128,6 +130,7 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { assertTrue(vcnCaps.hasTransport(TRANSPORT_CELLULAR)); assertTrue(vcnCaps.hasCapability(NET_CAPABILITY_NOT_METERED)); assertTrue(vcnCaps.hasCapability(NET_CAPABILITY_NOT_ROAMING)); + assertTrue(vcnCaps.getUnderlyingNetworks().equals(List.of(underlyingNetwork))); for (int cap : VcnGatewayConnectionConfigTest.EXPOSED_CAPS) { if (cap == NET_CAPABILITY_INTERNET || cap == NET_CAPABILITY_DUN) { |