diff options
135 files changed, 3112 insertions, 1323 deletions
diff --git a/ApiDocs.bp b/ApiDocs.bp index c1816467146d..a926ddc218a6 100644 --- a/ApiDocs.bp +++ b/ApiDocs.bp @@ -192,6 +192,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/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/apex/media/Android.bp b/apex/media/Android.bp index f2e64ce0b2c5..1a710a98b0a9 100644 --- a/apex/media/Android.bp +++ b/apex/media/Android.bp @@ -28,8 +28,8 @@ package { sdk { name: "media-module-sdk", bootclasspath_fragments: ["com.android.media-bootclasspath-fragment"], + systemserverclasspath_fragments: ["com.android.media-systemserverclasspath-fragment"], java_sdk_libs: [ "framework-media", - "service-media-s", ], } diff --git a/api/Android.bp b/api/Android.bp index 2d7b8bdb4eb0..ed2247b6eaa4 100644 --- a/api/Android.bp +++ b/api/Android.bp @@ -430,7 +430,7 @@ genrule { } genrule { - name: "services-system-server-current.txt", + name: "frameworks-base-api-system-server-current.txt", srcs: [ ":service-media-s{.system-server.api.txt}", ":service-permission{.system-server.api.txt}", @@ -457,7 +457,7 @@ genrule { } genrule { - name: "services-system-server-removed.txt", + name: "frameworks-base-api-system-server-removed.txt", srcs: [ ":service-media-s{.system-server.removed-api.txt}", ":service-permission{.system-server.removed-api.txt}", diff --git a/core/api/current.txt b/core/api/current.txt index 738851b78b30..0eba9d75fdfc 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -25516,6 +25516,7 @@ package android.media.tv { field public static final String COLUMN_CONTENT_ID = "content_id"; field public static final String COLUMN_CONTENT_RATING = "content_rating"; field public static final String COLUMN_DURATION_MILLIS = "duration_millis"; + field public static final String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis"; field public static final String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number"; field public static final String COLUMN_EPISODE_TITLE = "episode_title"; field public static final String COLUMN_INTENT_URI = "intent_uri"; @@ -25546,6 +25547,7 @@ package android.media.tv { field public static final String COLUMN_SHORT_DESCRIPTION = "short_description"; field public static final String COLUMN_SPLIT_ID = "split_id"; field public static final String COLUMN_STARTING_PRICE = "starting_price"; + field public static final String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis"; field public static final String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio"; field public static final String COLUMN_THUMBNAIL_URI = "thumbnail_uri"; field public static final String COLUMN_TITLE = "title"; @@ -25708,6 +25710,7 @@ package android.media.tv { field public static final String COLUMN_CONTENT_ID = "content_id"; field public static final String COLUMN_CONTENT_RATING = "content_rating"; field public static final String COLUMN_DURATION_MILLIS = "duration_millis"; + field public static final String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis"; field public static final String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number"; field public static final String COLUMN_EPISODE_TITLE = "episode_title"; field public static final String COLUMN_INTENT_URI = "intent_uri"; @@ -25739,6 +25742,7 @@ package android.media.tv { field public static final String COLUMN_SHORT_DESCRIPTION = "short_description"; field public static final String COLUMN_SPLIT_ID = "split_id"; field public static final String COLUMN_STARTING_PRICE = "starting_price"; + field public static final String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis"; field public static final String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio"; field public static final String COLUMN_THUMBNAIL_URI = "thumbnail_uri"; field public static final String COLUMN_TITLE = "title"; @@ -31423,6 +31427,7 @@ 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); diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt index b574d0441258..49df45ac0c4f 100644 --- a/core/api/module-lib-current.txt +++ b/core/api/module-lib-current.txt @@ -311,6 +311,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..6f825ae4e003 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -2128,6 +2128,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; @@ -9138,6 +9139,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"; 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/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/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/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java index 3b744a73e75e..06ce0530d475 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; } } @@ -2307,7 +2307,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..9caeb297ace3 100644 --- a/core/java/android/bluetooth/BluetoothDevice.java +++ b/core/java/android/bluetooth/BluetoothDevice.java @@ -1186,11 +1186,6 @@ public final class BluetoothDevice implements Parcelable, Attributable { mAttributionSource = attributionSource; } - /** {@hide} */ - public void prepareToEnterProcess(@NonNull AttributionSource attributionSource) { - setAttributionSource(attributionSource); - } - @Override public boolean equals(@Nullable Object o) { if (o instanceof BluetoothDevice) { diff --git a/core/java/android/bluetooth/BluetoothLeAudio.java b/core/java/android/bluetooth/BluetoothLeAudio.java index 3ea865bfd6ec..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 @@ -199,11 +265,8 @@ public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable { * * <p> * <ul> - * <li> {@link #GROUP_STATUS_IDLE} </li> - * <li> {@link #GROUP_STATUS_STREAMING} </li> - * <li> {@link #GROUP_STATUS_SUSPENDED} </li> - * <li> {@link #GROUP_STATUS_RECONFIGURED} </li> - * <li> {@link #GROUP_STATUS_DESTROYED} </li> + * <li> {@link #GROUP_STATUS_ACTIVE} </li> + * <li> {@link #GROUP_STATUS_INACTIVE} </li> * </ul> * <p> * @hide @@ -241,6 +304,30 @@ public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable { private final BluetoothAdapter mAdapter; private final AttributionSource mAttributionSource; + /** + * Indicating that group is Active ( Audio device is available ) + * @hide + */ + public static final int GROUP_STATUS_ACTIVE = IBluetoothLeAudio.GROUP_STATUS_ACTIVE; + + /** + * Indicating that group is Inactive ( Audio device is not available ) + * @hide + */ + 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", IBluetoothLeAudio.class.getName()) { @@ -433,7 +520,7 @@ public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable { * <p> This API returns false in scenarios like the profile on the * device is not connected or Bluetooth is not turned on. * When this API returns true, it is guaranteed that the - * {@link #ACTION_LEAUDIO_ACTIVE_DEVICE_CHANGED} intent will be broadcasted + * {@link #ACTION_LE_AUDIO_ACTIVE_DEVICE_CHANGED} intent will be broadcasted * with the active device. * * @@ -512,6 +599,85 @@ public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable { } /** + * Set volume for the streaming devices + * + * @param volume volume to set + * @hide + */ + @RequiresBluetoothConnectPermission + @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) + public void setVolume(int volume) { + if (VDBG) log("setVolume(vol: " + volume + " )"); + try { + final IBluetoothLeAudio service = getService(); + if (service != null && mAdapter.isEnabled()) { + service.setVolume(volume, mAttributionSource); + return; + } + if (service == null) Log.w(TAG, "Proxy not attached to service"); + return; + } catch (RemoteException e) { + Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); + return; + } + } + + /** + * 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/BluetoothManager.java b/core/java/android/bluetooth/BluetoothManager.java index 20152f3d2471..b5df4db2460d 100644 --- a/core/java/android/bluetooth/BluetoothManager.java +++ b/core/java/android/bluetooth/BluetoothManager.java @@ -62,15 +62,15 @@ public final class BluetoothManager { private static final String TAG = "BluetoothManager"; private static final boolean DBG = false; - private final AttributionSource mAttributionSource; + private static AttributionSource sAttributionSource = null; private final BluetoothAdapter mAdapter; /** * @hide */ public BluetoothManager(Context context) { - mAttributionSource = resolveAttributionSource(context); - mAdapter = BluetoothAdapter.createAdapter(mAttributionSource); + sAttributionSource = resolveAttributionSource(context); + mAdapter = BluetoothAdapter.createAdapter(sAttributionSource); } /** {@hide} */ @@ -79,6 +79,9 @@ public final class BluetoothManager { if (context != null) { res = context.getAttributionSource(); } + else if (sAttributionSource != null) { + return sAttributionSource; + } if (res == null) { res = ActivityThread.currentAttributionSource(); } @@ -198,8 +201,8 @@ public final class BluetoothManager { IBluetoothGatt iGatt = managerService.getBluetoothGatt(); if (iGatt == null) return devices; devices = Attributable.setAttributionSource( - iGatt.getDevicesMatchingConnectionStates(states, mAttributionSource), - mAttributionSource); + iGatt.getDevicesMatchingConnectionStates(states, sAttributionSource), + sAttributionSource); } catch (RemoteException e) { Log.e(TAG, "", e); } diff --git a/core/java/android/bluetooth/BluetoothUuid.java b/core/java/android/bluetooth/BluetoothUuid.java index 67b725221206..858819e15abc 100644 --- a/core/java/android/bluetooth/BluetoothUuid.java +++ b/core/java/android/bluetooth/BluetoothUuid.java @@ -155,12 +155,11 @@ public final class BluetoothUuid { @SystemApi public static final ParcelUuid HEARING_AID = ParcelUuid.fromString("0000FDF0-0000-1000-8000-00805f9b34fb"); - /** Placeholder until specification is released - * @hide */ + /** @hide */ @NonNull @SystemApi public static final ParcelUuid LE_AUDIO = - ParcelUuid.fromString("EEEEEEEE-EEEE-EEEE-EEEE-EEEEEEEEEEEE"); + ParcelUuid.fromString("0000184E-0000-1000-8000-00805F9B34FB"); /** @hide */ @NonNull @SystemApi @@ -189,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/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/Intent.java b/core/java/android/content/Intent.java index d811040b6bb2..2fd437db14a7 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -31,7 +31,6 @@ import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.TestApi; import android.app.AppGlobals; -import android.bluetooth.BluetoothDevice; import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; @@ -11462,16 +11461,6 @@ public class Intent implements Parcelable, Cloneable { if (fromProtectedComponent) { mLocalFlags |= LOCAL_FLAG_FROM_PROTECTED_COMPONENT; } - - // Special attribution fix-up logic for any BluetoothDevice extras - // passed via Bluetooth intents - if (mAction != null && mAction.startsWith("android.bluetooth.") - && hasExtra(BluetoothDevice.EXTRA_DEVICE)) { - final BluetoothDevice device = getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); - if (device != null) { - device.prepareToEnterProcess(source); - } - } } /** @hide */ 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/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/os/OWNERS b/core/java/android/os/OWNERS index e7c3a834f3a6..92861fba40a3 100644 --- a/core/java/android/os/OWNERS +++ b/core/java/android/os/OWNERS @@ -1,18 +1,18 @@ # Haptics -per-file CombinedVibrationEffect.aidl = michaelwr@google.com -per-file CombinedVibrationEffect.java = michaelwr@google.com -per-file ExternalVibration.aidl = michaelwr@google.com -per-file ExternalVibration.java = michaelwr@google.com -per-file IExternalVibrationController.aidl = michaelwr@google.com -per-file IExternalVibratorService.aidl = michaelwr@google.com -per-file IVibratorManagerService.aidl = michaelwr@google.com -per-file NullVibrator.java = michaelwr@google.com -per-file SystemVibrator.java = michaelwr@google.com -per-file SystemVibratorManager.java = michaelwr@google.com -per-file VibrationEffect.aidl = michaelwr@google.com -per-file VibrationEffect.java = michaelwr@google.com -per-file Vibrator.java = michaelwr@google.com -per-file VibratorManager.java = michaelwr@google.com +per-file CombinedVibrationEffect.aidl = file:/services/core/java/com/android/server/vibrator/OWNERS +per-file CombinedVibrationEffect.java = file:/services/core/java/com/android/server/vibrator/OWNERS +per-file ExternalVibration.aidl = file:/services/core/java/com/android/server/vibrator/OWNERS +per-file ExternalVibration.java = file:/services/core/java/com/android/server/vibrator/OWNERS +per-file IExternalVibrationController.aidl = file:/services/core/java/com/android/server/vibrator/OWNERS +per-file IExternalVibratorService.aidl = file:/services/core/java/com/android/server/vibrator/OWNERS +per-file IVibratorManagerService.aidl = file:/services/core/java/com/android/server/vibrator/OWNERS +per-file NullVibrator.java = file:/services/core/java/com/android/server/vibrator/OWNERS +per-file SystemVibrator.java = file:/services/core/java/com/android/server/vibrator/OWNERS +per-file SystemVibratorManager.java = file:/services/core/java/com/android/server/vibrator/OWNERS +per-file VibrationEffect.aidl = file:/services/core/java/com/android/server/vibrator/OWNERS +per-file VibrationEffect.java = file:/services/core/java/com/android/server/vibrator/OWNERS +per-file Vibrator.java = file:/services/core/java/com/android/server/vibrator/OWNERS +per-file VibratorManager.java = file:/services/core/java/com/android/server/vibrator/OWNERS # PowerManager per-file IPowerManager.aidl = michaelwr@google.com, santoscordon@google.com diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java index 44d51db80f86..ab2c8c0e31d3 100644 --- a/core/java/android/os/Parcel.java +++ b/core/java/android/os/Parcel.java @@ -384,6 +384,8 @@ public final class Parcel { 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 +401,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>() { @@ -717,11 +719,26 @@ public final class Parcel { /** * Report whether the parcel contains any marshalled file descriptors. */ - public final boolean hasFileDescriptors() { + public boolean hasFileDescriptors() { return nativeHasFileDescriptors(mNativePtr); } /** + * 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 used in {@link #readValue(ClassLoader)} / {@link #writeValue(Object)} * has file descriptors. * @@ -2874,9 +2891,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) { @@ -3536,15 +3555,26 @@ 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; @@ -3592,7 +3622,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 +3631,7 @@ public final class Parcel { public boolean hasFileDescriptors() { Parcel source = mSource; return (source != null) - ? getValueParcel(source).hasFileDescriptors() + ? source.hasFileDescriptors(mPosition, mLength) : Parcel.hasFileDescriptors(mObject); } @@ -3662,10 +3692,7 @@ public final class Parcel { 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); + parcel.appendFrom(source, mPosition, mLength); mValueParcel = parcel; } return parcel; @@ -3869,8 +3896,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, @@ -3936,8 +3966,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 class or there there was an error + * trying to read the {@link Parcelable.Creator}. */ @Nullable public <T> Parcelable.Creator<T> readParcelableCreator( @@ -4348,8 +4381,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/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..25e3a4fcccc5 100644 --- a/core/java/android/provider/DeviceConfig.java +++ b/core/java/android/provider/DeviceConfig.java @@ -298,6 +298,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/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/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/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/jni/android_os_Parcel.cpp b/core/jni/android_os_Parcel.cpp index aadd320eb2e1..be9aaaf407db 100644 --- a/core/jni/android_os_Parcel.cpp +++ b/core/jni/android_os_Parcel.cpp @@ -596,13 +596,10 @@ static jint android_os_Parcel_compareData(JNIEnv* env, jclass clazz, jlong thisN jlong otherNativePtr) { Parcel* thisParcel = reinterpret_cast<Parcel*>(thisNativePtr); - if (thisParcel == NULL) { - return 0; - } + LOG_ALWAYS_FATAL_IF(thisParcel == nullptr, "Should not be null"); + Parcel* otherParcel = reinterpret_cast<Parcel*>(otherNativePtr); - if (otherParcel == NULL) { - return thisParcel->getOpenAshmemSize(); - } + LOG_ALWAYS_FATAL_IF(otherParcel == nullptr, "Should not be null"); return thisParcel->compareData(*otherParcel); } @@ -638,6 +635,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> @@ -727,11 +740,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; } @@ -831,6 +844,7 @@ static const JNINativeMethod gParcelMethods[] = { {"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}, @@ -838,7 +852,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/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/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/OWNERS b/core/tests/coretests/src/android/os/OWNERS index 9a9b4748d4f1..a42285eedbf4 100644 --- a/core/tests/coretests/src/android/os/OWNERS +++ b/core/tests/coretests/src/android/os/OWNERS @@ -2,11 +2,11 @@ per-file BrightnessLimit.java = michaelwr@google.com, santoscordon@google.com # Haptics -per-file CombinedVibrationEffectTest.java = michaelwr@google.com -per-file ExternalVibrationTest.java = michaelwr@google.com -per-file VibrationEffectTest.java = michaelwr@google.com -per-file VibratorInfoTest.java = michaelwr@google.com -per-file VibratorTest.java = michaelwr@google.com +per-file CombinedVibrationEffectTest.java = file:/services/core/java/com/android/server/vibrator/OWNERS +per-file ExternalVibrationTest.java = file:/services/core/java/com/android/server/vibrator/OWNERS +per-file VibrationEffectTest.java = file:/services/core/java/com/android/server/vibrator/OWNERS +per-file VibratorInfoTest.java = file:/services/core/java/com/android/server/vibrator/OWNERS +per-file VibratorTest.java = file:/services/core/java/com/android/server/vibrator/OWNERS # Power -per-file PowerManager*.java = michaelwr@google.com, santoscordon@google.com +per-file PowerManager*.java = michaelwr@google.com, santoscordon@google.com
\ No newline at end of file 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/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index c068963adc92..ed8cdb941792 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -5203,21 +5203,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/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/tv/TvContract.java b/media/java/android/media/tv/TvContract.java index 30a14c84b72e..a0f6fb9577c3 100644 --- a/media/java/android/media/tv/TvContract.java +++ b/media/java/android/media/tv/TvContract.java @@ -1658,6 +1658,25 @@ public final class TvContract { */ String COLUMN_CONTENT_ID = "content_id"; + /** + * The start time of this TV program, in milliseconds since the epoch. + * + * <p>Should be empty if this program is not live. + * + * <p>Type: INTEGER (long) + * @see #COLUMN_LIVE + */ + String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis"; + + /** + * The end time of this TV program, in milliseconds since the epoch. + * + * <p>Should be empty if this program is not live. + * + * <p>Type: INTEGER (long) + * @see #COLUMN_LIVE + */ + String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis"; } /** Column definitions for the TV channels table. */ 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 7ce9b516990e..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; @@ -69,6 +70,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> // Some Hearing Aids (especially the 2nd device) needs more time to do service discovery private static final long MAX_HEARING_AIDS_DELAY_FOR_AUTO_CONNECT = 15000; private static final long MAX_HOGP_DELAY_FOR_AUTO_CONNECT = 30000; + private static final long MAX_LEAUDIO_DELAY_FOR_AUTO_CONNECT = 30000; private static final long MAX_MEDIA_PROFILE_CONNECT_DELAY = 60000; private final Context mContext; @@ -108,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 @@ -132,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; @@ -265,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; @@ -540,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; } @@ -618,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); @@ -649,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; @@ -743,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); + } } /** @@ -757,6 +784,8 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> timeout = MAX_HOGP_DELAY_FOR_AUTO_CONNECT; } else if (ArrayUtils.contains(uuids, BluetoothUuid.HEARING_AID)) { timeout = MAX_HEARING_AIDS_DELAY_FOR_AUTO_CONNECT; + } else if (ArrayUtils.contains(uuids, BluetoothUuid.LE_AUDIO)) { + timeout = MAX_LEAUDIO_DELAY_FOR_AUTO_CONNECT; } if (BluetoothUtils.D) { @@ -981,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; @@ -1012,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; @@ -1054,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) @@ -1089,7 +1122,8 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> private boolean isProfileConnectedFail() { return mIsA2dpProfileConnectedFail || mIsHearingAidProfileConnectedFail - || (!isConnectedSapDevice() && mIsHeadsetProfileConnectedFail); + || (!isConnectedSapDevice() && mIsHeadsetProfileConnectedFail) + || mIsLeAudioProfileConnectedFail; } /** @@ -1100,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()) { @@ -1125,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; @@ -1163,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) { @@ -1232,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/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/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/proto/src/criticalevents/OWNERS b/proto/src/criticalevents/OWNERS new file mode 100644 index 000000000000..07c0e70574f0 --- /dev/null +++ b/proto/src/criticalevents/OWNERS @@ -0,0 +1 @@ +include /services/core/java/com/android/server/criticalevents/OWNERS 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/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/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index edf832f0fc22..c11c4def1b50 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); 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/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index 565c9ae2142c..243a336b31f2 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -1270,6 +1270,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 +1293,6 @@ public class Vpn { } finally { Binder.restoreCallingIdentity(token); } - mNetworkAgent.setUnderlyingNetworks((mConfig.underlyingNetworks != null) - ? Arrays.asList(mConfig.underlyingNetworks) : null); updateState(DetailedState.CONNECTED, "agentConnect"); } 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/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/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/vibrator/OWNERS b/services/core/java/com/android/server/vibrator/OWNERS index 7e7335d68d3b..08f0a90485cc 100644 --- a/services/core/java/com/android/server/vibrator/OWNERS +++ b/services/core/java/com/android/server/vibrator/OWNERS @@ -1 +1,3 @@ +lsandrade@google.com michaelwr@google.com +sbowden@google.com
\ No newline at end of file diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index f3ba56a03aef..08f3b1a8c6e0 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -3387,9 +3387,15 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { final List<RemoteAction> actions = r.pictureInPictureArgs.getActions(); mRootWindowContainer.moveActivityToPinnedRootTask( r, "enterPictureInPictureMode"); - final Task rootTask = r.getRootTask(); - rootTask.setPictureInPictureAspectRatio(aspectRatio); - rootTask.setPictureInPictureActions(actions); + final Task task = r.getTask(); + task.setPictureInPictureAspectRatio(aspectRatio); + task.setPictureInPictureActions(actions); + + // Continue the pausing process after entering pip. + if (task.getPausingActivity() == r) { + task.schedulePauseActivity(r, false /* userLeaving */, + false /* pauseImmediately */, "auto-pip"); + } } }; diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index ced5af126e49..516be553d5f8 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -5771,23 +5771,8 @@ class Task extends WindowContainer<WindowContainer> { + "directly: %s", prev); didAutoPip = mAtmService.enterPictureInPictureMode(prev, prev.pictureInPictureArgs); - mPausingActivity = null; } else { - ProtoLog.v(WM_DEBUG_STATES, "Enqueueing pending pause: %s", prev); - try { - EventLogTags.writeWmPauseActivity(prev.mUserId, System.identityHashCode(prev), - prev.shortComponentName, "userLeaving=" + userLeaving, reason); - - mAtmService.getLifecycleManager().scheduleTransaction(prev.app.getThread(), - prev.appToken, PauseActivityItem.obtain(prev.finishing, userLeaving, - prev.configChangeFlags, pauseImmediately)); - } catch (Exception e) { - // Ignore exception, if process died other code will cleanup. - Slog.w(TAG, "Exception thrown during pause", e); - mPausingActivity = null; - mLastPausedActivity = null; - mTaskSupervisor.mNoHistoryActivities.remove(prev); - } + schedulePauseActivity(prev, userLeaving, pauseImmediately, reason); } } else { mPausingActivity = null; @@ -5802,7 +5787,7 @@ class Task extends WindowContainer<WindowContainer> { } // If already entered PIP mode, no need to keep pausing. - if (mPausingActivity != null && !didAutoPip) { + if (mPausingActivity != null) { // Have the window manager pause its key dispatching until the new // activity has started. If we're pausing the activity just because // the screen is being turned off and the UI is sleeping, don't interrupt @@ -5835,6 +5820,25 @@ class Task extends WindowContainer<WindowContainer> { } } + void schedulePauseActivity(ActivityRecord prev, boolean userLeaving, + boolean pauseImmediately, String reason) { + ProtoLog.v(WM_DEBUG_STATES, "Enqueueing pending pause: %s", prev); + try { + EventLogTags.writeWmPauseActivity(prev.mUserId, System.identityHashCode(prev), + prev.shortComponentName, "userLeaving=" + userLeaving, reason); + + mAtmService.getLifecycleManager().scheduleTransaction(prev.app.getThread(), + prev.appToken, PauseActivityItem.obtain(prev.finishing, userLeaving, + prev.configChangeFlags, pauseImmediately)); + } catch (Exception e) { + // Ignore exception, if process died other code will cleanup. + Slog.w(TAG, "Exception thrown during pause", e); + mPausingActivity = null; + mLastPausedActivity = null; + mTaskSupervisor.mNoHistoryActivities.remove(prev); + } + } + @VisibleForTesting void completePauseLocked(boolean resumeNext, ActivityRecord resuming) { // Complete the pausing process of a pausing activity, so it doesn't make sense to 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/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/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 8e910c999c07..73e6c76fe214 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -1312,9 +1312,14 @@ public class CarrierConfigManager { /** * Determines whether a maximum size limit for IMS conference calls is enforced on the device. * When {@code true}, IMS conference calls will be limited to at most - * {@link #KEY_IMS_CONFERENCE_SIZE_LIMIT_INT} participants. When {@code false}, no attempt is made - * to limit the number of participants in a conference (the carrier will raise an error when an - * attempt is made to merge too many participants into a conference). + * {@link #KEY_IMS_CONFERENCE_SIZE_LIMIT_INT} participants. When {@code false}, no attempt is + * made to limit the number of participants in a conference (the carrier will raise an error + * when an attempt is made to merge too many participants into a conference). + * <p> + * Note: The maximum size of a conference can ONLY be supported where + * {@link #KEY_SUPPORT_IMS_CONFERENCE_EVENT_PACKAGE_BOOL} is {@code true} since the platform + * needs conference event package data to accurately know the number of participants in the + * conference. */ public static final String KEY_IS_IMS_CONFERENCE_SIZE_ENFORCED_BOOL = "is_ims_conference_size_enforced_bool"; 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/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/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/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/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); } |