diff options
231 files changed, 5781 insertions, 3007 deletions
diff --git a/Android.bp b/Android.bp index d976b9172602..fc713ff25e54 100644 --- a/Android.bp +++ b/Android.bp @@ -294,6 +294,7 @@ java_defaults { srcs: [ ":framework-non-updatable-sources", "core/java/**/*.logtags", + ":apex-info-list", ], aidl: { generate_get_transaction_name: true, @@ -432,11 +433,8 @@ filegroup { "core/java/android/util/LocalLog.java", "core/java/com/android/internal/util/HexDump.java", "core/java/com/android/internal/util/IndentingPrintWriter.java", - "core/java/com/android/internal/util/IState.java", "core/java/com/android/internal/util/MessageUtils.java", "core/java/com/android/internal/util/RingBufferIndices.java", - "core/java/com/android/internal/util/State.java", - "core/java/com/android/internal/util/StateMachine.java", "core/java/com/android/internal/util/WakeupMessage.java", "core/java/com/android/internal/util/TokenBucket.java", ], diff --git a/ApiDocs.bp b/ApiDocs.bp index a926ddc218a6..8af2e02f8d08 100644 --- a/ApiDocs.bp +++ b/ApiDocs.bp @@ -112,7 +112,6 @@ stubs_defaults { } // Defaults module for doc-stubs targets that use module source code as input. -// This is the default/normal. stubs_defaults { name: "framework-doc-stubs-sources-default", defaults: ["framework-doc-stubs-default"], @@ -147,12 +146,6 @@ droidstubs { } droidstubs { - name: "framework-doc-stubs", - defaults: ["framework-doc-stubs-sources-default"], - args: metalava_framework_docs_args, -} - -droidstubs { name: "framework-doc-system-stubs", defaults: ["framework-doc-stubs-sources-default"], args: metalava_framework_docs_args + @@ -160,11 +153,8 @@ droidstubs { api_levels_sdk_type: "system", } -// Experimental target building doc stubs with module stub source code as input. -// This is intended to eventually replace framework-doc-stubs, once all diffs -// have been eliminated. droidstubs { - name: "framework-doc-stubs-module-stubs", + name: "framework-doc-stubs", defaults: ["framework-doc-stubs-default"], args: metalava_framework_docs_args, srcs: [ diff --git a/PACKAGE_MANAGER_OWNERS b/PACKAGE_MANAGER_OWNERS new file mode 100644 index 000000000000..e4549b4de164 --- /dev/null +++ b/PACKAGE_MANAGER_OWNERS @@ -0,0 +1,3 @@ +chiuwinson@google.com +patb@google.com +schfan@google.com
\ No newline at end of file diff --git a/apex/blobstore/README.md b/apex/blobstore/README.md new file mode 100644 index 000000000000..69af436bf325 --- /dev/null +++ b/apex/blobstore/README.md @@ -0,0 +1,125 @@ +<!-- + 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 +--> + +# BlobStore Manager + +## Introduction +* BlobStoreManager is a system service added in Android R release that facilitates sharing of + data blobs among apps. +* Apps that would like to share data blobs with other apps can do so by contributing those + data blobs with the System and can choose how they would like the System to share the data blobs + with other apps. +* Apps can access data blobs shared by other apps from the System using checksum of the data blobs + (plus some other data attributes. More details [below](#blob-handle)). +* The APIs provided by the BlobStoreManager are meant to reduce storage and network usage by + reusing the data available on the device instead of downloading the same data again and having + multiple copies of the same data on disk. +* It is not meant to provide access to the data which apps otherwise would not be able to access. + In other words, if an app’s only means of obtaining access to certain data is through + BlobStoreManager, then that use case is not really intended or supported. +* For example, if earlier an app was downloading certain shared data from a server, then by using + BlobStoreManager, it can first check whether or not the data is already available on the device + before downloading. + +## Concepts +### Blob handle +Blob handle is the identifier of the data and it is what apps need to use for referring to the +data blobs. Currently, this is made of following bits of information: +* SHA256 checksum of data +* Data label: A user readable string that indicates what the data blob is. + This is meant to be used when surfacing a list of blobs to the user. +* Data expiry time: A timestamp after which the data blob should be considered invalid and not + allowed to be accessed by any app. +* Data tag: An opaque string associated with the blob. System does not interpret this in any way or + use it for any purposes other than when checking whether two Blob handle identifiers are referring + to the same data blob. This is meant to be used by the apps, either for categorization for + data blobs or for adding additional identifiers. For example, an app can add tags like + *machine_learning* or *media* depending on the data blob if necessary. + +When comparing two Blob handles, the System will compare all the pieces of information above and +only when two Blob handles are equal, the data blobs corresponding to those identifiers are +considered equal. + +### Blob sharing session +Session is a way to allow apps to contribute data over multiple time intervals. Each session is +associated with a unique Identifier that is created and obtained by the apps by calling +[BlobStoreManager#createSession](https://developer.android.com/reference/android/app/blob/BlobStoreManager#createSession(android.app.blob.BlobHandle)). +Apps can save the Identifier associated with a session and use it to open and close it +multiple times for contributing the data. For example, if an app is downloading +some content over the network, it can start a Session and start contributing this data to the +System immediately and if the network connection is lost for any reason, the app can close this +session. When the download resumes, the app can reopen the session and start contributing again. +Note that once the entire data is contributed, the app has no reason to hold on to the Session Id. + +### Blob commit +Since a data blob can be contributed in a session over multiple time intervals, an app closing a +session does not imply that the contribution is completed. So, *commit* is added as an explicit +event / signal for the app to indicate that the contribution of the data blob is completed. +At this point, the System can verify the data blob does indeed correspond to the Blob handle used +by the app and prevent the app from making any further modifications to the data blob. Once the +data blob is committed and verified by the System, it is available for other applications to access. + +### Access modes +When an application contributes a data blob to the System, it can choose to specify how it would +like the System to share this data blob with other applications. Access modes refer to the type of +access that apps specified when contributing a data blob. As of Android S release, there are +four access modes: +* Allow specific packages: Apps can specify a specific set of applications that are allowed to + access their data blob. +* Allow packages with the same signature: Apps can specify that only the applications that are + signed with the same certificate as them can access their data blob. +* Allow public access: Apps can specify that any other app on the device can access their data blob. +* Allow private access: Apps can specify that no other app can access their data blob unless they + happen to contribute the same data blob. + * Note that in this case, two apps might download the same data blob and contribute to the System + in which case we are not saving anything in terms of bandwidth usage, but we would still be + saving disk usage since we would be keeping only one copy of data on disk. + +### Lease +Leasing a blob is a way to specify that an application is interested in using a data blob +and would like the System to not delete this data blob. Applications can also access a blob +without holding a lease on it, in which case the System can choose to delete the data blob at any +time. So, if an application wants to make sure a data blob is available for access for a certain +period, it is recommended that the application acquire a lease on the data blob. Applications can +either specify upfront how long they would like to hold the lease for (which is called the lease +expiry time), or they can acquire a lease without specifying a time period and release the lease +when they are done with the data blob. + +## Sharing data blobs across users +By default, data blobs are only accessible to applications in the user in which the data blob was +contributed, but if an application holds the permission +[ACCESS_BLOBS_ACROSS_USERS](https://developer.android.com/reference/android/Manifest.permission#ACCESS_BLOBS_ACROSS_USERS), +then they are allowed to access blobs that are contributed by the applications in the other users. +As of Android S, this permission is only available to following set of applications: +* Apps signed with the platform certificate +* Privileged applications +* Applications holding the + [ASSISTANT](https://developer.android.com/reference/android/app/role/RoleManager#ROLE_ASSISTANT) + role +* Development applications + +Note that the access modes that applications choose while committing the data blobs still apply +when these data blobs are accessed across users. So for example, if *appA* contributed a +data blob in *user0* and specified to share this data blob with only a specific set of +applications [*appB*, *appC*], then *appD* on *user10* will not be able to access this data blob +even if the app is granted the `ACCESS_BLOBS_ACROSS_USERS` permission. + +When apps that are allowed to access blobs across users +(i.e. those holding the permission `ACCESS_BLOBS_ACROSS_USERS`) try to access a data blob, +they can do so as if it is any other data blob. In other words, the applications don’t need to +know where the data blob is contributed, because the System will automatically check and will +allow access if this data blob is available either on the user in which the calling application +is running in or other users.
\ No newline at end of file diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java index 4e46aa3f42d5..9564dde7fe06 100644 --- a/cmds/am/src/com/android/commands/am/Am.java +++ b/cmds/am/src/com/android/commands/am/Am.java @@ -41,6 +41,10 @@ public class Am extends BaseCommand { private IActivityManager mAm; private IPackageManager mPm; + Am() { + svcInit(); + } + /** * Command-line entry point. * @@ -50,6 +54,20 @@ public class Am extends BaseCommand { (new Am()).run(args); } + private void svcInit() { + mAm = ActivityManager.getService(); + if (mAm == null) { + System.err.println(NO_SYSTEM_ERROR_CODE); + return; + } + + mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package")); + if (mPm == null) { + System.err.println(NO_SYSTEM_ERROR_CODE); + return; + } + } + @Override public void onShowUsage(PrintStream out) { try { @@ -61,19 +79,6 @@ public class Am extends BaseCommand { @Override public void onRun() throws Exception { - - mAm = ActivityManager.getService(); - if (mAm == null) { - System.err.println(NO_SYSTEM_ERROR_CODE); - throw new AndroidException("Can't connect to activity manager; is the system running?"); - } - - mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package")); - if (mPm == null) { - System.err.println(NO_SYSTEM_ERROR_CODE); - throw new AndroidException("Can't connect to package manager; is the system running?"); - } - String op = nextArgRequired(); if (op.equals("instrument")) { diff --git a/cmds/am/src/com/android/commands/am/Instrument.java b/cmds/am/src/com/android/commands/am/Instrument.java index 1e72ddf8ecfc..0b439df403e0 100644 --- a/cmds/am/src/com/android/commands/am/Instrument.java +++ b/cmds/am/src/com/android/commands/am/Instrument.java @@ -545,6 +545,8 @@ public class Instrument { mWm.setAnimationScales(oldAnims); } } + // Exit from here instead of going down the path of normal shutdown which is slow. + System.exit(0); } private static String readLogcat(long startTimeMs) { diff --git a/cmds/idmap2/OWNERS b/cmds/idmap2/OWNERS index 69dfcc98340d..062ffd41348a 100644 --- a/cmds/idmap2/OWNERS +++ b/cmds/idmap2/OWNERS @@ -1,4 +1,4 @@ set noparent toddke@google.com -rtmitchell@google.com -patb@google.com
\ No newline at end of file +patb@google.com +zyy@google.com diff --git a/config/README.md b/config/README.md new file mode 100644 index 000000000000..450a5c695c82 --- /dev/null +++ b/config/README.md @@ -0,0 +1,13 @@ +# Configuration files for ART compiling the framework + +* boot-image-profile.txt: A list of methods from the boot classpath to be compiled by dex2oat. + The order in the file is not relevant. +* boot-profile.txt: An ordered list of methods from the boot classpath to be compiled by + the JIT in the order provided in the file. Used by JIT zygote, when on-device + signing failed. +* dirty-image-objects: List of objects in the boot image which are known to + become dirty. This helps binning objects in the image file. +* preloaded-classes: classes that will be allocated in the boot image, and + initialized by the zygote. +* preloaded-classes-denylist: Classes that should not be initialized in the + zygote, as they have app-specific behavior. diff --git a/core/api/current.txt b/core/api/current.txt index 743f5a0d9ce9..f21518c7f83d 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -112,6 +112,7 @@ package android { field public static final String MODIFY_PHONE_STATE = "android.permission.MODIFY_PHONE_STATE"; field public static final String MOUNT_FORMAT_FILESYSTEMS = "android.permission.MOUNT_FORMAT_FILESYSTEMS"; field public static final String MOUNT_UNMOUNT_FILESYSTEMS = "android.permission.MOUNT_UNMOUNT_FILESYSTEMS"; + field public static final String NEARBY_WIFI_DEVICES = "android.permission.NEARBY_WIFI_DEVICES"; field public static final String NFC = "android.permission.NFC"; field public static final String NFC_PREFERRED_PAYMENT_INFO = "android.permission.NFC_PREFERRED_PAYMENT_INFO"; field public static final String NFC_TRANSACTION_EVENT = "android.permission.NFC_TRANSACTION_EVENT"; @@ -8647,12 +8648,14 @@ package android.bluetooth { method public android.bluetooth.BluetoothDevice getRemoteDevice(byte[]); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public int getScanMode(); method public int getState(); + method public int isCisCentralSupported(); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public boolean isDiscovering(); method public boolean isEnabled(); method public boolean isLe2MPhySupported(); method public boolean isLeCodedPhySupported(); method public boolean isLeExtendedAdvertisingSupported(); method public boolean isLePeriodicAdvertisingSupported(); + method public int isLePeriodicAdvertisingSyncTransferSenderSupported(); method public boolean isMultipleAdvertisementSupported(); method public boolean isOffloadedFilteringSupported(); method public boolean isOffloadedScanBatchingSupported(); @@ -9122,8 +9125,10 @@ package android.bluetooth { method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean requestMtu(int); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean setCharacteristicNotification(android.bluetooth.BluetoothGattCharacteristic, boolean); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public void setPreferredPhy(int, int, int); - method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean writeCharacteristic(android.bluetooth.BluetoothGattCharacteristic); - method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean writeDescriptor(android.bluetooth.BluetoothGattDescriptor); + method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean writeCharacteristic(android.bluetooth.BluetoothGattCharacteristic); + method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int writeCharacteristic(@NonNull android.bluetooth.BluetoothGattCharacteristic, @NonNull byte[], int); + method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean writeDescriptor(android.bluetooth.BluetoothGattDescriptor); + method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int writeDescriptor(@NonNull android.bluetooth.BluetoothGattDescriptor, @NonNull byte[]); field public static final int CONNECTION_PRIORITY_BALANCED = 0; // 0x0 field public static final int CONNECTION_PRIORITY_HIGH = 1; // 0x1 field public static final int CONNECTION_PRIORITY_LOW_POWER = 2; // 0x2 @@ -9142,11 +9147,14 @@ package android.bluetooth { public abstract class BluetoothGattCallback { ctor public BluetoothGattCallback(); - method public void onCharacteristicChanged(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic); - method public void onCharacteristicRead(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic, int); + method @Deprecated public void onCharacteristicChanged(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic); + method public void onCharacteristicChanged(@NonNull android.bluetooth.BluetoothGatt, @NonNull android.bluetooth.BluetoothGattCharacteristic, @NonNull byte[]); + method @Deprecated public void onCharacteristicRead(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic, int); + method public void onCharacteristicRead(@NonNull android.bluetooth.BluetoothGatt, @NonNull android.bluetooth.BluetoothGattCharacteristic, @NonNull byte[], int); method public void onCharacteristicWrite(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic, int); method public void onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int); - method public void onDescriptorRead(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattDescriptor, int); + method @Deprecated public void onDescriptorRead(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattDescriptor, int); + method public void onDescriptorRead(@NonNull android.bluetooth.BluetoothGatt, @NonNull android.bluetooth.BluetoothGattDescriptor, int, @NonNull byte[]); method public void onDescriptorWrite(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattDescriptor, int); method public void onMtuChanged(android.bluetooth.BluetoothGatt, int, int); method public void onPhyRead(android.bluetooth.BluetoothGatt, int, int, int); @@ -9163,20 +9171,20 @@ package android.bluetooth { method public int describeContents(); method public android.bluetooth.BluetoothGattDescriptor getDescriptor(java.util.UUID); method public java.util.List<android.bluetooth.BluetoothGattDescriptor> getDescriptors(); - method public Float getFloatValue(int, int); + method @Deprecated public Float getFloatValue(int, int); method public int getInstanceId(); - method public Integer getIntValue(int, int); + method @Deprecated public Integer getIntValue(int, int); method public int getPermissions(); method public int getProperties(); method public android.bluetooth.BluetoothGattService getService(); - method public String getStringValue(int); + method @Deprecated public String getStringValue(int); method public java.util.UUID getUuid(); - method public byte[] getValue(); + method @Deprecated public byte[] getValue(); method public int getWriteType(); - method public boolean setValue(byte[]); - method public boolean setValue(int, int, int); - method public boolean setValue(int, int, int, int); - method public boolean setValue(String); + method @Deprecated public boolean setValue(byte[]); + method @Deprecated public boolean setValue(int, int, int); + method @Deprecated public boolean setValue(int, int, int, int); + method @Deprecated public boolean setValue(String); method public void setWriteType(int); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothGattCharacteristic> CREATOR; @@ -9216,8 +9224,8 @@ package android.bluetooth { method public android.bluetooth.BluetoothGattCharacteristic getCharacteristic(); method public int getPermissions(); method public java.util.UUID getUuid(); - method public byte[] getValue(); - method public boolean setValue(byte[]); + method @Deprecated public byte[] getValue(); + method @Deprecated public boolean setValue(byte[]); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothGattDescriptor> CREATOR; field public static final byte[] DISABLE_NOTIFICATION_VALUE; @@ -9505,7 +9513,12 @@ package android.bluetooth { field public static final int ERROR_BLUETOOTH_NOT_ALLOWED = 2; // 0x2 field public static final int ERROR_BLUETOOTH_NOT_ENABLED = 1; // 0x1 field public static final int ERROR_DEVICE_NOT_BONDED = 3; // 0x3 + field public static final int ERROR_FEATURE_NOT_SUPPORTED = 10; // 0xa + field public static final int ERROR_GATT_WRITE_NOT_ALLOWED = 101; // 0x65 + field public static final int ERROR_GATT_WRITE_REQUEST_BUSY = 102; // 0x66 field public static final int ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION = 6; // 0x6 + field public static final int ERROR_MISSING_BLUETOOTH_PRIVILEGED_PERMISSION = 8; // 0x8 + field public static final int ERROR_PROFILE_SERVICE_NOT_BOUND = 9; // 0x9 field public static final int ERROR_UNKNOWN = 2147483647; // 0x7fffffff field public static final int SUCCESS = 0; // 0x0 } @@ -31414,6 +31427,8 @@ package android.os { method @Nullable public double[] createDoubleArray(); method @Nullable public float[] createFloatArray(); method @Nullable public int[] createIntArray(); + method @Nullable public <T extends android.os.IInterface> T[] createInterfaceArray(@NonNull java.util.function.IntFunction<T[]>, @NonNull java.util.function.Function<android.os.IBinder,T>); + method @Nullable public <T extends android.os.IInterface> java.util.ArrayList<T> createInterfaceArrayList(@NonNull java.util.function.Function<android.os.IBinder,T>); method @Nullable public long[] createLongArray(); method @Nullable public String[] createStringArray(); method @Nullable public java.util.ArrayList<java.lang.String> createStringArrayList(); @@ -31432,7 +31447,9 @@ package android.os { method @NonNull public static android.os.Parcel obtain(); method @NonNull public static android.os.Parcel obtain(@NonNull android.os.IBinder); method @Nullable public Object[] readArray(@Nullable ClassLoader); + method @Nullable public <T> T[] readArray(@Nullable ClassLoader, @NonNull Class<T>); method @Nullable public java.util.ArrayList readArrayList(@Nullable ClassLoader); + method @Nullable public <T> java.util.ArrayList<T> readArrayList(@Nullable ClassLoader, @NonNull Class<? extends T>); method public void readBinderArray(@NonNull android.os.IBinder[]); method public void readBinderList(@NonNull java.util.List<android.os.IBinder>); method public boolean readBoolean(); @@ -31450,25 +31467,32 @@ package android.os { method public float readFloat(); method public void readFloatArray(@NonNull float[]); method @Nullable public java.util.HashMap readHashMap(@Nullable ClassLoader); + method @Nullable public <K, V> java.util.HashMap<K,V> readHashMap(@Nullable ClassLoader, @NonNull Class<? extends K>, @NonNull Class<? extends V>); method public int readInt(); method public void readIntArray(@NonNull int[]); + method public <T extends android.os.IInterface> void readInterfaceArray(@NonNull T[], @NonNull java.util.function.Function<android.os.IBinder,T>); + method public <T extends android.os.IInterface> void readInterfaceList(@NonNull java.util.List<T>, @NonNull java.util.function.Function<android.os.IBinder,T>); method public void readList(@NonNull java.util.List, @Nullable ClassLoader); method public <T> void readList(@NonNull java.util.List<? super T>, @Nullable ClassLoader, @NonNull Class<T>); method public long readLong(); method public void readLongArray(@NonNull long[]); method public void readMap(@NonNull java.util.Map, @Nullable ClassLoader); + method public <K, V> void readMap(@NonNull java.util.Map<? super K,? super V>, @Nullable ClassLoader, @NonNull Class<K>, @NonNull Class<V>); method @Nullable public <T extends android.os.Parcelable> T readParcelable(@Nullable ClassLoader); method @Nullable public <T extends android.os.Parcelable> T readParcelable(@Nullable ClassLoader, @NonNull Class<T>); method @Nullable public android.os.Parcelable[] readParcelableArray(@Nullable ClassLoader); + method @Nullable public <T> T[] readParcelableArray(@Nullable ClassLoader, @NonNull Class<T>); method @Nullable public android.os.Parcelable.Creator<?> readParcelableCreator(@Nullable ClassLoader); method @Nullable public <T> android.os.Parcelable.Creator<T> readParcelableCreator(@Nullable ClassLoader, @NonNull Class<T>); method @NonNull public <T extends android.os.Parcelable> java.util.List<T> readParcelableList(@NonNull java.util.List<T>, @Nullable ClassLoader); method @Nullable public android.os.PersistableBundle readPersistableBundle(); method @Nullable public android.os.PersistableBundle readPersistableBundle(@Nullable ClassLoader); method @Nullable public java.io.Serializable readSerializable(); + method @Nullable public <T extends java.io.Serializable> T readSerializable(@Nullable ClassLoader, @NonNull Class<T>); method @NonNull public android.util.Size readSize(); method @NonNull public android.util.SizeF readSizeF(); method @Nullable public <T> android.util.SparseArray<T> readSparseArray(@Nullable ClassLoader); + method @Nullable public <T> android.util.SparseArray<T> readSparseArray(@Nullable ClassLoader, @NonNull Class<? extends T>); method @Nullable public android.util.SparseBooleanArray readSparseBooleanArray(); method @Nullable public String readString(); method public void readStringArray(@NonNull String[]); @@ -31501,6 +31525,8 @@ package android.os { method public void writeFloatArray(@Nullable float[]); method public void writeInt(int); method public void writeIntArray(@Nullable int[]); + method public <T extends android.os.IInterface> void writeInterfaceArray(@Nullable T[]); + method public <T extends android.os.IInterface> void writeInterfaceList(@Nullable java.util.List<T>); method public void writeInterfaceToken(@NonNull String); method public void writeList(@Nullable java.util.List); method public void writeLong(long); @@ -40678,6 +40704,7 @@ package android.telephony { method @NonNull public java.util.List<java.lang.Integer> getBands(); method @NonNull public java.util.List<java.lang.String> getMccMncs(); method public int getPriority(); + method @NonNull public java.util.List<android.telephony.RadioAccessSpecifier> getRadioAccessSpecifiers(); method public int getSubId(); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.telephony.AvailableNetworkInfo> CREATOR; @@ -40686,6 +40713,14 @@ package android.telephony { field public static final int PRIORITY_MED = 2; // 0x2 } + public static final class AvailableNetworkInfo.Builder { + ctor public AvailableNetworkInfo.Builder(int); + method @NonNull public android.telephony.AvailableNetworkInfo build(); + method @NonNull public android.telephony.AvailableNetworkInfo.Builder setMccMncs(@NonNull java.util.List<java.lang.String>); + method @NonNull public android.telephony.AvailableNetworkInfo.Builder setPriority(int); + method @NonNull public android.telephony.AvailableNetworkInfo.Builder setRadioAccessSpecifiers(@NonNull java.util.List<android.telephony.RadioAccessSpecifier>); + } + public final class BarringInfo implements android.os.Parcelable { method public int describeContents(); method @NonNull public android.telephony.BarringInfo.BarringServiceInfo getBarringServiceInfo(int); @@ -40719,11 +40754,11 @@ package android.telephony { } public class CarrierConfigManager { - method @Nullable public android.os.PersistableBundle getConfig(); - method @Nullable public android.os.PersistableBundle getConfigByComponentForSubId(@NonNull String, int); - method @Nullable public android.os.PersistableBundle getConfigForSubId(int); + method @Nullable @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public android.os.PersistableBundle getConfig(); + method @Nullable @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public android.os.PersistableBundle getConfigByComponentForSubId(@NonNull String, int); + method @Nullable @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public android.os.PersistableBundle getConfigForSubId(int); method public static boolean isConfigForIdentifiedCarrier(android.os.PersistableBundle); - method public void notifyConfigChangedForSubId(int); + method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void notifyConfigChangedForSubId(int); field public static final String ACTION_CARRIER_CONFIG_CHANGED = "android.telephony.action.CARRIER_CONFIG_CHANGED"; field public static final int CARRIER_NR_AVAILABILITY_NSA = 1; // 0x1 field public static final int CARRIER_NR_AVAILABILITY_SA = 2; // 0x2 @@ -40794,6 +40829,7 @@ package android.telephony { field public static final String KEY_CARRIER_RCS_PROVISIONING_REQUIRED_BOOL = "carrier_rcs_provisioning_required_bool"; field public static final String KEY_CARRIER_SETTINGS_ACTIVITY_COMPONENT_NAME_STRING = "carrier_settings_activity_component_name_string"; field public static final String KEY_CARRIER_SETTINGS_ENABLE_BOOL = "carrier_settings_enable_bool"; + field public static final String KEY_CARRIER_SUPPORTS_OPP_DATA_AUTO_PROVISIONING_BOOL = "carrier_supports_opp_data_auto_provisioning_bool"; field public static final String KEY_CARRIER_SUPPORTS_SS_OVER_UT_BOOL = "carrier_supports_ss_over_ut_bool"; field public static final String KEY_CARRIER_USE_IMS_FIRST_FOR_EMERGENCY_BOOL = "carrier_use_ims_first_for_emergency_bool"; field public static final String KEY_CARRIER_USSD_METHOD_INT = "carrier_ussd_method_int"; @@ -40855,6 +40891,8 @@ package android.telephony { field public static final String KEY_ENABLE_DIALER_KEY_VIBRATION_BOOL = "enable_dialer_key_vibration_bool"; field public static final String KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL = "enhanced_4g_lte_on_by_default_bool"; field public static final String KEY_ENHANCED_4G_LTE_TITLE_VARIANT_INT = "enhanced_4g_lte_title_variant_int"; + field public static final String KEY_ESIM_DOWNLOAD_RETRY_BACKOFF_TIMER_SEC_INT = "esim_download_retry_backoff_timer_sec_int"; + field public static final String KEY_ESIM_MAX_DOWNLOAD_RETRY_ATTEMPTS_INT = "esim_max_download_retry_attempts_int"; field public static final String KEY_FORCE_HOME_NETWORK_BOOL = "force_home_network_bool"; field public static final String KEY_GSM_DTMF_TONE_DELAY_INT = "gsm_dtmf_tone_delay_int"; field public static final String KEY_GSM_NONROAMING_NETWORKS_STRING_ARRAY = "gsm_nonroaming_networks_string_array"; @@ -40957,6 +40995,7 @@ package android.telephony { field public static final String KEY_SHOW_WFC_LOCATION_PRIVACY_POLICY_BOOL = "show_wfc_location_privacy_policy_bool"; field public static final String KEY_SIMPLIFIED_NETWORK_SETTINGS_BOOL = "simplified_network_settings_bool"; field public static final String KEY_SIM_NETWORK_UNLOCK_ALLOW_DISMISS_BOOL = "sim_network_unlock_allow_dismiss_bool"; + field public static final String KEY_SMDP_SERVER_ADDRESS_STRING = "smdp_server_address_string"; field public static final String KEY_SMS_REQUIRES_DESTINATION_NUMBER_CONVERSION_BOOL = "sms_requires_destination_number_conversion_bool"; field public static final String KEY_SUPPORTS_CALL_COMPOSER_BOOL = "supports_call_composer_bool"; field public static final String KEY_SUPPORTS_DEVICE_TO_DEVICE_COMMUNICATION_USING_DTMF_BOOL = "supports_device_to_device_communication_using_dtmf_bool"; @@ -42729,7 +42768,7 @@ package android.telephony { method public boolean isEmergencyNumber(@NonNull String); method public boolean isHearingAidCompatibilitySupported(); method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRECISE_PHONE_STATE, "android.permission.READ_PRIVILEGED_PHONE_STATE"}) public boolean isManualNetworkSelectionAllowed(); - method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean isModemEnabledForSlot(int); + method @RequiresPermission(anyOf={android.Manifest.permission.READ_PHONE_STATE, "android.permission.READ_PRIVILEGED_PHONE_STATE"}) public boolean isModemEnabledForSlot(int); method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int isMultiSimSupported(); method public boolean isNetworkRoaming(); method public boolean isRadioInterfaceCapabilitySupported(@NonNull String); diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt index 49df45ac0c4f..9af6c1b340b6 100644 --- a/core/api/module-lib-current.txt +++ b/core/api/module-lib-current.txt @@ -113,6 +113,11 @@ package android.media { public class AudioManager { method public void adjustStreamVolumeForUid(int, int, int, @NonNull String, int, int, int); method public void adjustSuggestedStreamVolumeForUid(int, int, int, @NonNull String, int, int, int); + method @RequiresPermission("android.permission.BLUETOOTH_STACK") public void setA2dpSuspended(boolean); + method @RequiresPermission("android.permission.BLUETOOTH_STACK") public void setBluetoothHeadsetProperties(@NonNull String, boolean, boolean); + method @RequiresPermission("android.permission.BLUETOOTH_STACK") public void setHfpEnabled(boolean); + method @RequiresPermission("android.permission.BLUETOOTH_STACK") public void setHfpSamplingRate(int); + method @RequiresPermission("android.permission.BLUETOOTH_STACK") public void setHfpVolume(int); method public void setStreamVolumeForUid(int, int, int, @NonNull String, int, int, int); field public static final int FLAG_FROM_KEY = 4096; // 0x1000 } @@ -292,6 +297,10 @@ package android.os { method @Nullable public android.os.IBinder getOrThrow() throws android.os.StatsServiceManager.ServiceNotFoundException; } + public class SystemConfigManager { + method @NonNull public java.util.List<android.content.ComponentName> getEnabledComponentOverrides(@NonNull String); + } + } package android.os.storage { diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 6f825ae4e003..78e6a07c8705 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -475,6 +475,8 @@ package android.app { field public static final String OPSTR_AUTO_REVOKE_PERMISSIONS_IF_UNUSED = "android:auto_revoke_permissions_if_unused"; field public static final String OPSTR_BIND_ACCESSIBILITY_SERVICE = "android:bind_accessibility_service"; field public static final String OPSTR_CHANGE_WIFI_STATE = "android:change_wifi_state"; + field public static final String OPSTR_ESTABLISH_VPN_MANAGER = "android:establish_vpn_manager"; + field public static final String OPSTR_ESTABLISH_VPN_SERVICE = "android:establish_vpn_service"; field public static final String OPSTR_GET_ACCOUNTS = "android:get_accounts"; field public static final String OPSTR_GPS = "android:gps"; field public static final String OPSTR_INSTANT_APP_START_FOREGROUND = "android:instant_app_start_foreground"; @@ -1935,6 +1937,22 @@ package android.bluetooth { field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.a2dp-sink.profile.action.CONNECTION_STATE_CHANGED"; } + public final class BluetoothActivityEnergyInfo implements android.os.Parcelable { + method public int getBluetoothStackState(); + method public long getControllerEnergyUsed(); + method public long getControllerIdleTimeMillis(); + method public long getControllerRxTimeMillis(); + method public long getControllerTxTimeMillis(); + method public long getTimestampMillis(); + method @NonNull public java.util.List<android.bluetooth.UidTraffic> getUidTraffic(); + method public boolean isValid(); + field public static final int BT_STACK_STATE_INVALID = 0; // 0x0 + field public static final int BT_STACK_STATE_STATE_ACTIVE = 1; // 0x1 + field public static final int BT_STACK_STATE_STATE_IDLE = 3; // 0x3 + field public static final int BT_STACK_STATE_STATE_SCANNING = 2; // 0x2 + field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothActivityEnergyInfo> CREATOR; + } + public final class BluetoothAdapter { method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean addOnMetadataChangedListener(@NonNull android.bluetooth.BluetoothDevice, @NonNull java.util.concurrent.Executor, @NonNull android.bluetooth.BluetoothAdapter.OnMetadataChangedListener); method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean disable(boolean); @@ -2234,6 +2252,13 @@ package android.bluetooth { method @NonNull public android.bluetooth.OobData.LeBuilder setRandomizerHash(@NonNull byte[]); } + public final class UidTraffic implements java.lang.Cloneable android.os.Parcelable { + method public long getRxBytes(); + method public long getTxBytes(); + method public int getUid(); + field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.UidTraffic> CREATOR; + } + } package android.bluetooth.le { @@ -8556,7 +8581,6 @@ package android.os { public class SystemConfigManager { method @NonNull @RequiresPermission(android.Manifest.permission.READ_CARRIER_APP_INFO) public java.util.Set<java.lang.String> getDisabledUntilUsedPreinstalledCarrierApps(); method @NonNull @RequiresPermission(android.Manifest.permission.READ_CARRIER_APP_INFO) public java.util.Map<java.lang.String,java.util.List<java.lang.String>> getDisabledUntilUsedPreinstalledCarrierAssociatedApps(); - method @NonNull public java.util.List<java.lang.String> getEnabledComponentOverrides(@NonNull String); method @NonNull @RequiresPermission(android.Manifest.permission.GET_RUNTIME_PERMISSIONS) public int[] getSystemPermissionUids(@NonNull String); } @@ -9126,6 +9150,7 @@ package android.provider { field public static final String NAMESPACE_BIOMETRICS = "biometrics"; field public static final String NAMESPACE_BLOBSTORE = "blobstore"; field public static final String NAMESPACE_BLUETOOTH = "bluetooth"; + field public static final String NAMESPACE_CAPTIVEPORTALLOGIN = "captive_portal_login"; field public static final String NAMESPACE_CLIPBOARD = "clipboard"; field public static final String NAMESPACE_CONNECTIVITY = "connectivity"; field public static final String NAMESPACE_CONTENT_CAPTURE = "content_capture"; @@ -9161,6 +9186,7 @@ package android.provider { field public static final String NAMESPACE_SYSTEMUI = "systemui"; field public static final String NAMESPACE_SYSTEM_TIME = "system_time"; field public static final String NAMESPACE_TELEPHONY = "telephony"; + field public static final String NAMESPACE_TETHERING = "tethering"; field public static final String NAMESPACE_TEXTCLASSIFIER = "textclassifier"; field public static final String NAMESPACE_WINDOW_MANAGER_NATIVE_BOOT = "window_manager_native_boot"; } diff --git a/core/java/android/accounts/Account.java b/core/java/android/accounts/Account.java index 0d6a07938e95..e6cdcc0ee742 100644 --- a/core/java/android/accounts/Account.java +++ b/core/java/android/accounts/Account.java @@ -31,6 +31,7 @@ import android.util.Log; import com.android.internal.annotations.GuardedBy; +import java.util.Objects; import java.util.Set; /** @@ -86,6 +87,12 @@ public class Account implements Parcelable { if (TextUtils.isEmpty(type)) { throw new IllegalArgumentException("the type must not be empty: " + type); } + if (name.length() > 200) { + throw new IllegalArgumentException("account name is longer than 200 characters"); + } + if (type.length() > 200) { + throw new IllegalArgumentException("account type is longer than 200 characters"); + } this.name = name; this.type = type; this.accessId = accessId; diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index db5dcc5c264b..af59ea1d22ff 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -77,7 +77,6 @@ import android.os.IBinder; import android.os.Looper; import android.os.Parcelable; import android.os.PersistableBundle; -import android.os.PowerManager; import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager.ServiceNotFoundException; @@ -8788,9 +8787,7 @@ public class Activity extends ContextThemeWrapper * the activity is visible after the screen is turned on when the lockscreen is up. In addition, * if this flag is set and the activity calls {@link * KeyguardManager#requestDismissKeyguard(Activity, KeyguardManager.KeyguardDismissCallback)} - * the screen will turn on. If the screen is off and device is not secured, this flag can turn - * screen on and dismiss keyguard to make this activity visible and resume, which can be used to - * replace {@link PowerManager#ACQUIRE_CAUSES_WAKEUP} + * the screen will turn on. * * @param turnScreenOn {@code true} to turn on the screen; {@code false} otherwise. * diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 6c3795d7c607..bfff27a82f5b 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -464,11 +464,7 @@ public final class ActivityThread extends ClientTransactionHandler @Override public int hashCode() { - return hashCode(authority, userId); - } - - public static int hashCode(final String auth, final int userIdent) { - return ((auth != null) ? auth.hashCode() : 0) ^ userIdent; + return ((authority != null) ? authority.hashCode() : 0) ^ userId; } } @@ -490,7 +486,7 @@ public final class ActivityThread extends ClientTransactionHandler // Note we never removes items from this map but that's okay because there are only so many // users and so many authorities. @GuardedBy("mGetProviderKeys") - final SparseArray<ProviderKey> mGetProviderKeys = new SparseArray<>(); + final ArrayMap<ProviderKey, ProviderKey> mGetProviderKeys = new ArrayMap<>(); final ArrayMap<Activity, ArrayList<OnActivityPausedListener>> mOnPauseListeners = new ArrayMap<Activity, ArrayList<OnActivityPausedListener>>(); @@ -7020,11 +7016,11 @@ public final class ActivityThread extends ClientTransactionHandler } private ProviderKey getGetProviderKey(String auth, int userId) { - final int key = ProviderKey.hashCode(auth, userId); + final ProviderKey key = new ProviderKey(auth, userId); synchronized (mGetProviderKeys) { ProviderKey lock = mGetProviderKeys.get(key); if (lock == null) { - lock = new ProviderKey(auth, userId); + lock = key; mGetProviderKeys.put(key, lock); } return lock; diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index d932a29beca6..63f700b8883c 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -1292,6 +1292,9 @@ public class AppOpsManager { /** @hide */ public static final int OP_UWB_RANGING = AppProtoEnums.APP_OP_UWB_RANGING; + /** @hide */ + public static final int OP_NEARBY_WIFI_DEVICES = AppProtoEnums.APP_OP_NEARBY_WIFI_DEVICES; + /** * Activity recognition being accessed by an activity recognition source, which * is a component that already has access since it is the one that detects @@ -1310,9 +1313,23 @@ public class AppOpsManager { public static final int OP_RECORD_INCOMING_PHONE_AUDIO = AppProtoEnums.APP_OP_RECORD_INCOMING_PHONE_AUDIO; + /** + * VPN app establishes a connection through the VpnService API. + * + * @hide + */ + public static final int OP_ESTABLISH_VPN_SERVICE = AppProtoEnums.APP_OP_ESTABLISH_VPN_SERVICE; + + /** + * VPN app establishes a connection through the VpnManager API. + * + * @hide + */ + public static final int OP_ESTABLISH_VPN_MANAGER = AppProtoEnums.APP_OP_ESTABLISH_VPN_MANAGER; + /** @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public static final int _NUM_OP = 116; + public static final int _NUM_OP = 119; /** Access to coarse location information. */ public static final String OPSTR_COARSE_LOCATION = "android:coarse_location"; @@ -1731,6 +1748,8 @@ public class AppOpsManager { public static final String OPSTR_MANAGE_MEDIA = "android:manage_media"; /** @hide */ public static final String OPSTR_UWB_RANGING = "android:uwb_ranging"; + /** @hide */ + public static final String OPSTR_NEARBY_WIFI_DEVICES = "android:nearby_wifi_devices"; /** * Activity recognition being accessed by an activity recognition source, which @@ -1749,6 +1768,22 @@ public class AppOpsManager { public static final String OPSTR_RECORD_INCOMING_PHONE_AUDIO = "android:record_incoming_phone_audio"; + /** + * VPN app establishes a connection through the VpnService API. + * + * @hide + */ + @SystemApi + public static final String OPSTR_ESTABLISH_VPN_SERVICE = "android:establish_vpn_service"; + + /** + * VPN app establishes a connection through the VpnManager API. + * + * @hide + */ + @SystemApi + public static final String OPSTR_ESTABLISH_VPN_MANAGER = "android:establish_vpn_manager"; + /** {@link #sAppOpsToNote} not initialized yet for this op */ private static final byte SHOULD_COLLECT_NOTE_OP_NOT_INITIALIZED = 0; /** Should not collect noting of this app-op in {@link #sAppOpsToNote} */ @@ -1819,6 +1854,7 @@ public class AppOpsManager { OP_BLUETOOTH_CONNECT, OP_BLUETOOTH_ADVERTISE, OP_UWB_RANGING, + OP_NEARBY_WIFI_DEVICES, // APPOP PERMISSIONS OP_ACCESS_NOTIFICATIONS, @@ -1963,6 +1999,9 @@ public class AppOpsManager { OP_ACTIVITY_RECOGNITION, // OP_ACTIVITY_RECOGNITION_SOURCE OP_BLUETOOTH_ADVERTISE, // OP_BLUETOOTH_ADVERTISE OP_RECORD_INCOMING_PHONE_AUDIO, // OP_RECORD_INCOMING_PHONE_AUDIO + OP_NEARBY_WIFI_DEVICES, // OP_NEARBY_WIFI_DEVICES + OP_ESTABLISH_VPN_SERVICE, // OP_ESTABLISH_VPN_SERVICE + OP_ESTABLISH_VPN_MANAGER, // OP_ESTABLISH_VPN_MANAGER }; /** @@ -2085,6 +2124,9 @@ public class AppOpsManager { OPSTR_ACTIVITY_RECOGNITION_SOURCE, OPSTR_BLUETOOTH_ADVERTISE, OPSTR_RECORD_INCOMING_PHONE_AUDIO, + OPSTR_NEARBY_WIFI_DEVICES, + OPSTR_ESTABLISH_VPN_SERVICE, + OPSTR_ESTABLISH_VPN_MANAGER, }; /** @@ -2208,6 +2250,9 @@ public class AppOpsManager { "ACTIVITY_RECOGNITION_SOURCE", "BLUETOOTH_ADVERTISE", "RECORD_INCOMING_PHONE_AUDIO", + "NEARBY_WIFI_DEVICES", + "ESTABLISH_VPN_SERVICE", + "ESTABLISH_VPN_MANAGER", }; /** @@ -2332,6 +2377,9 @@ public class AppOpsManager { null, // no permission for OP_ACTIVITY_RECOGNITION_SOURCE, Manifest.permission.BLUETOOTH_ADVERTISE, null, // no permission for OP_RECORD_INCOMING_PHONE_AUDIO, + Manifest.permission.NEARBY_WIFI_DEVICES, + null, // no permission for OP_ESTABLISH_VPN_SERVICE + null, // no permission for OP_ESTABLISH_VPN_MANAGER }; /** @@ -2456,6 +2504,9 @@ public class AppOpsManager { null, // ACTIVITY_RECOGNITION_SOURCE null, // BLUETOOTH_ADVERTISE null, // RECORD_INCOMING_PHONE_AUDIO + null, // NEARBY_WIFI_DEVICES + null, // ESTABLISH_VPN_SERVICE + null, // ESTABLISH_VPN_MANAGER }; /** @@ -2579,6 +2630,9 @@ public class AppOpsManager { null, // ACTIVITY_RECOGNITION_SOURCE null, // BLUETOOTH_ADVERTISE null, // RECORD_INCOMING_PHONE_AUDIO + null, // NEARBY_WIFI_DEVICES + null, // ESTABLISH_VPN_SERVICE + null, // ESTABLISH_VPN_MANAGER }; /** @@ -2701,6 +2755,9 @@ public class AppOpsManager { AppOpsManager.MODE_ALLOWED, // ACTIVITY_RECOGNITION_SOURCE AppOpsManager.MODE_ALLOWED, // BLUETOOTH_ADVERTISE AppOpsManager.MODE_ALLOWED, // RECORD_INCOMING_PHONE_AUDIO + AppOpsManager.MODE_ALLOWED, // NEARBY_WIFI_DEVICES + AppOpsManager.MODE_ALLOWED, // ESTABLISH_VPN_SERVICE + AppOpsManager.MODE_ALLOWED, // ESTABLISH_VPN_MANAGER }; /** @@ -2827,6 +2884,9 @@ public class AppOpsManager { false, // ACTIVITY_RECOGNITION_SOURCE false, // BLUETOOTH_ADVERTISE false, // RECORD_INCOMING_PHONE_AUDIO + false, // NEARBY_WIFI_DEVICES + false, // OP_ESTABLISH_VPN_SERVICE + false, // OP_ESTABLISH_VPN_MANAGER }; /** diff --git a/core/java/android/app/ApplicationLoaders.java b/core/java/android/app/ApplicationLoaders.java index 08cd0b34ee0a..53b16d3a8170 100644 --- a/core/java/android/app/ApplicationLoaders.java +++ b/core/java/android/app/ApplicationLoaders.java @@ -48,18 +48,19 @@ public class ApplicationLoaders { ClassLoader parent, String classLoaderName) { return getClassLoaderWithSharedLibraries(zip, targetSdkVersion, isBundled, librarySearchPath, libraryPermittedPath, parent, classLoaderName, - null, null); + null, null, null); } ClassLoader getClassLoaderWithSharedLibraries( String zip, int targetSdkVersion, boolean isBundled, String librarySearchPath, String libraryPermittedPath, ClassLoader parent, String classLoaderName, - List<ClassLoader> sharedLibraries, List<String> nativeSharedLibraries) { + List<ClassLoader> sharedLibraries, List<String> nativeSharedLibraries, + List<ClassLoader> sharedLibrariesLoadedAfterApp) { // For normal usage the cache key used is the same as the zip path. return getClassLoader(zip, targetSdkVersion, isBundled, librarySearchPath, libraryPermittedPath, parent, zip, classLoaderName, sharedLibraries, - nativeSharedLibraries); + nativeSharedLibraries, sharedLibrariesLoadedAfterApp); } /** @@ -71,7 +72,8 @@ public class ApplicationLoaders { */ ClassLoader getSharedLibraryClassLoaderWithSharedLibraries(String zip, int targetSdkVersion, boolean isBundled, String librarySearchPath, String libraryPermittedPath, - ClassLoader parent, String classLoaderName, List<ClassLoader> sharedLibraries) { + ClassLoader parent, String classLoaderName, List<ClassLoader> sharedLibraries, + List<ClassLoader> sharedLibrariesAfter) { ClassLoader loader = getCachedNonBootclasspathSystemLib(zip, parent, classLoaderName, sharedLibraries); if (loader != null) { @@ -86,14 +88,15 @@ public class ApplicationLoaders { nativeSharedLibraries.add("ALL"); return getClassLoaderWithSharedLibraries(zip, targetSdkVersion, isBundled, librarySearchPath, libraryPermittedPath, parent, classLoaderName, sharedLibraries, - nativeSharedLibraries); + nativeSharedLibraries, sharedLibrariesAfter); } private ClassLoader getClassLoader(String zip, int targetSdkVersion, boolean isBundled, String librarySearchPath, String libraryPermittedPath, ClassLoader parent, String cacheKey, String classLoaderName, List<ClassLoader> sharedLibraries, - List<String> nativeSharedLibraries) { + List<String> nativeSharedLibraries, + List<ClassLoader> sharedLibrariesLoadedAfterApp) { /* * This is the parent we use if they pass "null" in. In theory * this should be the "system" class loader; in practice we @@ -123,7 +126,7 @@ public class ApplicationLoaders { ClassLoader classloader = ClassLoaderFactory.createClassLoader( zip, librarySearchPath, libraryPermittedPath, parent, targetSdkVersion, isBundled, classLoaderName, sharedLibraries, - nativeSharedLibraries); + nativeSharedLibraries, sharedLibrariesLoadedAfterApp); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); @@ -140,7 +143,8 @@ public class ApplicationLoaders { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, zip); ClassLoader loader = ClassLoaderFactory.createClassLoader( - zip, null, parent, classLoaderName, sharedLibraries); + zip, null, parent, classLoaderName, sharedLibraries, + null /*sharedLibrariesLoadedAfterApp*/); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); return loader; } @@ -196,7 +200,7 @@ public class ApplicationLoaders { ClassLoader classLoader = getClassLoader(path, Build.VERSION.SDK_INT, true /*isBundled*/, null /*librarySearchPath*/, null /*libraryPermittedPath*/, null /*parent*/, null /*cacheKey*/, null /*classLoaderName*/, sharedLibraries /*sharedLibraries*/, - null /* nativeSharedLibraries */); + null /* nativeSharedLibraries */, null /*sharedLibrariesLoadedAfterApp*/); if (classLoader == null) { // bad configuration or break in classloading code @@ -267,7 +271,8 @@ public class ApplicationLoaders { // stub's APK path, when the actual package path is the donor APK. return getClassLoader(packagePath, Build.VERSION.SDK_INT, false, libsPath, null, null, cacheKey, null /* classLoaderName */, null /* sharedLibraries */, - null /* nativeSharedLibraries */); + null /* nativeSharedLibraries */, + null /*sharedLibrariesLoadedAfterApp*/); } /** diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java index a2c9795204ad..f6d27e125cd7 100644 --- a/core/java/android/app/LoadedApk.java +++ b/core/java/android/app/LoadedApk.java @@ -54,10 +54,12 @@ import android.text.TextUtils; import android.util.AndroidRuntimeException; import android.util.ArrayMap; import android.util.Log; +import android.util.Pair; import android.util.Slog; import android.util.SparseArray; import android.view.DisplayAdjustments; +import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.ArrayUtils; @@ -76,6 +78,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Enumeration; +import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Objects; @@ -700,7 +703,7 @@ public final class LoadedApk { ClassLoader createSharedLibraryLoader(SharedLibraryInfo sharedLibrary, boolean isBundledApp, String librarySearchPath, String libraryPermittedPath) { List<String> paths = sharedLibrary.getAllCodePaths(); - List<ClassLoader> sharedLibraries = createSharedLibrariesLoaders( + Pair<List<ClassLoader>, List<ClassLoader>> sharedLibraries = createSharedLibrariesLoaders( sharedLibrary.getDependencies(), isBundledApp, librarySearchPath, libraryPermittedPath); final String jars = (paths.size() == 1) ? paths.get(0) : @@ -711,15 +714,31 @@ public final class LoadedApk { return ApplicationLoaders.getDefault().getSharedLibraryClassLoaderWithSharedLibraries(jars, mApplicationInfo.targetSdkVersion, isBundledApp, librarySearchPath, libraryPermittedPath, /* parent */ null, - /* classLoaderName */ null, sharedLibraries); + /* classLoaderName */ null, sharedLibraries.first, sharedLibraries.second); } - private List<ClassLoader> createSharedLibrariesLoaders(List<SharedLibraryInfo> sharedLibraries, + /** + * + * @return a {@link Pair} of List<ClassLoader> where the first is for standard shared libraries + * and the second is list for shared libraries that code should be loaded after the dex + */ + private Pair<List<ClassLoader>, List<ClassLoader>> createSharedLibrariesLoaders( + List<SharedLibraryInfo> sharedLibraries, boolean isBundledApp, String librarySearchPath, String libraryPermittedPath) { - if (sharedLibraries == null) { - return null; + if (sharedLibraries == null || sharedLibraries.isEmpty()) { + return new Pair<>(null, null); } + + // if configured to do so, shared libs are split into 2 collections: those that are + // on the class path before the applications code, which is standard, and those + // specified to be loaded after the applications code. + HashSet<String> libsToLoadAfter = new HashSet<>(); + Resources systemR = Resources.getSystem(); + Collections.addAll(libsToLoadAfter, systemR.getStringArray( + R.array.config_sharedLibrariesLoadedAfterApp)); + List<ClassLoader> loaders = new ArrayList<>(); + List<ClassLoader> after = new ArrayList<>(); for (SharedLibraryInfo info : sharedLibraries) { if (info.isNative()) { // Native shared lib doesn't contribute to the native lib search path. Its name is @@ -727,10 +746,19 @@ public final class LoadedApk { // default linker namespace. continue; } - loaders.add(createSharedLibraryLoader( - info, isBundledApp, librarySearchPath, libraryPermittedPath)); + if (libsToLoadAfter.contains(info.getName())) { + if (DEBUG) { + Slog.v(ActivityThread.TAG, + info.getName() + " will be loaded after application code"); + } + after.add(createSharedLibraryLoader( + info, isBundledApp, librarySearchPath, libraryPermittedPath)); + } else { + loaders.add(createSharedLibraryLoader( + info, isBundledApp, librarySearchPath, libraryPermittedPath)); + } } - return loaders; + return new Pair<>(loaders, after); } private StrictMode.ThreadPolicy allowThreadDiskReads() { @@ -955,9 +983,9 @@ public final class LoadedApk { // as this is early and necessary. StrictMode.ThreadPolicy oldPolicy = allowThreadDiskReads(); - List<ClassLoader> sharedLibraries = createSharedLibrariesLoaders( - mApplicationInfo.sharedLibraryInfos, isBundledApp, librarySearchPath, - libraryPermittedPath); + Pair<List<ClassLoader>, List<ClassLoader>> sharedLibraries = + createSharedLibrariesLoaders(mApplicationInfo.sharedLibraryInfos, isBundledApp, + librarySearchPath, libraryPermittedPath); List<String> nativeSharedLibraries = new ArrayList<>(); if (mApplicationInfo.sharedLibraryInfos != null) { @@ -971,7 +999,8 @@ public final class LoadedApk { mDefaultClassLoader = ApplicationLoaders.getDefault().getClassLoaderWithSharedLibraries( zip, mApplicationInfo.targetSdkVersion, isBundledApp, librarySearchPath, libraryPermittedPath, mBaseClassLoader, - mApplicationInfo.classLoaderName, sharedLibraries, nativeSharedLibraries); + mApplicationInfo.classLoaderName, sharedLibraries.first, nativeSharedLibraries, + sharedLibraries.second); mAppComponentFactory = createAppFactory(mApplicationInfo, mDefaultClassLoader); setThreadPolicy(oldPolicy); diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index 32ea41b2c75f..e2fd35940b52 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -1914,39 +1914,6 @@ public final class SystemServiceRegistry { public abstract T createService() throws ServiceNotFoundException; } - /** - * Like StaticServiceFetcher, creates only one instance of the service per application, but when - * creating the service for the first time, passes it the application context of the creating - * application. - * - * TODO: Delete this once its only user (ConnectivityManager) is known to work well in the - * case where multiple application components each have their own ConnectivityManager object. - */ - static abstract class StaticApplicationContextServiceFetcher<T> implements ServiceFetcher<T> { - private T mCachedInstance; - - @Override - public final T getService(ContextImpl ctx) { - synchronized (StaticApplicationContextServiceFetcher.this) { - if (mCachedInstance == null) { - Context appContext = ctx.getApplicationContext(); - // If the application context is null, we're either in the system process or - // it's the application context very early in app initialization. In both these - // cases, the passed-in ContextImpl will not be freed, so it's safe to pass it - // to the service. http://b/27532714 . - try { - mCachedInstance = createService(appContext != null ? appContext : ctx); - } catch (ServiceNotFoundException e) { - onServiceNotFound(e); - } - } - return mCachedInstance; - } - } - - public abstract T createService(Context applicationContext) throws ServiceNotFoundException; - } - /** @hide */ public static void onServiceNotFound(ServiceNotFoundException e) { // We're mostly interested in tracking down long-lived core system diff --git a/core/java/android/bluetooth/BluetoothActivityEnergyInfo.java b/core/java/android/bluetooth/BluetoothActivityEnergyInfo.java index df065bf1bf8d..c17a7b4b3dfd 100644 --- a/core/java/android/bluetooth/BluetoothActivityEnergyInfo.java +++ b/core/java/android/bluetooth/BluetoothActivityEnergyInfo.java @@ -16,18 +16,26 @@ package android.bluetooth; +import android.annotation.ElapsedRealtimeLong; +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; -import java.util.Arrays; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Collections; +import java.util.List; /** * Record of energy and activity information from controller and * underlying bt stack state.Timestamp the record with system - * time + * time. * * @hide */ +@SystemApi(client = SystemApi.Client.PRIVILEGED_APPS) public final class BluetoothActivityEnergyInfo implements Parcelable { private final long mTimestamp; private int mBluetoothStackState; @@ -35,13 +43,24 @@ public final class BluetoothActivityEnergyInfo implements Parcelable { private long mControllerRxTimeMs; private long mControllerIdleTimeMs; private long mControllerEnergyUsed; - private UidTraffic[] mUidTraffic; + private List<UidTraffic> mUidTraffic; + + /** @hide */ + @IntDef(prefix = { "BT_STACK_STATE_" }, value = { + BT_STACK_STATE_INVALID, + BT_STACK_STATE_STATE_ACTIVE, + BT_STACK_STATE_STATE_SCANNING, + BT_STACK_STATE_STATE_IDLE + }) + @Retention(RetentionPolicy.SOURCE) + public @interface BluetoothStackState {} public static final int BT_STACK_STATE_INVALID = 0; public static final int BT_STACK_STATE_STATE_ACTIVE = 1; public static final int BT_STACK_STATE_STATE_SCANNING = 2; public static final int BT_STACK_STATE_STATE_IDLE = 3; + /** @hide */ public BluetoothActivityEnergyInfo(long timestamp, int stackState, long txTime, long rxTime, long idleTime, long energyUsed) { mTimestamp = timestamp; @@ -52,17 +71,18 @@ public final class BluetoothActivityEnergyInfo implements Parcelable { mControllerEnergyUsed = energyUsed; } - @SuppressWarnings("unchecked") - BluetoothActivityEnergyInfo(Parcel in) { + /** @hide */ + private BluetoothActivityEnergyInfo(Parcel in) { mTimestamp = in.readLong(); mBluetoothStackState = in.readInt(); mControllerTxTimeMs = in.readLong(); mControllerRxTimeMs = in.readLong(); mControllerIdleTimeMs = in.readLong(); mControllerEnergyUsed = in.readLong(); - mUidTraffic = in.createTypedArray(UidTraffic.CREATOR); + mUidTraffic = in.createTypedArrayList(UidTraffic.CREATOR); } + /** @hide */ @Override public String toString() { return "BluetoothActivityEnergyInfo{" @@ -72,11 +92,11 @@ public final class BluetoothActivityEnergyInfo implements Parcelable { + " mControllerRxTimeMs=" + mControllerRxTimeMs + " mControllerIdleTimeMs=" + mControllerIdleTimeMs + " mControllerEnergyUsed=" + mControllerEnergyUsed - + " mUidTraffic=" + Arrays.toString(mUidTraffic) + + " mUidTraffic=" + mUidTraffic + " }"; } - public static final @android.annotation.NonNull Parcelable.Creator<BluetoothActivityEnergyInfo> CREATOR = + public static final @NonNull Parcelable.Creator<BluetoothActivityEnergyInfo> CREATOR = new Parcelable.Creator<BluetoothActivityEnergyInfo>() { public BluetoothActivityEnergyInfo createFromParcel(Parcel in) { return new BluetoothActivityEnergyInfo(in); @@ -87,9 +107,8 @@ public final class BluetoothActivityEnergyInfo implements Parcelable { } }; - + /** @hide */ @Override - @SuppressWarnings("unchecked") public void writeToParcel(Parcel out, int flags) { out.writeLong(mTimestamp); out.writeInt(mBluetoothStackState); @@ -97,17 +116,21 @@ public final class BluetoothActivityEnergyInfo implements Parcelable { out.writeLong(mControllerRxTimeMs); out.writeLong(mControllerIdleTimeMs); out.writeLong(mControllerEnergyUsed); - out.writeTypedArray(mUidTraffic, flags); + out.writeTypedList(mUidTraffic); } + /** @hide */ @Override public int describeContents() { return 0; } /** - * @return bt stack reported state + * Get the Bluetooth stack state associated with the energy info. + * + * @return one of {@link #BluetoothStackState} states */ + @BluetoothStackState public int getBluetoothStackState() { return mBluetoothStackState; } @@ -134,7 +157,7 @@ public final class BluetoothActivityEnergyInfo implements Parcelable { } /** - * product of current(mA), voltage(V) and time(ms) + * Get the product of current (mA), voltage (V), and time (ms). * * @return energy used */ @@ -143,22 +166,31 @@ public final class BluetoothActivityEnergyInfo implements Parcelable { } /** - * @return timestamp(real time elapsed in milliseconds since boot) of record creation. + * @return timestamp (real time elapsed in milliseconds since boot) of record creation */ - public long getTimeStamp() { + public @ElapsedRealtimeLong long getTimestampMillis() { return mTimestamp; } - public UidTraffic[] getUidTraffic() { + /** + * Get the {@link List} of each application {@link android.bluetooth.UidTraffic}. + * + * @return current {@link List} of {@link android.bluetooth.UidTraffic} + */ + public @NonNull List<UidTraffic> getUidTraffic() { + if (mUidTraffic == null) { + return Collections.emptyList(); + } return mUidTraffic; } - public void setUidTraffic(UidTraffic[] traffic) { + /** @hide */ + public void setUidTraffic(List<UidTraffic> traffic) { mUidTraffic = traffic; } /** - * @return if the record is valid + * @return true if the record Tx time, Rx time, and Idle time are more than 0. */ public boolean isValid() { return ((mControllerTxTimeMs >= 0) && (mControllerRxTimeMs >= 0) diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java index 06ce0530d475..dac8ffe5e008 100644 --- a/core/java/android/bluetooth/BluetoothAdapter.java +++ b/core/java/android/bluetooth/BluetoothAdapter.java @@ -2272,6 +2272,66 @@ public final class BluetoothAdapter { return false; } + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(value = { + BluetoothStatusCodes.SUCCESS, + BluetoothStatusCodes.ERROR_UNKNOWN, + BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED, + BluetoothStatusCodes.ERROR_FEATURE_NOT_SUPPORTED, + }) + public @interface LeFeatureReturnValues {} + + /** + * Returns {@link BluetoothStatusCodes#SUCCESS} if LE Connected Isochronous Stream Central + * feature is supported, returns {@link BluetoothStatusCodes#ERROR_FEATURE_NOT_SUPPORTED} if + * the feature is not supported or an error code. + * + * @return whether the chipset supports the LE Connected Isochronous Stream Central feature + */ + @RequiresNoPermission + public @LeFeatureReturnValues int isCisCentralSupported() { + if (!getLeAccess()) { + return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; + } + try { + mServiceLock.readLock().lock(); + if (mService != null) { + return mService.isCisCentralSupported(); + } + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } finally { + mServiceLock.readLock().unlock(); + } + return BluetoothStatusCodes.ERROR_UNKNOWN; + } + + /** + * Returns {@link BluetoothStatusCodes#SUCCESS} if LE Periodic Advertising Sync Transfer Sender + * feature is supported, returns {@link BluetoothStatusCodes#ERROR_FEATURE_NOT_SUPPORTED} if the + * feature is not supported or an error code + * + * @return whether the chipset supports the LE Periodic Advertising Sync Transfer Sender feature + */ + @RequiresNoPermission + public @LeFeatureReturnValues int isLePeriodicAdvertisingSyncTransferSenderSupported() { + if (!getLeAccess()) { + return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; + } + try { + mServiceLock.readLock().lock(); + if (mService != null) { + return mService.isLePeriodicAdvertisingSyncTransferSenderSupported(); + } + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } finally { + mServiceLock.readLock().unlock(); + } + return BluetoothStatusCodes.ERROR_UNKNOWN; + } + /** * Return the maximum LE advertising data length in bytes, * if LE Extended Advertising feature is supported, 0 otherwise. diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java index 9caeb297ace3..6e918bd6243d 100644 --- a/core/java/android/bluetooth/BluetoothDevice.java +++ b/core/java/android/bluetooth/BluetoothDevice.java @@ -1186,6 +1186,11 @@ 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) { @@ -1335,7 +1340,10 @@ public final class BluetoothDevice implements Parcelable, Attributable { if (alias == null) { return getName(); } - return alias; + return alias + .replace('\t', ' ') + .replace('\n', ' ') + .replace('\r', ' '); } catch (RemoteException e) { Log.e(TAG, "", e); } diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java index ca898bd6a5ef..4e7c01ad2db1 100644 --- a/core/java/android/bluetooth/BluetoothGatt.java +++ b/core/java/android/bluetooth/BluetoothGatt.java @@ -16,6 +16,8 @@ package android.bluetooth; +import android.annotation.IntDef; +import android.annotation.NonNull; import android.annotation.RequiresNoPermission; import android.annotation.RequiresPermission; import android.annotation.SuppressLint; @@ -29,6 +31,8 @@ import android.os.ParcelUuid; import android.os.RemoteException; import android.util.Log; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.List; import java.util.UUID; @@ -140,27 +144,6 @@ public final class BluetoothGatt implements BluetoothProfile { public static final int CONNECTION_PRIORITY_LOW_POWER = 2; /** - * A GATT writeCharacteristic request is started successfully. - * - * @hide - */ - public static final int GATT_WRITE_REQUEST_SUCCESS = 0; - - /** - * A GATT writeCharacteristic request failed to start. - * - * @hide - */ - public static final int GATT_WRITE_REQUEST_FAIL = 1; - - /** - * A GATT writeCharacteristic request is issued to a busy remote device. - * - * @hide - */ - public static final int GATT_WRITE_REQUEST_BUSY = 2; - - /** * No authentication required. * * @hide @@ -430,6 +413,9 @@ public final class BluetoothGatt implements BluetoothProfile { if (callback != null) { if (status == 0) characteristic.setValue(value); callback.onCharacteristicRead(BluetoothGatt.this, characteristic, + value, status); + // Keep calling deprecated callback to maintain app compatibility + callback.onCharacteristicRead(BluetoothGatt.this, characteristic, status); } } @@ -443,7 +429,8 @@ public final class BluetoothGatt implements BluetoothProfile { */ @Override @SuppressLint("AndroidFrameworkRequiresPermission") - public void onCharacteristicWrite(String address, int status, int handle) { + public void onCharacteristicWrite(String address, int status, int handle, + byte[] value) { if (VDBG) { Log.d(TAG, "onCharacteristicWrite() - Device=" + address + " handle=" + handle + " Status=" + status); @@ -467,12 +454,13 @@ public final class BluetoothGatt implements BluetoothProfile { try { final int authReq = (mAuthRetryState == AUTH_RETRY_STATE_IDLE) ? AUTHENTICATION_NO_MITM : AUTHENTICATION_MITM; - int requestStatus = GATT_WRITE_REQUEST_FAIL; + int requestStatus = BluetoothStatusCodes.ERROR_UNKNOWN; for (int i = 0; i < WRITE_CHARACTERISTIC_MAX_RETRIES; i++) { requestStatus = mService.writeCharacteristic(mClientIf, address, handle, characteristic.getWriteType(), authReq, - characteristic.getValue(), mAttributionSource); - if (requestStatus != GATT_WRITE_REQUEST_BUSY) { + value, mAttributionSource); + if (requestStatus + != BluetoothStatusCodes.ERROR_GATT_WRITE_REQUEST_BUSY) { break; } try { @@ -488,7 +476,6 @@ public final class BluetoothGatt implements BluetoothProfile { } mAuthRetryState = AUTH_RETRY_STATE_IDLE; - runOrQueueCallback(new Runnable() { @Override public void run() { @@ -525,6 +512,9 @@ public final class BluetoothGatt implements BluetoothProfile { if (callback != null) { characteristic.setValue(value); callback.onCharacteristicChanged(BluetoothGatt.this, + characteristic, value); + // Keep calling deprecated callback to maintain app compatibility + callback.onCharacteristicChanged(BluetoothGatt.this, characteristic); } } @@ -578,6 +568,9 @@ public final class BluetoothGatt implements BluetoothProfile { final BluetoothGattCallback callback = mCallback; if (callback != null) { if (status == 0) descriptor.setValue(value); + callback.onDescriptorRead(BluetoothGatt.this, descriptor, status, + value); + // Keep calling deprecated callback to maintain app compatibility callback.onDescriptorRead(BluetoothGatt.this, descriptor, status); } } @@ -590,7 +583,8 @@ public final class BluetoothGatt implements BluetoothProfile { */ @Override @SuppressLint("AndroidFrameworkRequiresPermission") - public void onDescriptorWrite(String address, int status, int handle) { + public void onDescriptorWrite(String address, int status, int handle, + byte[] value) { if (VDBG) { Log.d(TAG, "onDescriptorWrite() - Device=" + address + " handle=" + handle); @@ -614,7 +608,7 @@ public final class BluetoothGatt implements BluetoothProfile { final int authReq = (mAuthRetryState == AUTH_RETRY_STATE_IDLE) ? AUTHENTICATION_NO_MITM : AUTHENTICATION_MITM; mService.writeDescriptor(mClientIf, address, handle, - authReq, descriptor.getValue(), mAttributionSource); + authReq, value, mAttributionSource); mAuthRetryState++; return; } catch (RemoteException e) { @@ -1194,8 +1188,8 @@ public final class BluetoothGatt implements BluetoothProfile { * Reads the requested characteristic from the associated remote device. * * <p>This is an asynchronous operation. The result of the read operation - * is reported by the {@link BluetoothGattCallback#onCharacteristicRead} - * callback. + * is reported by the {@link BluetoothGattCallback#onCharacteristicRead(BluetoothGatt, + * BluetoothGattCharacteristic, byte[], int)} callback. * * @param characteristic Characteristic to read from the remote device * @return true, if the read operation was initiated successfully @@ -1240,8 +1234,8 @@ public final class BluetoothGatt implements BluetoothProfile { * Reads the characteristic using its UUID from the associated remote device. * * <p>This is an asynchronous operation. The result of the read operation - * is reported by the {@link BluetoothGattCallback#onCharacteristicRead} - * callback. + * is reported by the {@link BluetoothGattCallback#onCharacteristicRead(BluetoothGatt, + * BluetoothGattCharacteristic, byte[], int)} callback. * * @param uuid UUID of characteristic to read from the remote device * @return true, if the read operation was initiated successfully @@ -1284,40 +1278,94 @@ public final class BluetoothGatt implements BluetoothProfile { * * @param characteristic Characteristic to write on the remote device * @return true, if the write operation was initiated successfully + * @throws IllegalArgumentException if characteristic or its value are null + * + * @deprecated Use {@link BluetoothGatt#writeCharacteristic(BluetoothGattCharacteristic, byte[], + * int)} as this is not memory safe. */ + @Deprecated @RequiresLegacyBluetoothPermission @RequiresBluetoothConnectPermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean writeCharacteristic(BluetoothGattCharacteristic characteristic) { - if ((characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_WRITE) == 0 - && (characteristic.getProperties() - & BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) == 0) { + try { + return writeCharacteristic(characteristic, characteristic.getValue(), + characteristic.getWriteType()) == BluetoothStatusCodes.SUCCESS; + } catch (Exception e) { return false; } + } + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(value = { + BluetoothStatusCodes.SUCCESS, + BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION, + BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_PRIVILEGED_PERMISSION, + BluetoothStatusCodes.ERROR_DEVICE_NOT_CONNECTED, + BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND, + BluetoothStatusCodes.ERROR_GATT_WRITE_NOT_ALLOWED, + BluetoothStatusCodes.ERROR_GATT_WRITE_REQUEST_BUSY, + BluetoothStatusCodes.ERROR_UNKNOWN + }) + public @interface WriteOperationReturnValues{} + /** + * Writes a given characteristic and its values to the associated remote device. + * + * <p>Once the write operation has been completed, the + * {@link BluetoothGattCallback#onCharacteristicWrite} callback is invoked, + * reporting the result of the operation. + * + * @param characteristic Characteristic to write on the remote device + * @return whether the characteristic was successfully written to + * @throws IllegalArgumentException if characteristic or value are null + */ + @RequiresBluetoothConnectPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) + @WriteOperationReturnValues + public int writeCharacteristic(@NonNull BluetoothGattCharacteristic characteristic, + @NonNull byte[] value, int writeType) { + if (characteristic == null) { + throw new IllegalArgumentException("characteristic must not be null"); + } + if (value == null) { + throw new IllegalArgumentException("value must not be null"); + } if (VDBG) Log.d(TAG, "writeCharacteristic() - uuid: " + characteristic.getUuid()); - if (mService == null || mClientIf == 0 || characteristic.getValue() == null) return false; + if ((characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_WRITE) == 0 + && (characteristic.getProperties() + & BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) == 0) { + return BluetoothStatusCodes.ERROR_GATT_WRITE_NOT_ALLOWED; + } + if (mService == null || mClientIf == 0) { + return BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND; + } BluetoothGattService service = characteristic.getService(); - if (service == null) return false; + if (service == null) { + throw new IllegalArgumentException("Characteristic must have a non-null service"); + } BluetoothDevice device = service.getDevice(); - if (device == null) return false; + if (device == null) { + throw new IllegalArgumentException("Service must have a non-null device"); + } synchronized (mDeviceBusyLock) { if (mDeviceBusy) { - return false; + return BluetoothStatusCodes.ERROR_GATT_WRITE_REQUEST_BUSY; } mDeviceBusy = true; } - int requestStatus = GATT_WRITE_REQUEST_FAIL; + int requestStatus = BluetoothStatusCodes.ERROR_UNKNOWN; try { for (int i = 0; i < WRITE_CHARACTERISTIC_MAX_RETRIES; i++) { requestStatus = mService.writeCharacteristic(mClientIf, device.getAddress(), - characteristic.getInstanceId(), characteristic.getWriteType(), - AUTHENTICATION_NONE, characteristic.getValue(), mAttributionSource); - if (requestStatus != GATT_WRITE_REQUEST_BUSY) { + characteristic.getInstanceId(), writeType, AUTHENTICATION_NONE, value, + mAttributionSource); + if (requestStatus != BluetoothStatusCodes.ERROR_GATT_WRITE_REQUEST_BUSY) { break; } try { @@ -1330,10 +1378,10 @@ public final class BluetoothGatt implements BluetoothProfile { synchronized (mDeviceBusyLock) { mDeviceBusy = false; } - return false; + throw e.rethrowFromSystemServer(); } - return requestStatus == GATT_WRITE_REQUEST_SUCCESS; + return requestStatus; } /** @@ -1384,45 +1432,86 @@ public final class BluetoothGatt implements BluetoothProfile { /** * Write the value of a given descriptor to the associated remote device. * - * <p>A {@link BluetoothGattCallback#onDescriptorWrite} callback is - * triggered to report the result of the write operation. + * <p>A {@link BluetoothGattCallback#onDescriptorWrite} callback is triggered to report the + * result of the write operation. * * @param descriptor Descriptor to write to the associated remote device * @return true, if the write operation was initiated successfully + * @throws IllegalArgumentException if descriptor or its value are null + * + * @deprecated Use {@link BluetoothGatt#writeDescriptor(BluetoothGattDescriptor, byte[])} as + * this is not memory safe. */ + @Deprecated @RequiresLegacyBluetoothPermission @RequiresBluetoothConnectPermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean writeDescriptor(BluetoothGattDescriptor descriptor) { + try { + return writeDescriptor(descriptor, descriptor.getValue()) + == BluetoothStatusCodes.SUCCESS; + } catch (Exception e) { + return false; + } + } + + /** + * Write the value of a given descriptor to the associated remote device. + * + * <p>A {@link BluetoothGattCallback#onDescriptorWrite} callback is triggered to report the + * result of the write operation. + * + * @param descriptor Descriptor to write to the associated remote device + * @return true, if the write operation was initiated successfully + * @throws IllegalArgumentException if descriptor or value are null + */ + @RequiresBluetoothConnectPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) + @WriteOperationReturnValues + public int writeDescriptor(@NonNull BluetoothGattDescriptor descriptor, + @NonNull byte[] value) { + if (descriptor == null) { + throw new IllegalArgumentException("descriptor must not be null"); + } + if (value == null) { + throw new IllegalArgumentException("value must not be null"); + } if (VDBG) Log.d(TAG, "writeDescriptor() - uuid: " + descriptor.getUuid()); - if (mService == null || mClientIf == 0 || descriptor.getValue() == null) return false; + if (mService == null || mClientIf == 0) { + return BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND; + } BluetoothGattCharacteristic characteristic = descriptor.getCharacteristic(); - if (characteristic == null) return false; + if (characteristic == null) { + throw new IllegalArgumentException("Descriptor must have a non-null characteristic"); + } BluetoothGattService service = characteristic.getService(); - if (service == null) return false; + if (service == null) { + throw new IllegalArgumentException("Characteristic must have a non-null service"); + } BluetoothDevice device = service.getDevice(); - if (device == null) return false; + if (device == null) { + throw new IllegalArgumentException("Service must have a non-null device"); + } synchronized (mDeviceBusyLock) { - if (mDeviceBusy) return false; + if (mDeviceBusy) return BluetoothStatusCodes.ERROR_GATT_WRITE_REQUEST_BUSY; mDeviceBusy = true; } try { - mService.writeDescriptor(mClientIf, device.getAddress(), descriptor.getInstanceId(), - AUTHENTICATION_NONE, descriptor.getValue(), mAttributionSource); + return mService.writeDescriptor(mClientIf, device.getAddress(), + descriptor.getInstanceId(), AUTHENTICATION_NONE, value, mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "", e); synchronized (mDeviceBusyLock) { mDeviceBusy = false; } - return false; + e.rethrowFromSystemServer(); } - - return true; + return BluetoothStatusCodes.ERROR_UNKNOWN; } /** @@ -1431,9 +1520,9 @@ public final class BluetoothGatt implements BluetoothProfile { * <p>Once a reliable write transaction has been initiated, all calls * to {@link #writeCharacteristic} are sent to the remote device for * verification and queued up for atomic execution. The application will - * receive an {@link BluetoothGattCallback#onCharacteristicWrite} callback - * in response to every {@link #writeCharacteristic} call and is responsible - * for verifying if the value has been transmitted accurately. + * receive a {@link BluetoothGattCallback#onCharacteristicWrite} callback in response to every + * {@link #writeCharacteristic(BluetoothGattCharacteristic, byte[], int)} call and is + * responsible for verifying if the value has been transmitted accurately. * * <p>After all characteristics have been queued up and verified, * {@link #executeReliableWrite} will execute all writes. If a characteristic @@ -1530,9 +1619,9 @@ public final class BluetoothGatt implements BluetoothProfile { * Enable or disable notifications/indications for a given characteristic. * * <p>Once notifications are enabled for a characteristic, a - * {@link BluetoothGattCallback#onCharacteristicChanged} callback will be - * triggered if the remote device indicates that the given characteristic - * has changed. + * {@link BluetoothGattCallback#onCharacteristicChanged(BluetoothGatt, + * BluetoothGattCharacteristic, byte[])} callback will be triggered if the remote device + * indicates that the given characteristic has changed. * * @param characteristic The characteristic for which to enable notifications * @param enable Set to true to enable notifications/indications diff --git a/core/java/android/bluetooth/BluetoothGattCallback.java b/core/java/android/bluetooth/BluetoothGattCallback.java index 1c40cff076f6..d0a5a1e729fe 100644 --- a/core/java/android/bluetooth/BluetoothGattCallback.java +++ b/core/java/android/bluetooth/BluetoothGattCallback.java @@ -80,16 +80,34 @@ public abstract class BluetoothGattCallback { /** * Callback reporting the result of a characteristic read operation. * - * @param gatt GATT client invoked {@link BluetoothGatt#readCharacteristic} + * @param gatt GATT client invoked + * {@link BluetoothGatt#readCharacteristic(BluetoothGattCharacteristic)} * @param characteristic Characteristic that was read from the associated remote device. - * @param status {@link BluetoothGatt#GATT_SUCCESS} if the read operation was completed - * successfully. + * @param status {@link BluetoothGatt#GATT_SUCCESS} if the read operation was completed + * successfully. + * @deprecated Use {@link BluetoothGattCallback#onCharacteristicRead(BluetoothGatt, + * BluetoothGattCharacteristic, byte[], int)} as it is memory safe */ + @Deprecated public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { } /** + * Callback reporting the result of a characteristic read operation. + * + * @param gatt GATT client invoked + * {@link BluetoothGatt#readCharacteristic(BluetoothGattCharacteristic)} + * @param characteristic Characteristic that was read from the associated remote device. + * @param value the value of the characteristic + * @param status {@link BluetoothGatt#GATT_SUCCESS} if the read operation was completed + * successfully. + */ + public void onCharacteristicRead(@NonNull BluetoothGatt gatt, @NonNull + BluetoothGattCharacteristic characteristic, @NonNull byte[] value, int status) { + } + + /** * Callback indicating the result of a characteristic write operation. * * <p>If this callback is invoked while a reliable write transaction is @@ -98,10 +116,13 @@ public abstract class BluetoothGattCallback { * value to the desired value to be written. If the values don't match, * the application must abort the reliable write transaction. * - * @param gatt GATT client invoked {@link BluetoothGatt#writeCharacteristic} + * @param gatt GATT client that invoked + * {@link BluetoothGatt#writeCharacteristic(BluetoothGattCharacteristic, + * byte[], int)} * @param characteristic Characteristic that was written to the associated remote device. - * @param status The result of the write operation {@link BluetoothGatt#GATT_SUCCESS} if the - * operation succeeds. + * @param status The result of the write operation {@link BluetoothGatt#GATT_SUCCESS} if + * the + * operation succeeds. */ public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { @@ -110,33 +131,68 @@ public abstract class BluetoothGattCallback { /** * Callback triggered as a result of a remote characteristic notification. * - * @param gatt GATT client the characteristic is associated with + * @param gatt GATT client the characteristic is associated with * @param characteristic Characteristic that has been updated as a result of a remote - * notification event. + * notification event. + * @deprecated Use {@link BluetoothGattCallback#onCharacteristicChanged(BluetoothGatt, + * BluetoothGattCharacteristic, byte[])} as it is memory safe by providing the characteristic + * value at the time of notification. */ + @Deprecated public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { } /** + * Callback triggered as a result of a remote characteristic notification. Note that the value + * within the characteristic object may have changed since receiving the remote characteristic + * notification, so check the parameter value for the value at the time of notification. + * + * @param gatt GATT client the characteristic is associated with + * @param characteristic Characteristic that has been updated as a result of a remote + * notification event. + * @param value notified characteristic value + */ + public void onCharacteristicChanged(@NonNull BluetoothGatt gatt, + @NonNull BluetoothGattCharacteristic characteristic, @NonNull byte[] value) { + } + + /** * Callback reporting the result of a descriptor read operation. * - * @param gatt GATT client invoked {@link BluetoothGatt#readDescriptor} + * @param gatt GATT client invoked {@link BluetoothGatt#readDescriptor} * @param descriptor Descriptor that was read from the associated remote device. - * @param status {@link BluetoothGatt#GATT_SUCCESS} if the read operation was completed - * successfully + * @param status {@link BluetoothGatt#GATT_SUCCESS} if the read operation was completed + * successfully + * @deprecated Use {@link BluetoothGattCallback#onDescriptorRead(BluetoothGatt, + * BluetoothGattDescriptor, int, byte[])} as it is memory safe by providing the descriptor + * value at the time it was read. */ + @Deprecated public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { } /** + * Callback reporting the result of a descriptor read operation. + * + * @param gatt GATT client invoked {@link BluetoothGatt#readDescriptor} + * @param descriptor Descriptor that was read from the associated remote device. + * @param status {@link BluetoothGatt#GATT_SUCCESS} if the read operation was completed + * successfully + * @param value the descriptor value at the time of the read operation + */ + public void onDescriptorRead(@NonNull BluetoothGatt gatt, + @NonNull BluetoothGattDescriptor descriptor, int status, @NonNull byte[] value) { + } + + /** * Callback indicating the result of a descriptor write operation. * - * @param gatt GATT client invoked {@link BluetoothGatt#writeDescriptor} + * @param gatt GATT client invoked {@link BluetoothGatt#writeDescriptor} * @param descriptor Descriptor that was writte to the associated remote device. - * @param status The result of the write operation {@link BluetoothGatt#GATT_SUCCESS} if the - * operation succeeds. + * @param status The result of the write operation {@link BluetoothGatt#GATT_SUCCESS} if the + * operation succeeds. */ public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { diff --git a/core/java/android/bluetooth/BluetoothGattCharacteristic.java b/core/java/android/bluetooth/BluetoothGattCharacteristic.java index 8a7d4baf5add..c5e986e895b2 100644 --- a/core/java/android/bluetooth/BluetoothGattCharacteristic.java +++ b/core/java/android/bluetooth/BluetoothGattCharacteristic.java @@ -451,8 +451,8 @@ public class BluetoothGattCharacteristic implements Parcelable { * Set the write type for this characteristic * * <p>Setting the write type of a characteristic determines how the - * {@link BluetoothGatt#writeCharacteristic} function write this - * characteristic. + * {@link BluetoothGatt#writeCharacteristic(BluetoothGattCharacteristic, byte[], int)} function + * write this characteristic. * * @param writeType The write type to for this characteristic. Can be one of: {@link * #WRITE_TYPE_DEFAULT}, {@link #WRITE_TYPE_NO_RESPONSE} or {@link #WRITE_TYPE_SIGNED}. @@ -504,7 +504,10 @@ public class BluetoothGattCharacteristic implements Parcelable { * operation or if a characteristic update notification has been received. * * @return Cached value of the characteristic + * + * @deprecated Use {@link BluetoothGatt#readCharacteristic(BluetoothGattCharacteristic)} instead */ + @Deprecated public byte[] getValue() { return mValue; } @@ -521,7 +524,11 @@ public class BluetoothGattCharacteristic implements Parcelable { * @param formatType The format type used to interpret the characteristic value. * @param offset Offset at which the integer value can be found. * @return Cached value of the characteristic or null of offset exceeds value size. + * + * @deprecated Use {@link BluetoothGatt#readCharacteristic(BluetoothGattCharacteristic)} to get + * the characteristic value */ + @Deprecated public Integer getIntValue(int formatType, int offset) { if ((offset + getTypeLen(formatType)) > mValue.length) return null; @@ -558,7 +565,11 @@ public class BluetoothGattCharacteristic implements Parcelable { * @param offset Offset at which the float value can be found. * @return Cached value of the characteristic at a given offset or null if the requested offset * exceeds the value size. + * + * @deprecated Use {@link BluetoothGatt#readCharacteristic(BluetoothGattCharacteristic)} to get + * the characteristic value */ + @Deprecated public Float getFloatValue(int formatType, int offset) { if ((offset + getTypeLen(formatType)) > mValue.length) return null; @@ -580,7 +591,11 @@ public class BluetoothGattCharacteristic implements Parcelable { * * @param offset Offset at which the string value can be found. * @return Cached value of the characteristic + * + * @deprecated Use {@link BluetoothGatt#readCharacteristic(BluetoothGattCharacteristic)} to get + * the characteristic value */ + @Deprecated public String getStringValue(int offset) { if (mValue == null || offset > mValue.length) return null; byte[] strBytes = new byte[mValue.length - offset]; @@ -599,7 +614,11 @@ public class BluetoothGattCharacteristic implements Parcelable { * @param value New value for this characteristic * @return true if the locally stored value has been set, false if the requested value could not * be stored locally. + * + * @deprecated Pass the characteristic value directly into + * {@link BluetoothGatt#writeCharacteristic(BluetoothGattCharacteristic, byte[], int)} */ + @Deprecated public boolean setValue(byte[] value) { mValue = value; return true; @@ -613,7 +632,11 @@ public class BluetoothGattCharacteristic implements Parcelable { * @param formatType Integer format type used to transform the value parameter * @param offset Offset at which the value should be placed * @return true if the locally stored value has been set + * + * @deprecated Pass the characteristic value directly into + * {@link BluetoothGatt#writeCharacteristic(BluetoothGattCharacteristic, byte[], int)} */ + @Deprecated public boolean setValue(int value, int formatType, int offset) { int len = offset + getTypeLen(formatType); if (mValue == null) mValue = new byte[len]; @@ -660,7 +683,11 @@ public class BluetoothGattCharacteristic implements Parcelable { * @param formatType Float format type used to transform the value parameter * @param offset Offset at which the value should be placed * @return true if the locally stored value has been set + * + * @deprecated Pass the characteristic value directly into + * {@link BluetoothGatt#writeCharacteristic(BluetoothGattCharacteristic, byte[], int)} */ + @Deprecated public boolean setValue(int mantissa, int exponent, int formatType, int offset) { int len = offset + getTypeLen(formatType); if (mValue == null) mValue = new byte[len]; @@ -697,7 +724,11 @@ public class BluetoothGattCharacteristic implements Parcelable { * * @param value New value for this characteristic * @return true if the locally stored value has been set + * + * @deprecated Pass the characteristic value directly into + * {@link BluetoothGatt#writeCharacteristic(BluetoothGattCharacteristic, byte[], int)} */ + @Deprecated public boolean setValue(String value) { mValue = value.getBytes(); return true; diff --git a/core/java/android/bluetooth/BluetoothGattDescriptor.java b/core/java/android/bluetooth/BluetoothGattDescriptor.java index ed5ea0873020..a35d5b99fd7b 100644 --- a/core/java/android/bluetooth/BluetoothGattDescriptor.java +++ b/core/java/android/bluetooth/BluetoothGattDescriptor.java @@ -260,7 +260,10 @@ public class BluetoothGattDescriptor implements Parcelable { * operation. * * @return Cached value of the descriptor + * + * @deprecated Use {@link BluetoothGatt#readDescriptor(BluetoothGattDescriptor)} instead */ + @Deprecated public byte[] getValue() { return mValue; } @@ -276,7 +279,11 @@ public class BluetoothGattDescriptor implements Parcelable { * @param value New value for this descriptor * @return true if the locally stored value has been set, false if the requested value could not * be stored locally. + * + * @deprecated Pass the descriptor value directly into + * {@link BluetoothGatt#writeDescriptor(BluetoothGattDescriptor, byte[])} */ + @Deprecated public boolean setValue(byte[] value) { mValue = value; return true; diff --git a/core/java/android/bluetooth/BluetoothHeadsetClient.java b/core/java/android/bluetooth/BluetoothHeadsetClient.java index 83108d22e0c3..a5a247087209 100644 --- a/core/java/android/bluetooth/BluetoothHeadsetClient.java +++ b/core/java/android/bluetooth/BluetoothHeadsetClient.java @@ -817,7 +817,7 @@ public final class BluetoothHeadsetClient implements BluetoothProfile { @RequiresBluetoothConnectPermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public Bundle getCurrentAgEvents(BluetoothDevice device) { - if (DBG) log("getCurrentCalls()"); + if (DBG) log("getCurrentAgEvents()"); final IBluetoothHeadsetClient service = getService(); if (service != null && isEnabled() && isValidDevice(device)) { diff --git a/core/java/android/bluetooth/BluetoothManager.java b/core/java/android/bluetooth/BluetoothManager.java index b5df4db2460d..20152f3d2471 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 static AttributionSource sAttributionSource = null; + private final AttributionSource mAttributionSource; private final BluetoothAdapter mAdapter; /** * @hide */ public BluetoothManager(Context context) { - sAttributionSource = resolveAttributionSource(context); - mAdapter = BluetoothAdapter.createAdapter(sAttributionSource); + mAttributionSource = resolveAttributionSource(context); + mAdapter = BluetoothAdapter.createAdapter(mAttributionSource); } /** {@hide} */ @@ -79,9 +79,6 @@ public final class BluetoothManager { if (context != null) { res = context.getAttributionSource(); } - else if (sAttributionSource != null) { - return sAttributionSource; - } if (res == null) { res = ActivityThread.currentAttributionSource(); } @@ -201,8 +198,8 @@ public final class BluetoothManager { IBluetoothGatt iGatt = managerService.getBluetoothGatt(); if (iGatt == null) return devices; devices = Attributable.setAttributionSource( - iGatt.getDevicesMatchingConnectionStates(states, sAttributionSource), - sAttributionSource); + iGatt.getDevicesMatchingConnectionStates(states, mAttributionSource), + mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "", e); } diff --git a/core/java/android/bluetooth/BluetoothStatusCodes.java b/core/java/android/bluetooth/BluetoothStatusCodes.java index 3e46c498e336..ca01784efd88 100644 --- a/core/java/android/bluetooth/BluetoothStatusCodes.java +++ b/core/java/android/bluetooth/BluetoothStatusCodes.java @@ -79,6 +79,33 @@ public final class BluetoothStatusCodes { public static final int ERROR_MISSING_BLUETOOTH_SCAN_PERMISSION = 7; /** + * Error code indicating that the caller does not have the + * {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} permission + */ + public static final int ERROR_MISSING_BLUETOOTH_PRIVILEGED_PERMISSION = 8; + + /** + * Error code indicating that the profile service is not bound. You can bind a profile service + * by calling {@link BluetoothAdapter#getProfileProxy} + */ + public static final int ERROR_PROFILE_SERVICE_NOT_BOUND = 9; + + /** + * Error code indicating that the feature is not supported. + */ + public static final int ERROR_FEATURE_NOT_SUPPORTED = 10; + + /** + * A GATT writeCharacteristic request is not permitted on the remote device. + */ + public static final int ERROR_GATT_WRITE_NOT_ALLOWED = 101; + + /** + * A GATT writeCharacteristic request is issued to a busy remote device. + */ + public static final int ERROR_GATT_WRITE_REQUEST_BUSY = 102; + + /** * If another application has already requested {@link OobData} then another fetch will be * disallowed until the callback is removed. * diff --git a/core/java/android/bluetooth/UidTraffic.java b/core/java/android/bluetooth/UidTraffic.java index 2ee786a59091..9982fa6121e4 100644 --- a/core/java/android/bluetooth/UidTraffic.java +++ b/core/java/android/bluetooth/UidTraffic.java @@ -15,6 +15,7 @@ */ package android.bluetooth; +import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; @@ -23,27 +24,27 @@ import android.os.Parcelable; * * @hide */ -public class UidTraffic implements Cloneable, Parcelable { +@SystemApi(client = SystemApi.Client.PRIVILEGED_APPS) +public final class UidTraffic implements Cloneable, Parcelable { private final int mAppUid; private long mRxBytes; private long mTxBytes; - public UidTraffic(int appUid) { - mAppUid = appUid; - } - + /** @hide */ public UidTraffic(int appUid, long rx, long tx) { mAppUid = appUid; mRxBytes = rx; mTxBytes = tx; } - UidTraffic(Parcel in) { + /** @hide */ + private UidTraffic(Parcel in) { mAppUid = in.readInt(); mRxBytes = in.readLong(); mTxBytes = in.readLong(); } + /** @hide */ @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(mAppUid); @@ -51,44 +52,60 @@ public class UidTraffic implements Cloneable, Parcelable { dest.writeLong(mTxBytes); } + /** @hide */ public void setRxBytes(long bytes) { mRxBytes = bytes; } + /** @hide */ public void setTxBytes(long bytes) { mTxBytes = bytes; } + /** @hide */ public void addRxBytes(long bytes) { mRxBytes += bytes; } + /** @hide */ public void addTxBytes(long bytes) { mTxBytes += bytes; } + /** + * @return corresponding app Uid + */ public int getUid() { return mAppUid; } + /** + * @return rx bytes count + */ public long getRxBytes() { return mRxBytes; } + /** + * @return tx bytes count + */ public long getTxBytes() { return mTxBytes; } + /** @hide */ @Override public int describeContents() { return 0; } + /** @hide */ @Override public UidTraffic clone() { return new UidTraffic(mAppUid, mRxBytes, mTxBytes); } + /** @hide */ @Override public String toString() { return "UidTraffic{mAppUid=" + mAppUid + ", mRxBytes=" + mRxBytes + ", mTxBytes=" diff --git a/core/java/android/bluetooth/le/BluetoothLeUtils.java b/core/java/android/bluetooth/le/BluetoothLeUtils.java index 6381f557c1b2..ed50b09597bb 100644 --- a/core/java/android/bluetooth/le/BluetoothLeUtils.java +++ b/core/java/android/bluetooth/le/BluetoothLeUtils.java @@ -24,6 +24,7 @@ import java.util.Iterator; import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.UUID; /** * Helper class for Bluetooth LE utils. @@ -137,4 +138,21 @@ public class BluetoothLeUtils { } } + /** + * Compares two UUIDs with a UUID mask. + * + * @param data first {@link #UUID} to compare. + * @param uuid second {@link #UUID} to compare. + * @param mask mask {@link #UUID}. + * @return true if both UUIDs are equals when masked, false otherwise. + */ + static boolean maskedEquals(UUID data, UUID uuid, UUID mask) { + if (mask == null) { + return Objects.equals(data, uuid); + } + return (data.getLeastSignificantBits() & mask.getLeastSignificantBits()) + == (uuid.getLeastSignificantBits() & mask.getLeastSignificantBits()) + && (data.getMostSignificantBits() & mask.getMostSignificantBits()) + == (uuid.getMostSignificantBits() & mask.getMostSignificantBits()); + } } diff --git a/core/java/android/bluetooth/le/ScanFilter.java b/core/java/android/bluetooth/le/ScanFilter.java index 8ff018121ab0..b059193ae03f 100644 --- a/core/java/android/bluetooth/le/ScanFilter.java +++ b/core/java/android/bluetooth/le/ScanFilter.java @@ -28,8 +28,6 @@ import android.os.Parcel; import android.os.ParcelUuid; import android.os.Parcelable; -import com.android.internal.util.BitUtils; - import java.util.Arrays; import java.util.List; import java.util.Objects; @@ -448,7 +446,7 @@ public final class ScanFilter implements Parcelable { // Check if the uuid pattern matches the particular service uuid. private static boolean matchesServiceUuid(UUID uuid, UUID mask, UUID data) { - return BitUtils.maskedEquals(data, uuid, mask); + return BluetoothLeUtils.maskedEquals(data, uuid, mask); } /** @@ -478,7 +476,7 @@ public final class ScanFilter implements Parcelable { // Check if the solicitation uuid pattern matches the particular service solicitation uuid. private static boolean matchesServiceSolicitationUuid(UUID solicitationUuid, UUID solicitationUuidMask, UUID data) { - return BitUtils.maskedEquals(data, solicitationUuid, solicitationUuidMask); + return BluetoothLeUtils.maskedEquals(data, solicitationUuid, solicitationUuidMask); } // Check whether the data pattern matches the parsed data. diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 2fd437db14a7..e781c2fce2b2 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -31,6 +31,7 @@ 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; @@ -1146,6 +1147,10 @@ public class Intent implements Parcelable, Cloneable { * numbers. Applications can <strong>dial</strong> emergency numbers using * {@link #ACTION_DIAL}, however. * + * <p>Note: An app filling the {@link android.app.role.RoleManager#ROLE_DIALER} role should use + * {@link android.telecom.TelecomManager#placeCall(Uri, Bundle)} to place calls rather than + * relying on this intent. + * * <p>Note: if you app targets {@link android.os.Build.VERSION_CODES#M M} * and above and declares as using the {@link android.Manifest.permission#CALL_PHONE} * permission which is not granted, then attempting to use this action will @@ -11461,6 +11466,16 @@ 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/OWNERS b/core/java/android/content/OWNERS index c7f92c9714f0..660368aeca14 100644 --- a/core/java/android/content/OWNERS +++ b/core/java/android/content/OWNERS @@ -2,11 +2,9 @@ per-file Context.java = * per-file ContextWrapper.java = * per-file Content* = file:/services/core/java/com/android/server/am/OWNERS -per-file IntentFilter.java = toddke@google.com -per-file IntentFilter.java = patb@google.com +per-file IntentFilter.java = file:/PACKAGE_MANAGER_OWNERS per-file IntentFilter.java = file:/services/core/java/com/android/server/am/OWNERS -per-file Intent.java = toddke@google.com -per-file Intent.java = patb@google.com +per-file Intent.java = file:/PACKAGE_MANAGER_OWNERS per-file Intent.java = file:/services/core/java/com/android/server/wm/OWNERS per-file Intent.java = file:/services/core/java/com/android/server/am/OWNERS per-file AutofillOptions* = file:/core/java/android/service/autofill/OWNERS diff --git a/core/java/android/content/om/OWNERS b/core/java/android/content/om/OWNERS index 91a0abfe711a..3669817e9844 100644 --- a/core/java/android/content/om/OWNERS +++ b/core/java/android/content/om/OWNERS @@ -3,4 +3,4 @@ toddke@android.com toddke@google.com patb@google.com -rtmitchell@google.com +zyy@google.com diff --git a/core/java/android/content/res/OWNERS b/core/java/android/content/res/OWNERS index bc2355c6af5e..d12d920b2a54 100644 --- a/core/java/android/content/res/OWNERS +++ b/core/java/android/content/res/OWNERS @@ -3,4 +3,4 @@ toddke@android.com toddke@google.com patb@google.com -rtmitchell@google.com +zyy@google.com diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java index 7ef5bac092f6..86052484eaf6 100644 --- a/core/java/android/net/IpSecAlgorithm.java +++ b/core/java/android/net/IpSecAlgorithm.java @@ -232,11 +232,10 @@ public final class IpSecAlgorithm implements Parcelable { ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_HMAC_SHA512, SDK_VERSION_ZERO); ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_CRYPT_AES_GCM, SDK_VERSION_ZERO); - // STOPSHIP: b/170424293 Use Build.VERSION_CODES.S when it is defined - ALGO_TO_REQUIRED_FIRST_SDK.put(CRYPT_AES_CTR, Build.VERSION_CODES.R + 1); - ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_AES_XCBC, Build.VERSION_CODES.R + 1); - ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_AES_CMAC, Build.VERSION_CODES.R + 1); - ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_CRYPT_CHACHA20_POLY1305, Build.VERSION_CODES.R + 1); + ALGO_TO_REQUIRED_FIRST_SDK.put(CRYPT_AES_CTR, Build.VERSION_CODES.S); + ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_AES_XCBC, Build.VERSION_CODES.S); + ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_AES_CMAC, Build.VERSION_CODES.S); + ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_CRYPT_CHACHA20_POLY1305, Build.VERSION_CODES.S); } private static final Set<String> ENABLED_ALGOS = diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index 1d07a0330bc5..eb8f43e3d073 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -220,8 +220,10 @@ public class NetworkIdentity implements Comparable<NetworkIdentity> { String networkId = null; boolean roaming = !snapshot.getNetworkCapabilities().hasCapability( NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING); - boolean metered = !snapshot.getNetworkCapabilities().hasCapability( - NetworkCapabilities.NET_CAPABILITY_NOT_METERED); + boolean metered = !(snapshot.getNetworkCapabilities().hasCapability( + NetworkCapabilities.NET_CAPABILITY_NOT_METERED) + || snapshot.getNetworkCapabilities().hasCapability( + NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED)); final int oemManaged = getOemBitfield(snapshot.getNetworkCapabilities()); diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index 08f75df5d82d..ee24084e63c6 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -160,19 +160,19 @@ public class NetworkTemplate implements Parcelable { } /** - * Template to match cellular networks with the given IMSI and {@code ratType}. - * Use {@link #NETWORK_TYPE_ALL} to include all network types when filtering. - * See {@code TelephonyManager.NETWORK_TYPE_*}. + * Template to match cellular networks with the given IMSI, {@code ratType} and + * {@code metered}. Use {@link #NETWORK_TYPE_ALL} to include all network types when + * filtering. See {@code TelephonyManager.NETWORK_TYPE_*}. */ public static NetworkTemplate buildTemplateMobileWithRatType(@Nullable String subscriberId, - @NetworkType int ratType) { + @NetworkType int ratType, int metered) { if (TextUtils.isEmpty(subscriberId)) { return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null, null, - METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL, + metered, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_EXACT); } return new NetworkTemplate(MATCH_MOBILE, subscriberId, new String[]{subscriberId}, null, - METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL, + metered, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_EXACT); } @@ -305,6 +305,7 @@ public class NetworkTemplate implements Parcelable { } } + // TODO: Deprecate this constructor, mark it @UnsupportedAppUsage(maxTargetSdk = S) @UnsupportedAppUsage public NetworkTemplate(int matchRule, String subscriberId, String networkId) { this(matchRule, subscriberId, new String[] { subscriberId }, networkId); @@ -312,9 +313,14 @@ public class NetworkTemplate implements Parcelable { public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, String networkId) { - this(matchRule, subscriberId, matchSubscriberIds, networkId, METERED_ALL, ROAMING_ALL, - DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL, - SUBSCRIBER_ID_MATCH_RULE_EXACT); + // Older versions used to only match MATCH_MOBILE and MATCH_MOBILE_WILDCARD templates + // to metered networks. It is now possible to match mobile with any meteredness, but + // in order to preserve backward compatibility of @UnsupportedAppUsage methods, this + //constructor passes METERED_YES for these types. + this(matchRule, subscriberId, matchSubscriberIds, networkId, + (matchRule == MATCH_MOBILE || matchRule == MATCH_MOBILE_WILDCARD) ? METERED_YES + : METERED_ALL , ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, + OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_EXACT); } // TODO: Remove it after updating all of the caller. @@ -589,11 +595,7 @@ public class NetworkTemplate implements Parcelable { // TODO: consider matching against WiMAX subscriber identity return true; } else { - // Only metered mobile network would be matched regardless of metered filter. - // This is used to exclude non-metered APNs, e.g. IMS. See ag/908650. - // TODO: Respect metered filter and remove mMetered condition. - return (ident.mType == TYPE_MOBILE && ident.mMetered) - && !ArrayUtils.isEmpty(mMatchSubscriberIds) + return ident.mType == TYPE_MOBILE && !ArrayUtils.isEmpty(mMatchSubscriberIds) && ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId) && matchesCollapsedRatType(ident); } @@ -707,8 +709,7 @@ public class NetworkTemplate implements Parcelable { if (ident.mType == TYPE_WIMAX) { return true; } else { - return (ident.mType == TYPE_MOBILE && ident.mMetered) - && matchesCollapsedRatType(ident); + return ident.mType == TYPE_MOBILE && matchesCollapsedRatType(ident); } } @@ -776,8 +777,8 @@ public class NetworkTemplate implements Parcelable { } /** - * Examine the given template and normalize if it refers to a "merged" - * mobile subscriber. We pick the "lowest" merged subscriber as the primary + * Examine the given template and normalize it. + * We pick the "lowest" merged subscriber as the primary * for key purposes, and expand the template to match all other merged * subscribers. * <p> @@ -792,8 +793,8 @@ public class NetworkTemplate implements Parcelable { } /** - * Examine the given template and normalize if it refers to a "merged" - * mobile subscriber. We pick the "lowest" merged subscriber as the primary + * Examine the given template and normalize it. + * We pick the "lowest" merged subscriber as the primary * for key purposes, and expand the template to match all other merged * subscribers. * @@ -805,7 +806,12 @@ public class NetworkTemplate implements Parcelable { * A, but also matches B. */ public static NetworkTemplate normalize(NetworkTemplate template, List<String[]> mergedList) { - if (!template.isMatchRuleMobile()) return template; + // Now there are several types of network which uses SubscriberId to store network + // information. For instances: + // The TYPE_WIFI with subscriberId means that it is a merged carrier wifi network. + // The TYPE_CARRIER means that the network associate to specific carrier network. + + if (template.mSubscriberId == null) return template; for (String[] merged : mergedList) { if (ArrayUtils.contains(merged, template.mSubscriberId)) { diff --git a/core/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java b/core/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java index 09f528369ffb..be573721936b 100644 --- a/core/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java +++ b/core/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java @@ -79,6 +79,7 @@ public final class IkeSessionParamsUtils { IKE_OPTIONS.add(IkeSessionParams.IKE_OPTION_EAP_ONLY_AUTH); IKE_OPTIONS.add(IkeSessionParams.IKE_OPTION_MOBIKE); IKE_OPTIONS.add(IkeSessionParams.IKE_OPTION_FORCE_PORT_4500); + IKE_OPTIONS.add(IkeSessionParams.IKE_OPTION_INITIAL_CONTACT); } /** Serializes an IkeSessionParams to a PersistableBundle. */ diff --git a/core/java/android/os/BaseBundle.java b/core/java/android/os/BaseBundle.java index 2a344f6c2b6b..ad3de25fecc2 100644 --- a/core/java/android/os/BaseBundle.java +++ b/core/java/android/os/BaseBundle.java @@ -103,7 +103,7 @@ public class BaseBundle { * are unparcelled, mParcelledData willbe set to null. */ @UnsupportedAppUsage - Parcel mParcelledData = null; + volatile Parcel mParcelledData = null; /** * Whether {@link #mParcelledData} was generated by native code or not. @@ -182,13 +182,56 @@ public class BaseBundle { * @param b a Bundle to be copied. */ BaseBundle(BaseBundle b) { - copyInternal(b, false); + this(b, /* deep */ false); } /** - * Special constructor that does not initialize the bundle. + * Constructs a {@link BaseBundle} containing a copy of {@code from}. + * + * @param from The bundle to be copied. + * @param deep Whether is a deep or shallow copy. + * + * @hide */ - BaseBundle(boolean doInit) { + BaseBundle(BaseBundle from, boolean deep) { + synchronized (from) { + mClassLoader = from.mClassLoader; + + if (from.mMap != null) { + if (!deep) { + mMap = new ArrayMap<>(from.mMap); + } else { + final ArrayMap<String, Object> fromMap = from.mMap; + final int n = fromMap.size(); + mMap = new ArrayMap<>(n); + for (int i = 0; i < n; i++) { + mMap.append(fromMap.keyAt(i), deepCopyValue(fromMap.valueAt(i))); + } + } + } else { + mMap = null; + } + + final Parcel parcelledData; + if (from.mParcelledData != null) { + if (from.isEmptyParcel()) { + parcelledData = NoImagePreloadHolder.EMPTY_PARCEL; + mParcelledByNative = false; + } else { + parcelledData = Parcel.obtain(); + parcelledData.appendFrom(from.mParcelledData, 0, + from.mParcelledData.dataSize()); + parcelledData.setDataPosition(0); + mParcelledByNative = from.mParcelledByNative; + } + } else { + parcelledData = null; + mParcelledByNative = false; + } + + // Keep as last statement to ensure visibility of other fields + mParcelledData = parcelledData; + } } /** @@ -323,8 +366,8 @@ public class BaseBundle { } else { mMap.erase(); } - mParcelledData = null; mParcelledByNative = false; + mParcelledData = null; return; } @@ -358,8 +401,8 @@ public class BaseBundle { if (recycleParcel) { recycleParcel(parcelledData); } - mParcelledData = null; mParcelledByNative = false; + mParcelledData = null; } if (DEBUG) { Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this)) @@ -501,44 +544,7 @@ public class BaseBundle { mMap.clear(); } - void copyInternal(BaseBundle from, boolean deep) { - synchronized (from) { - if (from.mParcelledData != null) { - if (from.isEmptyParcel()) { - mParcelledData = NoImagePreloadHolder.EMPTY_PARCEL; - mParcelledByNative = false; - } else { - mParcelledData = Parcel.obtain(); - mParcelledData.appendFrom(from.mParcelledData, 0, - from.mParcelledData.dataSize()); - mParcelledData.setDataPosition(0); - mParcelledByNative = from.mParcelledByNative; - } - } else { - mParcelledData = null; - mParcelledByNative = false; - } - - if (from.mMap != null) { - if (!deep) { - mMap = new ArrayMap<>(from.mMap); - } else { - final ArrayMap<String, Object> fromMap = from.mMap; - final int N = fromMap.size(); - mMap = new ArrayMap<>(N); - for (int i = 0; i < N; i++) { - mMap.append(fromMap.keyAt(i), deepCopyValue(fromMap.valueAt(i))); - } - } - } else { - mMap = null; - } - - mClassLoader = from.mClassLoader; - } - } - - Object deepCopyValue(Object value) { + private Object deepCopyValue(Object value) { if (value == null) { return null; } @@ -570,7 +576,7 @@ public class BaseBundle { return value; } - ArrayList deepcopyArrayList(ArrayList from) { + private ArrayList deepcopyArrayList(ArrayList from) { final int N = from.size(); ArrayList out = new ArrayList(N); for (int i=0; i<N; i++) { @@ -1717,9 +1723,9 @@ public class BaseBundle { if (length < 0) { throw new RuntimeException("Bad length in parcel: " + length); } else if (length == 0) { + mParcelledByNative = false; // Empty Bundle or end of data. mParcelledData = NoImagePreloadHolder.EMPTY_PARCEL; - mParcelledByNative = false; return; } else if (length % 4 != 0) { throw new IllegalStateException("Bundle length is not aligned by 4: " + length); @@ -1757,8 +1763,8 @@ public class BaseBundle { + ": " + length + " bundle bytes starting at " + offset); p.setDataPosition(0); - mParcelledData = p; mParcelledByNative = isNativeBundle; + mParcelledData = p; } /** {@hide} */ diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java index 635f58182b34..b069fb336d55 100644 --- a/core/java/android/os/Binder.java +++ b/core/java/android/os/Binder.java @@ -53,7 +53,7 @@ import java.lang.reflect.Modifier; * * <p>Most developers will not implement this class directly, instead using the * <a href="{@docRoot}guide/components/aidl.html">aidl</a> tool to describe the desired - * interface, having it generate the appropriate Binder subclass. You can, + * interface, having it generate the appropriate Binder subclass. You can, * however, derive directly from Binder to implement your own custom RPC * protocol or simply instantiate a raw Binder object directly to use as a * token that can be shared across processes. @@ -63,17 +63,17 @@ import java.lang.reflect.Modifier; * To use this correctly, you must be doing so within the context of a top-level * application component (a {@link android.app.Service}, {@link android.app.Activity}, * or {@link android.content.ContentProvider}) that lets the system know your process - * should remain running.</p> + * should remain running. * * <p>You must keep in mind the situations in which your process * could go away, and thus require that you later re-create a new Binder and re-attach - * it when the process starts again. For example, if you are using this within an + * it when the process starts again. For example, if you are using this within an * {@link android.app.Activity}, your activity's process may be killed any time the * activity is not started; if the activity is later re-created you will need to * create a new Binder and hand it back to the correct place again; you need to be * aware that your process may be started for another reason (for example to receive * a broadcast) that will not involve re-creating the activity and thus run its code - * to create a new Binder.</p> + * to create a new Binder. * * @see IBinder */ @@ -94,14 +94,15 @@ public class Binder implements IBinder { /** * Value to represents that a calling work source is not set. * - * This constatnt needs to be kept in sync with IPCThreadState::kUnsetWorkSource. + * <p>This constant needs to be kept in sync with IPCThreadState::kUnsetWorkSource. * * @hide */ public static final int UNSET_WORKSOURCE = -1; /** - * Control whether dump() calls are allowed. + * Control whether {@link #dump(FileDescriptor, PrintWriter, String[]) dump()} + * calls are allowed. */ private static volatile String sDumpDisabled = null; @@ -188,7 +189,7 @@ public class Binder implements IBinder { sObserver = observer; } - /** {@hide} */ + /** @hide */ static volatile boolean sWarnOnBlocking = false; /** @@ -207,8 +208,8 @@ public class Binder implements IBinder { /** * Allow blocking calls on the given interface, overriding the requested * value of {@link #setWarnOnBlocking(boolean)}. - * <p> - * This should only be rarely called when you are <em>absolutely sure</em> + * + * <p>This should only be rarely called when you are <em>absolutely sure</em> * the remote interface is a built-in system component that can never be * upgraded. In particular, this <em>must never</em> be called for * interfaces hosted by package that could be upgraded or replaced, @@ -258,7 +259,9 @@ public class Binder implements IBinder { ThreadLocal.withInitial(() -> sWarnOnBlocking); /** - * Allow blocking calls for the current thread. See {@link #allowBlocking}. + * Allow blocking calls for the current thread. + * + * @see {@link #allowBlocking}. * * @hide */ @@ -267,7 +270,9 @@ public class Binder implements IBinder { } /** - * Reset the current thread to the default blocking behavior. See {@link #defaultBlocking}. + * Reset the current thread to the default blocking behavior. + * + * @see {@link #defaultBlocking}. * * @hide */ @@ -286,10 +291,10 @@ public class Binder implements IBinder { /** * Return the ID of the process that sent you the current transaction - * that is being processed. This pid can be used with higher-level + * that is being processed. This PID can be used with higher-level * system services to determine its identity and check permissions. * If the current thread is not currently executing an incoming transaction, - * then its own pid is returned. + * then its own PID is returned. * * Warning: oneway transactions do not receive PID. */ @@ -297,11 +302,11 @@ public class Binder implements IBinder { public static final native int getCallingPid(); /** - * Return the Linux uid assigned to the process that sent you the - * current transaction that is being processed. This uid can be used with + * Return the Linux UID assigned to the process that sent you the + * current transaction that is being processed. This UID can be used with * higher-level system services to determine its identity and check - * permissions. If the current thread is not currently executing an - * incoming transaction, then its own uid is returned. + * permissions. If the current thread is not currently executing an + * incoming transaction, then its own UID is returned. */ @CriticalNative public static final native int getCallingUid(); @@ -313,17 +318,17 @@ public class Binder implements IBinder { * @hide */ @CriticalNative - public static final native boolean isHandlingTransaction(); + public static final native boolean isDirectlyHandlingTransaction(); /** - * Return the Linux uid assigned to the process that sent the transaction + * Return the Linux UID assigned to the process that sent the transaction * currently being processed. * * @throws IllegalStateException if the current thread is not currently - * executing an incoming transaction. + * executing an incoming transaction. */ public static final int getCallingUidOrThrow() { - if (!isHandlingTransaction()) { + if (!isDirectlyHandlingTransaction()) { throw new IllegalStateException( "Thread is not in a binder transcation"); } @@ -332,18 +337,20 @@ public class Binder implements IBinder { /** * Return the UserHandle assigned to the process that sent you the - * current transaction that is being processed. This is the user - * of the caller. It is distinct from {@link #getCallingUid()} in that a + * current transaction that is being processed. This is the user + * of the caller. It is distinct from {@link #getCallingUid()} in that a * particular user will have multiple distinct apps running under it each - * with their own uid. If the current thread is not currently executing an + * with their own UID. If the current thread is not currently executing an * incoming transaction, then its own UserHandle is returned. + * + * @see UserHandle */ public static final @NonNull UserHandle getCallingUserHandle() { return UserHandle.of(UserHandle.getUserId(getCallingUid())); } /** - * Reset the identity of the incoming IPC on the current thread. This can + * Reset the identity of the incoming IPC on the current thread. This can * be useful if, while handling an incoming call, you will be calling * on interfaces of other objects that may be local to your process and * need to do permission checks on the calls coming into them (so they @@ -376,10 +383,10 @@ public class Binder implements IBinder { /** * Convenience method for running the provided action enclosed in - * {@link #clearCallingIdentity}/{@link #restoreCallingIdentity} + * {@link #clearCallingIdentity}/{@link #restoreCallingIdentity}. * - * Any exception thrown by the given action will be caught and rethrown after the call to - * {@link #restoreCallingIdentity} + * <p>Any exception thrown by the given action will be caught and + * rethrown after the call to {@link #restoreCallingIdentity}. * * @hide */ @@ -400,10 +407,10 @@ public class Binder implements IBinder { /** * Convenience method for running the provided action enclosed in - * {@link #clearCallingIdentity}/{@link #restoreCallingIdentity} returning the result + * {@link #clearCallingIdentity}/{@link #restoreCallingIdentity} returning the result. * - * Any exception thrown by the given action will be caught and rethrown after the call to - * {@link #restoreCallingIdentity} + * <p>Any exception thrown by the given action will be caught and rethrown after + * the call to {@link #restoreCallingIdentity}. * * @hide */ @@ -428,12 +435,13 @@ public class Binder implements IBinder { * * <p>The StrictMode settings are kept in two places: a Java-level * threadlocal for libcore/Dalvik, and a native threadlocal (set - * here) for propagation via Binder calls. This is a little + * here) for propagation via Binder calls. This is a little * unfortunate, but necessary to break otherwise more unfortunate * dependencies either of Dalvik on Android, or Android * native-only code on Dalvik. * * @see StrictMode + * * @hide */ @CriticalNative @@ -443,6 +451,7 @@ public class Binder implements IBinder { * Gets the current native thread-local StrictMode policy mask. * * @see #setThreadStrictModePolicy + * * @hide */ @CriticalNative @@ -459,7 +468,7 @@ public class Binder implements IBinder { * reasons, we only support one UID. This UID represents the original user responsible for the * binder calls. * - * <p>{@link Binder#restoreCallingWorkSource(long)} must always be called after setting the + * <p>{@link #restoreCallingWorkSource(long)} must always be called after setting the * worksource. * * <p>A typical use case would be @@ -477,16 +486,16 @@ public class Binder implements IBinder { * * @param workSource The original UID responsible for the binder call. * @return token to restore original work source. - **/ + */ @CriticalNative public static final native long setCallingWorkSourceUid(int workSource); /** * Returns the work source set by the caller. * - * Unlike {@link Binder#getCallingUid()}, this result of this method cannot be trusted. The + * <p>Unlike {@link #getCallingUid()}, this result of this method cannot be trusted. The * caller can set the value to whatever they want. Only use this value if you trust the calling - * uid. + * UID. * * @return The original UID responsible for the binder transaction. */ @@ -499,7 +508,7 @@ public class Binder implements IBinder { * <p>The work source will be propagated for future outgoing binder transactions * executed on this thread. * - * <p>{@link Binder#restoreCallingWorkSource(long)} must always be called after clearing the + * <p>{@link #restoreCallingWorkSource(long)} must always be called after clearing the * worksource. * * <p>A typical use case would be @@ -513,13 +522,13 @@ public class Binder implements IBinder { * </pre> * * @return token to restore original work source. - **/ + */ @CriticalNative public static final native long clearCallingWorkSource(); /** * Restores the work source on this thread using a token returned by - * {@link #setCallingWorkSourceUid(int) or {@link clearCallingWorkSource()}. + * {@link #setCallingWorkSourceUid(int)} or {@link #clearCallingWorkSource()}. * * <p>A typical use case would be * <pre> @@ -530,7 +539,7 @@ public class Binder implements IBinder { * Binder.restoreCallingWorkSource(token); * } * </pre> - **/ + */ @CriticalNative public static final native void restoreCallingWorkSource(long token); @@ -553,7 +562,7 @@ public class Binder implements IBinder { * Use a VINTF-stability binder w/o VINTF requirements. Should be called * on a binder before it is sent out of process. * - * This must be called before the object is sent to another process. + * <p>This must be called before the object is sent to another process. * * @hide */ @@ -561,7 +570,7 @@ public class Binder implements IBinder { /** * Flush any Binder commands pending in the current thread to the kernel - * driver. This can be + * driver. This can be * useful to call before performing an operation that may block for a long * time, to ensure that any pending object references have been released * in order to prevent the process from holding on to objects longer than @@ -570,7 +579,7 @@ public class Binder implements IBinder { public static final native void flushPendingCommands(); /** - * Add the calling thread to the IPC thread pool. This function does + * Add the calling thread to the IPC thread pool. This function does * not return until the current process is exiting. */ public static final void joinThreadPool() { @@ -579,6 +588,7 @@ public class Binder implements IBinder { /** * Returns true if the specified interface is a proxy. + * * @hide */ public static final boolean isProxy(IInterface iface) { @@ -588,6 +598,7 @@ public class Binder implements IBinder { /** * Call blocks until the number of executing binder threads is less * than the maximum number of binder threads allowed for this process. + * * @hide */ public static final native void blockUntilThreadAvailable(); @@ -595,7 +606,7 @@ public class Binder implements IBinder { /** * Default constructor just initializes the object. * - * If you're creating a Binder token (a Binder object without an attached interface), + * <p>If you're creating a Binder token (a Binder object without an attached interface), * you should use {@link #Binder(String)} instead. */ public Binder() { @@ -605,7 +616,7 @@ public class Binder implements IBinder { /** * Constructor for creating a raw Binder object (token) along with a descriptor. * - * The descriptor of binder objects usually specifies the interface they are implementing. + * <p>The descriptor of binder objects usually specifies the interface they are implementing. * In case of binder tokens, no interface is implemented, and the descriptor can be used * as a sort of tag to help identify the binder token. This will help identify remote * references to these objects more easily when debugging. @@ -614,7 +625,7 @@ public class Binder implements IBinder { * Instead of creating multiple tokens with the same descriptor, consider adding a suffix to * help identify them. */ - public Binder(@Nullable String descriptor) { + public Binder(@Nullable String descriptor) { mObject = getNativeBBinderHolder(); NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mObject); @@ -631,9 +642,9 @@ public class Binder implements IBinder { /** * Convenience method for associating a specific interface with the Binder. - * After calling, queryLocalInterface() will be implemented for you - * to return the given owner IInterface when the corresponding - * descriptor is requested. + * After calling, {@link #queryLocalInterface(String) queryLocalInterface()} + * will be implemented for you to return the given owner IInterface when + * the corresponding descriptor is requested. */ public void attachInterface(@Nullable IInterface owner, @Nullable String descriptor) { mOwner = owner; @@ -666,8 +677,8 @@ public class Binder implements IBinder { } /** - * Use information supplied to attachInterface() to return the - * associated IInterface if it matches the requested + * Use information supplied to {@link #attachInterface attachInterface()} + * to return the associated {@link IInterface} if it matches the requested * descriptor. */ public @Nullable IInterface queryLocalInterface(@NonNull String descriptor) { @@ -678,14 +689,15 @@ public class Binder implements IBinder { } /** - * Control disabling of dump calls in this process. This is used by the system + * Control disabling of dump calls in this process. This is used by the system * process watchdog to disable incoming dump calls while it has detecting the system - * is hung and is reporting that back to the activity controller. This is to + * is hung and is reporting that back to the activity controller. This is to * prevent the controller from getting hung up on bug reports at this point. - * @hide * * @param msg The message to show instead of the dump; if null, dumps are * re-enabled. + * + * @hide */ public static void setDumpDisabled(String msg) { sDumpDisabled = msg; @@ -694,7 +706,8 @@ public class Binder implements IBinder { /** * Listener to be notified about each proxy-side binder call. * - * See {@link setProxyTransactListener}. + * @see {@link #setProxyTransactListener}. + * * @hide */ @SystemApi @@ -702,7 +715,8 @@ public class Binder implements IBinder { /** * Called before onTransact. * - * @return an object that will be passed back to #onTransactEnded (or null). + * @return an object that will be passed back to {@link #onTransactEnded} (or null)., + * * @hide */ @Nullable @@ -713,15 +727,15 @@ public class Binder implements IBinder { /** * Called before onTransact. * - * @return an object that will be passed back to #onTransactEnded (or null). + * @return an object that will be passed back to {@link #onTransactEnded} (or null). */ @Nullable Object onTransactStarted(@NonNull IBinder binder, int transactionCode); /** - * Called after onTranact (even when an exception is thrown). + * Called after onTransact (even when an exception is thrown). * - * @param session The object return by #onTransactStarted. + * @param session The object return by {@link #onTransactStarted}. */ void onTransactEnded(@Nullable Object session); } @@ -732,16 +746,17 @@ public class Binder implements IBinder { * <li>By default, this listener will propagate the worksource if the outgoing call happens on * the same thread as the incoming binder call. * <li>Custom attribution can be done by calling {@link ThreadLocalWorkSource#setUid(int)}. + * * @hide */ public static class PropagateWorkSourceTransactListener implements ProxyTransactListener { @Override public Object onTransactStarted(IBinder binder, int transactionCode) { - // Note that {@link Binder#getCallingUid()} is already set to the UID of the current - // process when this method is called. - // - // We use ThreadLocalWorkSource instead. It also allows feature owners to set - // {@link ThreadLocalWorkSource#set(int) manually to attribute resources to a UID. + // Note that {@link #getCallingUid()} is already set to the UID of the current + // process when this method is called. + // + // We use {@link ThreadLocalWorkSource} instead. It also allows feature owners to set + // {@link ThreadLocalWorkSource#set(int)} manually to attribute resources to a UID. int uid = ThreadLocalWorkSource.getUid(); if (uid != ThreadLocalWorkSource.UID_NONE) { return Binder.setCallingWorkSourceUid(uid); @@ -770,6 +785,7 @@ public class Binder implements IBinder { * <li>The listener is called on the critical path of the binder transaction so be careful about * performance. * <li>Never execute another binder transaction inside the listener. + * * @hide */ @SystemApi @@ -778,7 +794,7 @@ public class Binder implements IBinder { } /** - * Default implementation is a stub that returns false. You will want + * Default implementation is a stub that returns false. You will want * to override this to do the appropriate unmarshalling of transactions. * * <p>If you want to call this, call transact(). @@ -786,15 +802,14 @@ public class Binder implements IBinder { * <p>Implementations that are returning a result should generally use * {@link Parcel#writeNoException() Parcel.writeNoException} and * {@link Parcel#writeException(Exception) Parcel.writeException} to propagate - * exceptions back to the caller.</p> + * exceptions back to the caller. * - * @param code The action to perform. This should - * be a number between {@link #FIRST_CALL_TRANSACTION} and - * {@link #LAST_CALL_TRANSACTION}. + * @param code The action to perform. This should be a number between + * {@link #FIRST_CALL_TRANSACTION} and {@link #LAST_CALL_TRANSACTION}. * @param data Marshalled data being received from the caller. * @param reply If the caller is expecting a result back, it should be marshalled * in to here. - * @param flags Additional operation flags. Either 0 for a normal + * @param flags Additional operation flags. Either 0 for a normal * RPC, or {@link #FLAG_ONEWAY} for a one-way RPC. * * @return Return true on a successful call; returning false is generally used to @@ -856,10 +871,12 @@ public class Binder implements IBinder { * Resolves a transaction code to a human readable name. * * <p>Default implementation is a stub that returns null. + * * <p>AIDL generated code will return the original method name. * * @param transactionCode The code to resolve. * @return A human readable name. + * * @hide */ public @Nullable String getTransactionName(int transactionCode) { @@ -925,7 +942,7 @@ public class Binder implements IBinder { * Print the object's state into the given stream. * * @param fd The raw file descriptor that the dump is being sent to. - * @param fout The file to which you should dump your state. This will be + * @param fout The file to which you should dump your state. This will be * closed for you after you return. * @param args additional arguments to the dump request. */ @@ -941,6 +958,7 @@ public class Binder implements IBinder { * @param callback Callback through which to interact with the invoking shell. * @param resultReceiver Called when the command has finished executing, with the result code. * @throws RemoteException + * * @hide */ public void shellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out, @@ -958,7 +976,8 @@ public class Binder implements IBinder { * * <p class="caution">Note: no permission checking is done before calling this method; you must * apply any security checks as appropriate for the command being executed. - * Consider using {@link ShellCommand} to help in the implementation.</p> + * Consider using {@link ShellCommand} to help in the implementation. + * * @hide */ public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out, @@ -1013,7 +1032,7 @@ public class Binder implements IBinder { * System services can implement this method to implement ADB shell commands. * * <p>A system binder service can implement it to handle shell commands on ADB. For example, - * the Job Scheduler service implements it to handle <code>adb shell cmd jobscheduler</code>. + * the Job Scheduler service implements it to handle {@code adb shell cmd jobscheduler}. * * <p>Commands are only executable by ADB shell; i.e. only {@link Process#SHELL_UID} and * {@link Process#ROOT_UID} can call them. @@ -1022,8 +1041,8 @@ public class Binder implements IBinder { * @param out standard output * @param err standard error * @param args arguments passed to the command. Can be empty. The first argument is typically - * a subcommand, such as {@code run} for {@code adb shell cmd jobscheduler run}. - * @return the status code returned from the <code>cmd</code> command. + * a subcommand, such as {@code run} for {@code adb shell cmd jobscheduler run}. + * @return the status code returned from the {@code cmd} command. * * @hide */ @@ -1051,7 +1070,7 @@ public class Binder implements IBinder { public final native void setExtension(@Nullable IBinder extension); /** - * Default implementation rewinds the parcels and calls onTransact. On + * Default implementation rewinds the parcels and calls onTransact. On * the remote side, transact calls into the binder to do the IPC. */ public final boolean transact(int code, @NonNull Parcel data, @Nullable Parcel reply, @@ -1083,7 +1102,7 @@ public class Binder implements IBinder { static void checkParcel(IBinder obj, int code, Parcel parcel, String msg) { if (CHECK_PARCEL_SIZE && parcel.dataSize() >= 800*1024) { - // Trying to send > 800k, this is way too much + // Trying to send > 800k, this is way too much. StringBuilder sb = new StringBuilder(); sb.append(msg); sb.append(": on "); @@ -1107,7 +1126,7 @@ public class Binder implements IBinder { private static native long getNativeBBinderHolder(); /** - * By default, we use the calling uid since we can always trust it. + * By default, we use the calling UID since we can always trust it. */ private static volatile BinderInternal.WorkSourceProvider sWorkSourceProvider = (x) -> Binder.getCallingUid(); @@ -1122,6 +1141,7 @@ public class Binder implements IBinder { * <li>The callback is called on the critical path of the binder transaction so be careful about * performance. * <li>Never execute another binder transaction inside the callback. + * * @hide */ public static void setWorkSourceProvider(BinderInternal.WorkSourceProvider workSourceProvider) { @@ -1131,12 +1151,12 @@ public class Binder implements IBinder { sWorkSourceProvider = workSourceProvider; } - // Entry point from android_util_Binder.cpp's onTransact + // Entry point from android_util_Binder.cpp's onTransact. @UnsupportedAppUsage private boolean execTransact(int code, long dataObj, long replyObj, int flags) { // At that point, the parcel request headers haven't been parsed so we do not know what - // WorkSource the caller has set. Use calling uid as the default. + // {@link WorkSource} the caller has set. Use calling UID as the default. final int callingUid = Binder.getCallingUid(); final long origWorkSource = ThreadLocalWorkSource.setUid(callingUid); try { @@ -1154,17 +1174,18 @@ public class Binder implements IBinder { observer != null ? observer.callStarted(this, code, UNSET_WORKSOURCE) : null; Parcel data = Parcel.obtain(dataObj); Parcel reply = Parcel.obtain(replyObj); - // theoretically, we should call transact, which will call onTransact, + // Theoretically, we should call transact, which will call onTransact, // but all that does is rewind it, and we just got these from an IPC, // so we'll just call it directly. boolean res; // Log any exceptions as warnings, don't silently suppress them. - // If the call was FLAG_ONEWAY then these exceptions disappear into the ether. + // If the call was {@link IBinder#FLAG_ONEWAY} then these exceptions + // disappear into the ether. final boolean tracingEnabled = Binder.isTracingEnabled(); try { final BinderCallHeavyHitterWatcher heavyHitterWatcher = sHeavyHitterWatcher; if (heavyHitterWatcher != null) { - // Notify the heavy hitter watcher, if it's enabled + // Notify the heavy hitter watcher, if it's enabled. heavyHitterWatcher.onTransaction(callingUid, getClass(), code); } if (tracingEnabled) { @@ -1197,7 +1218,7 @@ public class Binder implements IBinder { Log.w(TAG, "Caught a RuntimeException from the binder stub implementation.", e); } } else { - // Clear the parcel before writing the exception + // Clear the parcel before writing the exception. reply.setDataSize(0); reply.setDataPosition(0); reply.writeException(e); @@ -1209,7 +1230,7 @@ public class Binder implements IBinder { } if (observer != null) { // The parcel RPC headers have been called during onTransact so we can now access - // the worksource uid from the parcel. + // the worksource UID from the parcel. final int workSourceUid = sWorkSourceProvider.resolveWorkSourceUid( data.readCallingWorkSourceUid()); observer.callEnded(callSession, data.dataSize(), reply.dataSize(), workSourceUid); @@ -1220,9 +1241,9 @@ public class Binder implements IBinder { data.recycle(); // Just in case -- we are done with the IPC, so there should be no more strict - // mode violations that have gathered for this thread. Either they have been + // mode violations that have gathered for this thread. Either they have been // parceled and are now in transport off to the caller, or we are returning back - // to the main transaction loop to wait for another incoming transaction. Either + // to the main transaction loop to wait for another incoming transaction. Either // way, strict mode begone! StrictMode.clearGatheredViolations(); return res; diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java index 92eb7a5d047e..b2bbfd6c163d 100644 --- a/core/java/android/os/Bundle.java +++ b/core/java/android/os/Bundle.java @@ -102,6 +102,18 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable { } /** + * Constructs a {@link Bundle} containing a copy of {@code from}. + * + * @param from The bundle to be copied. + * @param deep Whether is a deep or shallow copy. + * + * @hide + */ + Bundle(Bundle from, boolean deep) { + super(from, deep); + } + + /** * If {@link #mParcelledData} is not null, copy the HAS FDS bit from it because it's fast. * Otherwise (if {@link #mParcelledData} is already null), leave {@link #FLAG_HAS_FDS_KNOWN} * unset, because scanning a map is slower. We'll do it lazily in @@ -167,13 +179,6 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable { } /** - * Constructs a Bundle without initializing it. - */ - Bundle(boolean doInit) { - super(doInit); - } - - /** * Make a Bundle for a single key/value pair. * * @hide @@ -260,9 +265,7 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable { * are referenced as-is and not copied in any way. */ public Bundle deepCopy() { - Bundle b = new Bundle(false); - b.copyInternal(this, true); - return b; + return new Bundle(this, /* deep */ true); } /** @@ -324,28 +327,10 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable { */ public boolean hasFileDescriptors() { if ((mFlags & FLAG_HAS_FDS_KNOWN) == 0) { - boolean fdFound = false; // keep going until we find one or run out of data - - if (mParcelledData != null) { - if (mParcelledData.hasFileDescriptors()) { - fdFound = true; - } - } else { - // It's been unparcelled, so we need to walk the map - for (int i=mMap.size()-1; i>=0; i--) { - Object obj = mMap.valueAt(i); - if (Parcel.hasFileDescriptors(obj)) { - fdFound = true; - break; - } - } - } - - if (fdFound) { - mFlags |= FLAG_HAS_FDS; - } else { - mFlags &= ~FLAG_HAS_FDS; - } + Parcel p = mParcelledData; + mFlags = (Parcel.hasFileDescriptors((p != null) ? p : mMap)) + ? mFlags | FLAG_HAS_FDS + : mFlags & ~FLAG_HAS_FDS; mFlags |= FLAG_HAS_FDS_KNOWN; } return (mFlags & FLAG_HAS_FDS) != 0; diff --git a/core/java/android/os/BytesMatcher.java b/core/java/android/os/BytesMatcher.java deleted file mode 100644 index 8974c5ee4e32..000000000000 --- a/core/java/android/os/BytesMatcher.java +++ /dev/null @@ -1,315 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.bluetooth.BluetoothUuid; -import android.net.MacAddress; -import android.text.TextUtils; -import android.util.Log; - -import com.android.internal.util.HexDump; - -import java.util.ArrayList; -import java.util.function.Predicate; - -/** - * Predicate that tests if a given {@code byte[]} value matches a set of - * configured rules. - * <p> - * Rules are tested in the order in which they were originally added, which - * means a narrow rule can reject a specific value before a later broader rule - * might accept that same value, or vice versa. - * <p> - * Matchers can contain rules of varying lengths, and tested values will only be - * matched against rules of the exact same length. This is designed to support - * {@link BluetoothUuid} style values which can be variable length. - * - * @hide - */ -public class BytesMatcher implements Predicate<byte[]> { - private static final String TAG = "BytesMatcher"; - - private static final char TYPE_EXACT_ACCEPT = '+'; - private static final char TYPE_EXACT_REJECT = '-'; - private static final char TYPE_PREFIX_ACCEPT = '⊆'; - private static final char TYPE_PREFIX_REJECT = '⊈'; - - private final ArrayList<Rule> mRules = new ArrayList<>(); - - private static class Rule { - public final char type; - public final @NonNull byte[] value; - public final @Nullable byte[] mask; - - public Rule(char type, @NonNull byte[] value, @Nullable byte[] mask) { - if (mask != null && value.length != mask.length) { - throw new IllegalArgumentException( - "Expected length " + value.length + " but found " + mask.length); - } - this.type = type; - this.value = value; - this.mask = mask; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - encode(builder); - return builder.toString(); - } - - public void encode(@NonNull StringBuilder builder) { - builder.append(type); - builder.append(HexDump.toHexString(value)); - if (mask != null) { - builder.append('/'); - builder.append(HexDump.toHexString(mask)); - } - } - - public boolean test(@NonNull byte[] value) { - switch (type) { - case TYPE_EXACT_ACCEPT: - case TYPE_EXACT_REJECT: - if (value.length != this.value.length) { - return false; - } - break; - case TYPE_PREFIX_ACCEPT: - case TYPE_PREFIX_REJECT: - if (value.length < this.value.length) { - return false; - } - break; - } - for (int i = 0; i < this.value.length; i++) { - byte local = this.value[i]; - byte remote = value[i]; - if (this.mask != null) { - local &= this.mask[i]; - remote &= this.mask[i]; - } - if (local != remote) { - return false; - } - } - return true; - } - } - - /** - * Add a rule that will result in {@link #test(byte[])} returning - * {@code true} when a value being tested matches it. This rule will only - * match values of the exact same length. - * <p> - * Rules are tested in the order in which they were originally added, which - * means a narrow rule can reject a specific value before a later broader - * rule might accept that same value, or vice versa. - * - * @param value to be matched - * @param mask to be applied to both values before testing for equality; if - * {@code null} then both values must match exactly - */ - public void addExactAcceptRule(@NonNull byte[] value, @Nullable byte[] mask) { - mRules.add(new Rule(TYPE_EXACT_ACCEPT, value, mask)); - } - - /** - * Add a rule that will result in {@link #test(byte[])} returning - * {@code false} when a value being tested matches it. This rule will only - * match values of the exact same length. - * <p> - * Rules are tested in the order in which they were originally added, which - * means a narrow rule can reject a specific value before a later broader - * rule might accept that same value, or vice versa. - * - * @param value to be matched - * @param mask to be applied to both values before testing for equality; if - * {@code null} then both values must match exactly - */ - public void addExactRejectRule(@NonNull byte[] value, @Nullable byte[] mask) { - mRules.add(new Rule(TYPE_EXACT_REJECT, value, mask)); - } - - /** - * Add a rule that will result in {@link #test(byte[])} returning - * {@code true} when a value being tested matches it. This rule will match - * values of the exact same length or longer. - * <p> - * Rules are tested in the order in which they were originally added, which - * means a narrow rule can reject a specific value before a later broader - * rule might accept that same value, or vice versa. - * - * @param value to be matched - * @param mask to be applied to both values before testing for equality; if - * {@code null} then both values must match exactly - */ - public void addPrefixAcceptRule(@NonNull byte[] value, @Nullable byte[] mask) { - mRules.add(new Rule(TYPE_PREFIX_ACCEPT, value, mask)); - } - - /** - * Add a rule that will result in {@link #test(byte[])} returning - * {@code false} when a value being tested matches it. This rule will match - * values of the exact same length or longer. - * <p> - * Rules are tested in the order in which they were originally added, which - * means a narrow rule can reject a specific value before a later broader - * rule might accept that same value, or vice versa. - * - * @param value to be matched - * @param mask to be applied to both values before testing for equality; if - * {@code null} then both values must match exactly - */ - public void addPrefixRejectRule(@NonNull byte[] value, @Nullable byte[] mask) { - mRules.add(new Rule(TYPE_PREFIX_REJECT, value, mask)); - } - - /** - * Test if the given {@code ParcelUuid} value matches the set of rules - * configured in this matcher. - */ - public boolean testBluetoothUuid(@NonNull ParcelUuid value) { - return test(BluetoothUuid.uuidToBytes(value)); - } - - /** - * Test if the given {@code MacAddress} value matches the set of rules - * configured in this matcher. - */ - public boolean testMacAddress(@NonNull MacAddress value) { - return test(value.toByteArray()); - } - - /** - * Test if the given {@code byte[]} value matches the set of rules - * configured in this matcher. - */ - @Override - public boolean test(@NonNull byte[] value) { - return test(value, false); - } - - /** - * Test if the given {@code byte[]} value matches the set of rules - * configured in this matcher. - */ - public boolean test(@NonNull byte[] value, boolean defaultValue) { - final int size = mRules.size(); - for (int i = 0; i < size; i++) { - final Rule rule = mRules.get(i); - if (rule.test(value)) { - switch (rule.type) { - case TYPE_EXACT_ACCEPT: - case TYPE_PREFIX_ACCEPT: - return true; - case TYPE_EXACT_REJECT: - case TYPE_PREFIX_REJECT: - return false; - } - } - } - return defaultValue; - } - - /** - * Encode the given matcher into a human-readable {@link String} which can - * be used to transport matchers across device boundaries. - * <p> - * The human-readable format is an ordered list separated by commas, where - * each rule is a {@code +} or {@code -} symbol indicating if the match - * should be accepted or rejected, then followed by a hex value and an - * optional hex mask. For example, {@code -caff,+cafe/ff00} is a valid - * encoded matcher. - * - * @see #decode(String) - */ - public static @NonNull String encode(@NonNull BytesMatcher matcher) { - final StringBuilder builder = new StringBuilder(); - final int size = matcher.mRules.size(); - for (int i = 0; i < size; i++) { - final Rule rule = matcher.mRules.get(i); - rule.encode(builder); - builder.append(','); - } - if (builder.length() > 0) { - builder.deleteCharAt(builder.length() - 1); - } - return builder.toString(); - } - - /** - * Decode the given human-readable {@link String} used to transport matchers - * across device boundaries. - * <p> - * The human-readable format is an ordered list separated by commas, where - * each rule is a {@code +} or {@code -} symbol indicating if the match - * should be accepted or rejected, then followed by a hex value and an - * optional hex mask. For example, {@code -caff,+cafe/ff00} is a valid - * encoded matcher. - * - * @see #encode(BytesMatcher) - */ - public static @NonNull BytesMatcher decode(@Nullable String value) { - final BytesMatcher matcher = new BytesMatcher(); - if (TextUtils.isEmpty(value)) return matcher; - - final int length = value.length(); - for (int i = 0; i < length;) { - final char type = value.charAt(i); - - int nextRule = value.indexOf(',', i); - int nextMask = value.indexOf('/', i); - - if (nextRule == -1) nextRule = length; - if (nextMask > nextRule) nextMask = -1; - - final byte[] ruleValue; - final byte[] ruleMask; - if (nextMask >= 0) { - ruleValue = HexDump.hexStringToByteArray(value.substring(i + 1, nextMask)); - ruleMask = HexDump.hexStringToByteArray(value.substring(nextMask + 1, nextRule)); - } else { - ruleValue = HexDump.hexStringToByteArray(value.substring(i + 1, nextRule)); - ruleMask = null; - } - - switch (type) { - case TYPE_EXACT_ACCEPT: - matcher.addExactAcceptRule(ruleValue, ruleMask); - break; - case TYPE_EXACT_REJECT: - matcher.addExactRejectRule(ruleValue, ruleMask); - break; - case TYPE_PREFIX_ACCEPT: - matcher.addPrefixAcceptRule(ruleValue, ruleMask); - break; - case TYPE_PREFIX_REJECT: - matcher.addPrefixRejectRule(ruleValue, ruleMask); - break; - default: - Log.w(TAG, "Ignoring unknown type " + type); - break; - } - - i = nextRule + 1; - } - return matcher; - } -} diff --git a/core/java/android/os/ISystemConfig.aidl b/core/java/android/os/ISystemConfig.aidl index d83d94a8ec77..15e3ce25122b 100644 --- a/core/java/android/os/ISystemConfig.aidl +++ b/core/java/android/os/ISystemConfig.aidl @@ -16,6 +16,8 @@ package android.os; +import android.content.ComponentName; + /** * Binder interface to query SystemConfig in the system server. * {@hide} @@ -44,5 +46,5 @@ interface ISystemConfig { /** * @see SystemConfigManager#getEnabledComponentOverrides */ - List<String> getEnabledComponentOverrides(String packageName); + List<ComponentName> getEnabledComponentOverrides(String packageName); } diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java index ab2c8c0e31d3..09e5a8f7382c 100644 --- a/core/java/android/os/Parcel.java +++ b/core/java/android/os/Parcel.java @@ -20,6 +20,7 @@ import static java.util.Objects.requireNonNull; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SuppressLint; import android.annotation.TestApi; import android.app.AppOpsManager; import android.compat.annotation.UnsupportedAppUsage; @@ -61,6 +62,8 @@ import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.function.Function; +import java.util.function.IntFunction; import java.util.function.Supplier; /** @@ -177,8 +180,12 @@ import java.util.function.Supplier; * {@link #writeStrongInterface(IInterface)}, {@link #readStrongBinder()}, * {@link #writeBinderArray(IBinder[])}, {@link #readBinderArray(IBinder[])}, * {@link #createBinderArray()}, + * {@link #writeInterfaceArray(T[])}, {@link #readInterfaceArray(T[], Function)}, + * {@link #createInterfaceArray(IntFunction, Function)}, * {@link #writeBinderList(List)}, {@link #readBinderList(List)}, - * {@link #createBinderArrayList()}.</p> + * {@link #createBinderArrayList()}, + * {@link #writeInterfaceList(List)}, {@link #readInterfaceList(List, Function)}, + * {@link #createInterfaceArrayList(Function)}.</p> * * <p>FileDescriptor objects, representing raw Linux file descriptor identifiers, * can be written and {@link ParcelFileDescriptor} objects returned to operate @@ -380,6 +387,8 @@ public final class Parcel { private static native void nativeUnmarshall( long nativePtr, byte[] data, int offset, int length); private static native int nativeCompareData(long thisNativePtr, long otherNativePtr); + private static native boolean nativeCompareDataInRange( + long ptrA, int offsetA, long ptrB, int offsetB, int length); private static native void nativeAppendFrom( long thisNativePtr, long otherNativePtr, int offset, int length); @CriticalNative @@ -677,11 +686,16 @@ public final class Parcel { } /** @hide */ - public final int compareData(Parcel other) { + public int compareData(Parcel other) { return nativeCompareData(mNativePtr, other.mNativePtr); } /** @hide */ + public static boolean compareData(Parcel a, int offsetA, Parcel b, int offsetB, int length) { + return nativeCompareDataInRange(a.mNativePtr, offsetA, b.mNativePtr, offsetB, length); + } + + /** @hide */ public final void setClassCookie(Class clz, Object cookie) { if (mClassCookies == null) { mClassCookies = new ArrayMap<>(); @@ -739,57 +753,70 @@ public final class Parcel { } /** - * Check if the object used in {@link #readValue(ClassLoader)} / {@link #writeValue(Object)} - * has file descriptors. + * Check if the object has file descriptors. + * + * <p>Objects supported are {@link Parcel} and objects that can be passed to {@link + * #writeValue(Object)}} * * <p>For most cases, it will use the self-reported {@link Parcelable#describeContents()} method * for that. * - * @throws IllegalArgumentException if you provide any object not supported by above methods. - * Most notably, if you pass {@link Parcel}, this method will throw, for that check - * {@link Parcel#hasFileDescriptors()} + * @throws IllegalArgumentException if you provide any object not supported by above methods + * (including if the unsupported object is inside a nested container). * * @hide */ public static boolean hasFileDescriptors(Object value) { - if (value instanceof LazyValue) { - return ((LazyValue) value).hasFileDescriptors(); + if (value instanceof Parcel) { + Parcel parcel = (Parcel) value; + if (parcel.hasFileDescriptors()) { + return true; + } + } else if (value instanceof LazyValue) { + LazyValue lazy = (LazyValue) value; + if (lazy.hasFileDescriptors()) { + return true; + } } else if (value instanceof Parcelable) { - if ((((Parcelable) value).describeContents() - & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0) { + Parcelable parcelable = (Parcelable) value; + if ((parcelable.describeContents() & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0) { return true; } - } else if (value instanceof Parcelable[]) { - Parcelable[] array = (Parcelable[]) value; - for (int n = array.length - 1; n >= 0; n--) { - Parcelable p = array[n]; - if (p != null && ((p.describeContents() - & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0)) { + } else if (value instanceof ArrayMap<?, ?>) { + ArrayMap<?, ?> map = (ArrayMap<?, ?>) value; + for (int i = 0, n = map.size(); i < n; i++) { + if (hasFileDescriptors(map.keyAt(i)) + || hasFileDescriptors(map.valueAt(i))) { + return true; + } + } + } else if (value instanceof Map<?, ?>) { + Map<?, ?> map = (Map<?, ?>) value; + for (Map.Entry<?, ?> entry : map.entrySet()) { + if (hasFileDescriptors(entry.getKey()) + || hasFileDescriptors(entry.getValue())) { + return true; + } + } + } else if (value instanceof List<?>) { + List<?> list = (List<?>) value; + for (int i = 0, n = list.size(); i < n; i++) { + if (hasFileDescriptors(list.get(i))) { return true; } } } else if (value instanceof SparseArray<?>) { SparseArray<?> array = (SparseArray<?>) value; - for (int n = array.size() - 1; n >= 0; n--) { - Object object = array.valueAt(n); - if (object instanceof Parcelable) { - Parcelable p = (Parcelable) object; - if (p != null && (p.describeContents() - & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0) { - return true; - } + for (int i = 0, n = array.size(); i < n; i++) { + if (hasFileDescriptors(array.valueAt(i))) { + return true; } } - } else if (value instanceof ArrayList<?>) { - ArrayList<?> array = (ArrayList<?>) value; - for (int n = array.size() - 1; n >= 0; n--) { - Object object = array.get(n); - if (object instanceof Parcelable) { - Parcelable p = (Parcelable) object; - if (p != null && ((p.describeContents() - & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0)) { - return true; - } + } else if (value instanceof Object[]) { + Object[] array = (Object[]) value; + for (int i = 0, n = array.length; i < n; i++) { + if (hasFileDescriptors(array[i])) { + return true; } } } else { @@ -1709,6 +1736,30 @@ public final class Parcel { } /** + * Flatten a homogeneous array containing an IInterface type into the parcel, + * at the current dataPosition() and growing dataCapacity() if needed. The + * type of the objects in the array must be one that implements IInterface. + * + * @param val The array of objects to be written. + * + * @see #createInterfaceArray + * @see #readInterfaceArray + * @see IInterface + */ + public final <T extends IInterface> void writeInterfaceArray( + @SuppressLint("ArrayReturn") @Nullable T[] val) { + if (val != null) { + int N = val.length; + writeInt(N); + for (int i=0; i<N; i++) { + writeStrongInterface(val[i]); + } + } else { + writeInt(-1); + } + } + + /** * @hide */ public final void writeCharSequenceArray(@Nullable CharSequence[] val) { @@ -1764,6 +1815,50 @@ public final class Parcel { } /** + * Read and return a new array of T (IInterface) from the parcel. + * + * @return the IInterface array of type T + * @param newArray a function to create an array of T with a given length + * @param asInterface a function to convert IBinder object into T (IInterface) + */ + @SuppressLint({"ArrayReturn", "NullableCollection", "SamShouldBeLast"}) + @Nullable + public final <T extends IInterface> T[] createInterfaceArray( + @NonNull IntFunction<T[]> newArray, @NonNull Function<IBinder, T> asInterface) { + int N = readInt(); + if (N >= 0) { + T[] val = newArray.apply(N); + for (int i=0; i<N; i++) { + val[i] = asInterface.apply(readStrongBinder()); + } + return val; + } else { + return null; + } + } + + /** + * Read an array of T (IInterface) from a parcel. + * + * @param asInterface a function to convert IBinder object into T (IInterface) + * + * @throws BadParcelableException Throws BadParcelableException if the length of `val` + * mismatches the number of items in the parcel. + */ + public final <T extends IInterface> void readInterfaceArray( + @SuppressLint("ArrayReturn") @NonNull T[] val, + @NonNull Function<IBinder, T> asInterface) { + int N = readInt(); + if (N == val.length) { + for (int i=0; i<N; i++) { + val[i] = asInterface.apply(readStrongBinder()); + } + } else { + throw new BadParcelableException("bad array lengths"); + } + } + + /** * Flatten a List containing a particular object type into the parcel, at * the current dataPosition() and growing dataCapacity() if needed. The * type of the objects in the list must be one that implements Parcelable. @@ -1877,6 +1972,28 @@ public final class Parcel { } /** + * Flatten a {@code List} containing T (IInterface) objects into this parcel + * at the current position. They can later be retrieved with + * {@link #createInterfaceArrayList} or {@link #readInterfaceList}. + * + * @see #createInterfaceArrayList + * @see #readInterfaceList + */ + public final <T extends IInterface> void writeInterfaceList(@Nullable List<T> val) { + if (val == null) { + writeInt(-1); + return; + } + int N = val.size(); + int i=0; + writeInt(N); + while (i < N) { + writeStrongInterface(val.get(i)); + i++; + } + } + + /** * Flatten a {@code List} containing arbitrary {@code Parcelable} objects into this parcel * at the current position. They can later be retrieved using * {@link #readParcelableList(List, ClassLoader)} if required. @@ -2440,9 +2557,9 @@ public final class Parcel { writeByteArray(baos.toByteArray()); } catch (IOException ioe) { - throw new RuntimeException("Parcelable encountered " + - "IOException writing serializable object (name = " + name + - ")", ioe); + throw new BadParcelableException("Parcelable encountered " + + "IOException writing serializable object (name = " + + name + ")", ioe); } } @@ -2875,8 +2992,24 @@ public final class Parcel { * from the parcel at the current dataPosition(). */ public final void readMap(@NonNull Map outVal, @Nullable ClassLoader loader) { - int N = readInt(); - readMapInternal(outVal, N, loader); + int n = readInt(); + readMapInternal(outVal, n, loader, /* clazzKey */ null, /* clazzValue */ null); + } + + /** + * Same as {@link #readMap(Map, ClassLoader)} but accepts {@code clazzKey} and + * {@code clazzValue} parameter as the types required for each key and value pair. + * + * @throws BadParcelableException If the item to be deserialized is not an instance of that + * class or any of its children class + */ + public <K, V> void readMap(@NonNull Map<? super K, ? super V> outVal, + @Nullable ClassLoader loader, @NonNull Class<K> clazzKey, + @NonNull Class<V> clazzValue) { + Objects.requireNonNull(clazzKey); + Objects.requireNonNull(clazzValue); + int n = readInt(); + readMapInternal(outVal, n, loader, clazzKey, clazzValue); } /** @@ -2914,16 +3047,38 @@ public final class Parcel { @Nullable public final HashMap readHashMap(@Nullable ClassLoader loader) { - int N = readInt(); - if (N < 0) { + int n = readInt(); + if (n < 0) { return null; } - HashMap m = new HashMap(N); - readMapInternal(m, N, loader); + HashMap m = new HashMap(n); + readMapInternal(m, n, loader, /* clazzKey */ null, /* clazzValue */ null); return m; } /** + * Same as {@link #readHashMap(ClassLoader)} but accepts {@code clazzKey} and + * {@code clazzValue} parameter as the types required for each key and value pair. + * + * @throws BadParcelableException if the item to be deserialized is not an instance of that + * class or any of its children class + */ + @SuppressLint({"ConcreteCollection", "NullableCollection"}) + @Nullable + public <K, V> HashMap<K, V> readHashMap(@Nullable ClassLoader loader, + @NonNull Class<? extends K> clazzKey, @NonNull Class<? extends V> clazzValue) { + Objects.requireNonNull(clazzKey); + Objects.requireNonNull(clazzValue); + int n = readInt(); + if (n < 0) { + return null; + } + HashMap<K, V> map = new HashMap<>(n); + readMapInternal(map, n, loader, clazzKey, clazzValue); + return map; + } + + /** * Read and return a new Bundle object from the parcel at the current * dataPosition(). Returns null if the previously written Bundle object was * null. @@ -3094,14 +3249,24 @@ public final class Parcel { * Parcelables. */ @Nullable - public final ArrayList readArrayList(@Nullable ClassLoader loader) { - int N = readInt(); - if (N < 0) { - return null; - } - ArrayList l = new ArrayList(N); - readListInternal(l, N, loader, /* clazz */ null); - return l; + public ArrayList readArrayList(@Nullable ClassLoader loader) { + return readArrayListInternal(loader, /* clazz */ null); + } + + /** + * Same as {@link #readArrayList(ClassLoader)} but accepts {@code clazz} parameter as + * the type required for each item. + * + * @throws BadParcelableException Throws BadParcelableException if the item to be deserialized + * is not an instance of that class or any of its children classes or there was an error + * trying to instantiate an element. + */ + @SuppressLint({"ConcreteCollection", "NullableCollection"}) + @Nullable + public <T> ArrayList<T> readArrayList(@Nullable ClassLoader loader, + @NonNull Class<? extends T> clazz) { + Objects.requireNonNull(clazz); + return readArrayListInternal(loader, clazz); } /** @@ -3111,14 +3276,23 @@ public final class Parcel { * Parcelables. */ @Nullable - public final Object[] readArray(@Nullable ClassLoader loader) { - int N = readInt(); - if (N < 0) { - return null; - } - Object[] l = new Object[N]; - readArrayInternal(l, N, loader); - return l; + public Object[] readArray(@Nullable ClassLoader loader) { + return readArrayInternal(loader, /* clazz */ null); + } + + /** + * Same as {@link #readArray(ClassLoader)} but accepts {@code clazz} parameter as + * the type required for each item. + * + * @throws BadParcelableException Throws BadParcelableException if the item to be deserialized + * is not an instance of that class or any of its children classes or there was an error + * trying to instantiate an element. + */ + @SuppressLint({"ArrayReturn", "NullableCollection"}) + @Nullable + public <T> T[] readArray(@Nullable ClassLoader loader, @NonNull Class<T> clazz) { + Objects.requireNonNull(clazz); + return readArrayInternal(loader, clazz); } /** @@ -3128,14 +3302,23 @@ public final class Parcel { * Parcelables. */ @Nullable - public final <T> SparseArray<T> readSparseArray(@Nullable ClassLoader loader) { - int N = readInt(); - if (N < 0) { - return null; - } - SparseArray sa = new SparseArray(N); - readSparseArrayInternal(sa, N, loader); - return sa; + public <T> SparseArray<T> readSparseArray(@Nullable ClassLoader loader) { + return readSparseArrayInternal(loader, /* clazz */ null); + } + + /** + * Same as {@link #readSparseArray(ClassLoader)} but accepts {@code clazz} parameter as + * the type required for each item. + * + * @throws BadParcelableException Throws BadParcelableException if the item to be deserialized + * is not an instance of that class or any of its children classes or there was an error + * trying to instantiate an element. + */ + @Nullable + public <T> SparseArray<T> readSparseArray(@Nullable ClassLoader loader, + @NonNull Class<? extends T> clazz) { + Objects.requireNonNull(clazz); + return readSparseArrayInternal(loader, clazz); } /** @@ -3331,6 +3514,32 @@ public final class Parcel { } /** + * Read and return a new ArrayList containing T (IInterface) objects from + * the parcel that was written with {@link #writeInterfaceList} at the + * current dataPosition(). Returns null if the + * previously written list object was null. + * + * @return A newly created ArrayList containing T (IInterface) + * + * @see #writeInterfaceList + */ + @SuppressLint({"ConcreteCollection", "NullableCollection"}) + @Nullable + public final <T extends IInterface> ArrayList<T> createInterfaceArrayList( + @NonNull Function<IBinder, T> asInterface) { + int N = readInt(); + if (N < 0) { + return null; + } + ArrayList<T> l = new ArrayList<T>(N); + while (N > 0) { + l.add(asInterface.apply(readStrongBinder())); + N--; + } + return l; + } + + /** * Read into the given List items String objects that were written with * {@link #writeStringList} at the current dataPosition(). * @@ -3373,6 +3582,28 @@ public final class Parcel { } /** + * Read into the given List items IInterface objects that were written with + * {@link #writeInterfaceList} at the current dataPosition(). + * + * @see #writeInterfaceList + */ + public final <T extends IInterface> void readInterfaceList(@NonNull List<T> list, + @NonNull Function<IBinder, T> asInterface) { + int M = list.size(); + int N = readInt(); + int i = 0; + for (; i < M && i < N; i++) { + list.set(i, asInterface.apply(readStrongBinder())); + } + for (; i<N; i++) { + list.add(asInterface.apply(readStrongBinder())); + } + for (; i<M; i++) { + list.remove(N); + } + } + + /** * Read the list of {@code Parcelable} objects at the current data position into the * given {@code list}. The contents of the {@code list} are replaced. If the serialized * list was {@code null}, {@code list} is cleared. @@ -3580,7 +3811,6 @@ public final class Parcel { private final int mType; @Nullable private final ClassLoader mLoader; @Nullable private Object mObject; - @Nullable private volatile Parcel mValueParcel; /** * This goes from non-null to null once. Always check the nullability of this object before @@ -3678,7 +3908,7 @@ public final class Parcel { return false; } // Finally we compare the payload. - return getValueParcel(source).compareData(value.getValueParcel(otherSource)) == 0; + return Parcel.compareData(source, mPosition, otherSource, value.mPosition, mLength); } @Override @@ -3686,17 +3916,6 @@ public final class Parcel { // Accessing mSource first to provide memory barrier for mObject return Objects.hash(mSource == null, mObject, mLoader, mType, mLength); } - - /** This extracts the parcel section responsible for the object and returns it. */ - private Parcel getValueParcel(Parcel source) { - Parcel parcel = mValueParcel; - if (parcel == null) { - parcel = Parcel.obtain(); - parcel.appendFrom(source, mPosition, mLength); - mValueParcel = parcel; - } - return parcel; - } } /** @@ -3794,7 +4013,7 @@ public final class Parcel { break; case VAL_SERIALIZABLE: - object = readSerializable(loader); + object = readSerializableInternal(loader, clazz); break; case VAL_PARCELABLEARRAY: @@ -3851,7 +4070,7 @@ public final class Parcel { "Parcel " + this + ": Unmarshalling unknown type code " + type + " at offset " + off); } - if (clazz != null && !clazz.isInstance(object)) { + if (object != null && clazz != null && !clazz.isInstance(object)) { throw new BadParcelableException("Unparcelled object " + object + " is not an instance of required class " + clazz.getName() + " provided in the parameter"); @@ -3910,7 +4129,6 @@ public final class Parcel { } /** - * * @param clazz The type of the parcelable expected or {@code null} for performing no checks. */ @SuppressWarnings("unchecked") @@ -3969,7 +4187,7 @@ public final class Parcel { * 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 + * is not an instance of that class or any of its children classes or there there was an error * trying to read the {@link Parcelable.Creator}. */ @Nullable @@ -4092,17 +4310,25 @@ public final class Parcel { return p; } - /** @hide */ + /** + * Same as {@link #readParcelableArray(ClassLoader)} but accepts {@code clazz} parameter as + * the type required for each item. + * + * @throws BadParcelableException Throws BadParcelableException if the item to be deserialized + * is not an instance of that class or any of its children classes or there was an error + * trying to instantiate an element. + */ + @SuppressLint({"ArrayReturn", "NullableCollection"}) + @SuppressWarnings("unchecked") @Nullable - public final <T extends Parcelable> T[] readParcelableArray(@Nullable ClassLoader loader, - @NonNull Class<T> clazz) { - int N = readInt(); - if (N < 0) { + public <T> T[] readParcelableArray(@Nullable ClassLoader loader, @NonNull Class<T> clazz) { + int n = readInt(); + if (n < 0) { return null; } - T[] p = (T[]) Array.newInstance(clazz, N); - for (int i = 0; i < N; i++) { - p[i] = readParcelable(loader); + T[] p = (T[]) Array.newInstance(clazz, n); + for (int i = 0; i < n; i++) { + p[i] = readParcelableInternal(loader, clazz); } return p; } @@ -4113,12 +4339,37 @@ public final class Parcel { * wasn't found in the parcel. */ @Nullable - public final Serializable readSerializable() { - return readSerializable(null); + public Serializable readSerializable() { + return readSerializableInternal(/* loader */ null, /* clazz */ null); } + /** + * Same as {@link #readSerializable()} but accepts {@code loader} parameter + * as the primary classLoader for resolving the Serializable class; and {@code clazz} parameter + * as the required type. + * + * @throws BadParcelableException Throws BadParcelableException if the item to be deserialized + * is not an instance of that class or any of its children class or there there was an error + * deserializing the object. + */ @Nullable - private final Serializable readSerializable(@Nullable final ClassLoader loader) { + public <T extends Serializable> T readSerializable(@Nullable ClassLoader loader, + @NonNull Class<T> clazz) { + Objects.requireNonNull(clazz); + return readSerializableInternal(loader, clazz); + } + + /** + * @param clazz The type of the serializable expected or {@code null} for performing no checks + */ + @Nullable + private <T> T readSerializableInternal(@Nullable final ClassLoader loader, + @Nullable Class<T> clazz) { + if (clazz != null && !Serializable.class.isAssignableFrom(clazz)) { + throw new BadParcelableException("About to unparcel a serializable object " + + " but class required " + clazz.getName() + " is not Serializable"); + } + String name = readString(); if (name == null) { // For some reason we were unable to read the name of the Serializable (either there @@ -4127,9 +4378,20 @@ public final class Parcel { return null; } - byte[] serializedData = createByteArray(); - ByteArrayInputStream bais = new ByteArrayInputStream(serializedData); try { + if (clazz != null && loader != null) { + // If custom classloader is provided, resolve the type of serializable using the + // name, then check the type before deserialization. As in this case we can resolve + // the class the same way as ObjectInputStream, using the provided classloader. + Class<?> cl = Class.forName(name, false, loader); + if (!clazz.isAssignableFrom(cl)) { + throw new BadParcelableException("Serializable object " + + cl.getName() + " is not a subclass of required class " + + clazz.getName() + " provided in the parameter"); + } + } + byte[] serializedData = createByteArray(); + ByteArrayInputStream bais = new ByteArrayInputStream(serializedData); ObjectInputStream ois = new ObjectInputStream(bais) { @Override protected Class<?> resolveClass(ObjectStreamClass osClass) @@ -4137,22 +4399,31 @@ public final class Parcel { // try the custom classloader if provided if (loader != null) { Class<?> c = Class.forName(osClass.getName(), false, loader); - if (c != null) { - return c; - } + return Objects.requireNonNull(c); } return super.resolveClass(osClass); } }; - return (Serializable) ois.readObject(); + T object = (T) ois.readObject(); + if (clazz != null && loader == null) { + // If custom classloader is not provided, check the type of the serializable using + // the deserialized object, as we cannot resolve the class the same way as + // ObjectInputStream. + if (!clazz.isAssignableFrom(object.getClass())) { + throw new BadParcelableException("Serializable object " + + object.getClass().getName() + " is not a subclass of required class " + + clazz.getName() + " provided in the parameter"); + } + } + return object; } catch (IOException ioe) { - throw new RuntimeException("Parcelable encountered " + - "IOException reading a Serializable object (name = " + name + - ")", ioe); + throw new BadParcelableException("Parcelable encountered " + + "IOException reading a Serializable object (name = " + + name + ")", ioe); } catch (ClassNotFoundException cnfe) { - throw new RuntimeException("Parcelable encountered " + - "ClassNotFoundException reading a Serializable object (name = " - + name + ")", cnfe); + throw new BadParcelableException("Parcelable encountered " + + "ClassNotFoundException reading a Serializable object (name = " + + name + ")", cnfe); } } @@ -4239,13 +4510,23 @@ public final class Parcel { destroy(); } - /* package */ void readMapInternal(@NonNull Map outVal, int N, + /** + * To be replaced by {@link #readMapInternal(Map, int, ClassLoader, Class, Class)}, but keep + * the old API for compatibility usages. + */ + /* package */ void readMapInternal(@NonNull Map outVal, int n, @Nullable ClassLoader loader) { - while (N > 0) { - Object key = readValue(loader); - Object value = readValue(loader); + readMapInternal(outVal, n, loader, /* clazzKey */null, /* clazzValue */null); + } + + /* package */ <K, V> void readMapInternal(@NonNull Map<? super K, ? super V> outVal, int n, + @Nullable ClassLoader loader, @Nullable Class<K> clazzKey, + @Nullable Class<V> clazzValue) { + while (n > 0) { + K key = readValue(loader, clazzKey); + V value = readValue(loader, clazzValue); outVal.put(key, value); - N--; + n--; } } @@ -4320,9 +4601,12 @@ public final class Parcel { return result; } - private void readListInternal(@NonNull List outVal, int n, - @Nullable ClassLoader loader) { - readListInternal(outVal, n, loader, null); + /** + * The method is replaced by {@link #readListInternal(List, int, ClassLoader, Class)}, however + * we are keeping this unused method here to allow unsupported app usages. + */ + private void readListInternal(@NonNull List outVal, int n, @Nullable ClassLoader loader) { + readListInternal(outVal, n, loader, /* clazz */ null); } /** @@ -4338,26 +4622,88 @@ public final class Parcel { } } + /** + * @param clazz The type of the object expected or {@code null} for performing no checks. + */ + @SuppressLint({"ConcreteCollection", "NullableCollection"}) + @Nullable + private <T> ArrayList<T> readArrayListInternal(@Nullable ClassLoader loader, + @Nullable Class<? extends T> clazz) { + int n = readInt(); + if (n < 0) { + return null; + } + ArrayList<T> l = new ArrayList<>(n); + readListInternal(l, n, loader, clazz); + return l; + } + + /** + * The method is replaced by {@link #readArrayInternal(ClassLoader, Class)}, however + * we are keeping this unused method here to allow unsupported app usages. + */ private void readArrayInternal(@NonNull Object[] outVal, int N, @Nullable ClassLoader loader) { for (int i = 0; i < N; i++) { - Object value = readValue(loader); - //Log.d(TAG, "Unmarshalling value=" + value); + Object value = readValue(loader, /* clazz */ null); outVal[i] = value; } } + /** + * @param clazz The type of the object expected or {@code null} for performing no checks. + */ + @SuppressWarnings("unchecked") + @Nullable + private <T> T[] readArrayInternal(@Nullable ClassLoader loader, @Nullable Class<T> clazz) { + int n = readInt(); + if (n < 0) { + return null; + } + T[] outVal = (T[]) ((clazz == null) ? new Object[n] : Array.newInstance(clazz, n)); + + for (int i = 0; i < n; i++) { + T value = readValue(loader, clazz); + outVal[i] = value; + } + return outVal; + } + + /** + * The method is replaced by {@link #readSparseArray(ClassLoader, Class)}, however + * we are keeping this unused method here to allow unsupported app usages. + */ private void readSparseArrayInternal(@NonNull SparseArray outVal, int N, @Nullable ClassLoader loader) { while (N > 0) { int key = readInt(); Object value = readValue(loader); - //Log.i(TAG, "Unmarshalling key=" + key + " value=" + value); outVal.append(key, value); N--; } } + /** + * @param clazz The type of the object expected or {@code null} for performing no checks. + */ + @Nullable + private <T> SparseArray<T> readSparseArrayInternal(@Nullable ClassLoader loader, + @Nullable Class<? extends T> clazz) { + int n = readInt(); + if (n < 0) { + return null; + } + SparseArray<T> outVal = new SparseArray<>(n); + + while (n > 0) { + int key = readInt(); + T value = readValue(loader, clazz); + outVal.append(key, value); + n--; + } + return outVal; + } + private void readSparseBooleanArrayInternal(@NonNull SparseBooleanArray outVal, int N) { while (N > 0) { diff --git a/core/java/android/os/PersistableBundle.java b/core/java/android/os/PersistableBundle.java index 7b55e710caeb..f4edcb1317f4 100644 --- a/core/java/android/os/PersistableBundle.java +++ b/core/java/android/os/PersistableBundle.java @@ -156,10 +156,15 @@ public final class PersistableBundle extends BaseBundle implements Cloneable, Pa } /** - * Constructs a PersistableBundle without initializing it. + * Constructs a {@link PersistableBundle} containing a copy of {@code from}. + * + * @param from The bundle to be copied. + * @param deep Whether is a deep or shallow copy. + * + * @hide */ - PersistableBundle(boolean doInit) { - super(doInit); + PersistableBundle(PersistableBundle from, boolean deep) { + super(from, deep); } /** @@ -190,9 +195,7 @@ public final class PersistableBundle extends BaseBundle implements Cloneable, Pa * are referenced as-is and not copied in any way. */ public PersistableBundle deepCopy() { - PersistableBundle b = new PersistableBundle(false); - b.copyInternal(this, true); - return b; + return new PersistableBundle(this, /* deep */ true); } /** diff --git a/core/java/android/os/SystemConfigManager.java b/core/java/android/os/SystemConfigManager.java index a6316df0780c..cde2063fdba5 100644 --- a/core/java/android/os/SystemConfigManager.java +++ b/core/java/android/os/SystemConfigManager.java @@ -17,10 +17,10 @@ package android.os; import android.Manifest; import android.annotation.NonNull; -import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; +import android.content.ComponentName; import android.content.Context; import android.util.ArraySet; import android.util.Log; @@ -138,9 +138,9 @@ public class SystemConfigManager { * @return The enabled component * {@hide} */ - @SystemApi + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @NonNull - public List<String> getEnabledComponentOverrides(@NonNull String packageName) { + public List<ComponentName> getEnabledComponentOverrides(@NonNull String packageName) { try { return mInterface.getEnabledComponentOverrides(packageName); } catch (RemoteException e) { diff --git a/core/java/android/os/health/HealthStats.java b/core/java/android/os/health/HealthStats.java index 74ce5157a548..6c648f136183 100644 --- a/core/java/android/os/health/HealthStats.java +++ b/core/java/android/os/health/HealthStats.java @@ -32,7 +32,7 @@ import java.util.Map; * Each of the keys references data in one of five data types: * * <p> - * A <b>measurement</b> metric contains a sinlge {@code long} value. That value may + * A <b>measurement</b> metric contains a single {@code long} value. That value may * be a count, a time, or some other type of value. The unit for a measurement * (COUNT, MS, etc) will always be in the name of the constant for the key to * retrieve it. For example, the diff --git a/core/java/android/os/health/UidHealthStats.java b/core/java/android/os/health/UidHealthStats.java index afc9d78dcbd1..488a5422becc 100644 --- a/core/java/android/os/health/UidHealthStats.java +++ b/core/java/android/os/health/UidHealthStats.java @@ -43,14 +43,14 @@ public final class UidHealthStats { /** * How many milliseconds this statistics report covers in wall-clock time while the - * device was on battery including both screen-on and screen-off time. + * device was on battery including only screen-off time. */ @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT) public static final int MEASUREMENT_REALTIME_SCREEN_OFF_BATTERY_MS = HealthKeys.BASE_UID + 3; /** * How many milliseconds this statistics report covers that the CPU was running while the - * device was on battery including both screen-on and screen-off time. + * device was on battery including only screen-off time. */ @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT) public static final int MEASUREMENT_UPTIME_SCREEN_OFF_BATTERY_MS = HealthKeys.BASE_UID + 4; @@ -65,7 +65,7 @@ public final class UidHealthStats { /** * Key for a TimerStat for the times a - * {@link android.os.PowerManager#PARTIAL_WAKE_LOCK full wake lock} + * {@link android.os.PowerManager#PARTIAL_WAKE_LOCK partial wake lock} * was acquired for this uid. */ @HealthKeys.Constant(type=HealthKeys.TYPE_TIMERS) diff --git a/core/java/android/permission/DEFAULT_PERMISSION_GRANT_POLICY_OWNERS b/core/java/android/permission/DEFAULT_PERMISSION_GRANT_POLICY_OWNERS new file mode 100644 index 000000000000..cb521c842816 --- /dev/null +++ b/core/java/android/permission/DEFAULT_PERMISSION_GRANT_POLICY_OWNERS @@ -0,0 +1,8 @@ +ewol@google.com +hackbod@google.com +jsharkey@google.com +narayan@google.com +patb@google.com +svetoslavganov@google.com +yamasani@google.com +zhanghai@google.com diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java index 25e3a4fcccc5..6644f1e91f1d 100644 --- a/core/java/android/provider/DeviceConfig.java +++ b/core/java/android/provider/DeviceConfig.java @@ -181,6 +181,22 @@ public final class DeviceConfig { public static final String NAMESPACE_CONNECTIVITY = "connectivity"; /** + * Namespace for CaptivePortalLogin module. + * + * @hide + */ + @SystemApi + public static final String NAMESPACE_CAPTIVEPORTALLOGIN = "captive_portal_login"; + + /** + * Namespace for Tethering module. + * + * @hide + */ + @SystemApi + public static final String NAMESPACE_TETHERING = "tethering"; + + /** * Namespace for content capture feature used by on-device machine intelligence * to provide suggestions in a privacy-safe manner. * @@ -606,6 +622,14 @@ public final class DeviceConfig { public static final String NAMESPACE_GAME_OVERLAY = "game_overlay"; /** + * Namespace for Android Virtualization Framework related features accessible by native code. + * + * @hide + */ + public static final String NAMESPACE_VIRTUALIZATION_FRAMEWORK_NATIVE = + "virtualization_framework_native"; + + /** * Namespace for Constrain Display APIs related features. * * @hide diff --git a/core/java/android/security/attestationverification/OWNERS b/core/java/android/security/attestationverification/OWNERS new file mode 100644 index 000000000000..80a1f44b8427 --- /dev/null +++ b/core/java/android/security/attestationverification/OWNERS @@ -0,0 +1,4 @@ +# Bug component: 1111194 + +dlm@google.com +dkrahn@google.com diff --git a/core/java/android/telephony/PhoneStateListener.java b/core/java/android/telephony/PhoneStateListener.java index d39b56ddabed..5b9d69c2f9ff 100644 --- a/core/java/android/telephony/PhoneStateListener.java +++ b/core/java/android/telephony/PhoneStateListener.java @@ -191,20 +191,6 @@ public class PhoneStateListener { public static final int LISTEN_SIGNAL_STRENGTHS = 0x00000100; /** - * Listen for changes of the network signal strengths (cellular) always reported from modem, - * even in some situations such as the screen of the device is off. - * - * @see #onSignalStrengthsChanged - * - * @hide - * @deprecated Use TelephonyManager#setSignalStrengthUpdateRequest - * instead. - */ - @Deprecated - @RequiresPermission(android.Manifest.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH) - public static final int LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH = 0x00000200; - - /** * Listen for changes to observed cell info. * * Listening to this event requires the {@link Manifest.permission#READ_PHONE_STATE} and diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java index bedad7344e9d..cb1cff9cda22 100644 --- a/core/java/android/telephony/TelephonyRegistryManager.java +++ b/core/java/android/telephony/TelephonyRegistryManager.java @@ -1041,10 +1041,6 @@ public class TelephonyRegistryManager { eventList.add(TelephonyCallback.EVENT_SIGNAL_STRENGTHS_CHANGED); } - if ((eventMask & PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH) != 0) { - eventList.add(TelephonyCallback.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED); - } - if ((eventMask & PhoneStateListener.LISTEN_CELL_INFO) != 0) { eventList.add(TelephonyCallback.EVENT_CELL_INFO_CHANGED); } diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index 8143cf953f19..ffce4617eec6 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -157,6 +157,7 @@ public final class SurfaceControl implements Parcelable { private static native boolean nativeGetAnimationFrameStats(WindowAnimationFrameStats outStats); private static native long[] nativeGetPhysicalDisplayIds(); + private static native long nativeGetPrimaryPhysicalDisplayId(); private static native IBinder nativeGetPhysicalDisplayToken(long physicalDisplayId); private static native IBinder nativeCreateDisplay(String name, boolean secure); private static native void nativeDestroyDisplay(IBinder displayToken); @@ -2266,6 +2267,15 @@ public final class SurfaceControl implements Parcelable { } /** + * Exposed to identify the correct display to apply the primary display orientation. Avoid using + * for any other purpose. + * @hide + */ + public static long getPrimaryPhysicalDisplayId() { + return nativeGetPrimaryPhysicalDisplayId(); + } + + /** * @hide */ public static IBinder getPhysicalDisplayToken(long physicalDisplayId) { diff --git a/core/java/com/android/internal/compat/OWNERS b/core/java/com/android/internal/compat/OWNERS index cfd0a4b079ad..ee3086ab2fdb 100644 --- a/core/java/com/android/internal/compat/OWNERS +++ b/core/java/com/android/internal/compat/OWNERS @@ -1,6 +1 @@ -# Use this reviewer by default. -platform-compat-eng+reviews@google.com - -andreionea@google.com -mathewi@google.com -satayev@google.com +include tools/platform-compat:/OWNERS diff --git a/core/java/com/android/internal/content/om/OverlayConfig.java b/core/java/com/android/internal/content/om/OverlayConfig.java index 3f3c9bdbe5f5..7c391186c839 100644 --- a/core/java/com/android/internal/content/om/OverlayConfig.java +++ b/core/java/com/android/internal/content/om/OverlayConfig.java @@ -25,17 +25,22 @@ import android.os.Trace; import android.util.ArrayMap; import android.util.Log; +import com.android.apex.ApexInfo; +import com.android.apex.XmlParser; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.content.om.OverlayConfigParser.OverlayPartition; import com.android.internal.content.om.OverlayConfigParser.ParsedConfiguration; import com.android.internal.content.om.OverlayScanner.ParsedOverlayInfo; import com.android.internal.util.Preconditions; +import com.android.internal.util.function.TriConsumer; import java.io.File; +import java.io.FileInputStream; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.Comparator; -import java.util.function.BiConsumer; +import java.util.List; import java.util.function.Supplier; /** @@ -73,7 +78,7 @@ public class OverlayConfig { public interface PackageProvider { /** Performs the given action for each package. */ - void forEachPackage(BiConsumer<ParsingPackageRead, Boolean> p); + void forEachPackage(TriConsumer<ParsingPackageRead, Boolean, File> p); } private static final Comparator<ParsedConfiguration> sStaticOverlayComparator = (c1, c2) -> { @@ -115,6 +120,8 @@ public class OverlayConfig { p))); } + ArrayMap<Integer, List<String>> activeApexesPerPartition = getActiveApexes(partitions); + boolean foundConfigFile = false; ArrayList<ParsedOverlayInfo> packageManagerOverlayInfos = null; @@ -123,7 +130,9 @@ public class OverlayConfig { final OverlayPartition partition = partitions.get(i); final OverlayScanner scanner = (scannerFactory == null) ? null : scannerFactory.get(); final ArrayList<ParsedConfiguration> partitionOverlays = - OverlayConfigParser.getConfigurations(partition, scanner); + OverlayConfigParser.getConfigurations(partition, scanner, + activeApexesPerPartition.getOrDefault(partition.type, + Collections.emptyList())); if (partitionOverlays != null) { foundConfigFile = true; overlays.addAll(partitionOverlays); @@ -145,7 +154,8 @@ public class OverlayConfig { // Filter out overlays not present in the partition. partitionOverlayInfos = new ArrayList<>(packageManagerOverlayInfos); for (int j = partitionOverlayInfos.size() - 1; j >= 0; j--) { - if (!partition.containsFile(partitionOverlayInfos.get(j).path)) { + if (!partition.containsFile(partitionOverlayInfos.get(j) + .getOriginalPartitionPath())) { partitionOverlayInfos.remove(j); } } @@ -292,16 +302,49 @@ public class OverlayConfig { private static ArrayList<ParsedOverlayInfo> getOverlayPackageInfos( @NonNull PackageProvider packageManager) { final ArrayList<ParsedOverlayInfo> overlays = new ArrayList<>(); - packageManager.forEachPackage((ParsingPackageRead p, Boolean isSystem) -> { + packageManager.forEachPackage((ParsingPackageRead p, Boolean isSystem, + @Nullable File preInstalledApexPath) -> { if (p.getOverlayTarget() != null && isSystem) { overlays.add(new ParsedOverlayInfo(p.getPackageName(), p.getOverlayTarget(), p.getTargetSdkVersion(), p.isOverlayIsStatic(), p.getOverlayPriority(), - new File(p.getBaseApkPath()))); + new File(p.getBaseApkPath()), preInstalledApexPath)); } }); return overlays; } + /** Returns a map of PartitionType to List of active APEX module names. */ + @NonNull + private static ArrayMap<Integer, List<String>> getActiveApexes( + @NonNull List<OverlayPartition> partitions) { + // An Overlay in an APEX, which is an update of an APEX in a given partition, + // is considered as belonging to that partition. + ArrayMap<Integer, List<String>> result = new ArrayMap<>(); + for (OverlayPartition partition : partitions) { + result.put(partition.type, new ArrayList<String>()); + } + // Read from apex-info-list because ApexManager is not accessible to zygote. + File apexInfoList = new File("/apex/apex-info-list.xml"); + if (apexInfoList.exists() && apexInfoList.canRead()) { + try (FileInputStream stream = new FileInputStream(apexInfoList)) { + List<ApexInfo> apexInfos = XmlParser.readApexInfoList(stream).getApexInfo(); + for (ApexInfo info : apexInfos) { + if (info.getIsActive()) { + for (OverlayPartition partition : partitions) { + if (partition.containsPath(info.getPreinstalledModulePath())) { + result.get(partition.type).add(info.getModuleName()); + break; + } + } + } + } + } catch (Exception e) { + Log.w(TAG, "Error reading apex-info-list: " + e); + } + } + return result; + } + /** Represents a single call to idmap create-multiple. */ @VisibleForTesting public static class IdmapInvocation { diff --git a/core/java/com/android/internal/content/om/OverlayConfigParser.java b/core/java/com/android/internal/content/om/OverlayConfigParser.java index a86e5950c2f6..d48c2e764625 100644 --- a/core/java/com/android/internal/content/om/OverlayConfigParser.java +++ b/core/java/com/android/internal/content/om/OverlayConfigParser.java @@ -40,6 +40,7 @@ import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; +import java.util.List; /** * Responsible for parsing configurations of Runtime Resource Overlays that control mutability, @@ -192,13 +193,19 @@ final class OverlayConfigParser { */ @Nullable static ArrayList<ParsedConfiguration> getConfigurations( - @NonNull OverlayPartition partition, @Nullable OverlayScanner scanner) { - if (partition.getOverlayFolder() == null) { - return null; + @NonNull OverlayPartition partition, @Nullable OverlayScanner scanner, + @NonNull List<String> activeApexes) { + if (scanner != null) { + if (partition.getOverlayFolder() != null) { + scanner.scanDir(partition.getOverlayFolder()); + } + for (String apex : activeApexes) { + scanner.scanDir(new File("/apex/" + apex + "/overlay/")); + } } - if (scanner != null) { - scanner.scanDir(partition.getOverlayFolder()); + if (partition.getOverlayFolder() == null) { + return null; } final File configFile = new File(partition.getOverlayFolder(), CONFIG_DEFAULT_FILENAME); diff --git a/core/java/com/android/internal/content/om/OverlayScanner.java b/core/java/com/android/internal/content/om/OverlayScanner.java index 6b5cb8d9b850..138d1ce91719 100644 --- a/core/java/com/android/internal/content/om/OverlayScanner.java +++ b/core/java/com/android/internal/content/om/OverlayScanner.java @@ -47,23 +47,38 @@ public class OverlayScanner { public final boolean isStatic; public final int priority; public final File path; + @Nullable public final File preInstalledApexPath; public ParsedOverlayInfo(String packageName, String targetPackageName, - int targetSdkVersion, boolean isStatic, int priority, File path) { + int targetSdkVersion, boolean isStatic, int priority, File path, + @Nullable File preInstalledApexPath) { this.packageName = packageName; this.targetPackageName = targetPackageName; this.targetSdkVersion = targetSdkVersion; this.isStatic = isStatic; this.priority = priority; this.path = path; + this.preInstalledApexPath = preInstalledApexPath; } @Override public String toString() { return getClass().getSimpleName() + String.format("{packageName=%s" + ", targetPackageName=%s, targetSdkVersion=%s, isStatic=%s" - + ", priority=%s, path=%s}", - packageName, targetPackageName, targetSdkVersion, isStatic, priority, path); + + ", priority=%s, path=%s, preInstalledApexPath=%s}", + packageName, targetPackageName, targetSdkVersion, isStatic, + priority, path, preInstalledApexPath); + } + + /** + * Retrieves the path of the overlay in its original installation partition. + * + * An Overlay in an APEX, which is an update of an APEX in a given partition, + * is considered as belonging to that partition. + */ + @NonNull + public File getOriginalPartitionPath() { + return preInstalledApexPath != null ? preInstalledApexPath : path; } } @@ -138,6 +153,6 @@ public class OverlayScanner { return apkLite.getTargetPackageName() == null ? null : new ParsedOverlayInfo(apkLite.getPackageName(), apkLite.getTargetPackageName(), apkLite.getTargetSdkVersion(), apkLite.isOverlayIsStatic(), - apkLite.getOverlayPriority(), new File(apkLite.getPath())); + apkLite.getOverlayPriority(), new File(apkLite.getPath()), null); } } diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 8c63f38494ea..630851d126cc 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -12143,7 +12143,7 @@ public class BatteryStatsImpl extends BatteryStats { rxTimeMs = info.getControllerRxTimeMillis(); txTimeMs = info.getControllerTxTimeMillis(); energy = info.getControllerEnergyUsed(); - if (info.getUidTraffic() != null) { + if (!info.getUidTraffic().isEmpty()) { for (UidTraffic traffic : info.getUidTraffic()) { uidRxBytes.put(traffic.getUid(), traffic.getRxBytes()); uidTxBytes.put(traffic.getUid(), traffic.getTxBytes()); @@ -12294,10 +12294,10 @@ public class BatteryStatsImpl extends BatteryStats { long totalTxBytes = 0; long totalRxBytes = 0; - final UidTraffic[] uidTraffic = info.getUidTraffic(); - final int numUids = uidTraffic != null ? uidTraffic.length : 0; + final List<UidTraffic> uidTraffic = info.getUidTraffic(); + final int numUids = uidTraffic.size(); for (int i = 0; i < numUids; i++) { - final UidTraffic traffic = uidTraffic[i]; + final UidTraffic traffic = uidTraffic.get(i); final long rxBytes = traffic.getRxBytes() - mLastBluetoothActivityInfo.uidRxBytes.get( traffic.getUid()); final long txBytes = traffic.getTxBytes() - mLastBluetoothActivityInfo.uidTxBytes.get( @@ -12320,7 +12320,7 @@ public class BatteryStatsImpl extends BatteryStats { if ((totalTxBytes != 0 || totalRxBytes != 0) && (leftOverRxTimeMs != 0 || leftOverTxTimeMs != 0)) { for (int i = 0; i < numUids; i++) { - final UidTraffic traffic = uidTraffic[i]; + final UidTraffic traffic = uidTraffic.get(i); final int uid = traffic.getUid(); final long rxBytes = traffic.getRxBytes() - mLastBluetoothActivityInfo.uidRxBytes.get(uid); diff --git a/core/java/com/android/internal/os/ClassLoaderFactory.java b/core/java/com/android/internal/os/ClassLoaderFactory.java index d347f2e21dd2..8b0411de5477 100644 --- a/core/java/com/android/internal/os/ClassLoaderFactory.java +++ b/core/java/com/android/internal/os/ClassLoaderFactory.java @@ -80,15 +80,20 @@ public class ClassLoaderFactory { */ public static ClassLoader createClassLoader(String dexPath, String librarySearchPath, ClassLoader parent, String classloaderName, - List<ClassLoader> sharedLibraries) { + List<ClassLoader> sharedLibraries, List<ClassLoader> sharedLibrariesLoadedAfter) { ClassLoader[] arrayOfSharedLibraries = (sharedLibraries == null) ? null : sharedLibraries.toArray(new ClassLoader[sharedLibraries.size()]); + ClassLoader[] arrayOfSharedLibrariesLoadedAfterApp = (sharedLibrariesLoadedAfter == null) + ? null + : sharedLibrariesLoadedAfter.toArray( + new ClassLoader[sharedLibrariesLoadedAfter.size()]); if (isPathClassLoaderName(classloaderName)) { - return new PathClassLoader(dexPath, librarySearchPath, parent, arrayOfSharedLibraries); + return new PathClassLoader(dexPath, librarySearchPath, parent, arrayOfSharedLibraries, + arrayOfSharedLibrariesLoadedAfterApp); } else if (isDelegateLastClassLoaderName(classloaderName)) { return new DelegateLastClassLoader(dexPath, librarySearchPath, parent, - arrayOfSharedLibraries); + arrayOfSharedLibraries, arrayOfSharedLibrariesLoadedAfterApp); } throw new AssertionError("Invalid classLoaderName: " + classloaderName); @@ -102,20 +107,20 @@ public class ClassLoaderFactory { String librarySearchPath, String libraryPermittedPath, ClassLoader parent, int targetSdkVersion, boolean isNamespaceShared, String classLoaderName) { return createClassLoader(dexPath, librarySearchPath, libraryPermittedPath, - parent, targetSdkVersion, isNamespaceShared, classLoaderName, null, null); + parent, targetSdkVersion, isNamespaceShared, classLoaderName, null, null, null); } - /** * Create a ClassLoader and initialize a linker-namespace for it. */ public static ClassLoader createClassLoader(String dexPath, String librarySearchPath, String libraryPermittedPath, ClassLoader parent, int targetSdkVersion, boolean isNamespaceShared, String classLoaderName, - List<ClassLoader> sharedLibraries, List<String> nativeSharedLibraries) { + List<ClassLoader> sharedLibraries, List<String> nativeSharedLibraries, + List<ClassLoader> sharedLibrariesAfter) { final ClassLoader classLoader = createClassLoader(dexPath, librarySearchPath, parent, - classLoaderName, sharedLibraries); + classLoaderName, sharedLibraries, sharedLibrariesAfter); String sonameList = ""; if (nativeSharedLibraries != null) { diff --git a/core/java/com/android/internal/os/SomeArgs.java b/core/java/com/android/internal/os/SomeArgs.java index 5ec882cee3c8..475caa5dc85c 100644 --- a/core/java/com/android/internal/os/SomeArgs.java +++ b/core/java/com/android/internal/os/SomeArgs.java @@ -63,6 +63,8 @@ public final class SomeArgs { public int argi4; public int argi5; public int argi6; + public long argl1; + public long argl2; private SomeArgs() { /* do nothing - reduce visibility */ @@ -129,5 +131,7 @@ public final class SomeArgs { argi4 = 0; argi5 = 0; argi6 = 0; + argl1 = 0; + argl2 = 0; } } diff --git a/core/jni/android_os_Parcel.cpp b/core/jni/android_os_Parcel.cpp index be9aaaf407db..0d530f6aa2bb 100644 --- a/core/jni/android_os_Parcel.cpp +++ b/core/jni/android_os_Parcel.cpp @@ -604,6 +604,25 @@ static jint android_os_Parcel_compareData(JNIEnv* env, jclass clazz, jlong thisN return thisParcel->compareData(*otherParcel); } +static jboolean android_os_Parcel_compareDataInRange(JNIEnv* env, jclass clazz, jlong thisNativePtr, + jint thisOffset, jlong otherNativePtr, + jint otherOffset, jint length) { + Parcel* thisParcel = reinterpret_cast<Parcel*>(thisNativePtr); + LOG_ALWAYS_FATAL_IF(thisParcel == nullptr, "Should not be null"); + + Parcel* otherParcel = reinterpret_cast<Parcel*>(otherNativePtr); + LOG_ALWAYS_FATAL_IF(otherParcel == nullptr, "Should not be null"); + + int result; + status_t err = + thisParcel->compareDataInRange(thisOffset, *otherParcel, otherOffset, length, &result); + if (err != NO_ERROR) { + signalExceptionForError(env, clazz, err); + return JNI_FALSE; + } + return (result == 0) ? JNI_TRUE : JNI_FALSE; +} + static void android_os_Parcel_appendFrom(JNIEnv* env, jclass clazz, jlong thisNativePtr, jlong otherNativePtr, jint offset, jint length) { @@ -841,6 +860,7 @@ static const JNINativeMethod gParcelMethods[] = { {"nativeMarshall", "(J)[B", (void*)android_os_Parcel_marshall}, {"nativeUnmarshall", "(J[BII)V", (void*)android_os_Parcel_unmarshall}, {"nativeCompareData", "(JJ)I", (void*)android_os_Parcel_compareData}, + {"nativeCompareDataInRange", "(JIJII)Z", (void*)android_os_Parcel_compareDataInRange}, {"nativeAppendFrom", "(JJII)V", (void*)android_os_Parcel_appendFrom}, // @CriticalNative {"nativeHasFileDescriptors", "(J)Z", (void*)android_os_Parcel_hasFileDescriptors}, diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp index 793b4eba788c..61b91ddaa2e7 100644 --- a/core/jni/android_util_Binder.cpp +++ b/core/jni/android_util_Binder.cpp @@ -959,8 +959,7 @@ static jint android_os_Binder_getCallingUid() return IPCThreadState::self()->getCallingUid(); } -static jboolean android_os_Binder_isHandlingTransaction() -{ +static jboolean android_os_Binder_isDirectlyHandlingTransaction() { return getCurrentServingCall() == BinderCallType::BINDER; } @@ -1056,6 +1055,7 @@ static void android_os_Binder_setExtension(JNIEnv* env, jobject obj, jobject ext // ---------------------------------------------------------------------------- +// clang-format off static const JNINativeMethod gBinderMethods[] = { /* name, signature, funcPtr */ // @CriticalNative @@ -1063,7 +1063,7 @@ static const JNINativeMethod gBinderMethods[] = { // @CriticalNative { "getCallingUid", "()I", (void*)android_os_Binder_getCallingUid }, // @CriticalNative - { "isHandlingTransaction", "()Z", (void*)android_os_Binder_isHandlingTransaction }, + { "isDirectlyHandlingTransaction", "()Z", (void*)android_os_Binder_isDirectlyHandlingTransaction }, // @CriticalNative { "clearCallingIdentity", "()J", (void*)android_os_Binder_clearCallingIdentity }, // @CriticalNative @@ -1088,6 +1088,7 @@ static const JNINativeMethod gBinderMethods[] = { { "getExtension", "()Landroid/os/IBinder;", (void*)android_os_Binder_getExtension }, { "setExtension", "(Landroid/os/IBinder;)V", (void*)android_os_Binder_setExtension }, }; +// clang-format on const char* const kBinderPathName = "android/os/Binder"; diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index 8d12df226ffe..e47718305b7c 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -889,6 +889,12 @@ static jlongArray nativeGetPhysicalDisplayIds(JNIEnv* env, jclass clazz) { return array; } +static jlong nativeGetPrimaryPhysicalDisplayId(JNIEnv* env, jclass clazz) { + PhysicalDisplayId displayId; + SurfaceComposerClient::getPrimaryPhysicalDisplayId(&displayId); + return static_cast<jlong>(displayId.value); +} + static jobject nativeGetPhysicalDisplayToken(JNIEnv* env, jclass clazz, jlong physicalDisplayId) { sp<IBinder> token = SurfaceComposerClient::getPhysicalDisplayToken(PhysicalDisplayId(physicalDisplayId)); @@ -1879,6 +1885,8 @@ static const JNINativeMethod sSurfaceControlMethods[] = { (void*)nativeReleaseFrameRateFlexibilityToken }, {"nativeGetPhysicalDisplayIds", "()[J", (void*)nativeGetPhysicalDisplayIds }, + {"nativeGetPrimaryPhysicalDisplayId", "()J", + (void*)nativeGetPrimaryPhysicalDisplayId }, {"nativeGetPhysicalDisplayToken", "(J)Landroid/os/IBinder;", (void*)nativeGetPhysicalDisplayToken }, {"nativeCreateDisplay", "(Ljava/lang/String;Z)Landroid/os/IBinder;", diff --git a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp index be82879c8411..ef6fd7dd6829 100644 --- a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp +++ b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp @@ -36,6 +36,7 @@ #include <inttypes.h> #include <sys/stat.h> #include <sys/types.h> +#include <linux/fs.h> #include <memory> @@ -253,6 +254,16 @@ copyFileIfChanged(JNIEnv *env, void* arg, ZipFileRO* zipFile, ZipEntryRO zipEntr return INSTALL_FAILED_CONTAINER_ERROR; } + // If a filesystem like f2fs supports per-file compression, set the compression bit before data + // writes + unsigned int flags; + if (ioctl(fd, FS_IOC_GETFLAGS, &flags) == -1) { + ALOGE("Failed to call FS_IOC_GETFLAGS on %s: %s\n", localTmpFileName, strerror(errno)); + } else if ((flags & FS_COMPR_FL) == 0) { + flags |= FS_COMPR_FL; + ioctl(fd, FS_IOC_SETFLAGS, &flags); + } + if (!zipFile->uncompressEntry(zipEntry, fd)) { ALOGE("Failed uncompressing %s to %s\n", fileName, localTmpFileName); close(fd); diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp index 6f5cc5314d0b..40f6e4f63cd7 100644 --- a/core/jni/fd_utils.cpp +++ b/core/jni/fd_utils.cpp @@ -138,6 +138,14 @@ bool FileDescriptorAllowlist::IsAllowed(const std::string& path) const { return true; } + // Allow Runtime Resource Overlays inside APEXes. + static const char* kOverlayPathSuffix = "/overlay"; + if (android::base::StartsWith(path, kApexPrefix) && + android::base::EndsWith(android::base::Dirname(path), kOverlayPathSuffix) && + android::base::EndsWith(path, kApkSuffix) && path.find("/../") == std::string::npos) { + return true; + } + static const char* kOverlayIdmapPrefix = "/data/resource-cache/"; static const char* kOverlayIdmapSuffix = ".apk@idmap"; if (android::base::StartsWith(path, kOverlayIdmapPrefix) && diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto index fa1e9d4afcdf..a62ddd084aab 100644 --- a/core/proto/android/server/windowmanagerservice.proto +++ b/core/proto/android/server/windowmanagerservice.proto @@ -351,6 +351,7 @@ message ActivityRecordProto { optional bool translucent = 30; optional bool pip_auto_enter_enabled = 31; optional bool in_size_compat_mode = 32; + optional float min_aspect_ratio = 33; } /* represents WindowToken */ diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index bd89578f4208..d727a55615f2 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -252,6 +252,11 @@ android:name="com.android.bluetooth.BluetoothMapContentObserver.action.MESSAGE_DELIVERY" /> <protected-broadcast android:name="android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED" /> + <protected-broadcast android:name="android.bluetooth.action.LE_AUDIO_CONNECTION_STATE_CHANGED" /> + <protected-broadcast android:name="android.bluetooth.action.LE_AUDIO_ACTIVE_DEVICE_CHANGED" /> + <protected-broadcast android:name="android.bluetooth.action.LE_AUDIO_CONF_CHANGED" /> + <protected-broadcast android:name="android.bluetooth.action.LE_AUDIO_GROUP_NODE_STATUS_CHANGED" /> + <protected-broadcast android:name="android.bluetooth.action.LE_AUDIO_GROUP_STATUS_CHANGED" /> <protected-broadcast android:name="android.bluetooth.action.TETHERING_STATE_CHANGED" /> <protected-broadcast android:name="android.bluetooth.pbap.profile.action.CONNECTION_STATE_CHANGED" /> @@ -1976,6 +1981,14 @@ android:label="@string/permlab_uwb_ranging" android:protectionLevel="dangerous" /> + <!-- Required to be able to advertise and connect to nearby devices via Wi-Fi. + <p>Protection level: dangerous --> + <permission android:name="android.permission.NEARBY_WIFI_DEVICES" + android:permissionGroup="android.permission-group.UNDEFINED" + android:description="@string/permdesc_nearby_wifi_devices" + android:label="@string/permlab_nearby_wifi_devices" + android:protectionLevel="dangerous" /> + <!-- @SystemApi @TestApi Allows an application to suspend other apps, which will prevent the user from using them until they are unsuspended. @hide @@ -2386,7 +2399,7 @@ <permission android:name="android.permission.READ_ACTIVE_EMERGENCY_SESSION" android:protectionLevel="signature" /> - <!-- Allows listen permission to always reported signal strength. + <!-- Allows listen permission to always reported system signal strength. @hide Used internally. --> <permission android:name="android.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH" android:protectionLevel="signature" /> diff --git a/core/res/OWNERS b/core/res/OWNERS index 684202bdb29e..165dcad896c9 100644 --- a/core/res/OWNERS +++ b/core/res/OWNERS @@ -28,3 +28,6 @@ yamasani@google.com # Multiuser per-file res/xml/config_user_types.xml = file:/MULTIUSER_OWNERS + +# Car +per-file res/values/dimens_car.xml = file:/platform/packages/services/Car:/OWNERS
\ No newline at end of file diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index aa05b13984ec..8496a478af97 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -5047,6 +5047,14 @@ to 0, the seconds hand will be disabled. --> <integer name="config_defaultAnalogClockSecondsHandFps">1</integer> + <!-- List of shared library packages that should be loaded by the classloader after the + code and resources provided by applications. This value will be set by the manufacturer --> + <string-array name="config_sharedLibrariesLoadedAfterApp" translatable="false"> + </string-array> + <!-- the number of the max cached processes in the system. --> <integer name="config_customizedMaxCachedProcesses">32</integer> + + <!-- Whether this device should support taking app snapshots on closure --> + <bool name="config_disableTaskSnapshots">false</bool> </resources> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index a99a22009e3b..a350d14d92ab 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -1488,6 +1488,11 @@ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=120]--> <string name="permdesc_uwb_ranging">Allow the app to determine relative position between nearby Ultra-Wideband devices</string> + <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=50]--> + <string name="permlab_nearby_wifi_devices">interact with nearby Wi\u2011Fi devices</string> + <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=120]--> + <string name="permdesc_nearby_wifi_devices">Allows the app to advertise, connect, and determine the relative position of nearby Wi\u2011Fi devices</string> + <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> <string name="permlab_preferredPaymentInfo">Preferred NFC Payment Service Information</string> <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 092be40c499e..d06dafe9b3e7 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -4403,7 +4403,7 @@ <java-symbol type="string" name="view_and_control_notification_title" /> <java-symbol type="string" name="view_and_control_notification_content" /> <java-symbol type="array" name="config_accessibility_allowed_install_source" /> - + <!-- Translation --> <java-symbol type="string" name="ui_translation_accessibility_translated_text" /> <java-symbol type="string" name="ui_translation_accessibility_translation_finished" /> @@ -4425,5 +4425,12 @@ <java-symbol type="bool" name="config_volumeShowRemoteSessions" /> + <!-- List of shared library packages that should be loaded by the classloader after the + code and resources provided by applications. --> + <java-symbol type="array" name="config_sharedLibrariesLoadedAfterApp" /> + <java-symbol type="integer" name="config_customizedMaxCachedProcesses" /> + + <java-symbol type="bool" name="config_disableTaskSnapshots" /> + </resources> diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml index f1c66c5891f2..4c20ae1b099c 100644 --- a/core/res/res/xml/sms_short_codes.xml +++ b/core/res/res/xml/sms_short_codes.xml @@ -105,6 +105,9 @@ http://www.tja.ee/public/documents/Elektrooniline_side/Oigusaktid/ENG/Estonian_Numbering_Plan_annex_06_09_2010.mht --> <shortcode country="ee" pattern="1\\d{2,4}" premium="90\\d{5}|15330|1701[0-3]" free="116\\d{3}|95034" /> + <!-- Egypt: 4 digits, known codes listed --> + <shortcode country="eg" pattern="\\d{4}" free="1499" /> + <!-- Spain: 5-6 digits: 25xxx, 27xxx, 280xx, 35xxx, 37xxx, 795xxx, 797xxx, 995xxx, 997xxx, plus EU. http://www.legallink.es/?q=en/content/which-current-regulatory-status-premium-rate-services-spain --> <shortcode country="es" premium="[23][57]\\d{3}|280\\d{2}|[79]9[57]\\d{3}" free="116\\d{3}|22791|222145|22189" /> @@ -196,7 +199,7 @@ <shortcode country="nl" pattern="\\d{4}" premium="4466|5040" free="116\\d{3}|2223|6225|2223|1662" /> <!-- Nigeria --> - <shortcode country="ng" pattern="\\d{1,5}" free="2441|55019" /> + <shortcode country="ng" pattern="\\d{1,5}" free="2441|55020" /> <!-- Norway: 4-5 digits (not confirmed), known premium codes listed --> <shortcode country="no" pattern="\\d{4,5}" premium="2201|222[67]" free="2171" /> diff --git a/core/tests/PlatformCompatFramework/OWNERS b/core/tests/PlatformCompatFramework/OWNERS index cfd0a4b079ad..ee3086ab2fdb 100644 --- a/core/tests/PlatformCompatFramework/OWNERS +++ b/core/tests/PlatformCompatFramework/OWNERS @@ -1,6 +1 @@ -# Use this reviewer by default. -platform-compat-eng+reviews@google.com - -andreionea@google.com -mathewi@google.com -satayev@google.com +include tools/platform-compat:/OWNERS diff --git a/core/tests/bluetoothtests/Android.bp b/core/tests/bluetoothtests/Android.bp index a2e4dff8f826..68416dd65466 100644 --- a/core/tests/bluetoothtests/Android.bp +++ b/core/tests/bluetoothtests/Android.bp @@ -15,7 +15,10 @@ android_test { "android.test.runner", "android.test.base", ], - static_libs: ["junit"], + static_libs: [ + "junit", + "modules-utils-bytesmatcher", + ], platform_apis: true, certificate: "platform", } diff --git a/core/tests/bluetoothtests/src/android/bluetooth/le/ScanRecordTest.java b/core/tests/bluetoothtests/src/android/bluetooth/le/ScanRecordTest.java index c287ea9d8567..4e817d4a0d91 100644 --- a/core/tests/bluetoothtests/src/android/bluetooth/le/ScanRecordTest.java +++ b/core/tests/bluetoothtests/src/android/bluetooth/le/ScanRecordTest.java @@ -16,11 +16,11 @@ package android.bluetooth.le; -import android.os.BytesMatcher; import android.os.ParcelUuid; import android.test.suitebuilder.annotation.SmallTest; import com.android.internal.util.HexDump; +import com.android.modules.utils.BytesMatcher; import junit.framework.TestCase; diff --git a/core/tests/coretests/src/android/os/BundleTest.java b/core/tests/coretests/src/android/os/BundleTest.java index ddd0070588ed..09f48403cf31 100644 --- a/core/tests/coretests/src/android/os/BundleTest.java +++ b/core/tests/coretests/src/android/os/BundleTest.java @@ -273,16 +273,21 @@ public class BundleTest { Parcelable p1 = new CustomParcelable(13, "Tiramisu"); Parcelable p2 = new CustomParcelable(13, "Tiramisu"); Bundle a = new Bundle(); - a.putParcelable("key", p1); + a.putParcelable("key1", p1); a.readFromParcel(getParcelledBundle(a)); a.setClassLoader(getClass().getClassLoader()); Bundle b = new Bundle(); - b.putParcelable("key", p2); + // Adding extra element so that the position of the elements of interest in their respective + // source parcels are different so we can cover that case of Parcel.compareData(). We'll + // remove the element later so the map is equal. + b.putString("key0", "string"); + b.putParcelable("key1", p2); b.readFromParcel(getParcelledBundle(b)); b.setClassLoader(getClass().getClassLoader()); - // 2 lazy values with identical parcels inside a.isEmpty(); b.isEmpty(); + b.remove("key0"); + // 2 lazy values with identical parcels inside assertTrue(Bundle.kindofEquals(a, b)); } diff --git a/core/tests/coretests/src/android/os/BytesMatcherTest.java b/core/tests/coretests/src/android/os/BytesMatcherTest.java deleted file mode 100644 index b28e3090edd0..000000000000 --- a/core/tests/coretests/src/android/os/BytesMatcherTest.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import static com.android.internal.util.HexDump.hexStringToByteArray; - -import android.bluetooth.BluetoothUuid; -import android.net.MacAddress; - -import androidx.test.filters.SmallTest; - -import junit.framework.TestCase; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -@RunWith(JUnit4.class) -@SmallTest -public class BytesMatcherTest extends TestCase { - @Test - public void testEmpty() throws Exception { - BytesMatcher matcher = BytesMatcher.decode(""); - assertFalse(matcher.test(hexStringToByteArray("cafe"))); - assertFalse(matcher.test(hexStringToByteArray(""))); - } - - @Test - public void testExact() throws Exception { - BytesMatcher matcher = BytesMatcher.decode("+cafe"); - assertTrue(matcher.test(hexStringToByteArray("cafe"))); - assertFalse(matcher.test(hexStringToByteArray("beef"))); - assertFalse(matcher.test(hexStringToByteArray("ca"))); - assertFalse(matcher.test(hexStringToByteArray("cafe00"))); - } - - @Test - public void testMask() throws Exception { - BytesMatcher matcher = BytesMatcher.decode("+cafe/ff00"); - assertTrue(matcher.test(hexStringToByteArray("cafe"))); - assertTrue(matcher.test(hexStringToByteArray("ca88"))); - assertFalse(matcher.test(hexStringToByteArray("beef"))); - assertFalse(matcher.test(hexStringToByteArray("ca"))); - assertFalse(matcher.test(hexStringToByteArray("cafe00"))); - } - - @Test - public void testPrefix() throws Exception { - BytesMatcher matcher = BytesMatcher.decode("⊆cafe,⊆beef/ff00"); - assertTrue(matcher.test(hexStringToByteArray("cafe"))); - assertFalse(matcher.test(hexStringToByteArray("caff"))); - assertTrue(matcher.test(hexStringToByteArray("cafecafe"))); - assertFalse(matcher.test(hexStringToByteArray("ca"))); - assertTrue(matcher.test(hexStringToByteArray("beef"))); - assertTrue(matcher.test(hexStringToByteArray("beff"))); - assertTrue(matcher.test(hexStringToByteArray("beffbeff"))); - assertFalse(matcher.test(hexStringToByteArray("be"))); - } - - @Test - public void testMacAddress() throws Exception { - BytesMatcher matcher = BytesMatcher.decode("+cafe00112233/ffffff000000"); - assertTrue(matcher.testMacAddress( - MacAddress.fromString("ca:fe:00:00:00:00"))); - assertFalse(matcher.testMacAddress( - MacAddress.fromString("f0:0d:00:00:00:00"))); - } - - @Test - public void testBluetoothUuid() throws Exception { - BytesMatcher matcher = BytesMatcher.decode("+cafe/ff00"); - assertTrue(matcher.testBluetoothUuid( - BluetoothUuid.parseUuidFrom(hexStringToByteArray("cafe")))); - assertFalse(matcher.testBluetoothUuid( - BluetoothUuid.parseUuidFrom(hexStringToByteArray("beef")))); - } - - /** - * Verify that single matcher can be configured to match Bluetooth UUIDs of - * varying lengths. - */ - @Test - public void testBluetoothUuid_Mixed() throws Exception { - BytesMatcher matcher = BytesMatcher.decode("+aaaa/ff00,+bbbbbbbb/ffff0000"); - assertTrue(matcher.testBluetoothUuid( - BluetoothUuid.parseUuidFrom(hexStringToByteArray("aaaa")))); - assertFalse(matcher.testBluetoothUuid( - BluetoothUuid.parseUuidFrom(hexStringToByteArray("bbbb")))); - assertTrue(matcher.testBluetoothUuid( - BluetoothUuid.parseUuidFrom(hexStringToByteArray("bbbbbbbb")))); - assertFalse(matcher.testBluetoothUuid( - BluetoothUuid.parseUuidFrom(hexStringToByteArray("aaaaaaaa")))); - } - - @Test - public void testSerialize_Empty() throws Exception { - BytesMatcher matcher = new BytesMatcher(); - matcher = BytesMatcher.decode(BytesMatcher.encode(matcher)); - - // Also very empty and null values - BytesMatcher.decode(""); - BytesMatcher.decode(null); - } - - @Test - public void testSerialize_Exact() throws Exception { - BytesMatcher matcher = new BytesMatcher(); - matcher.addExactRejectRule(hexStringToByteArray("cafe00112233"), - hexStringToByteArray("ffffff000000")); - matcher.addExactRejectRule(hexStringToByteArray("beef00112233"), - null); - matcher.addExactAcceptRule(hexStringToByteArray("000000000000"), - hexStringToByteArray("000000000000")); - - assertFalse(matcher.test(hexStringToByteArray("cafe00ffffff"))); - assertFalse(matcher.test(hexStringToByteArray("beef00112233"))); - assertTrue(matcher.test(hexStringToByteArray("beef00ffffff"))); - - // Bounce through serialization pass and confirm it still works - matcher = BytesMatcher.decode(BytesMatcher.encode(matcher)); - - assertFalse(matcher.test(hexStringToByteArray("cafe00ffffff"))); - assertFalse(matcher.test(hexStringToByteArray("beef00112233"))); - assertTrue(matcher.test(hexStringToByteArray("beef00ffffff"))); - } - - @Test - public void testSerialize_Prefix() throws Exception { - BytesMatcher matcher = new BytesMatcher(); - matcher.addExactRejectRule(hexStringToByteArray("aa"), null); - matcher.addExactAcceptRule(hexStringToByteArray("bb"), null); - matcher.addPrefixAcceptRule(hexStringToByteArray("aa"), null); - matcher.addPrefixRejectRule(hexStringToByteArray("bb"), null); - - assertFalse(matcher.test(hexStringToByteArray("aa"))); - assertTrue(matcher.test(hexStringToByteArray("bb"))); - assertTrue(matcher.test(hexStringToByteArray("aaaa"))); - assertFalse(matcher.test(hexStringToByteArray("bbbb"))); - - // Bounce through serialization pass and confirm it still works - matcher = BytesMatcher.decode(BytesMatcher.encode(matcher)); - - assertFalse(matcher.test(hexStringToByteArray("aa"))); - assertTrue(matcher.test(hexStringToByteArray("bb"))); - assertTrue(matcher.test(hexStringToByteArray("aaaa"))); - assertFalse(matcher.test(hexStringToByteArray("bbbb"))); - } - - @Test - public void testOrdering_RejectFirst() throws Exception { - BytesMatcher matcher = BytesMatcher.decode("-ff/0f,+ff/f0"); - assertFalse(matcher.test(hexStringToByteArray("ff"))); - assertTrue(matcher.test(hexStringToByteArray("f0"))); - assertFalse(matcher.test(hexStringToByteArray("0f"))); - } - - @Test - public void testOrdering_AcceptFirst() throws Exception { - BytesMatcher matcher = BytesMatcher.decode("+ff/f0,-ff/0f"); - assertTrue(matcher.test(hexStringToByteArray("ff"))); - assertTrue(matcher.test(hexStringToByteArray("f0"))); - assertFalse(matcher.test(hexStringToByteArray("0f"))); - } -} diff --git a/core/tests/coretests/src/android/os/ParcelTest.java b/core/tests/coretests/src/android/os/ParcelTest.java index dcb3e2f23da8..fdd278b9c621 100644 --- a/core/tests/coretests/src/android/os/ParcelTest.java +++ b/core/tests/coretests/src/android/os/ParcelTest.java @@ -17,6 +17,9 @@ package android.os; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; import android.platform.test.annotations.Presubmit; @@ -110,4 +113,130 @@ public class ParcelTest { assertEquals(string, p.readString16()); } } + + @Test + public void testCompareDataInRange_whenSameData() { + Parcel pA = Parcel.obtain(); + int iA = pA.dataPosition(); + pA.writeInt(13); + pA.writeString("Tiramisu"); + int length = pA.dataPosition() - iA; + Parcel pB = Parcel.obtain(); + pB.writeString("Prefix"); + int iB = pB.dataPosition(); + pB.writeInt(13); + pB.writeString("Tiramisu"); + + assertTrue(Parcel.compareData(pA, iA, pB, iB, length)); + } + + @Test + public void testCompareDataInRange_whenSameDataWithBinder() { + Binder binder = new Binder(); + Parcel pA = Parcel.obtain(); + int iA = pA.dataPosition(); + pA.writeInt(13); + pA.writeStrongBinder(binder); + pA.writeString("Tiramisu"); + int length = pA.dataPosition() - iA; + Parcel pB = Parcel.obtain(); + pB.writeString("Prefix"); + int iB = pB.dataPosition(); + pB.writeInt(13); + pB.writeStrongBinder(binder); + pB.writeString("Tiramisu"); + + assertTrue(Parcel.compareData(pA, iA, pB, iB, length)); + } + + @Test + public void testCompareDataInRange_whenDifferentData() { + Parcel pA = Parcel.obtain(); + int iA = pA.dataPosition(); + pA.writeInt(13); + pA.writeString("Tiramisu"); + int length = pA.dataPosition() - iA; + Parcel pB = Parcel.obtain(); + int iB = pB.dataPosition(); + pB.writeString("Prefix"); + pB.writeInt(13); + pB.writeString("Tiramisu"); + + assertFalse(Parcel.compareData(pA, iA, pB, iB, length)); + } + + @Test + public void testCompareDataInRange_whenLimitOutOfBounds_throws() { + Parcel pA = Parcel.obtain(); + int iA = pA.dataPosition(); + pA.writeInt(12); + pA.writeString("Tiramisu"); + int length = pA.dataPosition() - iA; + Parcel pB = Parcel.obtain(); + pB.writeString("Prefix"); + int iB = pB.dataPosition(); + pB.writeInt(13); + pB.writeString("Tiramisu"); + pB.writeInt(-1); + + assertThrows(IllegalArgumentException.class, + () -> Parcel.compareData(pA, iA + length, pB, iB, 1)); + assertThrows(IllegalArgumentException.class, + () -> Parcel.compareData(pA, iA, pB, pB.dataSize(), 1)); + assertThrows(IllegalArgumentException.class, + () -> Parcel.compareData(pA, iA, pB, iB, length + 1)); + assertThrows(IllegalArgumentException.class, + () -> Parcel.compareData(pA, iA + length + 1, pB, iB, 0)); + assertThrows(IllegalArgumentException.class, + () -> Parcel.compareData(pA, iA, pB, iB + pB.dataSize() + 1, 0)); + } + + @Test + public void testCompareDataInRange_whenLengthZero() { + Parcel pA = Parcel.obtain(); + int iA = pA.dataPosition(); + pA.writeInt(12); + pA.writeString("Tiramisu"); + int length = pA.dataPosition() - iA; + Parcel pB = Parcel.obtain(); + pB.writeString("Prefix"); + int iB = pB.dataPosition(); + pB.writeInt(13); + pB.writeString("Tiramisu"); + + assertTrue(Parcel.compareData(pA, 0, pB, iB, 0)); + assertTrue(Parcel.compareData(pA, iA + length, pB, iB, 0)); + assertTrue(Parcel.compareData(pA, iA, pB, pB.dataSize(), 0)); + } + + @Test + public void testCompareDataInRange_whenNegativeLength_throws() { + Parcel pA = Parcel.obtain(); + int iA = pA.dataPosition(); + pA.writeInt(12); + pA.writeString("Tiramisu"); + Parcel pB = Parcel.obtain(); + pB.writeString("Prefix"); + int iB = pB.dataPosition(); + pB.writeInt(13); + pB.writeString("Tiramisu"); + + assertThrows(IllegalArgumentException.class, () -> Parcel.compareData(pA, iA, pB, iB, -1)); + } + + @Test + public void testCompareDataInRange_whenNegativeOffset_throws() { + Parcel pA = Parcel.obtain(); + int iA = pA.dataPosition(); + pA.writeInt(12); + pA.writeString("Tiramisu"); + Parcel pB = Parcel.obtain(); + pB.writeString("Prefix"); + int iB = pB.dataPosition(); + pB.writeInt(13); + pB.writeString("Tiramisu"); + + assertThrows(IllegalArgumentException.class, () -> Parcel.compareData(pA, -1, pB, iB, 0)); + assertThrows(IllegalArgumentException.class, () -> Parcel.compareData(pA, 0, pB, -1, 0)); + } } diff --git a/core/tests/coretests/src/com/android/internal/content/res/OverlayConfigIterationRule.java b/core/tests/coretests/src/com/android/internal/content/res/OverlayConfigIterationRule.java index c50c818be716..e2c40d8b699b 100644 --- a/core/tests/coretests/src/com/android/internal/content/res/OverlayConfigIterationRule.java +++ b/core/tests/coretests/src/com/android/internal/content/res/OverlayConfigIterationRule.java @@ -28,6 +28,7 @@ import android.util.ArrayMap; import com.android.internal.content.om.OverlayConfig.PackageProvider; import com.android.internal.content.om.OverlayScanner; import com.android.internal.content.om.OverlayScanner.ParsedOverlayInfo; +import com.android.internal.util.function.TriConsumer; import org.junit.Assert; import org.junit.rules.TestRule; @@ -39,7 +40,6 @@ import org.mockito.invocation.InvocationOnMock; import java.io.File; import java.io.IOException; import java.util.Map; -import java.util.function.BiConsumer; import java.util.function.Supplier; /** @@ -73,7 +73,7 @@ public class OverlayConfigIterationRule implements TestRule { final File canonicalPath = new File(path.getCanonicalPath()); mOverlayStubResults.put(canonicalPath, new ParsedOverlayInfo( packageName, targetPackage, targetSdkVersion, isStatic, priority, - canonicalPath)); + canonicalPath, null)); } catch (IOException e) { Assert.fail("Failed to add overlay " + e); } @@ -135,8 +135,8 @@ public class OverlayConfigIterationRule implements TestRule { mIteration = Iteration.SYSTEM_SERVER; doAnswer((InvocationOnMock invocation) -> { final Object[] args = invocation.getArguments(); - final BiConsumer<ParsingPackageRead, Boolean> f = - (BiConsumer<ParsingPackageRead, Boolean>) args[0]; + final TriConsumer<ParsingPackageRead, Boolean, File> f = + (TriConsumer<ParsingPackageRead, Boolean, File>) args[0]; for (Map.Entry<File, ParsedOverlayInfo> overlay : mOverlayStubResults.entrySet()) { final ParsingPackageRead a = Mockito.mock(ParsingPackageRead.class); @@ -147,7 +147,8 @@ public class OverlayConfigIterationRule implements TestRule { when(a.isOverlayIsStatic()).thenReturn(info.isStatic); when(a.getOverlayPriority()).thenReturn(info.priority); when(a.getBaseApkPath()).thenReturn(info.path.getPath()); - f.accept(a, !info.path.getPath().contains("data/overlay")); + f.accept(a, !info.path.getPath().contains("data/overlay"), + /*preInstalledApexPath=*/null); } return null; }).when(mPkgProvider).forEachPackage(any()); diff --git a/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java index 5c8479406c03..d361da95a1b9 100644 --- a/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java +++ b/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java @@ -33,6 +33,8 @@ import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import java.util.ArrayList; + @RunWith(AndroidJUnit4.class) @SmallTest public class BluetoothPowerCalculatorTest { @@ -105,10 +107,10 @@ public class BluetoothPowerCalculatorTest { final BluetoothActivityEnergyInfo info = new BluetoothActivityEnergyInfo(1000, BluetoothActivityEnergyInfo.BT_STACK_STATE_STATE_ACTIVE, 7000, 5000, 0, reportedEnergyUc); - info.setUidTraffic(new UidTraffic[]{ - new UidTraffic(Process.BLUETOOTH_UID, 1000, 2000), - new UidTraffic(APP_UID, 3000, 4000) - }); + info.setUidTraffic(new ArrayList<UidTraffic>(){{ + add(new UidTraffic(Process.BLUETOOTH_UID, 1000, 2000)); + add(new UidTraffic(APP_UID, 3000, 4000)); + }}); mStatsRule.getBatteryStats().updateBluetoothStateLocked(info, consumedEnergyUc, 1000, 1000); } diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json index b67988ee9646..c94b3d5ce6b2 100644 --- a/data/etc/services.core.protolog.json +++ b/data/etc/services.core.protolog.json @@ -499,6 +499,12 @@ "group": "WM_DEBUG_STATES", "at": "com\/android\/server\/wm\/ActivityRecord.java" }, + "-1556507536": { + "message": "Passing transform hint %d for window %s%s", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, "-1554521902": { "message": "showInsets(ime) was requested by different window: %s ", "level": "WARN", diff --git a/graphics/java/android/graphics/HardwareRenderer.java b/graphics/java/android/graphics/HardwareRenderer.java index c3b1cd74d29b..b61ae1259cf5 100644 --- a/graphics/java/android/graphics/HardwareRenderer.java +++ b/graphics/java/android/graphics/HardwareRenderer.java @@ -22,6 +22,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.app.Activity; import android.app.ActivityManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.pm.ActivityInfo; import android.content.res.Configuration; @@ -1075,6 +1076,53 @@ public class HardwareRenderer { ProcessInitializer.sInstance.setContext(context); } + /** + * Returns true if HardwareRender will produce output. + * + * This value is global to the process and affects all uses of HardwareRenderer, + * including + * those created by the system such as those used by the View tree when using hardware + * accelerated rendering. + * + * Default is true in all production environments, but may be false in testing-focused + * emulators or if {@link #setDrawingEnabled(boolean)} is used. + * + * Backported from android T. + * + * @hide + */ + @UnsupportedAppUsage + public static boolean isDrawingEnabled() { + return nIsDrawingEnabled(); + } + + /** + * Toggles whether or not HardwareRenderer will produce drawing output globally in the current + * process. + * + * This applies to all HardwareRenderer instances, including those created by the platform such + * as those used by the system for hardware accelerated View rendering. + * + * The capability to disable drawing output is intended for test environments, primarily + * headless ones. By setting this to false, tests that launch activities or interact with Views + * can be quicker with less RAM usage by skipping the final step of View drawing. All View + * lifecycle events will occur as normal, only the final step of rendering on the GPU to the + * display will be skipped. + * + * This can be toggled on and off at will, so screenshot tests can also run in this same + * environment by toggling drawing back on and forcing a frame to be drawn such as by calling + * view#invalidate(). Once drawn and the screenshot captured, this can then be turned back off. + * + * Backported from android T. + * + * @hide + */ + // TODO: Add link to androidx's Screenshot library for help with this + @UnsupportedAppUsage + public static void setDrawingEnabled(boolean drawingEnabled) { + nSetDrawingEnabled(drawingEnabled); + } + private static final class DestroyContextRunnable implements Runnable { private final long mNativeInstance; @@ -1393,4 +1441,8 @@ public class HardwareRenderer { private static native void nInitDisplayInfo(int width, int height, float refreshRate, int wideColorDataspace, long appVsyncOffsetNanos, long presentationDeadlineNanos); + + private static native void nSetDrawingEnabled(boolean drawingEnabled); + + private static native boolean nIsDrawingEnabled(); } diff --git a/libs/WindowManager/Shell/tests/OWNERS b/libs/WindowManager/Shell/tests/OWNERS index d80699de8a2d..f49e80ae16b1 100644 --- a/libs/WindowManager/Shell/tests/OWNERS +++ b/libs/WindowManager/Shell/tests/OWNERS @@ -1,3 +1,4 @@ # Bug component: 909476 # includes OWNERS from parent directories natanieljr@google.com +pablogamito@google.com diff --git a/libs/androidfw/OWNERS b/libs/androidfw/OWNERS index 610fd80fe73c..17f5164cf417 100644 --- a/libs/androidfw/OWNERS +++ b/libs/androidfw/OWNERS @@ -1,6 +1,6 @@ set noparent toddke@google.com -rtmitchell@google.com +zyy@google.com patb@google.com per-file CursorWindow.cpp=omakoto@google.com diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp index b8fa55a18dac..c804418e8380 100644 --- a/libs/hwui/Properties.cpp +++ b/libs/hwui/Properties.cpp @@ -88,6 +88,8 @@ bool Properties::enableWebViewOverlays = false; StretchEffectBehavior Properties::stretchEffectBehavior = StretchEffectBehavior::ShaderHWUI; +DrawingEnabled Properties::drawingEnabled = DrawingEnabled::NotInitialized; + bool Properties::load() { bool prevDebugLayersUpdates = debugLayersUpdates; bool prevDebugOverdraw = debugOverdraw; @@ -141,6 +143,9 @@ bool Properties::load() { enableWebViewOverlays = base::GetBoolProperty(PROPERTY_WEBVIEW_OVERLAYS_ENABLED, false); + // call isDrawingEnabled to force loading of the property + isDrawingEnabled(); + return (prevDebugLayersUpdates != debugLayersUpdates) || (prevDebugOverdraw != debugOverdraw); } @@ -210,5 +215,19 @@ void Properties::overrideRenderPipelineType(RenderPipelineType type, bool inUnit sRenderPipelineType = type; } +void Properties::setDrawingEnabled(bool newDrawingEnabled) { + drawingEnabled = newDrawingEnabled ? DrawingEnabled::On : DrawingEnabled::Off; + enableRTAnimations = newDrawingEnabled; +} + +bool Properties::isDrawingEnabled() { + if (drawingEnabled == DrawingEnabled::NotInitialized) { + bool drawingEnabledProp = base::GetBoolProperty(PROPERTY_DRAWING_ENABLED, true); + drawingEnabled = drawingEnabledProp ? DrawingEnabled::On : DrawingEnabled::Off; + enableRTAnimations = drawingEnabledProp; + } + return drawingEnabled == DrawingEnabled::On; +} + } // namespace uirenderer } // namespace android diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h index 7df6e2c92247..7f9782bf8d20 100644 --- a/libs/hwui/Properties.h +++ b/libs/hwui/Properties.h @@ -187,6 +187,12 @@ enum DebugLevel { */ #define PROPERTY_WEBVIEW_OVERLAYS_ENABLED "debug.hwui.webview_overlays_enabled" +/** + * Property for globally GL drawing state. Can be overridden per process with + * setDrawingEnabled. + */ +#define PROPERTY_DRAWING_ENABLED "debug.hwui.drawing_enabled" + /////////////////////////////////////////////////////////////////////////////// // Misc /////////////////////////////////////////////////////////////////////////////// @@ -208,6 +214,8 @@ enum class StretchEffectBehavior { UniformScale // Uniform scale stretch everywhere }; +enum class DrawingEnabled { NotInitialized, On, Off }; + /** * Renderthread-only singleton which manages several static rendering properties. Most of these * are driven by system properties which are queried once at initialization, and again if init() @@ -301,6 +309,11 @@ public: stretchEffectBehavior = behavior; } + // Represents if drawing is enabled. Should only be Off in headless testing environments + static DrawingEnabled drawingEnabled; + static bool isDrawingEnabled(); + static void setDrawingEnabled(bool enable); + private: static StretchEffectBehavior stretchEffectBehavior; static ProfileType sProfileType; diff --git a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp index 54367b8334cb..9e56584ed582 100644 --- a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp +++ b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp @@ -817,6 +817,14 @@ static void android_view_ThreadedRenderer_initDisplayInfo(JNIEnv*, jclass, jint DeviceInfo::setPresentationDeadlineNanos(presentationDeadlineNanos); } +static void android_view_ThreadedRenderer_setDrawingEnabled(JNIEnv*, jclass, jboolean enabled) { + Properties::setDrawingEnabled(enabled); +} + +static jboolean android_view_ThreadedRenderer_isDrawingEnabled(JNIEnv*, jclass) { + return Properties::isDrawingEnabled(); +} + // ---------------------------------------------------------------------------- // HardwareRendererObserver // ---------------------------------------------------------------------------- @@ -953,6 +961,9 @@ static const JNINativeMethod gMethods[] = { {"preload", "()V", (void*)android_view_ThreadedRenderer_preload}, {"isWebViewOverlaysEnabled", "()Z", (void*)android_view_ThreadedRenderer_isWebViewOverlaysEnabled}, + {"nSetDrawingEnabled", "(Z)V", (void*)android_view_ThreadedRenderer_setDrawingEnabled}, + {"nIsDrawingEnabled", "()Z", (void*)android_view_ThreadedRenderer_isDrawingEnabled}, + }; static JavaVM* mJvm = nullptr; diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index 2f3a509831d1..bb0b1352c360 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -256,7 +256,7 @@ void CanvasContext::setStopped(bool stopped) { } void CanvasContext::allocateBuffers() { - if (mNativeSurface) { + if (mNativeSurface && Properties::isDrawingEnabled()) { ANativeWindow_tryAllocateBuffers(mNativeSurface->getNativeWindow()); } } @@ -480,7 +480,8 @@ nsecs_t CanvasContext::draw() { SkRect dirty; mDamageAccumulator.finish(&dirty); - if (dirty.isEmpty() && Properties::skipEmptyFrames && !surfaceRequiresRedraw()) { + if (!Properties::isDrawingEnabled() || + (dirty.isEmpty() && Properties::skipEmptyFrames && !surfaceRequiresRedraw())) { mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame); if (auto grContext = getGrContext()) { // Submit to ensure that any texture uploads complete and Skia can diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index 6dbfcc349d50..2fed4686f16e 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -90,9 +90,17 @@ public: * and false otherwise (e.g. cache limits have been exceeded). */ bool pinImages(std::vector<SkImage*>& mutableImages) { + if (!Properties::isDrawingEnabled()) { + return true; + } return mRenderPipeline->pinImages(mutableImages); } - bool pinImages(LsaVector<sk_sp<Bitmap>>& images) { return mRenderPipeline->pinImages(images); } + bool pinImages(LsaVector<sk_sp<Bitmap>>& images) { + if (!Properties::isDrawingEnabled()) { + return true; + } + return mRenderPipeline->pinImages(images); + } /** * Unpin any image that had be previously pinned to the GPU cache diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index ed8cdb941792..cf7039b9ed5c 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -3255,6 +3255,54 @@ public class AudioManager { } /** + * @hide + */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK) + public void setHfpEnabled(boolean enable) { + AudioSystem.setParameters("hfp_enable=" + enable); + } + + /** + * @hide + */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK) + public void setHfpVolume(int volume) { + AudioSystem.setParameters("hfp_volume=" + volume); + } + + /** + * @hide + */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK) + public void setHfpSamplingRate(int rate) { + AudioSystem.setParameters("hfp_set_sampling_rate=" + rate); + } + + /** + * @hide + */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK) + public void setBluetoothHeadsetProperties(@NonNull String name, boolean hasNrecEnabled, + boolean hasWbsEnabled) { + AudioSystem.setParameters("bt_headset_name=" + name + + ";bt_headset_nrec=" + (hasNrecEnabled ? "on" : "off") + + ";bt_wbs=" + (hasWbsEnabled ? "on" : "off")); + } + + /** + * @hide + */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK) + public void setA2dpSuspended(boolean enable) { + AudioSystem.setParameters("A2dpSuspended=" + enable); + } + + /** * Gets a variable number of parameter values from audio hardware. * * @param keys list of parameters diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java index 8b9153621165..de31a7f5c184 100644 --- a/media/java/android/media/MediaCodec.java +++ b/media/java/android/media/MediaCodec.java @@ -60,10 +60,10 @@ import java.util.concurrent.locks.ReentrantLock; with {@link MediaExtractor}, {@link MediaSync}, {@link MediaMuxer}, {@link MediaCrypto}, {@link MediaDrm}, {@link Image}, {@link Surface}, and {@link AudioTrack}.) <p> - <center><object style="width: 540px; height: 205px;" type="image/svg+xml" - data="../../../images/media/mediacodec_buffers.svg"><img - src="../../../images/media/mediacodec_buffers.png" style="width: 540px; height: 205px" - alt="MediaCodec buffer flow diagram"></object></center> + <center> + <img src="../../../images/media/mediacodec_buffers.svg" style="width: 540px; height: 205px" + alt="MediaCodec buffer flow diagram"> + </center> <p> In broad terms, a codec processes input data to generate output data. It processes data asynchronously and uses a set of input and output buffers. At a simplistic level, you request @@ -268,10 +268,10 @@ import java.util.concurrent.locks.ReentrantLock; Uninitialized, Configured and Error, whereas the Executing state conceptually progresses through three sub-states: Flushed, Running and End-of-Stream. <p> - <center><object style="width: 516px; height: 353px;" type="image/svg+xml" - data="../../../images/media/mediacodec_states.svg"><img - src="../../../images/media/mediacodec_states.png" style="width: 519px; height: 356px" - alt="MediaCodec state diagram"></object></center> + <center> + <img src="../../../images/media/mediacodec_states.svg" style="width: 519px; height: 356px" + alt="MediaCodec state diagram"> + </center> <p> When you create a codec using one of the factory methods, the codec is in the Uninitialized state. First, you need to configure it via {@link #configure configure(…)}, which brings @@ -513,10 +513,10 @@ import java.util.concurrent.locks.ReentrantLock; Similarly, upon an initial call to {@code start} the codec will move directly to the Running sub-state and start passing available input buffers via the callback. <p> - <center><object style="width: 516px; height: 353px;" type="image/svg+xml" - data="../../../images/media/mediacodec_async_states.svg"><img - src="../../../images/media/mediacodec_async_states.png" style="width: 516px; height: 353px" - alt="MediaCodec state diagram for asynchronous operation"></object></center> + <center> + <img src="../../../images/media/mediacodec_async_states.svg" style="width: 516px; height: 353px" + alt="MediaCodec state diagram for asynchronous operation"> + </center> <p> MediaCodec is typically used like this in asynchronous mode: <pre class=prettyprint> diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java index 49477b94cbe0..374cc7592faf 100644 --- a/media/java/android/media/MediaCodecInfo.java +++ b/media/java/android/media/MediaCodecInfo.java @@ -182,10 +182,15 @@ public final class MediaCodecInfo { public String mName; public int mValue; public boolean mDefault; + public boolean mInternal; public Feature(String name, int value, boolean def) { + this(name, value, def, false /* internal */); + } + public Feature(String name, int value, boolean def, boolean internal) { mName = name; mValue = value; mDefault = def; + mInternal = internal; } } @@ -579,6 +584,11 @@ public final class MediaCodecInfo { public static final String FEATURE_LowLatency = "low-latency"; /** + * Do not include in REGULAR_CODECS list in MediaCodecList. + */ + private static final String FEATURE_SpecialCodec = "special-codec"; + + /** * <b>video encoder only</b>: codec supports quantization parameter bounds. * @see MediaFormat#KEY_VIDEO_QP_MAX * @see MediaFormat#KEY_VIDEO_QP_MIN @@ -616,6 +626,8 @@ public final class MediaCodecInfo { new Feature(FEATURE_MultipleFrames, (1 << 5), false), new Feature(FEATURE_DynamicTimestamp, (1 << 6), false), new Feature(FEATURE_LowLatency, (1 << 7), true), + // feature to exclude codec from REGULAR codec list + new Feature(FEATURE_SpecialCodec, (1 << 30), false, true), }; private static final Feature[] encoderFeatures = { @@ -623,6 +635,8 @@ public final class MediaCodecInfo { new Feature(FEATURE_MultipleFrames, (1 << 1), false), new Feature(FEATURE_DynamicTimestamp, (1 << 2), false), new Feature(FEATURE_QpBounds, (1 << 3), false), + // feature to exclude codec from REGULAR codec list + new Feature(FEATURE_SpecialCodec, (1 << 30), false, true), }; /** @hide */ @@ -630,7 +644,9 @@ public final class MediaCodecInfo { Feature[] features = getValidFeatures(); String[] res = new String[features.length]; for (int i = 0; i < res.length; i++) { - res[i] = features[i].mName; + if (!features[i].mInternal) { + res[i] = features[i].mName; + } } return res; } @@ -778,6 +794,10 @@ public final class MediaCodecInfo { // check feature support for (Feature feat: getValidFeatures()) { + if (feat.mInternal) { + continue; + } + Integer yesNo = (Integer)map.get(MediaFormat.KEY_FEATURE_ + feat.mName); if (yesNo == null) { continue; @@ -1091,7 +1111,9 @@ public final class MediaCodecInfo { mFlagsRequired |= feat.mValue; } mFlagsSupported |= feat.mValue; - mDefaultFormat.setInteger(key, 1); + if (!feat.mInternal) { + mDefaultFormat.setInteger(key, 1); + } // TODO restrict features by mFlagsVerified once all codecs reliably verify them } } diff --git a/media/java/android/media/PlayerBase.java b/media/java/android/media/PlayerBase.java index 86ed50bacb63..72ee00f03774 100644 --- a/media/java/android/media/PlayerBase.java +++ b/media/java/android/media/PlayerBase.java @@ -102,6 +102,13 @@ public abstract class PlayerBase { mState = AudioPlaybackConfiguration.PLAYER_STATE_IDLE; }; + /** @hide */ + public int getPlayerIId() { + synchronized (mLock) { + return mPlayerIId; + } + } + /** * Call from derived class when instantiation / initialization is successful */ diff --git a/media/jni/Android.bp b/media/jni/Android.bp index bc73f6ad1ad2..c775b6f7afc2 100644 --- a/media/jni/Android.bp +++ b/media/jni/Android.bp @@ -183,8 +183,8 @@ cc_library_shared { "libmedia", "libnativehelper", "libutils", - "tv_tuner_aidl_interface-ndk_platform", - "tv_tuner_resource_manager_aidl_interface-ndk_platform", + "tv_tuner_aidl_interface-ndk", + "tv_tuner_resource_manager_aidl_interface-ndk", ], static_libs: [ diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp index 2636ab227646..8dcdc989ec8f 100644 --- a/media/jni/android_media_MediaPlayer.cpp +++ b/media/jni/android_media_MediaPlayer.cpp @@ -953,7 +953,7 @@ android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_t Parcel* parcel = parcelForJavaObject(env, jAttributionSource); android::content::AttributionSourceState attributionSource; attributionSource.readFromParcel(parcel); - sp<MediaPlayer> mp = new MediaPlayer(attributionSource); + sp<MediaPlayer> mp = sp<MediaPlayer>::make(attributionSource); if (mp == NULL) { jniThrowException(env, "java/lang/RuntimeException", "Out of memory"); return; diff --git a/mms/OWNERS b/mms/OWNERS index 7f05a2a24d6e..f56845ed80c7 100644 --- a/mms/OWNERS +++ b/mms/OWNERS @@ -3,16 +3,15 @@ set noparent tgunn@google.com breadley@google.com rgreenwalt@google.com -amitmahajan@google.com fionaxu@google.com jackyu@google.com jminjie@google.com satk@google.com shuoq@google.com -nazaninb@google.com sarahchin@google.com xiaotonj@google.com huiwang@google.com jayachandranc@google.com chinmayd@google.com amruthr@google.com +sasindran@google.com diff --git a/packages/CarrierDefaultApp/OWNERS b/packages/CarrierDefaultApp/OWNERS index 0d23f053499c..b9de5a3919f5 100644 --- a/packages/CarrierDefaultApp/OWNERS +++ b/packages/CarrierDefaultApp/OWNERS @@ -2,17 +2,16 @@ set noparent tgunn@google.com breadley@google.com rgreenwalt@google.com -amitmahajan@google.com fionaxu@google.com jackyu@google.com jminjie@google.com satk@google.com shuoq@google.com -nazaninb@google.com sarahchin@google.com xiaotonj@google.com huiwang@google.com jayachandranc@google.com chinmayd@google.com amruthr@google.com +sasindran@google.com diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java index c1a0a9a92cc2..b4cafd8548f4 100644 --- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java +++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java @@ -93,9 +93,9 @@ public class CompanionDeviceActivity extends Activity { final DeviceFilterPair selectedDevice = getService().mDevicesFound.get(0); setTitle(Html.fromHtml(getString( R.string.confirmation_title, - getCallingAppName(), - profileName, - selectedDevice.getDisplayName()), 0)); + Html.escapeHtml(getCallingAppName()), + Html.escapeHtml(selectedDevice.getDisplayName())), 0)); + mPairButton = findViewById(R.id.button_pair); mPairButton.setOnClickListener(v -> onDeviceConfirmed(getService().mSelectedDevice)); getService().mSelectedDevice = selectedDevice; @@ -108,8 +108,8 @@ public class CompanionDeviceActivity extends Activity { mPairButton = findViewById(R.id.button_pair); mPairButton.setVisibility(View.GONE); setTitle(Html.fromHtml(getString(R.string.chooser_title, - profileName, - getCallingAppName()), 0)); + Html.escapeHtml(profileName), + Html.escapeHtml(getCallingAppName())), 0)); mDeviceListView = findViewById(R.id.device_list); mDevicesAdapter = new DevicesAdapter(); mDeviceListView.setAdapter(mDevicesAdapter); diff --git a/packages/PackageInstaller/OWNERS b/packages/PackageInstaller/OWNERS index c6331133367a..27368705c6b0 100644 --- a/packages/PackageInstaller/OWNERS +++ b/packages/PackageInstaller/OWNERS @@ -1,7 +1,5 @@ svetoslavganov@google.com -toddke@google.com -patb@google.com -suprabh@google.com +include /PACKAGE_MANAGER_OWNERS # For automotive related changes rogerxue@google.com diff --git a/packages/SettingsLib/src/com/android/settingslib/inputmethod/OWNERS b/packages/SettingsLib/src/com/android/settingslib/inputmethod/OWNERS index a0e28baee3f6..e3e28cbcd3f2 100644 --- a/packages/SettingsLib/src/com/android/settingslib/inputmethod/OWNERS +++ b/packages/SettingsLib/src/com/android/settingslib/inputmethod/OWNERS @@ -1,5 +1,3 @@ -# Default reviewers for this and subdirectories. -takaoka@google.com -yukawa@google.com +# Bug component: 34867 -# Emergency approvers in case the above are not available
\ No newline at end of file +include platform/frameworks/base:/services/core/java/com/android/server/inputmethod/OWNERS
\ No newline at end of file diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/SimStatusImeiInfoPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/SimStatusImeiInfoPreferenceControllerTest.java index 5252c6c82754..52d243a14e2f 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/SimStatusImeiInfoPreferenceControllerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/SimStatusImeiInfoPreferenceControllerTest.java @@ -20,9 +20,8 @@ import static com.google.common.truth.Truth.assertThat; import static org.robolectric.shadow.api.Shadow.extract; -import android.net.ConnectivityManager; import android.os.UserManager; -import android.util.SparseBooleanArray; +import android.telephony.TelephonyManager; import org.junit.Before; import org.junit.Test; @@ -35,7 +34,7 @@ import org.robolectric.annotation.Implements; @RunWith(RobolectricTestRunner.class) @Config(shadows = {SimStatusImeiInfoPreferenceControllerTest.ShadowUserManager.class, - SimStatusImeiInfoPreferenceControllerTest.ShadowConnectivityManager.class}) + SimStatusImeiInfoPreferenceControllerTest.ShadowTelephonyManager.class}) public class SimStatusImeiInfoPreferenceControllerTest { private AbstractSimStatusImeiInfoPreferenceController mController; @@ -56,9 +55,9 @@ public class SimStatusImeiInfoPreferenceControllerTest { ShadowUserManager userManager = extract(RuntimeEnvironment.application.getSystemService(UserManager.class)); userManager.setIsAdminUser(true); - ShadowConnectivityManager connectivityManager = - extract(RuntimeEnvironment.application.getSystemService(ConnectivityManager.class)); - connectivityManager.setNetworkSupported(ConnectivityManager.TYPE_MOBILE, true); + ShadowTelephonyManager telephonyManager = + extract(RuntimeEnvironment.application.getSystemService(TelephonyManager.class)); + telephonyManager.setDataCapable(true); assertThat(mController.isAvailable()).isTrue(); } @@ -68,9 +67,9 @@ public class SimStatusImeiInfoPreferenceControllerTest { ShadowUserManager userManager = extract(RuntimeEnvironment.application.getSystemService(UserManager.class)); userManager.setIsAdminUser(true); - ShadowConnectivityManager connectivityManager = - extract(RuntimeEnvironment.application.getSystemService(ConnectivityManager.class)); - connectivityManager.setNetworkSupported(ConnectivityManager.TYPE_MOBILE, false); + ShadowTelephonyManager telephonyManager = + extract(RuntimeEnvironment.application.getSystemService(TelephonyManager.class)); + telephonyManager.setDataCapable(false); assertThat(mController.isAvailable()).isFalse(); } @@ -99,19 +98,17 @@ public class SimStatusImeiInfoPreferenceControllerTest { } } - @Implements(ConnectivityManager.class) - public static class ShadowConnectivityManager - extends org.robolectric.shadows.ShadowConnectivityManager { - - private final SparseBooleanArray mSupportedNetworkTypes = new SparseBooleanArray(); - - private void setNetworkSupported(int networkType, boolean supported) { - mSupportedNetworkTypes.put(networkType, supported); + @Implements(TelephonyManager.class) + public static class ShadowTelephonyManager + extends org.robolectric.shadows.ShadowTelephonyManager { + private boolean mDataCapable = false; + private void setDataCapable(boolean capable) { + mDataCapable = capable; } @Implementation - public boolean isNetworkSupported(int networkType) { - return mSupportedNetworkTypes.get(networkType); + public boolean isDataCapable() { + return mDataCapable; } } } diff --git a/packages/SettingsProvider/OWNERS b/packages/SettingsProvider/OWNERS index 6c61d4b91d36..5ade9716c8cb 100644 --- a/packages/SettingsProvider/OWNERS +++ b/packages/SettingsProvider/OWNERS @@ -2,6 +2,4 @@ hackbod@android.com hackbod@google.com narayan@google.com svetoslavganov@google.com -schfan@google.com -toddke@google.com -patb@google.com +include /PACKAGE_MANAGER_OWNERS diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index 54fb6475197a..76b0b385dbda 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -641,6 +641,15 @@ </intent-filter> </receiver> + <receiver + android:name=".ProfcollectUploadReceiver" + android:exported="true" + android:permission="android.permission.TRIGGER_SHELL_PROFCOLLECT_UPLOAD" > + <intent-filter> + <action android:name="com.android.shell.action.PROFCOLLECT_UPLOAD" /> + </intent-filter> + </receiver> + <service android:name=".BugreportProgressService" android:exported="false"/> diff --git a/packages/Shell/res/xml/file_provider_paths.xml b/packages/Shell/res/xml/file_provider_paths.xml index 225c7571e7e2..85d7dd372294 100644 --- a/packages/Shell/res/xml/file_provider_paths.xml +++ b/packages/Shell/res/xml/file_provider_paths.xml @@ -1,3 +1,4 @@ <paths xmlns:android="http://schemas.android.com/apk/res/android"> <files-path name="bugreports" path="bugreports/" /> + <root-path name="profcollect" path="/data/misc/profcollectd/report/" /> </paths> diff --git a/packages/Shell/src/com/android/shell/ProfcollectUploadReceiver.java b/packages/Shell/src/com/android/shell/ProfcollectUploadReceiver.java new file mode 100644 index 000000000000..d2da724796cb --- /dev/null +++ b/packages/Shell/src/com/android/shell/ProfcollectUploadReceiver.java @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.shell; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.net.Uri; +import android.util.Log; + +import androidx.core.content.FileProvider; + +import com.android.internal.R; + +import java.io.File; +import java.util.List; + +/** + * A proxy service that relays report upload requests to the uploader app, while translating + * the path to the report to a content URI owned by this service. + */ +public final class ProfcollectUploadReceiver extends BroadcastReceiver { + private static final String AUTHORITY = "com.android.shell"; + private static final String PROFCOLLECT_DATA_ROOT = "/data/misc/profcollectd/report/"; + + private static final String LOG_TAG = "ProfcollectUploadReceiver"; + + @Override + public void onReceive(Context context, Intent intent) { + Log.i(LOG_TAG, "Received upload intent"); + + String uploaderPkg = getUploaderPackageName(context); + String uploaderAction = getUploaderActionName(context); + + try { + ApplicationInfo info = context.getPackageManager().getApplicationInfo(uploaderPkg, + 0); + if ((info.flags & ApplicationInfo.FLAG_SYSTEM) == 0) { + Log.e(LOG_TAG, "The profcollect uploader app " + uploaderPkg + + " must be a system application"); + return; + } + } catch (PackageManager.NameNotFoundException e) { + Log.e(LOG_TAG, "Cannot find profcollect uploader app " + uploaderPkg); + return; + } + + String filename = intent.getStringExtra("filename"); + File reportFile = new File(PROFCOLLECT_DATA_ROOT + filename); + Uri reportUri = FileProvider.getUriForFile(context, AUTHORITY, reportFile); + Intent uploadIntent = + new Intent(uploaderAction) + .setPackage(uploaderPkg) + .putExtra("EXTRA_DESTINATION", "PROFCOLLECT") + .putExtra("EXTRA_PACKAGE_NAME", context.getPackageName()) + .setData(reportUri) + .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) + .addFlags(Intent.FLAG_RECEIVER_FOREGROUND); + + List<ResolveInfo> receivers = + context.getPackageManager().queryBroadcastReceivers(uploadIntent, 0); + if (receivers == null || receivers.isEmpty()) { + Log.e(LOG_TAG, "No one to receive upload intent, abort upload."); + return; + } + + context.grantUriPermission(uploaderPkg, reportUri, + Intent.FLAG_GRANT_READ_URI_PERMISSION); + context.sendBroadcast(uploadIntent); + } + + private String getUploaderPackageName(Context context) { + return context.getResources().getString( + R.string.config_defaultProfcollectReportUploaderApp); + } + + private String getUploaderActionName(Context context) { + return context.getResources().getString( + R.string.config_defaultProfcollectReportUploaderAction); + } +} diff --git a/packages/SystemUI/OWNERS b/packages/SystemUI/OWNERS index 1cf14f2362de..ce23a8bc09ca 100644 --- a/packages/SystemUI/OWNERS +++ b/packages/SystemUI/OWNERS @@ -22,6 +22,7 @@ hwwang@google.com hyunyoungs@google.com jaggies@google.com jamesoleary@google.com +jbolinger@google.com jdemeulenaere@google.com jeffdq@google.com jjaggi@google.com diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricUdfpsView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricUdfpsView.java index 376368fbf9d4..d80d9cc9d62d 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricUdfpsView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricUdfpsView.java @@ -21,12 +21,19 @@ import android.annotation.Nullable; import android.content.Context; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.util.AttributeSet; +import android.util.Log; +import android.widget.FrameLayout; +import android.widget.TextView; + +import com.android.systemui.R; /** * Manages the layout for under-display fingerprint sensors (UDFPS). Ensures that UI elements * do not overlap with */ public class AuthBiometricUdfpsView extends AuthBiometricFingerprintView { + private static final String TAG = "AuthBiometricUdfpsView"; + @Nullable private UdfpsDialogMeasureAdapter mMeasureAdapter; public AuthBiometricUdfpsView(Context context) { @@ -51,4 +58,23 @@ public class AuthBiometricUdfpsView extends AuthBiometricFingerprintView { ? mMeasureAdapter.onMeasureInternal(width, height, layoutParams) : layoutParams; } + + @Override + void onLayoutInternal() { + super.onLayoutInternal(); + + // Move the UDFPS icon and indicator text if necessary. This probably only needs to happen + // for devices where the UDFPS sensor is too low. + // TODO(b/201510778): Update this logic to support cases where the sensor or text overlap + // the button bar area. + final int bottomSpacerHeight = mMeasureAdapter.getBottomSpacerHeight(); + Log.w(TAG, "bottomSpacerHeight: " + bottomSpacerHeight); + if (bottomSpacerHeight < 0) { + FrameLayout iconFrame = findViewById(R.id.biometric_icon_frame); + iconFrame.setTranslationY(-bottomSpacerHeight); + + TextView indicator = findViewById(R.id.indicator); + indicator.setTranslationY(-bottomSpacerHeight); + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapter.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapter.java index 7ccfb865cd5a..6185e59b17d8 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapter.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapter.java @@ -45,6 +45,7 @@ public class UdfpsDialogMeasureAdapter { @NonNull private final FingerprintSensorPropertiesInternal mSensorProps; @Nullable private WindowManager mWindowManager; + private int mBottomSpacerHeight; public UdfpsDialogMeasureAdapter( @NonNull ViewGroup view, @NonNull FingerprintSensorPropertiesInternal sensorProps) { @@ -74,6 +75,16 @@ public class UdfpsDialogMeasureAdapter { } } + /** + * @return the actual (and possibly negative) bottom spacer height. If negative, this indicates + * that the UDFPS sensor is too low. Our current xml and custom measurement logic is very hard + * too cleanly support this case. So, let's have the onLayout code translate the sensor location + * instead. + */ + int getBottomSpacerHeight() { + return mBottomSpacerHeight; + } + @NonNull private AuthDialog.LayoutParams onMeasureInternalPortrait(int width, int height) { // Get the height of the everything below the icon. Currently, that's the indicator and @@ -86,7 +97,7 @@ public class UdfpsDialogMeasureAdapter { final int dialogMargin = getDialogMarginPx(); final int displayHeight = getWindowBounds().height(); final Insets navbarInsets = getNavbarInsets(); - final int bottomSpacerHeight = calculateBottomSpacerHeightForPortrait( + mBottomSpacerHeight = calculateBottomSpacerHeightForPortrait( mSensorProps, displayHeight, textIndicatorHeight, buttonBarHeight, dialogMargin, navbarInsets.bottom); @@ -122,9 +133,10 @@ public class UdfpsDialogMeasureAdapter { MeasureSpec.EXACTLY)); } else if (child.getId() == R.id.space_below_icon) { // Set the spacer height so the fingerprint icon is on the physical sensor area + final int clampedSpacerHeight = Math.max(mBottomSpacerHeight, 0); child.measure( MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(bottomSpacerHeight, MeasureSpec.EXACTLY)); + MeasureSpec.makeMeasureSpec(clampedSpacerHeight, MeasureSpec.EXACTLY)); } else { child.measure( MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), diff --git a/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java b/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java index 89786ee880ad..a617850ef0ae 100644 --- a/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java +++ b/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java @@ -139,7 +139,7 @@ public class NotificationPlayer implements OnCompletionListener, OnErrorListener + " with ducking", e); } player.start(); - if (DEBUG) { Log.d(mTag, "player.start"); } + if (DEBUG) { Log.d(mTag, "player.start piid:" + player.getPlayerIId()); } } catch (Exception e) { if (player != null) { player.release(); @@ -155,7 +155,13 @@ public class NotificationPlayer implements OnCompletionListener, OnErrorListener mPlayer = player; } if (mp != null) { - if (DEBUG) { Log.d(mTag, "mPlayer.release"); } + if (DEBUG) { + Log.d(mTag, "mPlayer.pause+release piid:" + player.getPlayerIId()); + } + mp.pause(); + try { + Thread.sleep(100); + } catch (InterruptedException ie) { } mp.release(); } this.notify(); @@ -244,6 +250,10 @@ public class NotificationPlayer implements OnCompletionListener, OnErrorListener try { mp.stop(); } catch (Exception e) { } + if (DEBUG) { + Log.i(mTag, "About to release MediaPlayer piid:" + + mp.getPlayerIId() + " due to notif cancelled"); + } mp.release(); synchronized(mQueueAudioFocusLock) { if (mAudioManagerWithAudioFocus != null) { @@ -284,7 +294,7 @@ public class NotificationPlayer implements OnCompletionListener, OnErrorListener public void onCompletion(MediaPlayer mp) { synchronized(mQueueAudioFocusLock) { if (mAudioManagerWithAudioFocus != null) { - if (DEBUG) Log.d(mTag, "onCompletion() abandonning AudioFocus"); + if (DEBUG) Log.d(mTag, "onCompletion() abandoning AudioFocus"); mAudioManagerWithAudioFocus.abandonAudioFocus(null); mAudioManagerWithAudioFocus = null; } else { @@ -310,6 +320,10 @@ public class NotificationPlayer implements OnCompletionListener, OnErrorListener } } if (mp != null) { + if (DEBUG) { + Log.i("NotificationPlayer", "About to release MediaPlayer piid:" + + mp.getPlayerIId() + " due to onCompletion"); + } mp.release(); } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java index 541ee2c4fe8f..4a75810f86db 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java @@ -51,6 +51,7 @@ import com.android.systemui.qs.external.TileServices; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.settings.UserTracker; import com.android.systemui.shared.plugins.PluginManager; +import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.statusbar.phone.AutoTileManager; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.phone.StatusBarIconController; @@ -95,6 +96,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D private final UiEventLogger mUiEventLogger; private final InstanceIdSequence mInstanceIdSequence; private final CustomTileStatePersister mCustomTileStatePersister; + private final FeatureFlags mFeatureFlags; private final List<Callback> mCallbacks = new ArrayList<>(); private AutoTileManager mAutoTiles; @@ -122,7 +124,8 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D UiEventLogger uiEventLogger, UserTracker userTracker, SecureSettings secureSettings, - CustomTileStatePersister customTileStatePersister + CustomTileStatePersister customTileStatePersister, + FeatureFlags featureFlags ) { mIconController = iconController; mContext = context; @@ -144,6 +147,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D mUserTracker = userTracker; mSecureSettings = secureSettings; mCustomTileStatePersister = customTileStatePersister; + mFeatureFlags = featureFlags; mainHandler.post(() -> { // This is technically a hack to avoid circular dependency of @@ -265,7 +269,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D if (newValue == null && UserManager.isDeviceInDemoMode(mContext)) { newValue = mContext.getResources().getString(R.string.quick_settings_tiles_retail_mode); } - final List<String> tileSpecs = loadTileSpecs(mContext, newValue); + final List<String> tileSpecs = loadTileSpecs(mContext, newValue, mFeatureFlags); int currentUser = mUserTracker.getUserId(); if (currentUser != mCurrentUser) { mUserContext = mUserTracker.getUserContext(); @@ -334,7 +338,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D if (newTiles.isEmpty() && !tileSpecs.isEmpty()) { // If we didn't manage to create any tiles, set it to empty (default) Log.d(TAG, "No valid tiles on tuning changed. Setting to default."); - changeTiles(currentSpecs, loadTileSpecs(mContext, "")); + changeTiles(currentSpecs, loadTileSpecs(mContext, "", mFeatureFlags)); } else { for (int i = 0; i < mCallbacks.size(); i++) { mCallbacks.get(i).onTilesChanged(); @@ -389,7 +393,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D private void changeTileSpecs(Predicate<List<String>> changeFunction) { final String setting = mSecureSettings.getStringForUser(TILES_SETTING, mCurrentUser); - final List<String> tileSpecs = loadTileSpecs(mContext, setting); + final List<String> tileSpecs = loadTileSpecs(mContext, setting, mFeatureFlags); if (changeFunction.test(tileSpecs)) { saveTilesToSettings(tileSpecs); } @@ -478,7 +482,8 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D throw new RuntimeException("Default factory didn't create view for " + tile.getTileSpec()); } - protected static List<String> loadTileSpecs(Context context, String tileList) { + protected static List<String> loadTileSpecs( + Context context, String tileList, FeatureFlags featureFlags) { final Resources res = context.getResources(); if (TextUtils.isEmpty(tileList)) { @@ -511,6 +516,21 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D } } } + if (featureFlags.isProviderModelSettingEnabled()) { + if (!tiles.contains("internet")) { + if (tiles.contains("wifi")) { + // Replace the WiFi with Internet, and remove the Cell + tiles.set(tiles.indexOf("wifi"), "internet"); + tiles.remove("cell"); + } else if (tiles.contains("cell")) { + // Replace the Cell with Internet + tiles.set(tiles.indexOf("cell"), "internet"); + } + } else { + tiles.remove("wifi"); + tiles.remove("cell"); + } + } return tiles; } diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java index 3c2f35b954ea..f2832b3d45ff 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java +++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java @@ -41,6 +41,7 @@ import com.android.systemui.qs.dagger.QSScope; import com.android.systemui.qs.external.CustomTile; import com.android.systemui.qs.tileimpl.QSTileImpl.DrawableIcon; import com.android.systemui.settings.UserTracker; +import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.util.leak.GarbageMonitor; import java.util.ArrayList; @@ -62,6 +63,7 @@ public class TileQueryHelper { private final Executor mBgExecutor; private final Context mContext; private final UserTracker mUserTracker; + private final FeatureFlags mFeatureFlags; private TileStateListener mListener; private boolean mFinished; @@ -71,12 +73,14 @@ public class TileQueryHelper { Context context, UserTracker userTracker, @Main Executor mainExecutor, - @Background Executor bgExecutor + @Background Executor bgExecutor, + FeatureFlags featureFlags ) { mContext = context; mMainExecutor = mainExecutor; mBgExecutor = bgExecutor; mUserTracker = userTracker; + mFeatureFlags = featureFlags; } public void setListener(TileStateListener listener) { @@ -117,6 +121,10 @@ public class TileQueryHelper { } final ArrayList<QSTile> tilesToAdd = new ArrayList<>(); + if (mFeatureFlags.isProviderModelSettingEnabled()) { + possibleTiles.remove("cell"); + possibleTiles.remove("wifi"); + } for (String spec : possibleTiles) { // Only add current and stock tiles that can be created from QSFactoryImpl. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java index 86c90c7bcb2e..9eb95c409009 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java @@ -16,7 +16,6 @@ package com.android.systemui.statusbar.notification.row; -import android.annotation.ColorInt; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; @@ -28,15 +27,12 @@ import com.android.systemui.statusbar.notification.stack.ExpandableViewState; import com.android.systemui.statusbar.notification.stack.ViewState; public class FooterView extends StackScrollerDecorView { - private final int mClearAllTopPadding; private FooterViewButton mDismissButton; private FooterViewButton mManageButton; private boolean mShowHistory; public FooterView(Context context, AttributeSet attrs) { super(context, attrs); - mClearAllTopPadding = context.getResources().getDimensionPixelSize( - R.dimen.clear_all_padding_top); } @Override @@ -55,11 +51,6 @@ public class FooterView extends StackScrollerDecorView { mManageButton = findViewById(R.id.manage_text); } - public void setTextColor(@ColorInt int color) { - mManageButton.setTextColor(color); - mDismissButton.setTextColor(color); - } - public void setManageButtonClickListener(OnClickListener listener) { mManageButton.setOnClickListener(listener); } @@ -95,21 +86,25 @@ public class FooterView extends StackScrollerDecorView { @Override protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); - int textColor = getResources().getColor(R.color.notif_pill_text); - Resources.Theme theme = getContext().getTheme(); - mDismissButton.setBackground( - getResources().getDrawable(R.drawable.notif_footer_btn_background, theme)); - mDismissButton.setTextColor(textColor); - mManageButton.setBackground( - getResources().getDrawable(R.drawable.notif_footer_btn_background, theme)); - mManageButton = findViewById(R.id.manage_text); + updateColors(); mDismissButton.setText(R.string.clear_all_notifications_text); - mManageButton.setTextColor(textColor); mDismissButton.setContentDescription( mContext.getString(R.string.accessibility_clear_all)); showHistory(mShowHistory); } + /** + * Update the text and background colors for the current color palette and night mode setting. + */ + public void updateColors() { + Resources.Theme theme = mContext.getTheme(); + int textColor = getResources().getColor(R.color.notif_pill_text, theme); + mDismissButton.setBackground(theme.getDrawable(R.drawable.notif_footer_btn_background)); + mDismissButton.setTextColor(textColor); + mManageButton.setBackground(theme.getDrawable(R.drawable.notif_footer_btn_background)); + mManageButton.setTextColor(textColor); + } + @Override public ExpandableViewState createExpandableViewState() { return new FooterViewState(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index 289c32f17b31..0660daab3720 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -4231,7 +4231,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable final @ColorInt int textColor = Utils.getColorAttrDefaultColor(mContext, android.R.attr.textColorPrimary); mSectionsManager.setHeaderForegroundColor(textColor); - mFooterView.setTextColor(textColor); + mFooterView.updateColors(); mEmptyShadeView.setTextColor(textColor); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java index 3ee3e55c749a..7f89b2629a6a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java @@ -139,7 +139,7 @@ public class QSFragmentTest extends SysuiBaseFragmentTest { () -> mock(AutoTileManager.class), mock(DumpManager.class), mock(BroadcastDispatcher.class), Optional.of(mock(StatusBar.class)), mock(QSLogger.class), mock(UiEventLogger.class), mock(UserTracker.class), - mock(SecureSettings.class), mock(CustomTileStatePersister.class)); + mock(SecureSettings.class), mock(CustomTileStatePersister.class), mFeatureFlags); qs.setHost(host); qs.setListening(true); diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java index 9e97f801be3e..4cbad5f15c5f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java @@ -63,6 +63,7 @@ import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.settings.UserTracker; import com.android.systemui.shared.plugins.PluginManager; +import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.statusbar.phone.AutoTileManager; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.phone.StatusBarIconController; @@ -124,6 +125,8 @@ public class QSTileHostTest extends SysuiTestCase { private SecureSettings mSecureSettings; @Mock private CustomTileStatePersister mCustomTileStatePersister; + @Mock + private FeatureFlags mFeatureFlags; private Handler mHandler; private TestableLooper mLooper; @@ -137,9 +140,9 @@ public class QSTileHostTest extends SysuiTestCase { mQSTileHost = new TestQSTileHost(mContext, mIconController, mDefaultFactory, mHandler, mLooper.getLooper(), mPluginManager, mTunerService, mAutoTiles, mDumpManager, mBroadcastDispatcher, mStatusBar, mQSLogger, mUiEventLogger, mUserTracker, - mSecureSettings, mCustomTileStatePersister); + mSecureSettings, mCustomTileStatePersister, mFeatureFlags); setUpTileFactory(); - + when(mFeatureFlags.isProviderModelSettingEnabled()).thenReturn(false); when(mSecureSettings.getStringForUser(eq(QSTileHost.TILES_SETTING), anyInt())) .thenReturn(""); } @@ -169,13 +172,13 @@ public class QSTileHostTest extends SysuiTestCase { @Test public void testLoadTileSpecs_emptySetting() { - List<String> tiles = QSTileHost.loadTileSpecs(mContext, ""); + List<String> tiles = QSTileHost.loadTileSpecs(mContext, "", mFeatureFlags); assertFalse(tiles.isEmpty()); } @Test public void testLoadTileSpecs_nullSetting() { - List<String> tiles = QSTileHost.loadTileSpecs(mContext, null); + List<String> tiles = QSTileHost.loadTileSpecs(mContext, null, mFeatureFlags); assertFalse(tiles.isEmpty()); } @@ -189,6 +192,55 @@ public class QSTileHostTest extends SysuiTestCase { } @Test + public void testRemoveWifiAndCellularWithoutInternet() { + when(mFeatureFlags.isProviderModelSettingEnabled()).thenReturn(true); + mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "wifi, spec1, cell, spec2"); + + assertEquals("internet", mQSTileHost.mTileSpecs.get(0)); + assertEquals("spec1", mQSTileHost.mTileSpecs.get(1)); + assertEquals("spec2", mQSTileHost.mTileSpecs.get(2)); + } + + @Test + public void testRemoveWifiAndCellularWithInternet() { + when(mFeatureFlags.isProviderModelSettingEnabled()).thenReturn(true); + mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "wifi, spec1, cell, spec2, internet"); + + assertEquals("spec1", mQSTileHost.mTileSpecs.get(0)); + assertEquals("spec2", mQSTileHost.mTileSpecs.get(1)); + assertEquals("internet", mQSTileHost.mTileSpecs.get(2)); + } + + @Test + public void testRemoveWifiWithoutInternet() { + when(mFeatureFlags.isProviderModelSettingEnabled()).thenReturn(true); + mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1, wifi, spec2"); + + assertEquals("spec1", mQSTileHost.mTileSpecs.get(0)); + assertEquals("internet", mQSTileHost.mTileSpecs.get(1)); + assertEquals("spec2", mQSTileHost.mTileSpecs.get(2)); + } + + @Test + public void testRemoveCellWithInternet() { + when(mFeatureFlags.isProviderModelSettingEnabled()).thenReturn(true); + mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1, spec2, cell, internet"); + + assertEquals("spec1", mQSTileHost.mTileSpecs.get(0)); + assertEquals("spec2", mQSTileHost.mTileSpecs.get(1)); + assertEquals("internet", mQSTileHost.mTileSpecs.get(2)); + } + + @Test + public void testNoWifiNoCellularNoInternet() { + when(mFeatureFlags.isProviderModelSettingEnabled()).thenReturn(true); + mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1,spec2"); + + assertEquals("spec1", mQSTileHost.mTileSpecs.get(0)); + assertEquals("spec2", mQSTileHost.mTileSpecs.get(1)); + } + + @Test public void testSpecWithInvalidDoesNotUseDefault() { mContext.getOrCreateTestableResources() .addOverride(R.string.quick_settings_tiles, "spec1,spec2"); @@ -321,7 +373,7 @@ public class QSTileHostTest extends SysuiTestCase { @Test public void testLoadTileSpec_repeated() { - List<String> specs = QSTileHost.loadTileSpecs(mContext, "spec1,spec1,spec2"); + List<String> specs = QSTileHost.loadTileSpecs(mContext, "spec1,spec1,spec2", mFeatureFlags); assertEquals(2, specs.size()); assertEquals("spec1", specs.get(0)); @@ -332,7 +384,7 @@ public class QSTileHostTest extends SysuiTestCase { public void testLoadTileSpec_repeatedInDefault() { mContext.getOrCreateTestableResources() .addOverride(R.string.quick_settings_tiles_default, "spec1,spec1"); - List<String> specs = QSTileHost.loadTileSpecs(mContext, "default"); + List<String> specs = QSTileHost.loadTileSpecs(mContext, "default", mFeatureFlags); // Remove spurious tiles, like dbg:mem specs.removeIf(spec -> !"spec1".equals(spec)); @@ -343,7 +395,7 @@ public class QSTileHostTest extends SysuiTestCase { public void testLoadTileSpec_repeatedDefaultAndSetting() { mContext.getOrCreateTestableResources() .addOverride(R.string.quick_settings_tiles_default, "spec1"); - List<String> specs = QSTileHost.loadTileSpecs(mContext, "default,spec1"); + List<String> specs = QSTileHost.loadTileSpecs(mContext, "default,spec1", mFeatureFlags); // Remove spurious tiles, like dbg:mem specs.removeIf(spec -> !"spec1".equals(spec)); @@ -371,11 +423,12 @@ public class QSTileHostTest extends SysuiTestCase { Provider<AutoTileManager> autoTiles, DumpManager dumpManager, BroadcastDispatcher broadcastDispatcher, StatusBar statusBar, QSLogger qsLogger, UiEventLogger uiEventLogger, UserTracker userTracker, - SecureSettings secureSettings, CustomTileStatePersister customTileStatePersister) { + SecureSettings secureSettings, CustomTileStatePersister customTileStatePersister, + FeatureFlags featureFlags) { super(context, iconController, defaultFactory, mainHandler, bgLooper, pluginManager, tunerService, autoTiles, dumpManager, broadcastDispatcher, Optional.of(statusBar), qsLogger, uiEventLogger, userTracker, secureSettings, - customTileStatePersister); + customTileStatePersister, featureFlags); } @Override diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java index 4efcc5c3fc73..c5b67091d197 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java @@ -58,6 +58,7 @@ import com.android.systemui.plugins.qs.QSIconView; import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.qs.QSTileHost; import com.android.systemui.settings.UserTracker; +import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.time.FakeSystemClock; @@ -108,6 +109,8 @@ public class TileQueryHelperTest extends SysuiTestCase { private PackageManager mPackageManager; @Mock private UserTracker mUserTracker; + @Mock + private FeatureFlags mFeatureFlags; @Captor private ArgumentCaptor<List<TileQueryHelper.TileInfo>> mCaptor; @@ -133,12 +136,12 @@ public class TileQueryHelperTest extends SysuiTestCase { } } ).when(mQSTileHost).createTile(anyString()); - + when(mFeatureFlags.isProviderModelSettingEnabled()).thenReturn(false); FakeSystemClock clock = new FakeSystemClock(); mMainExecutor = new FakeExecutor(clock); mBgExecutor = new FakeExecutor(clock); mTileQueryHelper = new TileQueryHelper( - mContext, mUserTracker, mMainExecutor, mBgExecutor); + mContext, mUserTracker, mMainExecutor, mBgExecutor, mFeatureFlags); mTileQueryHelper.setListener(mListener); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java index 2b1840462291..01fa222896d3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java @@ -48,6 +48,7 @@ import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSFactoryImpl; import com.android.systemui.settings.UserTracker; import com.android.systemui.shared.plugins.PluginManager; +import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.statusbar.phone.AutoTileManager; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.phone.StatusBarIconController; @@ -98,6 +99,8 @@ public class TileServicesTest extends SysuiTestCase { private UserTracker mUserTracker; @Mock private SecureSettings mSecureSettings; + @Mock + private FeatureFlags mFeatureFlags; @Before public void setUp() throws Exception { @@ -119,7 +122,8 @@ public class TileServicesTest extends SysuiTestCase { mUiEventLogger, mUserTracker, mSecureSettings, - mock(CustomTileStatePersister.class)); + mock(CustomTileStatePersister.class), + mFeatureFlags); mTileService = new TestTileServices(host, Looper.getMainLooper(), mBroadcastDispatcher, mUserTracker); } diff --git a/rs/jni/Android.bp b/rs/jni/Android.bp new file mode 100644 index 000000000000..9a6fa8e8e423 --- /dev/null +++ b/rs/jni/Android.bp @@ -0,0 +1,54 @@ +// +// Copyright (C) 2021 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package { + // See: http://go/android-license-faq + default_applicable_licenses: ["frameworks_base_license"], +} + +cc_library_shared { + name: "librs_jni", + + srcs: ["android_renderscript_RenderScript.cpp"], + + shared_libs: [ + "libandroid", + "libandroid_runtime", + "libandroidfw", + "libRS", + "libcutils", + "libhwui", + "liblog", + "libutils", + "libui", + "libgui", + "libjnigraphics", + ], + + header_libs: [ + "jni_headers", + "libbase_headers", + ], + + include_dirs: ["frameworks/rs"], + + cflags: [ + "-Wno-unused-parameter", + "-Wunused", + "-Wunreachable-code", + "-Wno-deprecated-declarations", + ], +} diff --git a/rs/jni/Android.mk b/rs/jni/Android.mk deleted file mode 100644 index 0caba421dca8..000000000000 --- a/rs/jni/Android.mk +++ /dev/null @@ -1,37 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - android_renderscript_RenderScript.cpp - -LOCAL_SHARED_LIBRARIES := \ - libandroid \ - libandroid_runtime \ - libandroidfw \ - libRS \ - libcutils \ - libhwui \ - liblog \ - libutils \ - libui \ - libgui \ - libjnigraphics - -LOCAL_HEADER_LIBRARIES := \ - jni_headers \ - libbase_headers - -LOCAL_C_INCLUDES += \ - frameworks/rs - -LOCAL_CFLAGS += -Wno-unused-parameter -LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code -Wno-deprecated-declarations - -LOCAL_MODULE:= librs_jni -LOCAL_LICENSE_KINDS:= SPDX-license-identifier-Apache-2.0 -LOCAL_LICENSE_CONDITIONS:= notice -LOCAL_NOTICE_FILE:= $(LOCAL_PATH)/../../NOTICE -LOCAL_MODULE_TAGS := optional -LOCAL_REQUIRED_MODULES := libRS - -include $(BUILD_SHARED_LIBRARY) diff --git a/services/core/Android.bp b/services/core/Android.bp index 55b982b40611..2103bcc01b6a 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -138,9 +138,11 @@ java_library_static { "android.hardware.boot-V1.1-java", "android.hardware.boot-V1.2-java", "android.hardware.broadcastradio-V2.0-java", - "android.hardware.health-V1.0-java", - "android.hardware.health-V2.0-java", - "android.hardware.health-V2.1-java", + "android.hardware.health-V1.0-java", // HIDL + "android.hardware.health-V2.0-java", // HIDL + "android.hardware.health-V2.1-java", // HIDL + "android.hardware.health-V1-java", // AIDL + "android.hardware.health-translate-java", "android.hardware.light-V1-java", "android.hardware.tv.cec-V1.1-java", "android.hardware.weaver-V1.0-java", @@ -149,7 +151,7 @@ java_library_static { "android.hardware.biometrics.fingerprint-V2.3-java", "android.hardware.biometrics.fingerprint-V1-java", "android.hardware.oemlock-V1.0-java", - "android.hardware.configstore-V1.0-java", + "android.hardware.configstore-V1.1-java", "android.hardware.contexthub-V1.0-java", "android.hardware.rebootescrow-V1-java", "android.hardware.soundtrigger-V2.3-java", diff --git a/services/core/java/android/content/pm/OWNERS b/services/core/java/android/content/pm/OWNERS index 5eed0b509688..39931407ec1f 100644 --- a/services/core/java/android/content/pm/OWNERS +++ b/services/core/java/android/content/pm/OWNERS @@ -1 +1 @@ -include /core/java/android/content/pm/OWNERS
\ No newline at end of file +include /PACKAGE_MANAGER_OWNERS
\ No newline at end of file diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java index 1e608f5c1240..844ac86e8eb5 100644 --- a/services/core/java/com/android/server/BatteryService.java +++ b/services/core/java/com/android/server/BatteryService.java @@ -17,6 +17,7 @@ package com.android.server; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import static com.android.server.health.Utils.copyV1Battery; import android.annotation.Nullable; import android.app.ActivityManager; @@ -25,14 +26,8 @@ import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.database.ContentObserver; -import android.hardware.health.V1_0.HealthInfo; -import android.hardware.health.V2_0.IHealth; -import android.hardware.health.V2_0.Result; +import android.hardware.health.HealthInfo; import android.hardware.health.V2_1.BatteryCapacityLevel; -import android.hardware.health.V2_1.Constants; -import android.hardware.health.V2_1.IHealthInfoCallback; -import android.hidl.manager.V1_0.IServiceManager; -import android.hidl.manager.V1_0.IServiceNotification; import android.metrics.LogMaker; import android.os.BatteryManager; import android.os.BatteryManagerInternal; @@ -44,7 +39,6 @@ import android.os.Bundle; import android.os.DropBoxManager; import android.os.FileUtils; import android.os.Handler; -import android.os.HandlerThread; import android.os.IBatteryPropertiesRegistrar; import android.os.IBinder; import android.os.OsProtoEnums; @@ -62,15 +56,14 @@ import android.provider.Settings; import android.service.battery.BatteryServiceDumpProto; import android.sysprop.PowerProperties; import android.util.EventLog; -import android.util.MutableInt; import android.util.Slog; import android.util.proto.ProtoOutputStream; -import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IBatteryStats; import com.android.internal.logging.MetricsLogger; import com.android.internal.util.DumpUtils; import com.android.server.am.BatteryStatsService; +import com.android.server.health.HealthServiceWrapper; import com.android.server.lights.LightsManager; import com.android.server.lights.LogicalLight; @@ -81,11 +74,7 @@ import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayDeque; import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; import java.util.NoSuchElementException; -import java.util.Objects; -import java.util.concurrent.atomic.AtomicReference; /** * <p>BatteryService monitors the charging status, and charge level of the device @@ -149,7 +138,6 @@ public final class BatteryService extends SystemService { private HealthInfo mHealthInfo; private final HealthInfo mLastHealthInfo = new HealthInfo(); - private android.hardware.health.V2_1.HealthInfo mHealthInfo2p1; private boolean mBatteryLevelCritical; private int mLastBatteryStatus; private int mLastBatteryHealth; @@ -193,7 +181,6 @@ public final class BatteryService extends SystemService { private ActivityManagerInternal mActivityManagerInternal; private HealthServiceWrapper mHealthServiceWrapper; - private HealthHalCallback mHealthHalCallback; private BatteryPropertiesRegistrar mBatteryPropertiesRegistrar; private ArrayDeque<Bundle> mBatteryLevelsEventQueue; private long mLastBatteryLevelChangedSentMs; @@ -276,13 +263,9 @@ public final class BatteryService extends SystemService { private void registerHealthCallback() { traceBegin("HealthInitWrapper"); - mHealthServiceWrapper = new HealthServiceWrapper(); - mHealthHalCallback = new HealthHalCallback(); // IHealth is lazily retrieved. try { - mHealthServiceWrapper.init(mHealthHalCallback, - new HealthServiceWrapper.IServiceManagerSupplier() {}, - new HealthServiceWrapper.IHealthSupplier() {}); + mHealthServiceWrapper = HealthServiceWrapper.create(this::update); } catch (RemoteException ex) { Slog.e(TAG, "health: cannot register callback. (RemoteException)"); throw ex.rethrowFromSystemServer(); @@ -370,8 +353,8 @@ public final class BatteryService extends SystemService { } private boolean shouldShutdownLocked() { - if (mHealthInfo2p1.batteryCapacityLevel != BatteryCapacityLevel.UNSUPPORTED) { - return (mHealthInfo2p1.batteryCapacityLevel == BatteryCapacityLevel.CRITICAL); + if (mHealthInfo.batteryCapacityLevel != BatteryCapacityLevel.UNSUPPORTED) { + return (mHealthInfo.batteryCapacityLevel == BatteryCapacityLevel.CRITICAL); } if (mHealthInfo.batteryLevel > 0) { return false; @@ -413,7 +396,7 @@ public final class BatteryService extends SystemService { // shut down gracefully if temperature is too high (> 68.0C by default) // wait until the system has booted before attempting to display the // shutdown dialog. - if (mHealthInfo.batteryTemperature > mShutdownBatteryTemperature) { + if (mHealthInfo.batteryTemperatureTenthsCelsius > mShutdownBatteryTemperature) { mHandler.post(new Runnable() { @Override public void run() { @@ -430,51 +413,28 @@ public final class BatteryService extends SystemService { } } - private void update(android.hardware.health.V2_1.HealthInfo info) { + private void update(android.hardware.health.HealthInfo info) { traceBegin("HealthInfoUpdate"); - Trace.traceCounter(Trace.TRACE_TAG_POWER, "BatteryChargeCounter", - info.legacy.legacy.batteryChargeCounter); - Trace.traceCounter(Trace.TRACE_TAG_POWER, "BatteryCurrent", - info.legacy.legacy.batteryCurrent); - Trace.traceCounter(Trace.TRACE_TAG_POWER, "PlugType", - plugType(info.legacy.legacy)); - Trace.traceCounter(Trace.TRACE_TAG_POWER, "BatteryStatus", - info.legacy.legacy.batteryStatus); + Trace.traceCounter( + Trace.TRACE_TAG_POWER, "BatteryChargeCounter", info.batteryChargeCounterUah); + Trace.traceCounter(Trace.TRACE_TAG_POWER, "BatteryCurrent", info.batteryCurrentMicroamps); + Trace.traceCounter(Trace.TRACE_TAG_POWER, "PlugType", plugType(info)); + Trace.traceCounter(Trace.TRACE_TAG_POWER, "BatteryStatus", info.batteryStatus); synchronized (mLock) { if (!mUpdatesStopped) { - mHealthInfo = info.legacy.legacy; - mHealthInfo2p1 = info; + mHealthInfo = info; // Process the new values. processValuesLocked(false); mLock.notifyAll(); // for any waiters on new info } else { - copy(mLastHealthInfo, info.legacy.legacy); + copyV1Battery(mLastHealthInfo, info); } } traceEnd(); } - private static void copy(HealthInfo dst, HealthInfo src) { - dst.chargerAcOnline = src.chargerAcOnline; - dst.chargerUsbOnline = src.chargerUsbOnline; - dst.chargerWirelessOnline = src.chargerWirelessOnline; - dst.maxChargingCurrent = src.maxChargingCurrent; - dst.maxChargingVoltage = src.maxChargingVoltage; - dst.batteryStatus = src.batteryStatus; - dst.batteryHealth = src.batteryHealth; - dst.batteryPresent = src.batteryPresent; - dst.batteryLevel = src.batteryLevel; - dst.batteryVoltage = src.batteryVoltage; - dst.batteryTemperature = src.batteryTemperature; - dst.batteryCurrent = src.batteryCurrent; - dst.batteryCycleCount = src.batteryCycleCount; - dst.batteryFullCharge = src.batteryFullCharge; - dst.batteryChargeCounter = src.batteryChargeCounter; - dst.batteryTechnology = src.batteryTechnology; - } - private static int plugType(HealthInfo healthInfo) { if (healthInfo.chargerAcOnline) { return BatteryManager.BATTERY_PLUGGED_AC; @@ -505,11 +465,16 @@ public final class BatteryService extends SystemService { // Let the battery stats keep track of the current level. try { - mBatteryStats.setBatteryState(mHealthInfo.batteryStatus, mHealthInfo.batteryHealth, - mPlugType, mHealthInfo.batteryLevel, mHealthInfo.batteryTemperature, - mHealthInfo.batteryVoltage, mHealthInfo.batteryChargeCounter, - mHealthInfo.batteryFullCharge, - mHealthInfo2p1.batteryChargeTimeToFullNowSeconds); + mBatteryStats.setBatteryState( + mHealthInfo.batteryStatus, + mHealthInfo.batteryHealth, + mPlugType, + mHealthInfo.batteryLevel, + mHealthInfo.batteryTemperatureTenthsCelsius, + mHealthInfo.batteryVoltageMillivolts, + mHealthInfo.batteryChargeCounterUah, + mHealthInfo.batteryFullChargeUah, + mHealthInfo.batteryChargeTimeToFullNowSeconds); } catch (RemoteException e) { // Should never happen. } @@ -517,17 +482,18 @@ public final class BatteryService extends SystemService { shutdownIfNoPowerLocked(); shutdownIfOverTempLocked(); - if (force || (mHealthInfo.batteryStatus != mLastBatteryStatus || - mHealthInfo.batteryHealth != mLastBatteryHealth || - mHealthInfo.batteryPresent != mLastBatteryPresent || - mHealthInfo.batteryLevel != mLastBatteryLevel || - mPlugType != mLastPlugType || - mHealthInfo.batteryVoltage != mLastBatteryVoltage || - mHealthInfo.batteryTemperature != mLastBatteryTemperature || - mHealthInfo.maxChargingCurrent != mLastMaxChargingCurrent || - mHealthInfo.maxChargingVoltage != mLastMaxChargingVoltage || - mHealthInfo.batteryChargeCounter != mLastChargeCounter || - mInvalidCharger != mLastInvalidCharger)) { + if (force + || (mHealthInfo.batteryStatus != mLastBatteryStatus + || mHealthInfo.batteryHealth != mLastBatteryHealth + || mHealthInfo.batteryPresent != mLastBatteryPresent + || mHealthInfo.batteryLevel != mLastBatteryLevel + || mPlugType != mLastPlugType + || mHealthInfo.batteryVoltageMillivolts != mLastBatteryVoltage + || mHealthInfo.batteryTemperatureTenthsCelsius != mLastBatteryTemperature + || mHealthInfo.maxChargingCurrentMicroamps != mLastMaxChargingCurrent + || mHealthInfo.maxChargingVoltageMicrovolts != mLastMaxChargingVoltage + || mHealthInfo.batteryChargeCounterUah != mLastChargeCounter + || mInvalidCharger != mLastInvalidCharger)) { if (mPlugType != mLastPlugType) { if (mLastPlugType == BATTERY_PLUGGED_NONE) { @@ -584,8 +550,11 @@ public final class BatteryService extends SystemService { if (mHealthInfo.batteryLevel != mLastBatteryLevel) { // Don't do this just from voltage or temperature changes, that is // too noisy. - EventLog.writeEvent(EventLogTags.BATTERY_LEVEL, - mHealthInfo.batteryLevel, mHealthInfo.batteryVoltage, mHealthInfo.batteryTemperature); + EventLog.writeEvent( + EventLogTags.BATTERY_LEVEL, + mHealthInfo.batteryLevel, + mHealthInfo.batteryVoltageMillivolts, + mHealthInfo.batteryTemperatureTenthsCelsius); } if (mBatteryLevelCritical && !mLastBatteryLevelCritical && mPlugType == BATTERY_PLUGGED_NONE) { @@ -691,11 +660,11 @@ public final class BatteryService extends SystemService { mLastBatteryPresent = mHealthInfo.batteryPresent; mLastBatteryLevel = mHealthInfo.batteryLevel; mLastPlugType = mPlugType; - mLastBatteryVoltage = mHealthInfo.batteryVoltage; - mLastBatteryTemperature = mHealthInfo.batteryTemperature; - mLastMaxChargingCurrent = mHealthInfo.maxChargingCurrent; - mLastMaxChargingVoltage = mHealthInfo.maxChargingVoltage; - mLastChargeCounter = mHealthInfo.batteryChargeCounter; + mLastBatteryVoltage = mHealthInfo.batteryVoltageMillivolts; + mLastBatteryTemperature = mHealthInfo.batteryTemperatureTenthsCelsius; + mLastMaxChargingCurrent = mHealthInfo.maxChargingCurrentMicroamps; + mLastMaxChargingVoltage = mHealthInfo.maxChargingVoltageMicrovolts; + mLastChargeCounter = mHealthInfo.batteryChargeCounterUah; mLastBatteryLevelCritical = mBatteryLevelCritical; mLastInvalidCharger = mInvalidCharger; } @@ -718,13 +687,17 @@ public final class BatteryService extends SystemService { intent.putExtra(BatteryManager.EXTRA_SCALE, BATTERY_SCALE); intent.putExtra(BatteryManager.EXTRA_ICON_SMALL, icon); intent.putExtra(BatteryManager.EXTRA_PLUGGED, mPlugType); - intent.putExtra(BatteryManager.EXTRA_VOLTAGE, mHealthInfo.batteryVoltage); - intent.putExtra(BatteryManager.EXTRA_TEMPERATURE, mHealthInfo.batteryTemperature); + intent.putExtra(BatteryManager.EXTRA_VOLTAGE, mHealthInfo.batteryVoltageMillivolts); + intent.putExtra( + BatteryManager.EXTRA_TEMPERATURE, mHealthInfo.batteryTemperatureTenthsCelsius); intent.putExtra(BatteryManager.EXTRA_TECHNOLOGY, mHealthInfo.batteryTechnology); intent.putExtra(BatteryManager.EXTRA_INVALID_CHARGER, mInvalidCharger); - intent.putExtra(BatteryManager.EXTRA_MAX_CHARGING_CURRENT, mHealthInfo.maxChargingCurrent); - intent.putExtra(BatteryManager.EXTRA_MAX_CHARGING_VOLTAGE, mHealthInfo.maxChargingVoltage); - intent.putExtra(BatteryManager.EXTRA_CHARGE_COUNTER, mHealthInfo.batteryChargeCounter); + intent.putExtra( + BatteryManager.EXTRA_MAX_CHARGING_CURRENT, mHealthInfo.maxChargingCurrentMicroamps); + intent.putExtra( + BatteryManager.EXTRA_MAX_CHARGING_VOLTAGE, + mHealthInfo.maxChargingVoltageMicrovolts); + intent.putExtra(BatteryManager.EXTRA_CHARGE_COUNTER, mHealthInfo.batteryChargeCounterUah); if (DEBUG) { Slog.d(TAG, "Sending ACTION_BATTERY_CHANGED. scale:" + BATTERY_SCALE + ", info:" + mHealthInfo.toString()); @@ -744,9 +717,9 @@ public final class BatteryService extends SystemService { event.putBoolean(BatteryManager.EXTRA_BATTERY_LOW, mSentLowBatteryBroadcast); event.putInt(BatteryManager.EXTRA_SCALE, BATTERY_SCALE); event.putInt(BatteryManager.EXTRA_PLUGGED, mPlugType); - event.putInt(BatteryManager.EXTRA_VOLTAGE, mHealthInfo.batteryVoltage); - event.putInt(BatteryManager.EXTRA_TEMPERATURE, mHealthInfo.batteryTemperature); - event.putInt(BatteryManager.EXTRA_CHARGE_COUNTER, mHealthInfo.batteryChargeCounter); + event.putInt(BatteryManager.EXTRA_VOLTAGE, mHealthInfo.batteryVoltageMillivolts); + event.putInt(BatteryManager.EXTRA_TEMPERATURE, mHealthInfo.batteryTemperatureTenthsCelsius); + event.putInt(BatteryManager.EXTRA_CHARGE_COUNTER, mHealthInfo.batteryChargeCounterUah); event.putLong(BatteryManager.EXTRA_EVENT_TIMESTAMP, now); boolean queueWasEmpty = mBatteryLevelsEventQueue.isEmpty(); @@ -938,7 +911,7 @@ public final class BatteryService extends SystemService { } try { if (!mUpdatesStopped) { - copy(mLastHealthInfo, mHealthInfo); + copyV1Battery(mLastHealthInfo, mHealthInfo); } boolean update = true; switch (key) { @@ -961,10 +934,10 @@ public final class BatteryService extends SystemService { mHealthInfo.batteryLevel = Integer.parseInt(value); break; case "counter": - mHealthInfo.batteryChargeCounter = Integer.parseInt(value); + mHealthInfo.batteryChargeCounterUah = Integer.parseInt(value); break; case "temp": - mHealthInfo.batteryTemperature = Integer.parseInt(value); + mHealthInfo.batteryTemperatureTenthsCelsius = Integer.parseInt(value); break; case "invalid": mInvalidCharger = Integer.parseInt(value); @@ -1008,7 +981,7 @@ public final class BatteryService extends SystemService { private void setChargerAcOnline(boolean online, boolean forceUpdate) { if (!mUpdatesStopped) { - copy(mLastHealthInfo, mHealthInfo); + copyV1Battery(mLastHealthInfo, mHealthInfo); } mHealthInfo.chargerAcOnline = online; mUpdatesStopped = true; @@ -1017,7 +990,7 @@ public final class BatteryService extends SystemService { private void setBatteryLevel(int level, boolean forceUpdate) { if (!mUpdatesStopped) { - copy(mLastHealthInfo, mHealthInfo); + copyV1Battery(mLastHealthInfo, mHealthInfo); } mHealthInfo.batteryLevel = level; mUpdatesStopped = true; @@ -1026,7 +999,7 @@ public final class BatteryService extends SystemService { private void unplugBattery(boolean forceUpdate, PrintWriter pw) { if (!mUpdatesStopped) { - copy(mLastHealthInfo, mHealthInfo); + copyV1Battery(mLastHealthInfo, mHealthInfo); } mHealthInfo.chargerAcOnline = false; mHealthInfo.chargerUsbOnline = false; @@ -1038,7 +1011,7 @@ public final class BatteryService extends SystemService { private void resetBattery(boolean forceUpdate, @Nullable PrintWriter pw) { if (mUpdatesStopped) { mUpdatesStopped = false; - copy(mHealthInfo, mLastHealthInfo); + copyV1Battery(mHealthInfo, mLastHealthInfo); Binder.withCleanCallingIdentity(() -> processValuesLocked(forceUpdate, pw)); } if (mBatteryInputSuspended) { @@ -1073,16 +1046,16 @@ public final class BatteryService extends SystemService { pw.println(" AC powered: " + mHealthInfo.chargerAcOnline); pw.println(" USB powered: " + mHealthInfo.chargerUsbOnline); pw.println(" Wireless powered: " + mHealthInfo.chargerWirelessOnline); - pw.println(" Max charging current: " + mHealthInfo.maxChargingCurrent); - pw.println(" Max charging voltage: " + mHealthInfo.maxChargingVoltage); - pw.println(" Charge counter: " + mHealthInfo.batteryChargeCounter); + pw.println(" Max charging current: " + mHealthInfo.maxChargingCurrentMicroamps); + pw.println(" Max charging voltage: " + mHealthInfo.maxChargingVoltageMicrovolts); + pw.println(" Charge counter: " + mHealthInfo.batteryChargeCounterUah); pw.println(" status: " + mHealthInfo.batteryStatus); pw.println(" health: " + mHealthInfo.batteryHealth); pw.println(" present: " + mHealthInfo.batteryPresent); pw.println(" level: " + mHealthInfo.batteryLevel); pw.println(" scale: " + BATTERY_SCALE); - pw.println(" voltage: " + mHealthInfo.batteryVoltage); - pw.println(" temperature: " + mHealthInfo.batteryTemperature); + pw.println(" voltage: " + mHealthInfo.batteryVoltageMillivolts); + pw.println(" temperature: " + mHealthInfo.batteryTemperatureTenthsCelsius); pw.println(" technology: " + mHealthInfo.batteryTechnology); } else { Shell shell = new Shell(); @@ -1105,16 +1078,23 @@ public final class BatteryService extends SystemService { batteryPluggedValue = OsProtoEnums.BATTERY_PLUGGED_WIRELESS; } proto.write(BatteryServiceDumpProto.PLUGGED, batteryPluggedValue); - proto.write(BatteryServiceDumpProto.MAX_CHARGING_CURRENT, mHealthInfo.maxChargingCurrent); - proto.write(BatteryServiceDumpProto.MAX_CHARGING_VOLTAGE, mHealthInfo.maxChargingVoltage); - proto.write(BatteryServiceDumpProto.CHARGE_COUNTER, mHealthInfo.batteryChargeCounter); + proto.write( + BatteryServiceDumpProto.MAX_CHARGING_CURRENT, + mHealthInfo.maxChargingCurrentMicroamps); + proto.write( + BatteryServiceDumpProto.MAX_CHARGING_VOLTAGE, + mHealthInfo.maxChargingVoltageMicrovolts); + proto.write( + BatteryServiceDumpProto.CHARGE_COUNTER, mHealthInfo.batteryChargeCounterUah); proto.write(BatteryServiceDumpProto.STATUS, mHealthInfo.batteryStatus); proto.write(BatteryServiceDumpProto.HEALTH, mHealthInfo.batteryHealth); proto.write(BatteryServiceDumpProto.IS_PRESENT, mHealthInfo.batteryPresent); proto.write(BatteryServiceDumpProto.LEVEL, mHealthInfo.batteryLevel); proto.write(BatteryServiceDumpProto.SCALE, BATTERY_SCALE); - proto.write(BatteryServiceDumpProto.VOLTAGE, mHealthInfo.batteryVoltage); - proto.write(BatteryServiceDumpProto.TEMPERATURE, mHealthInfo.batteryTemperature); + proto.write(BatteryServiceDumpProto.VOLTAGE, mHealthInfo.batteryVoltageMillivolts); + proto.write( + BatteryServiceDumpProto.TEMPERATURE, + mHealthInfo.batteryTemperatureTenthsCelsius); proto.write(BatteryServiceDumpProto.TECHNOLOGY, mHealthInfo.batteryTechnology); } proto.flush(); @@ -1186,64 +1166,6 @@ public final class BatteryService extends SystemService { } } - private final class HealthHalCallback extends IHealthInfoCallback.Stub - implements HealthServiceWrapper.Callback { - @Override public void healthInfoChanged(android.hardware.health.V2_0.HealthInfo props) { - android.hardware.health.V2_1.HealthInfo propsLatest = - new android.hardware.health.V2_1.HealthInfo(); - propsLatest.legacy = props; - - propsLatest.batteryCapacityLevel = BatteryCapacityLevel.UNSUPPORTED; - propsLatest.batteryChargeTimeToFullNowSeconds = - Constants.BATTERY_CHARGE_TIME_TO_FULL_NOW_SECONDS_UNSUPPORTED; - - BatteryService.this.update(propsLatest); - } - - @Override public void healthInfoChanged_2_1(android.hardware.health.V2_1.HealthInfo props) { - BatteryService.this.update(props); - } - - // on new service registered - @Override public void onRegistration(IHealth oldService, IHealth newService, - String instance) { - if (newService == null) return; - - traceBegin("HealthUnregisterCallback"); - try { - if (oldService != null) { - int r = oldService.unregisterCallback(this); - if (r != Result.SUCCESS) { - Slog.w(TAG, "health: cannot unregister previous callback: " + - Result.toString(r)); - } - } - } catch (RemoteException ex) { - Slog.w(TAG, "health: cannot unregister previous callback (transaction error): " - + ex.getMessage()); - } finally { - traceEnd(); - } - - traceBegin("HealthRegisterCallback"); - try { - int r = newService.registerCallback(this); - if (r != Result.SUCCESS) { - Slog.w(TAG, "health: cannot register callback: " + Result.toString(r)); - return; - } - // registerCallback does NOT guarantee that update is called - // immediately, so request a manual update here. - newService.update(); - } catch (RemoteException ex) { - Slog.e(TAG, "health: cannot register callback (transaction error): " - + ex.getMessage()); - } finally { - traceEnd(); - } - } - } - private final class BinderService extends Binder { @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; @@ -1267,71 +1189,11 @@ public final class BatteryService extends SystemService { private final class BatteryPropertiesRegistrar extends IBatteryPropertiesRegistrar.Stub { @Override public int getProperty(int id, final BatteryProperty prop) throws RemoteException { - traceBegin("HealthGetProperty"); - try { - IHealth service = mHealthServiceWrapper.getLastService(); - if (service == null) throw new RemoteException("no health service"); - final MutableInt outResult = new MutableInt(Result.NOT_SUPPORTED); - switch(id) { - case BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER: - service.getChargeCounter((int result, int value) -> { - outResult.value = result; - if (result == Result.SUCCESS) prop.setLong(value); - }); - break; - case BatteryManager.BATTERY_PROPERTY_CURRENT_NOW: - service.getCurrentNow((int result, int value) -> { - outResult.value = result; - if (result == Result.SUCCESS) prop.setLong(value); - }); - break; - case BatteryManager.BATTERY_PROPERTY_CURRENT_AVERAGE: - service.getCurrentAverage((int result, int value) -> { - outResult.value = result; - if (result == Result.SUCCESS) prop.setLong(value); - }); - break; - case BatteryManager.BATTERY_PROPERTY_CAPACITY: - service.getCapacity((int result, int value) -> { - outResult.value = result; - if (result == Result.SUCCESS) prop.setLong(value); - }); - break; - case BatteryManager.BATTERY_PROPERTY_STATUS: - service.getChargeStatus((int result, int value) -> { - outResult.value = result; - if (result == Result.SUCCESS) prop.setLong(value); - }); - break; - case BatteryManager.BATTERY_PROPERTY_ENERGY_COUNTER: - service.getEnergyCounter((int result, long value) -> { - outResult.value = result; - if (result == Result.SUCCESS) prop.setLong(value); - }); - break; - } - return outResult.value; - } finally { - traceEnd(); - } + return mHealthServiceWrapper.getProperty(id, prop); } @Override public void scheduleUpdate() throws RemoteException { - mHealthServiceWrapper.getHandlerThread().getThreadHandler().post(() -> { - traceBegin("HealthScheduleUpdate"); - try { - IHealth service = mHealthServiceWrapper.getLastService(); - if (service == null) { - Slog.e(TAG, "no health service"); - return; - } - service.update(); - } catch (RemoteException ex) { - Slog.e(TAG, "Cannot call update on health HAL", ex); - } finally { - traceEnd(); - } - }); + mHealthServiceWrapper.scheduleUpdate(); } } @@ -1360,14 +1222,14 @@ public final class BatteryService extends SystemService { @Override public int getBatteryChargeCounter() { synchronized (mLock) { - return mHealthInfo.batteryChargeCounter; + return mHealthInfo.batteryChargeCounterUah; } } @Override public int getBatteryFullCharge() { synchronized (mLock) { - return mHealthInfo.batteryFullCharge; + return mHealthInfo.batteryFullChargeUah; } } @@ -1420,191 +1282,4 @@ public final class BatteryService extends SystemService { BatteryService.this.suspendBatteryInput(); } } - - /** - * HealthServiceWrapper wraps the internal IHealth service and refreshes the service when - * necessary. - * - * On new registration of IHealth service, {@link #onRegistration onRegistration} is called and - * the internal service is refreshed. - * On death of an existing IHealth service, the internal service is NOT cleared to avoid - * race condition between death notification and new service notification. Hence, - * a caller must check for transaction errors when calling into the service. - * - * @hide Should only be used internally. - */ - public static final class HealthServiceWrapper { - private static final String TAG = "HealthServiceWrapper"; - public static final String INSTANCE_HEALTHD = "backup"; - public static final String INSTANCE_VENDOR = "default"; - // All interesting instances, sorted by priority high -> low. - private static final List<String> sAllInstances = - Arrays.asList(INSTANCE_VENDOR, INSTANCE_HEALTHD); - - private final IServiceNotification mNotification = new Notification(); - private final HandlerThread mHandlerThread = new HandlerThread("HealthServiceHwbinder"); - // These variables are fixed after init. - private Callback mCallback; - private IHealthSupplier mHealthSupplier; - private String mInstanceName; - - // Last IHealth service received. - private final AtomicReference<IHealth> mLastService = new AtomicReference<>(); - - /** - * init should be called after constructor. For testing purposes, init is not called by - * constructor. - */ - public HealthServiceWrapper() { - } - - public IHealth getLastService() { - return mLastService.get(); - } - - /** - * See {@link #init(Callback, IServiceManagerSupplier, IHealthSupplier)} - */ - public void init() throws RemoteException, NoSuchElementException { - init(/* callback= */null, new HealthServiceWrapper.IServiceManagerSupplier() {}, - new HealthServiceWrapper.IHealthSupplier() {}); - } - - /** - * Start monitoring registration of new IHealth services. Only instances that are in - * {@code sAllInstances} and in device / framework manifest are used. This function should - * only be called once. - * - * mCallback.onRegistration() is called synchronously (aka in init thread) before - * this method returns if callback is not null. - * - * @throws RemoteException transaction error when talking to IServiceManager - * @throws NoSuchElementException if one of the following cases: - * - No service manager; - * - none of {@code sAllInstances} are in manifests (i.e. not - * available on this device), or none of these instances are available to current - * process. - * @throws NullPointerException when supplier is null - */ - void init(@Nullable Callback callback, - IServiceManagerSupplier managerSupplier, - IHealthSupplier healthSupplier) - throws RemoteException, NoSuchElementException, NullPointerException { - if (managerSupplier == null || healthSupplier == null) { - throw new NullPointerException(); - } - IServiceManager manager; - - mHealthSupplier = healthSupplier; - - // Initialize mLastService and call callback for the first time (in init thread) - IHealth newService = null; - for (String name : sAllInstances) { - traceBegin("HealthInitGetService_" + name); - try { - newService = healthSupplier.get(name); - } catch (NoSuchElementException ex) { - /* ignored, handled below */ - } finally { - traceEnd(); - } - if (newService != null) { - mInstanceName = name; - mLastService.set(newService); - break; - } - } - - if (mInstanceName == null || newService == null) { - throw new NoSuchElementException(String.format( - "No IHealth service instance among %s is available. Perhaps no permission?", - sAllInstances.toString())); - } - - if (callback != null) { - mCallback = callback; - mCallback.onRegistration(null, newService, mInstanceName); - } - - // Register for future service registrations - traceBegin("HealthInitRegisterNotification"); - mHandlerThread.start(); - try { - managerSupplier.get().registerForNotifications( - IHealth.kInterfaceName, mInstanceName, mNotification); - } finally { - traceEnd(); - } - Slog.i(TAG, "health: HealthServiceWrapper listening to instance " + mInstanceName); - } - - @VisibleForTesting - HandlerThread getHandlerThread() { - return mHandlerThread; - } - - interface Callback { - /** - * This function is invoked asynchronously when a new and related IServiceNotification - * is received. - * @param service the recently retrieved service from IServiceManager. - * Can be a dead service before service notification of a new service is delivered. - * Implementation must handle cases for {@link RemoteException}s when calling - * into service. - * @param instance instance name. - */ - void onRegistration(IHealth oldService, IHealth newService, String instance); - } - - /** - * Supplier of services. - * Must not return null; throw {@link NoSuchElementException} if a service is not available. - */ - interface IServiceManagerSupplier { - default IServiceManager get() throws NoSuchElementException, RemoteException { - return IServiceManager.getService(); - } - } - /** - * Supplier of services. - * Must not return null; throw {@link NoSuchElementException} if a service is not available. - */ - interface IHealthSupplier { - default IHealth get(String name) throws NoSuchElementException, RemoteException { - return IHealth.getService(name, true /* retry */); - } - } - - private class Notification extends IServiceNotification.Stub { - @Override - public final void onRegistration(String interfaceName, String instanceName, - boolean preexisting) { - if (!IHealth.kInterfaceName.equals(interfaceName)) return; - if (!mInstanceName.equals(instanceName)) return; - - // This runnable only runs on mHandlerThread and ordering is ensured, hence - // no locking is needed inside the runnable. - mHandlerThread.getThreadHandler().post(new Runnable() { - @Override - public void run() { - try { - IHealth newService = mHealthSupplier.get(mInstanceName); - IHealth oldService = mLastService.getAndSet(newService); - - // preexisting may be inaccurate (race). Check for equality here. - if (Objects.equals(newService, oldService)) return; - - Slog.i(TAG, "health: new instance registered " + mInstanceName); - // #init() may be called with null callback. Skip null callbacks. - if (mCallback == null) return; - mCallback.onRegistration(oldService, newService, mInstanceName); - } catch (NoSuchElementException | RemoteException ex) { - Slog.e(TAG, "health: Cannot get instance '" + mInstanceName - + "': " + ex.getMessage() + ". Perhaps no permission?"); - } - } - }); - } - } - } } diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index d6ee95131ea9..aeb814327e66 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -58,13 +58,13 @@ import android.system.OsConstants; import android.text.TextUtils; import android.util.Log; import android.util.Range; -import android.util.Slog; import android.util.SparseArray; import android.util.SparseBooleanArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Preconditions; +import com.android.net.module.util.BinderUtils; import com.android.net.module.util.NetdUtils; import com.android.net.module.util.PermissionUtils; @@ -1056,9 +1056,9 @@ public class IpSecService extends IIpSecService.Stub { public void systemReady() { if (isNetdAlive()) { - Slog.d(TAG, "IpSecService is ready"); + Log.d(TAG, "IpSecService is ready"); } else { - Slog.wtf(TAG, "IpSecService not ready: failed to connect to NetD Native Service!"); + Log.wtf(TAG, "IpSecService not ready: failed to connect to NetD Native Service!"); } } @@ -1332,7 +1332,7 @@ public class IpSecService extends IIpSecService.Stub { final INetd netd = mSrvConfig.getNetdInstance(); netd.ipSecAddTunnelInterface(intfName, localAddr, remoteAddr, ikey, okey, resourceId); - Binder.withCleanCallingIdentity(() -> { + BinderUtils.withCleanCallingIdentity(() -> { NetdUtils.setInterfaceUp(netd, intfName); }); diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java index 3ea0ce173745..c7e906876526 100644 --- a/services/core/java/com/android/server/NetworkManagementService.java +++ b/services/core/java/com/android/server/NetworkManagementService.java @@ -59,9 +59,6 @@ import android.net.NetworkStats; import android.net.RouteInfo; import android.net.TetherStatsParcel; import android.net.UidRangeParcel; -import android.net.shared.NetdUtils; -import android.net.shared.RouteUtils; -import android.net.shared.RouteUtils.ModifyOperation; import android.net.util.NetdService; import android.os.BatteryStats; import android.os.Binder; @@ -88,6 +85,8 @@ import com.android.internal.app.IBatteryStats; import com.android.internal.util.DumpUtils; import com.android.internal.util.HexDump; import com.android.internal.util.Preconditions; +import com.android.net.module.util.NetdUtils; +import com.android.net.module.util.NetdUtils.ModifyOperation; import com.google.android.collect.Maps; @@ -831,13 +830,13 @@ public class NetworkManagementService extends INetworkManagementService.Stub { @Override public void addRoute(int netId, RouteInfo route) { NetworkStack.checkNetworkStackPermission(mContext); - RouteUtils.modifyRoute(mNetdService, ModifyOperation.ADD, netId, route); + NetdUtils.modifyRoute(mNetdService, ModifyOperation.ADD, netId, route); } @Override public void removeRoute(int netId, RouteInfo route) { NetworkStack.checkNetworkStackPermission(mContext); - RouteUtils.modifyRoute(mNetdService, ModifyOperation.REMOVE, netId, route); + NetdUtils.modifyRoute(mNetdService, ModifyOperation.REMOVE, netId, route); } private ArrayList<String> readRouteList(String filename) { @@ -1785,7 +1784,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub { public void addInterfaceToLocalNetwork(String iface, List<RouteInfo> routes) { modifyInterfaceInNetwork(MODIFY_OPERATION_ADD, INetd.LOCAL_NET_ID, iface); // modifyInterfaceInNetwork already check calling permission. - RouteUtils.addRoutesToLocalNetwork(mNetdService, iface, routes); + NetdUtils.addRoutesToLocalNetwork(mNetdService, iface, routes); } @Override @@ -1796,7 +1795,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub { @Override public int removeRoutesFromLocalNetwork(List<RouteInfo> routes) { NetworkStack.checkNetworkStackPermission(mContext); - return RouteUtils.removeRoutesFromLocalNetwork(mNetdService, routes); + return NetdUtils.removeRoutesFromLocalNetwork(mNetdService, routes); } @Override diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index c11c4def1b50..5ed6c86bdc18 100644 --- a/services/core/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java @@ -47,6 +47,7 @@ import android.os.RemoteException; import android.os.UserHandle; import android.provider.DeviceConfig; import android.telecom.TelecomManager; +import android.telephony.AccessNetworkConstants; import android.telephony.Annotation; import android.telephony.Annotation.RadioPowerState; import android.telephony.Annotation.SrvccState; @@ -1029,7 +1030,6 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { return; } - int phoneId = getPhoneIdFromSubId(subId); synchronized (mRecords) { // register IBinder b = callback.asBinder(); @@ -1052,21 +1052,24 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { // Legacy applications pass SubscriptionManager.DEFAULT_SUB_ID, // force all illegal subId to SubscriptionManager.DEFAULT_SUB_ID if (!SubscriptionManager.isValidSubscriptionId(subId)) { + if (DBG) { + log("invalid subscription id, use default id"); + } r.subId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID; } else {//APP specify subID r.subId = subId; } - r.phoneId = phoneId; + r.phoneId = getPhoneIdFromSubId(r.subId); r.eventList = events; if (DBG) { - log("listen: Register r=" + r + " r.subId=" + r.subId + " phoneId=" + phoneId); + log("listen: Register r=" + r + " r.subId=" + r.subId + " r.phoneId=" + r.phoneId); } - if (notifyNow && validatePhoneId(phoneId)) { + if (notifyNow && validatePhoneId(r.phoneId)) { if (events.contains(TelephonyCallback.EVENT_SERVICE_STATE_CHANGED)){ try { - if (VDBG) log("listen: call onSSC state=" + mServiceState[phoneId]); - ServiceState rawSs = new ServiceState(mServiceState[phoneId]); + if (VDBG) log("listen: call onSSC state=" + mServiceState[r.phoneId]); + ServiceState rawSs = new ServiceState(mServiceState[r.phoneId]); if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) { r.callback.onServiceStateChanged(rawSs); } else if (checkCoarseLocationAccess(r, Build.VERSION_CODES.Q)) { @@ -1082,8 +1085,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } if (events.contains(TelephonyCallback.EVENT_SIGNAL_STRENGTH_CHANGED)) { try { - if (mSignalStrength[phoneId] != null) { - int gsmSignalStrength = mSignalStrength[phoneId] + if (mSignalStrength[r.phoneId] != null) { + int gsmSignalStrength = mSignalStrength[r.phoneId] .getGsmSignalStrength(); r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1 : gsmSignalStrength)); @@ -1096,7 +1099,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { TelephonyCallback.EVENT_MESSAGE_WAITING_INDICATOR_CHANGED)) { try { r.callback.onMessageWaitingIndicatorChanged( - mMessageWaiting[phoneId]); + mMessageWaiting[r.phoneId]); } catch (RemoteException ex) { remove(r.binder); } @@ -1105,7 +1108,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { TelephonyCallback.EVENT_CALL_FORWARDING_INDICATOR_CHANGED)) { try { r.callback.onCallForwardingIndicatorChanged( - mCallForwarding[phoneId]); + mCallForwarding[r.phoneId]); } catch (RemoteException ex) { remove(r.binder); } @@ -1113,11 +1116,11 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { if (validateEventAndUserLocked( r, TelephonyCallback.EVENT_CELL_LOCATION_CHANGED)) { try { - if (DBG_LOC) log("listen: mCellIdentity = " + mCellIdentity[phoneId]); + if (DBG_LOC) log("listen: mCellIdentity = " + mCellIdentity[r.phoneId]); if (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE) && checkFineLocationAccess(r, Build.VERSION_CODES.Q)) { // null will be translated to empty CellLocation object in client. - r.callback.onCellLocationChanged(mCellIdentity[phoneId]); + r.callback.onCellLocationChanged(mCellIdentity[r.phoneId]); } } catch (RemoteException ex) { remove(r.binder); @@ -1125,49 +1128,38 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } if (events.contains(TelephonyCallback.EVENT_LEGACY_CALL_STATE_CHANGED)) { try { - r.callback.onLegacyCallStateChanged(mCallState[phoneId], - getCallIncomingNumber(r, phoneId)); + r.callback.onLegacyCallStateChanged(mCallState[r.phoneId], + getCallIncomingNumber(r, r.phoneId)); } catch (RemoteException ex) { remove(r.binder); } } if (events.contains(TelephonyCallback.EVENT_CALL_STATE_CHANGED)) { try { - r.callback.onCallStateChanged(mCallState[phoneId]); + r.callback.onCallStateChanged(mCallState[r.phoneId]); } catch (RemoteException ex) { remove(r.binder); } } if (events.contains(TelephonyCallback.EVENT_DATA_CONNECTION_STATE_CHANGED)) { try { - r.callback.onDataConnectionStateChanged(mDataConnectionState[phoneId], - mDataConnectionNetworkType[phoneId]); + r.callback.onDataConnectionStateChanged(mDataConnectionState[r.phoneId], + mDataConnectionNetworkType[r.phoneId]); } catch (RemoteException ex) { remove(r.binder); } } if (events.contains(TelephonyCallback.EVENT_DATA_ACTIVITY_CHANGED)) { try { - r.callback.onDataActivity(mDataActivity[phoneId]); + r.callback.onDataActivity(mDataActivity[r.phoneId]); } catch (RemoteException ex) { remove(r.binder); } } if (events.contains(TelephonyCallback.EVENT_SIGNAL_STRENGTHS_CHANGED)) { try { - if (mSignalStrength[phoneId] != null) { - r.callback.onSignalStrengthsChanged(mSignalStrength[phoneId]); - } - } catch (RemoteException ex) { - remove(r.binder); - } - } - if (events.contains( - TelephonyCallback.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED)) { - updateReportSignalStrengthDecision(r.subId); - try { - if (mSignalStrength[phoneId] != null) { - r.callback.onSignalStrengthsChanged(mSignalStrength[phoneId]); + if (mSignalStrength[r.phoneId] != null) { + r.callback.onSignalStrengthsChanged(mSignalStrength[r.phoneId]); } } catch (RemoteException ex) { remove(r.binder); @@ -1176,11 +1168,13 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { if (validateEventAndUserLocked( r, TelephonyCallback.EVENT_CELL_INFO_CHANGED)) { try { - if (DBG_LOC) log("listen: mCellInfo[" + phoneId + "] = " - + mCellInfo.get(phoneId)); + if (DBG_LOC) { + log("listen: mCellInfo[" + r.phoneId + "] = " + + mCellInfo.get(r.phoneId)); + } if (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE) && checkFineLocationAccess(r, Build.VERSION_CODES.Q)) { - r.callback.onCellInfoChanged(mCellInfo.get(phoneId)); + r.callback.onCellInfoChanged(mCellInfo.get(r.phoneId)); } } catch (RemoteException ex) { remove(r.binder); @@ -1188,22 +1182,22 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } if (events.contains(TelephonyCallback.EVENT_PRECISE_CALL_STATE_CHANGED)) { try { - r.callback.onPreciseCallStateChanged(mPreciseCallState[phoneId]); + r.callback.onPreciseCallStateChanged(mPreciseCallState[r.phoneId]); } catch (RemoteException ex) { remove(r.binder); } } if (events.contains(TelephonyCallback.EVENT_CALL_DISCONNECT_CAUSE_CHANGED)) { try { - r.callback.onCallDisconnectCauseChanged(mCallDisconnectCause[phoneId], - mCallPreciseDisconnectCause[phoneId]); + r.callback.onCallDisconnectCauseChanged(mCallDisconnectCause[r.phoneId], + mCallPreciseDisconnectCause[r.phoneId]); } catch (RemoteException ex) { remove(r.binder); } } if (events.contains(TelephonyCallback.EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED)) { try { - r.callback.onImsCallDisconnectCauseChanged(mImsReasonInfo.get(phoneId)); + r.callback.onImsCallDisconnectCauseChanged(mImsReasonInfo.get(r.phoneId)); } catch (RemoteException ex) { remove(r.binder); } @@ -1212,7 +1206,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { TelephonyCallback.EVENT_PRECISE_DATA_CONNECTION_STATE_CHANGED)) { try { for (PreciseDataConnectionState pdcs - : mPreciseDataConnectionStates.get(phoneId).values()) { + : mPreciseDataConnectionStates.get(r.phoneId).values()) { r.callback.onPreciseDataConnectionStateChanged(pdcs); } } catch (RemoteException ex) { @@ -1229,29 +1223,29 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { if (events.contains(TelephonyCallback.EVENT_VOICE_ACTIVATION_STATE_CHANGED)) { try { r.callback.onVoiceActivationStateChanged( - mVoiceActivationState[phoneId]); + mVoiceActivationState[r.phoneId]); } catch (RemoteException ex) { remove(r.binder); } } if (events.contains(TelephonyCallback.EVENT_DATA_ACTIVATION_STATE_CHANGED)) { try { - r.callback.onDataActivationStateChanged(mDataActivationState[phoneId]); + r.callback.onDataActivationStateChanged(mDataActivationState[r.phoneId]); } catch (RemoteException ex) { remove(r.binder); } } if (events.contains(TelephonyCallback.EVENT_USER_MOBILE_DATA_STATE_CHANGED)) { try { - r.callback.onUserMobileDataStateChanged(mUserMobileDataState[phoneId]); + r.callback.onUserMobileDataStateChanged(mUserMobileDataState[r.phoneId]); } catch (RemoteException ex) { remove(r.binder); } } if (events.contains(TelephonyCallback.EVENT_DISPLAY_INFO_CHANGED)) { try { - if (mTelephonyDisplayInfos[phoneId] != null) { - r.callback.onDisplayInfoChanged(mTelephonyDisplayInfos[phoneId]); + if (mTelephonyDisplayInfos[r.phoneId] != null) { + r.callback.onDisplayInfoChanged(mTelephonyDisplayInfos[r.phoneId]); } } catch (RemoteException ex) { remove(r.binder); @@ -1288,20 +1282,20 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } if (events.contains(TelephonyCallback.EVENT_SRVCC_STATE_CHANGED)) { try { - r.callback.onSrvccStateChanged(mSrvccState[phoneId]); + r.callback.onSrvccStateChanged(mSrvccState[r.phoneId]); } catch (RemoteException ex) { remove(r.binder); } } if (events.contains(TelephonyCallback.EVENT_CALL_ATTRIBUTES_CHANGED)) { try { - r.callback.onCallAttributesChanged(mCallAttributes[phoneId]); + r.callback.onCallAttributesChanged(mCallAttributes[r.phoneId]); } catch (RemoteException ex) { remove(r.binder); } } if (events.contains(TelephonyCallback.EVENT_BARRING_INFO_CHANGED)) { - BarringInfo barringInfo = mBarringInfo.get(phoneId); + BarringInfo barringInfo = mBarringInfo.get(r.phoneId); BarringInfo biNoLocation = barringInfo != null ? barringInfo.createLocationInfoSanitizedCopy() : null; if (VDBG) log("listen: call onBarringInfoChanged=" + barringInfo); @@ -1319,8 +1313,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { r.callback.onPhysicalChannelConfigChanged( shouldSanitizeLocationForPhysicalChannelConfig(r) ? getLocationSanitizedConfigs( - mPhysicalChannelConfigs.get(phoneId)) - : mPhysicalChannelConfigs.get(phoneId)); + mPhysicalChannelConfigs.get(r.phoneId)) + : mPhysicalChannelConfigs.get(r.phoneId)); } catch (RemoteException ex) { remove(r.binder); } @@ -1329,7 +1323,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { TelephonyCallback.EVENT_DATA_ENABLED_CHANGED)) { try { r.callback.onDataEnabledChanged( - mIsDataEnabled[phoneId], mDataEnabledReason[phoneId]); + mIsDataEnabled[r.phoneId], mDataEnabledReason[r.phoneId]); } catch (RemoteException ex) { remove(r.binder); } @@ -1337,9 +1331,9 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { if (events.contains( TelephonyCallback.EVENT_LINK_CAPACITY_ESTIMATE_CHANGED)) { try { - if (mLinkCapacityEstimateLists.get(phoneId) != null) { + if (mLinkCapacityEstimateLists.get(r.phoneId) != null) { r.callback.onLinkCapacityEstimateChanged(mLinkCapacityEstimateLists - .get(phoneId)); + .get(r.phoneId)); } } catch (RemoteException ex) { remove(r.binder); @@ -1349,27 +1343,6 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } } - private void updateReportSignalStrengthDecision(int subscriptionId) { - synchronized (mRecords) { - TelephonyManager telephonyManager = (TelephonyManager) mContext - .getSystemService(Context.TELEPHONY_SERVICE); - for (Record r : mRecords) { - // If any of the system clients wants to always listen to signal strength, - // we need to set it on. - if (r.matchTelephonyCallbackEvent( - TelephonyCallback.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED)) { - telephonyManager.createForSubscriptionId(subscriptionId) - .setAlwaysReportSignalStrength(true); - return; - } - } - // If none of the system clients wants to always listen to signal strength, - // we need to set it off. - telephonyManager.createForSubscriptionId(subscriptionId) - .setAlwaysReportSignalStrength(false); - } - } - private String getCallIncomingNumber(Record record, int phoneId) { // Only reveal the incoming number if the record has read call log permission. return record.canReadCallLog() ? mCallIncomingNumber[phoneId] : ""; @@ -1453,14 +1426,6 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } mRecords.remove(i); - - // Every time a client that is registrating to always receive the signal - // strength is removed from registry records, we need to check if - // the signal strength decision needs to update on its slot. - if (r.matchTelephonyCallbackEvent( - TelephonyCallback.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED)) { - updateReportSignalStrengthDecision(r.subId); - } return; } } @@ -1581,7 +1546,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_SERVICE_STATE_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { ServiceState stateToSend; @@ -1643,7 +1608,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { if ((activationType == SIM_ACTIVATION_TYPE_VOICE) && r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_VOICE_ACTIVATION_STATE_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { if (DBG) { log("notifyVoiceActivationStateForPhoneId: callback.onVASC r=" + r + " subId=" + subId + " phoneId=" + phoneId @@ -1654,7 +1619,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { if ((activationType == SIM_ACTIVATION_TYPE_DATA) && r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_DATA_ACTIVATION_STATE_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { if (DBG) { log("notifyDataActivationStateForPhoneId: callback.onDASC r=" + r + " subId=" + subId + " phoneId=" + phoneId @@ -1692,11 +1657,9 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { log("notifySignalStrengthForPhoneId: r=" + r + " subId=" + subId + " phoneId=" + phoneId + " ss=" + signalStrength); } - if ((r.matchTelephonyCallbackEvent( + if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_SIGNAL_STRENGTHS_CHANGED) - || r.matchTelephonyCallbackEvent( - TelephonyCallback.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED)) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { if (DBG) { log("notifySignalStrengthForPhoneId: callback.onSsS r=" + r @@ -1710,7 +1673,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_SIGNAL_STRENGTH_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { int gsmSignalStrength = signalStrength.getGsmSignalStrength(); int ss = (gsmSignalStrength == 99 ? -1 : gsmSignalStrength); @@ -1757,7 +1720,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_CARRIER_NETWORK_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { r.callback.onCarrierNetworkChange(active); } catch (RemoteException ex) { @@ -1789,7 +1752,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (validateEventAndUserLocked( r, TelephonyCallback.EVENT_CELL_INFO_CHANGED) - && idMatch(r.subId, subId, phoneId) + && idMatch(r, subId, phoneId) && (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE) && checkFineLocationAccess(r, Build.VERSION_CODES.Q))) { try { @@ -1823,7 +1786,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_MESSAGE_WAITING_INDICATOR_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { r.callback.onMessageWaitingIndicatorChanged(mwi); } catch (RemoteException ex) { @@ -1850,7 +1813,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_USER_MOBILE_DATA_STATE_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { r.callback.onUserMobileDataStateChanged(state); } catch (RemoteException ex) { @@ -1889,7 +1852,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_DISPLAY_INFO_CHANGED) - && idMatchWithoutDefaultPhoneCheck(r.subId, subId)) { + && idMatch(r, subId, phoneId)) { try { if (!mConfigurationProvider.isDisplayInfoNrAdvancedSupported( r.callingPackage, Binder.getCallingUserHandle())) { @@ -1940,7 +1903,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_CALL_FORWARDING_INDICATOR_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { r.callback.onCallForwardingIndicatorChanged(cfi); } catch (RemoteException ex) { @@ -1969,7 +1932,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { // Notify by correct subId. if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_DATA_ACTIVITY_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { r.callback.onDataActivity(state); } catch (RemoteException ex) { @@ -1998,42 +1961,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { ApnSetting apnSetting = preciseState.getApnSetting(); - int apnTypes = apnSetting.getApnTypeBitmask(); - int state = preciseState.getState(); - int networkType = preciseState.getNetworkType(); - synchronized (mRecords) { if (validatePhoneId(phoneId)) { - // We only call the callback when the change is for default APN type. - if ((ApnSetting.TYPE_DEFAULT & apnTypes) != 0 - && (mDataConnectionState[phoneId] != state - || mDataConnectionNetworkType[phoneId] != networkType)) { - String str = "onDataConnectionStateChanged(" - + TelephonyUtils.dataStateToString(state) - + ", " + getNetworkTypeName(networkType) - + ") subId=" + subId + ", phoneId=" + phoneId; - log(str); - mLocalLog.log(str); - for (Record r : mRecords) { - if (r.matchTelephonyCallbackEvent( - TelephonyCallback.EVENT_DATA_CONNECTION_STATE_CHANGED) - && idMatch(r.subId, subId, phoneId)) { - try { - if (DBG) { - log("Notify data connection state changed on sub: " + subId); - } - r.callback.onDataConnectionStateChanged(state, networkType); - } catch (RemoteException ex) { - mRemoveList.add(r.binder); - } - } - } - handleRemoveListLocked(); - - mDataConnectionState[phoneId] = state; - mDataConnectionNetworkType[phoneId] = networkType; - } - Pair<Integer, ApnSetting> key = Pair.create(preciseState.getTransportType(), preciseState.getApnSetting()); PreciseDataConnectionState oldState = mPreciseDataConnectionStates.get(phoneId) @@ -2042,7 +1971,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_PRECISE_DATA_CONNECTION_STATE_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { r.callback.onPreciseDataConnectionStateChanged(preciseState); } catch (RemoteException ex) { @@ -2065,6 +1994,73 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { if (preciseState.getState() != TelephonyManager.DATA_DISCONNECTED) { mPreciseDataConnectionStates.get(phoneId).put(key, preciseState); } + + // Note that below is just the workaround for reporting the correct data connection + // state. The actual fix should be put in the new data stack in T. + // TODO: Remove the code below in T. + + // Collect all possible candidate data connection state for internet. Key is the + // data connection state, value is the precise data connection state. + Map<Integer, PreciseDataConnectionState> internetConnections = new ArrayMap<>(); + if (preciseState.getState() == TelephonyManager.DATA_DISCONNECTED + && preciseState.getApnSetting().getApnTypes() + .contains(ApnSetting.TYPE_DEFAULT)) { + internetConnections.put(TelephonyManager.DATA_DISCONNECTED, preciseState); + } + for (Map.Entry<Pair<Integer, ApnSetting>, PreciseDataConnectionState> entry : + mPreciseDataConnectionStates.get(phoneId).entrySet()) { + if (entry.getKey().first == AccessNetworkConstants.TRANSPORT_TYPE_WWAN + && entry.getKey().second.getApnTypes() + .contains(ApnSetting.TYPE_DEFAULT)) { + internetConnections.put(entry.getValue().getState(), entry.getValue()); + } + } + + // If any internet data is in connected state, then report connected, then check + // suspended, connecting, disconnecting, and disconnected. The order is very + // important. + int[] statesInPriority = new int[]{TelephonyManager.DATA_CONNECTED, + TelephonyManager.DATA_SUSPENDED, TelephonyManager.DATA_CONNECTING, + TelephonyManager.DATA_DISCONNECTING, + TelephonyManager.DATA_DISCONNECTED}; + int state = TelephonyManager.DATA_DISCONNECTED; + int networkType = TelephonyManager.NETWORK_TYPE_UNKNOWN; + for (int s : statesInPriority) { + if (internetConnections.containsKey(s)) { + state = s; + networkType = internetConnections.get(s).getNetworkType(); + break; + } + } + + if (mDataConnectionState[phoneId] != state + || mDataConnectionNetworkType[phoneId] != networkType) { + String str = "onDataConnectionStateChanged(" + + TelephonyUtils.dataStateToString(state) + + ", " + TelephonyManager.getNetworkTypeName(networkType) + + ") subId=" + subId + ", phoneId=" + phoneId; + log(str); + mLocalLog.log(str); + for (Record r : mRecords) { + if (r.matchTelephonyCallbackEvent( + TelephonyCallback.EVENT_DATA_CONNECTION_STATE_CHANGED) + && idMatch(r, subId, phoneId)) { + try { + if (DBG) { + log("Notify data connection state changed on sub: " + subId); + } + r.callback.onDataConnectionStateChanged(state, networkType); + } catch (RemoteException ex) { + mRemoveList.add(r.binder); + } + } + } + + mDataConnectionState[phoneId] = state; + mDataConnectionNetworkType[phoneId] = networkType; + + handleRemoveListLocked(); + } } } } @@ -2089,7 +2085,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (validateEventAndUserLocked( r, TelephonyCallback.EVENT_CELL_LOCATION_CHANGED) - && idMatch(r.subId, subId, phoneId) + && idMatch(r, subId, phoneId) && (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE) && checkFineLocationAccess(r, Build.VERSION_CODES.Q))) { try { @@ -2143,7 +2139,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_PRECISE_CALL_STATE_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { r.callback.onPreciseCallStateChanged(mPreciseCallState[phoneId]); } catch (RemoteException ex) { @@ -2152,7 +2148,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } if (notifyCallAttributes && r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_CALL_ATTRIBUTES_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { r.callback.onCallAttributesChanged(mCallAttributes[phoneId]); } catch (RemoteException ex) { @@ -2177,7 +2173,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_CALL_DISCONNECT_CAUSE_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { r.callback.onCallDisconnectCauseChanged(mCallDisconnectCause[phoneId], mCallPreciseDisconnectCause[phoneId]); @@ -2202,7 +2198,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { if (DBG_LOC) { log("notifyImsCallDisconnectCause: mImsReasonInfo=" @@ -2234,7 +2230,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_SRVCC_STATE_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { if (DBG_LOC) { log("notifySrvccStateChanged: mSrvccState=" + state + " r=" + r); @@ -2263,7 +2259,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } if ((r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_OEM_HOOK_RAW)) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { r.callback.onOemHookRawEvent(rawData); } catch (RemoteException ex) { @@ -2343,7 +2339,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_RADIO_POWER_STATE_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { r.callback.onRadioPowerStateChanged(state); } catch (RemoteException ex) { @@ -2372,7 +2368,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_EMERGENCY_NUMBER_LIST_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { r.callback.onEmergencyNumberListChanged(mEmergencyNumberList); if (VDBG) { @@ -2459,7 +2455,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_CALL_ATTRIBUTES_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { r.callback.onCallAttributesChanged(mCallAttributes[phoneId]); } catch (RemoteException ex) { @@ -2490,7 +2486,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_REGISTRATION_FAILURE) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { r.callback.onRegistrationFailed( checkFineLocationAccess(r, Build.VERSION_CODES.BASE) @@ -2533,7 +2529,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_BARRING_INFO_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { if (DBG_LOC) { log("notifyBarringInfo: mBarringInfo=" @@ -2578,7 +2574,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { if (DBG_LOC) { log("notifyPhysicalChannelConfig: mPhysicalChannelConfigs=" @@ -2645,7 +2641,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_DATA_ENABLED_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { r.callback.onDataEnabledChanged(enabled, reason); } catch (RemoteException ex) { @@ -2680,7 +2676,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_ALLOWED_NETWORK_TYPE_LIST_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { if (VDBG) { log("notifyAllowedNetworkTypesChanged: reason= " + reason @@ -2722,7 +2718,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_LINK_CAPACITY_ESTIMATE_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { r.callback.onLinkCapacityEstimateChanged(linkCapacityEstimateList); } catch (RemoteException ex) { @@ -3115,11 +3111,6 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION, null); } - if ((events.contains(TelephonyCallback.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED))) { - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH, null); - } - if (isPrivilegedPhoneStatePermissionRequired(events)) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, null); @@ -3172,33 +3163,24 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } /** - * If the registrant specified a subId, then we should only notify it if subIds match. - * If the registrant registered with DEFAULT subId, we should notify only when the related subId - * is default subId (which could be INVALID if there's no default subId). + * Match the sub id or phone id of the event to the record * - * This should be the correct way to check record ID match. in idMatch the record's phoneId is - * speculated based on subId passed by the registrant so it's not a good reference. - * But to avoid triggering potential regression only replace idMatch with it when an issue with - * idMatch is reported. Eventually this should replace all instances of idMatch. + * We follow the rules below: + * 1) If sub id of the event is invalid, phone id should be used. + * 2) The event on default sub should be notified to the records + * which register the default sub id. + * 3) Sub id should be exactly matched for all other cases. */ - private boolean idMatchWithoutDefaultPhoneCheck(int subIdInRecord, int subIdToNotify) { - if (subIdInRecord == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { - return (subIdToNotify == mDefaultSubId); - } else { - return (subIdInRecord == subIdToNotify); - } - } - - boolean idMatch(int rSubId, int subId, int phoneId) { + boolean idMatch(Record r, int subId, int phoneId) { - if(subId < 0) { - // Invalid case, we need compare phoneId with default one. - return (mDefaultPhoneId == phoneId); + if (subId < 0) { + // Invalid case, we need compare phoneId. + return (r.phoneId == phoneId); } - if(rSubId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { + if (r.subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { return (subId == mDefaultSubId); } else { - return (rSubId == subId); + return (r.subId == subId); } } @@ -3289,9 +3271,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } } - if (events.contains(TelephonyCallback.EVENT_SIGNAL_STRENGTHS_CHANGED) - || events.contains( - TelephonyCallback.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED)) { + if (events.contains(TelephonyCallback.EVENT_SIGNAL_STRENGTHS_CHANGED)) { try { if (mSignalStrength[phoneId] != null) { SignalStrength signalStrength = mSignalStrength[phoneId]; diff --git a/services/core/java/com/android/server/VpnManagerService.java b/services/core/java/com/android/server/VpnManagerService.java index a03425c0bb75..b48e21e4e2c6 100644 --- a/services/core/java/com/android/server/VpnManagerService.java +++ b/services/core/java/com/android/server/VpnManagerService.java @@ -681,7 +681,7 @@ public class VpnManagerService extends IVpnManager.Stub { intentFilter = new IntentFilter(); intentFilter.addAction(LockdownVpnTracker.ACTION_LOCKDOWN_RESET); mUserAllContext.registerReceiver( - mIntentReceiver, intentFilter, NETWORK_STACK, mHandler); + mIntentReceiver, intentFilter, NETWORK_STACK, mHandler, Context.RECEIVER_EXPORTED); } private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java index 731f7fec466c..ab2147dff853 100644 --- a/services/core/java/com/android/server/accounts/AccountManagerService.java +++ b/services/core/java/com/android/server/accounts/AccountManagerService.java @@ -1834,6 +1834,11 @@ public class AccountManagerService + ", skipping since the account already exists"); return false; } + if (accounts.accountsDb.findAllDeAccounts().size() > 100) { + Log.w(TAG, "insertAccountIntoDatabase: " + account.toSafeString() + + ", skipping since more than 50 accounts on device exist"); + return false; + } long accountId = accounts.accountsDb.insertCeAccount(account, password); if (accountId < 0) { Log.w(TAG, "insertAccountIntoDatabase: " + account.toSafeString() diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java index 3ccacd84a9f3..c5ac3907ecfe 100644 --- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java +++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java @@ -94,6 +94,8 @@ public class SettingsToPropertiesMapper { DeviceConfig.NAMESPACE_STATSD_NATIVE, DeviceConfig.NAMESPACE_STATSD_NATIVE_BOOT, DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT, + DeviceConfig.NAMESPACE_TETHERING, + DeviceConfig.NAMESPACE_VIRTUALIZATION_FRAMEWORK_NATIVE, DeviceConfig.NAMESPACE_WINDOW_MANAGER_NATIVE_BOOT, }; diff --git a/services/core/java/com/android/server/biometrics/AuthService.java b/services/core/java/com/android/server/biometrics/AuthService.java index 0cd2e3d0ff59..c97ad55ceeec 100644 --- a/services/core/java/com/android/server/biometrics/AuthService.java +++ b/services/core/java/com/android/server/biometrics/AuthService.java @@ -60,6 +60,7 @@ import android.os.Build; import android.os.IBinder; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.SystemProperties; import android.os.UserHandle; import android.provider.Settings; import android.util.Slog; @@ -70,6 +71,7 @@ import com.android.internal.util.ArrayUtils; import com.android.server.SystemService; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; /** @@ -81,6 +83,8 @@ public class AuthService extends SystemService { private static final String SETTING_HIDL_DISABLED = "com.android.server.biometrics.AuthService.hidlDisabled"; private static final int DEFAULT_HIDL_DISABLED = 0; + private static final String SYSPROP_FIRST_API_LEVEL = "ro.board.first_api_level"; + private static final String SYSPROP_API_LEVEL = "ro.board.api_level"; private final Injector mInjector; @@ -623,7 +627,16 @@ public class AuthService extends SystemService { final SensorConfig[] hidlConfigs; if (!mInjector.isHidlDisabled(getContext())) { - final String[] configStrings = mInjector.getConfiguration(getContext()); + final int firstApiLevel = SystemProperties.getInt(SYSPROP_FIRST_API_LEVEL, 0); + final int apiLevel = SystemProperties.getInt(SYSPROP_API_LEVEL, firstApiLevel); + String[] configStrings = mInjector.getConfiguration(getContext()); + if (configStrings.length == 0 && apiLevel == Build.VERSION_CODES.R) { + // For backwards compatibility with R where biometrics could work without being + // configured in config_biometric_sensors. In the absence of a vendor provided + // configuration, we assume the weakest biometric strength (i.e. convenience). + Slog.w(TAG, "Found R vendor partition without config_biometric_sensors"); + configStrings = generateRSdkCompatibleConfiguration(); + } hidlConfigs = new SensorConfig[configStrings.length]; for (int i = 0; i < configStrings.length; ++i) { hidlConfigs[i] = new SensorConfig(configStrings[i]); @@ -639,6 +652,31 @@ public class AuthService extends SystemService { } /** + * Generates an array of string configs with entries that correspond to the biometric features + * declared on the device. Returns an empty array if no biometric features are declared. + * Biometrics are assumed to be of the weakest strength class, i.e. convenience. + */ + private @NonNull String[] generateRSdkCompatibleConfiguration() { + final PackageManager pm = getContext().getPackageManager(); + final ArrayList<String> modalities = new ArrayList<>(); + if (pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) { + modalities.add(String.valueOf(BiometricAuthenticator.TYPE_FINGERPRINT)); + } + if (pm.hasSystemFeature(PackageManager.FEATURE_FACE)) { + modalities.add(String.valueOf(BiometricAuthenticator.TYPE_FACE)); + } + final String strength = String.valueOf(Authenticators.BIOMETRIC_CONVENIENCE); + final String[] configStrings = new String[modalities.size()]; + for (int i = 0; i < modalities.size(); ++i) { + final String id = String.valueOf(i); + final String modality = modalities.get(i); + configStrings[i] = String.join(":" /* delimiter */, id, modality, strength); + } + Slog.d(TAG, "Generated config_biometric_sensors: " + Arrays.toString(configStrings)); + return configStrings; + } + + /** * Registers HIDL and AIDL authenticators for all of the available modalities. * * @param hidlSensors Array of {@link SensorConfig} configuration for all of the HIDL sensors diff --git a/services/core/java/com/android/server/compat/OWNERS b/services/core/java/com/android/server/compat/OWNERS index cfd0a4b079ad..ee3086ab2fdb 100644 --- a/services/core/java/com/android/server/compat/OWNERS +++ b/services/core/java/com/android/server/compat/OWNERS @@ -1,6 +1 @@ -# Use this reviewer by default. -platform-compat-eng+reviews@google.com - -andreionea@google.com -mathewi@google.com -satayev@google.com +include tools/platform-compat:/OWNERS diff --git a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java index 091e6c4adf4d..a56a8ea993f0 100644 --- a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java +++ b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java @@ -227,7 +227,7 @@ public class MultipathPolicyTracker { subscriberId = tele.getSubscriberId(); mNetworkTemplate = new NetworkTemplate( NetworkTemplate.MATCH_MOBILE, subscriberId, new String[] { subscriberId }, - null, NetworkStats.METERED_ALL, NetworkStats.ROAMING_ALL, + null, NetworkStats.METERED_YES, NetworkStats.ROAMING_ALL, NetworkStats.DEFAULT_NETWORK_NO, NETWORK_TYPE_ALL, OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_EXACT); mUsageCallback = new UsageCallback() { diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index 243a336b31f2..bf4ef4879c9a 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -126,6 +126,7 @@ import com.android.server.net.BaseNetworkObserver; import libcore.io.IoUtils; import java.io.File; +import java.io.FileDescriptor; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -195,6 +196,7 @@ public class Vpn { private final Context mContext; private final ConnectivityManager mConnectivityManager; + private final AppOpsManager mAppOpsManager; // The context is for specific user which is created from mUserId private final Context mUserIdContext; @VisibleForTesting final Dependencies mDeps; @@ -407,6 +409,46 @@ public class Vpn { public boolean isInterfacePresent(final Vpn vpn, final String iface) { return vpn.jniCheck(iface) != 0; } + + /** + * @see ParcelFileDescriptor#adoptFd(int) + */ + public ParcelFileDescriptor adoptFd(Vpn vpn, int mtu) { + return ParcelFileDescriptor.adoptFd(jniCreate(vpn, mtu)); + } + + /** + * Call native method to create the VPN interface and return the FileDescriptor of /dev/tun. + */ + public int jniCreate(Vpn vpn, int mtu) { + return vpn.jniCreate(mtu); + } + + /** + * Call native method to get the interface name of VPN. + */ + public String jniGetName(Vpn vpn, int fd) { + return vpn.jniGetName(fd); + } + + /** + * Call native method to set the VPN addresses and return the number of addresses. + */ + public int jniSetAddresses(Vpn vpn, String interfaze, String addresses) { + return vpn.jniSetAddresses(interfaze, addresses); + } + + /** + * @see IoUtils#setBlocking(FileDescriptor, boolean) + */ + public void setBlocking(FileDescriptor fd, boolean blocking) { + try { + IoUtils.setBlocking(fd, blocking); + } catch (IOException e) { + throw new IllegalStateException( + "Cannot set tunnel's fd as blocking=" + blocking, e); + } + } } public Vpn(Looper looper, Context context, INetworkManagementService netService, INetd netd, @@ -431,6 +473,7 @@ public class Vpn { mVpnProfileStore = vpnProfileStore; mContext = context; mConnectivityManager = mContext.getSystemService(ConnectivityManager.class); + mAppOpsManager = mContext.getSystemService(AppOpsManager.class); mUserIdContext = context.createContextAsUser(UserHandle.of(userId), 0 /* flags */); mDeps = deps; mNms = netService; @@ -826,7 +869,6 @@ public class Vpn { VpnProfile profile = getVpnProfilePrivileged(alwaysOnPackage); if (profile != null) { startVpnProfilePrivileged(profile, alwaysOnPackage); - // If the above startVpnProfilePrivileged() call returns, the Ikev2VpnProfile was // correctly parsed, and the VPN has started running in a different thread. The only // other possibility is that the above call threw an exception, which will be @@ -974,9 +1016,15 @@ public class Vpn { } catch (Exception e) { // ignore } + mAppOpsManager.finishOp( + AppOpsManager.OPSTR_ESTABLISH_VPN_SERVICE, mOwnerUID, mPackage, null); mContext.unbindService(mConnection); cleanupVpnStateLocked(); } else if (mVpnRunner != null) { + if (!VpnConfig.LEGACY_VPN.equals(mPackage)) { + mAppOpsManager.finishOp( + AppOpsManager.OPSTR_ESTABLISH_VPN_MANAGER, mOwnerUID, mPackage, null); + } // cleanupVpnStateLocked() is called from mVpnRunner.exit() mVpnRunner.exit(); } @@ -1041,10 +1089,8 @@ public class Vpn { return false; } - final AppOpsManager appOpMgr = - (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE); for (final String appOpStr : toChange) { - appOpMgr.setMode( + mAppOpsManager.setMode( appOpStr, uid, packageName, @@ -1366,9 +1412,9 @@ public class Vpn { Set<Range<Integer>> oldUsers = mNetworkCapabilities.getUids(); // Configure the interface. Abort if any of these steps fails. - ParcelFileDescriptor tun = ParcelFileDescriptor.adoptFd(jniCreate(config.mtu)); + final ParcelFileDescriptor tun = mDeps.adoptFd(this, config.mtu); try { - String interfaze = jniGetName(tun.getFd()); + final String interfaze = mDeps.jniGetName(this, tun.getFd()); // TEMP use the old jni calls until there is support for netd address setting StringBuilder builder = new StringBuilder(); @@ -1376,7 +1422,7 @@ public class Vpn { builder.append(" "); builder.append(address); } - if (jniSetAddresses(interfaze, builder.toString()) < 1) { + if (mDeps.jniSetAddresses(this, interfaze, builder.toString()) < 1) { throw new IllegalArgumentException("At least one address must be specified"); } Connection connection = new Connection(); @@ -1422,11 +1468,11 @@ public class Vpn { jniReset(oldInterface); } - try { - IoUtils.setBlocking(tun.getFileDescriptor(), config.blocking); - } catch (IOException e) { - throw new IllegalStateException( - "Cannot set tunnel's fd as blocking=" + config.blocking, e); + mDeps.setBlocking(tun.getFileDescriptor(), config.blocking); + // Record that the VPN connection is established by an app which uses VpnService API. + if (oldNetworkAgent != mNetworkAgent) { + mAppOpsManager.startOp( + AppOpsManager.OPSTR_ESTABLISH_VPN_SERVICE, mOwnerUID, mPackage, null, null); } } catch (RuntimeException e) { IoUtils.closeQuietly(tun); @@ -1781,9 +1827,17 @@ public class Vpn { synchronized (Vpn.this) { if (interfaze.equals(mInterface) && jniCheck(interfaze) == 0) { if (mConnection != null) { + mAppOpsManager.finishOp( + AppOpsManager.OPSTR_ESTABLISH_VPN_SERVICE, mOwnerUID, mPackage, + null); mContext.unbindService(mConnection); cleanupVpnStateLocked(); } else if (mVpnRunner != null) { + if (!VpnConfig.LEGACY_VPN.equals(mPackage)) { + mAppOpsManager.finishOp( + AppOpsManager.OPSTR_ESTABLISH_VPN_MANAGER, mOwnerUID, mPackage, + null); + } // cleanupVpnStateLocked() is called from mVpnRunner.exit() mVpnRunner.exit(); } @@ -3254,8 +3308,7 @@ public class Vpn { * * @param packageName the package name of the app provisioning this profile */ - public synchronized void startVpnProfile( - @NonNull String packageName) { + public synchronized void startVpnProfile(@NonNull String packageName) { requireNonNull(packageName, "No package name provided"); enforceNotRestrictedUser(); @@ -3318,6 +3371,13 @@ public class Vpn { Log.d(TAG, "Unknown VPN profile type: " + profile.type); break; } + + // Record that the VPN connection is established by an app which uses VpnManager API. + if (!VpnConfig.LEGACY_VPN.equals(packageName)) { + mAppOpsManager.startOp( + AppOpsManager.OPSTR_ESTABLISH_VPN_MANAGER, mOwnerUID, mPackage, null, + null); + } } catch (GeneralSecurityException e) { // Reset mConfig mConfig = null; diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java index d66d7ee99f2e..329a69634f71 100644 --- a/services/core/java/com/android/server/display/DisplayModeDirector.java +++ b/services/core/java/com/android/server/display/DisplayModeDirector.java @@ -512,7 +512,10 @@ public class DisplayModeDirector { */ public void setShouldAlwaysRespectAppRequestedMode(boolean enabled) { synchronized (mLock) { - mAlwaysRespectAppRequest = enabled; + if (mAlwaysRespectAppRequest != enabled) { + mAlwaysRespectAppRequest = enabled; + notifyDesiredDisplayModeSpecsChangedLocked(); + } } } diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java index a2cb78d27a57..c27293c3cc09 100755 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java @@ -209,6 +209,12 @@ abstract class HdmiCecLocalDevice { void init() { assertRunOnServiceThread(); mPreferredAddress = getPreferredAddress(); + if (mHandler.hasMessages(MSG_DISABLE_DEVICE_TIMEOUT)) { + // Remove and trigger the queued message for clearing all actions when going to standby. + // This is necessary because the device may wake up before the message is triggered. + mHandler.removeMessages(MSG_DISABLE_DEVICE_TIMEOUT); + handleDisableDeviceTimeout(); + } mPendingActionClearedCallback = null; } diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java index e5a8a17df525..a571dc06db97 100644 --- a/services/core/java/com/android/server/hdmi/HdmiControlService.java +++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java @@ -3131,7 +3131,7 @@ public class HdmiControlService extends SystemService { Slog.v(TAG, "On standby-action cleared:" + device.mDeviceType); devices.remove(device); if (devices.isEmpty()) { - onStandbyCompleted(standbyAction); + onPendingActionsCleared(standbyAction); // We will not clear local devices here, since some OEM/SOC will keep passing // the received packets until the application processor enters to the sleep // actually. @@ -3193,10 +3193,17 @@ public class HdmiControlService extends SystemService { mHdmiCecNetwork.clearLocalDevices(); } + /** + * Normally called after all devices have cleared their pending actions, to execute the final + * phase of the standby flow. + * + * This can also be called during wakeup, when pending actions are cleared after failing to be + * cleared during standby. In this case, it does not execute the standby flow. + */ @ServiceThreadOnly - private void onStandbyCompleted(int standbyAction) { + private void onPendingActionsCleared(int standbyAction) { assertRunOnServiceThread(); - Slog.v(TAG, "onStandbyCompleted"); + Slog.v(TAG, "onPendingActionsCleared"); if (!mPowerStatusController.isPowerStatusTransientToStandby()) { return; diff --git a/services/core/java/com/android/server/health/HealthHalCallbackHidl.java b/services/core/java/com/android/server/health/HealthHalCallbackHidl.java new file mode 100644 index 000000000000..7a6698085c0d --- /dev/null +++ b/services/core/java/com/android/server/health/HealthHalCallbackHidl.java @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.health; + +import static android.hardware.health.Translate.h2aTranslate; + +import android.annotation.NonNull; +import android.hardware.health.V2_0.IHealth; +import android.hardware.health.V2_0.Result; +import android.hardware.health.V2_1.BatteryCapacityLevel; +import android.hardware.health.V2_1.Constants; +import android.hardware.health.V2_1.IHealthInfoCallback; +import android.os.RemoteException; +import android.os.Trace; +import android.util.Slog; + +/** + * On service registration, {@link HealthServiceWrapperHidl.Callback#onRegistration} is called, + * which registers {@code this}, a {@link IHealthInfoCallback}, to the health service. + * + * <p>When the health service has updates to health info, {@link HealthInfoCallback#update} is + * called. + * + * @hide + */ +class HealthHalCallbackHidl extends IHealthInfoCallback.Stub + implements HealthServiceWrapperHidl.Callback { + + private static final String TAG = HealthHalCallbackHidl.class.getSimpleName(); + + private static void traceBegin(String name) { + Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, name); + } + + private static void traceEnd() { + Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); + } + + private HealthInfoCallback mCallback; + + HealthHalCallbackHidl(@NonNull HealthInfoCallback callback) { + mCallback = callback; + } + + @Override + public void healthInfoChanged(android.hardware.health.V2_0.HealthInfo props) { + android.hardware.health.V2_1.HealthInfo propsLatest = + new android.hardware.health.V2_1.HealthInfo(); + propsLatest.legacy = props; + + propsLatest.batteryCapacityLevel = BatteryCapacityLevel.UNSUPPORTED; + propsLatest.batteryChargeTimeToFullNowSeconds = + Constants.BATTERY_CHARGE_TIME_TO_FULL_NOW_SECONDS_UNSUPPORTED; + + mCallback.update(h2aTranslate(propsLatest)); + } + + @Override + public void healthInfoChanged_2_1(android.hardware.health.V2_1.HealthInfo props) { + mCallback.update(h2aTranslate(props)); + } + + // on new service registered + @Override + public void onRegistration(IHealth oldService, IHealth newService, String instance) { + if (newService == null) return; + + traceBegin("HealthUnregisterCallback"); + try { + if (oldService != null) { + int r = oldService.unregisterCallback(this); + if (r != Result.SUCCESS) { + Slog.w( + TAG, + "health: cannot unregister previous callback: " + Result.toString(r)); + } + } + } catch (RemoteException ex) { + Slog.w( + TAG, + "health: cannot unregister previous callback (transaction error): " + + ex.getMessage()); + } finally { + traceEnd(); + } + + traceBegin("HealthRegisterCallback"); + try { + int r = newService.registerCallback(this); + if (r != Result.SUCCESS) { + Slog.w(TAG, "health: cannot register callback: " + Result.toString(r)); + return; + } + // registerCallback does NOT guarantee that update is called + // immediately, so request a manual update here. + newService.update(); + } catch (RemoteException ex) { + Slog.e(TAG, "health: cannot register callback (transaction error): " + ex.getMessage()); + } finally { + traceEnd(); + } + } +} diff --git a/services/core/java/com/android/server/health/HealthInfoCallback.java b/services/core/java/com/android/server/health/HealthInfoCallback.java new file mode 100644 index 000000000000..c2a77fc862fa --- /dev/null +++ b/services/core/java/com/android/server/health/HealthInfoCallback.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.health; + +/** + * A wrapper over HIDL / AIDL IHealthInfoCallback. + * + * @hide + */ +public interface HealthInfoCallback { + /** + * Signals to the client that health info is changed. + * + * @param props the new health info. + */ + void update(android.hardware.health.HealthInfo props); +} diff --git a/services/core/java/com/android/server/health/HealthServiceWrapper.java b/services/core/java/com/android/server/health/HealthServiceWrapper.java new file mode 100644 index 000000000000..9b97554ee259 --- /dev/null +++ b/services/core/java/com/android/server/health/HealthServiceWrapper.java @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.health; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.os.BatteryProperty; +import android.os.HandlerThread; +import android.os.IBatteryPropertiesRegistrar; +import android.os.RemoteException; + +import com.android.internal.annotations.VisibleForTesting; + +import java.util.NoSuchElementException; + +/** + * HealthServiceWrapper wraps the internal IHealth service and refreshes the service when necessary. + * This is essentially a wrapper over IHealth that is useful for BatteryService. + * + * <p>The implementation may be backed by a HIDL or AIDL HAL. + * + * <p>On new registration of IHealth service, the internal service is refreshed. On death of an + * existing IHealth service, the internal service is NOT cleared to avoid race condition between + * death notification and new service notification. Hence, a caller must check for transaction + * errors when calling into the service. + * + * @hide Should only be used internally. + */ +public abstract class HealthServiceWrapper { + /** @return the handler thread. Exposed for testing. */ + @VisibleForTesting + abstract HandlerThread getHandlerThread(); + + /** + * Calls into get*() functions in the health HAL. This reads into the kernel interfaces + * directly. + * + * @see IBatteryPropertiesRegistrar#getProperty + */ + public abstract int getProperty(int id, BatteryProperty prop) throws RemoteException; + + /** + * Calls update() in the health HAL. + * + * @see IBatteryPropertiesRegistrar#scheduleUpdate + */ + public abstract void scheduleUpdate() throws RemoteException; + + /** + * Calls into getHealthInfo() in the health HAL. This returns a cached value in the health HAL + * implementation. + * + * @return health info. {@code null} if no health HAL service. {@code null} if any + * service-specific error when calling {@code getHealthInfo}, e.g. it is unsupported. + * @throws RemoteException for any transaction-level errors + */ + public abstract android.hardware.health.HealthInfo getHealthInfo() throws RemoteException; + + /** + * Create a new HealthServiceWrapper instance. + * + * @param healthInfoCallback the callback to call when health info changes + * @return the new HealthServiceWrapper instance, which may be backed by HIDL or AIDL service. + * @throws RemoteException transaction errors + * @throws NoSuchElementException no HIDL or AIDL service is available + */ + public static HealthServiceWrapper create(@Nullable HealthInfoCallback healthInfoCallback) + throws RemoteException, NoSuchElementException { + return create( + healthInfoCallback == null ? null : new HealthHalCallbackHidl(healthInfoCallback), + new HealthServiceWrapperHidl.IServiceManagerSupplier() {}, + new HealthServiceWrapperHidl.IHealthSupplier() {}); + } + + /** + * Create a new HealthServiceWrapper instance for testing. + * + * @param hidlRegCallback callback for HIDL service registration, or {@code null} if the client + * does not care about HIDL service registration notifications + * @param hidlServiceManagerSupplier supplier of HIDL service manager + * @param hidlHealthSupplier supplier of HIDL health HAL + * @return the new HealthServiceWrapper instance, which may be backed by HIDL or AIDL service. + */ + @VisibleForTesting + static @NonNull HealthServiceWrapper create( + @Nullable HealthServiceWrapperHidl.Callback hidlRegCallback, + @NonNull HealthServiceWrapperHidl.IServiceManagerSupplier hidlServiceManagerSupplier, + @NonNull HealthServiceWrapperHidl.IHealthSupplier hidlHealthSupplier) + throws RemoteException, NoSuchElementException { + return new HealthServiceWrapperHidl( + hidlRegCallback, hidlServiceManagerSupplier, hidlHealthSupplier); + } +} diff --git a/services/core/java/com/android/server/health/HealthServiceWrapperHidl.java b/services/core/java/com/android/server/health/HealthServiceWrapperHidl.java new file mode 100644 index 000000000000..0301174a45c6 --- /dev/null +++ b/services/core/java/com/android/server/health/HealthServiceWrapperHidl.java @@ -0,0 +1,313 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.health; + +import static android.hardware.health.Translate.h2aTranslate; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.hardware.health.HealthInfo; +import android.hardware.health.V2_0.IHealth; +import android.hardware.health.V2_0.Result; +import android.hidl.manager.V1_0.IServiceManager; +import android.hidl.manager.V1_0.IServiceNotification; +import android.os.BatteryManager; +import android.os.BatteryProperty; +import android.os.HandlerThread; +import android.os.RemoteException; +import android.os.Trace; +import android.util.MutableInt; +import android.util.Slog; + +import com.android.internal.annotations.VisibleForTesting; + +import java.util.NoSuchElementException; +import java.util.Objects; +import java.util.concurrent.atomic.AtomicReference; + +/** + * Implement {@link HealthServiceWrapper} backed by the HIDL HAL. + * + * @hide + */ +final class HealthServiceWrapperHidl extends HealthServiceWrapper { + private static final String TAG = "HealthServiceWrapperHidl"; + public static final String INSTANCE_VENDOR = "default"; + + private final IServiceNotification mNotification = new Notification(); + private final HandlerThread mHandlerThread = new HandlerThread("HealthServiceHwbinder"); + // These variables are fixed after init. + private Callback mCallback; + private IHealthSupplier mHealthSupplier; + private String mInstanceName; + + // Last IHealth service received. + private final AtomicReference<IHealth> mLastService = new AtomicReference<>(); + + private static void traceBegin(String name) { + Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, name); + } + + private static void traceEnd() { + Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); + } + + @Override + public int getProperty(int id, final BatteryProperty prop) throws RemoteException { + traceBegin("HealthGetProperty"); + try { + IHealth service = mLastService.get(); + if (service == null) throw new RemoteException("no health service"); + final MutableInt outResult = new MutableInt(Result.NOT_SUPPORTED); + switch (id) { + case BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER: + service.getChargeCounter( + (int result, int value) -> { + outResult.value = result; + if (result == Result.SUCCESS) prop.setLong(value); + }); + break; + case BatteryManager.BATTERY_PROPERTY_CURRENT_NOW: + service.getCurrentNow( + (int result, int value) -> { + outResult.value = result; + if (result == Result.SUCCESS) prop.setLong(value); + }); + break; + case BatteryManager.BATTERY_PROPERTY_CURRENT_AVERAGE: + service.getCurrentAverage( + (int result, int value) -> { + outResult.value = result; + if (result == Result.SUCCESS) prop.setLong(value); + }); + break; + case BatteryManager.BATTERY_PROPERTY_CAPACITY: + service.getCapacity( + (int result, int value) -> { + outResult.value = result; + if (result == Result.SUCCESS) prop.setLong(value); + }); + break; + case BatteryManager.BATTERY_PROPERTY_STATUS: + service.getChargeStatus( + (int result, int value) -> { + outResult.value = result; + if (result == Result.SUCCESS) prop.setLong(value); + }); + break; + case BatteryManager.BATTERY_PROPERTY_ENERGY_COUNTER: + service.getEnergyCounter( + (int result, long value) -> { + outResult.value = result; + if (result == Result.SUCCESS) prop.setLong(value); + }); + break; + } + return outResult.value; + } finally { + traceEnd(); + } + } + + @Override + public void scheduleUpdate() throws RemoteException { + getHandlerThread() + .getThreadHandler() + .post( + () -> { + traceBegin("HealthScheduleUpdate"); + try { + IHealth service = mLastService.get(); + if (service == null) { + Slog.e(TAG, "no health service"); + return; + } + service.update(); + } catch (RemoteException ex) { + Slog.e(TAG, "Cannot call update on health HAL", ex); + } finally { + traceEnd(); + } + }); + } + + private static class Mutable<T> { + public T value; + } + + @Override + public HealthInfo getHealthInfo() throws RemoteException { + IHealth service = mLastService.get(); + if (service == null) return null; + final Mutable<HealthInfo> ret = new Mutable<>(); + service.getHealthInfo( + (result, value) -> { + if (result == Result.SUCCESS) { + ret.value = h2aTranslate(value.legacy); + } + }); + return ret.value; + } + + /** + * Start monitoring registration of new IHealth services. Only instance {@link #INSTANCE_VENDOR} + * and in device / framework manifest are used. This function should only be called once. + * + * <p>mCallback.onRegistration() is called synchronously (aka in init thread) before this method + * returns if callback is not null. + * + * @throws RemoteException transaction error when talking to IServiceManager + * @throws NoSuchElementException if one of the following cases: - No service manager; - {@link + * #INSTANCE_VENDOR} is not in manifests (i.e. not available on this device), or none of + * these instances are available to current process. + * @throws NullPointerException when supplier is null + */ + @VisibleForTesting + HealthServiceWrapperHidl( + @Nullable Callback callback, + @NonNull IServiceManagerSupplier managerSupplier, + @NonNull IHealthSupplier healthSupplier) + throws RemoteException, NoSuchElementException, NullPointerException { + if (managerSupplier == null || healthSupplier == null) { + throw new NullPointerException(); + } + mHealthSupplier = healthSupplier; + + // Initialize mLastService and call callback for the first time (in init thread) + IHealth newService = null; + traceBegin("HealthInitGetService_" + INSTANCE_VENDOR); + try { + newService = healthSupplier.get(INSTANCE_VENDOR); + } catch (NoSuchElementException ex) { + /* ignored, handled below */ + } finally { + traceEnd(); + } + if (newService != null) { + mInstanceName = INSTANCE_VENDOR; + mLastService.set(newService); + } + + if (mInstanceName == null || newService == null) { + throw new NoSuchElementException( + String.format( + "IHealth service instance %s isn't available. Perhaps no permission?", + INSTANCE_VENDOR)); + } + + if (callback != null) { + mCallback = callback; + mCallback.onRegistration(null, newService, mInstanceName); + } + + // Register for future service registrations + traceBegin("HealthInitRegisterNotification"); + mHandlerThread.start(); + try { + managerSupplier + .get() + .registerForNotifications(IHealth.kInterfaceName, mInstanceName, mNotification); + } finally { + traceEnd(); + } + Slog.i(TAG, "health: HealthServiceWrapper listening to instance " + mInstanceName); + } + + @VisibleForTesting + public HandlerThread getHandlerThread() { + return mHandlerThread; + } + + /** Service registration callback. */ + interface Callback { + /** + * This function is invoked asynchronously when a new and related IServiceNotification is + * received. + * + * @param service the recently retrieved service from IServiceManager. Can be a dead service + * before service notification of a new service is delivered. Implementation must handle + * cases for {@link RemoteException}s when calling into service. + * @param instance instance name. + */ + void onRegistration(IHealth oldService, IHealth newService, String instance); + } + + /** + * Supplier of services. Must not return null; throw {@link NoSuchElementException} if a service + * is not available. + */ + interface IServiceManagerSupplier { + default IServiceManager get() throws NoSuchElementException, RemoteException { + return IServiceManager.getService(); + } + } + + /** + * Supplier of services. Must not return null; throw {@link NoSuchElementException} if a service + * is not available. + */ + interface IHealthSupplier { + default IHealth get(String name) throws NoSuchElementException, RemoteException { + return IHealth.getService(name, true /* retry */); + } + } + + private class Notification extends IServiceNotification.Stub { + @Override + public final void onRegistration( + String interfaceName, String instanceName, boolean preexisting) { + if (!IHealth.kInterfaceName.equals(interfaceName)) return; + if (!mInstanceName.equals(instanceName)) return; + + // This runnable only runs on mHandlerThread and ordering is ensured, hence + // no locking is needed inside the runnable. + mHandlerThread + .getThreadHandler() + .post( + new Runnable() { + @Override + public void run() { + try { + IHealth newService = mHealthSupplier.get(mInstanceName); + IHealth oldService = mLastService.getAndSet(newService); + + // preexisting may be inaccurate (race). Check for equality + // here. + if (Objects.equals(newService, oldService)) return; + + Slog.i( + TAG, + "health: new instance registered " + mInstanceName); + // #init() may be called with null callback. Skip null + // callbacks. + if (mCallback == null) return; + mCallback.onRegistration( + oldService, newService, mInstanceName); + } catch (NoSuchElementException | RemoteException ex) { + Slog.e( + TAG, + "health: Cannot get instance '" + + mInstanceName + + "': " + + ex.getMessage() + + ". Perhaps no permission?"); + } + } + }); + } + } +} diff --git a/services/core/java/com/android/server/health/OWNERS b/services/core/java/com/android/server/health/OWNERS new file mode 100644 index 000000000000..81522fcaa09f --- /dev/null +++ b/services/core/java/com/android/server/health/OWNERS @@ -0,0 +1 @@ +file:platform/hardware/interfaces:/health/aidl/OWNERS diff --git a/services/core/java/com/android/server/health/Utils.java b/services/core/java/com/android/server/health/Utils.java new file mode 100644 index 000000000000..a8c978c50e42 --- /dev/null +++ b/services/core/java/com/android/server/health/Utils.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.health; + +/** + * Utils for {@link om.android.server.BatteryService} to deal with health info structs. + * + * @hide + */ +public class Utils { + private Utils() {} + + /** + * Copy health info struct. + * + * @param dst destination + * @param src source + */ + public static void copy( + android.hardware.health.V1_0.HealthInfo dst, + android.hardware.health.V1_0.HealthInfo src) { + dst.chargerAcOnline = src.chargerAcOnline; + dst.chargerUsbOnline = src.chargerUsbOnline; + dst.chargerWirelessOnline = src.chargerWirelessOnline; + dst.maxChargingCurrent = src.maxChargingCurrent; + dst.maxChargingVoltage = src.maxChargingVoltage; + dst.batteryStatus = src.batteryStatus; + dst.batteryHealth = src.batteryHealth; + dst.batteryPresent = src.batteryPresent; + dst.batteryLevel = src.batteryLevel; + dst.batteryVoltage = src.batteryVoltage; + dst.batteryTemperature = src.batteryTemperature; + dst.batteryCurrent = src.batteryCurrent; + dst.batteryCycleCount = src.batteryCycleCount; + dst.batteryFullCharge = src.batteryFullCharge; + dst.batteryChargeCounter = src.batteryChargeCounter; + dst.batteryTechnology = src.batteryTechnology; + } + + /** + * Copy battery fields of {@link android.hardware.health.HealthInfo} V1. This excludes + * non-battery fields like {@link android.hardware.health.HealthInfo#diskStats diskStats} and + * {@link android.hardware.health.HealthInfo#storageInfos storageInfos} + * + * @param dst destination + * @param src source + */ + public static void copyV1Battery( + android.hardware.health.HealthInfo dst, android.hardware.health.HealthInfo src) { + dst.chargerAcOnline = src.chargerAcOnline; + dst.chargerUsbOnline = src.chargerUsbOnline; + dst.chargerWirelessOnline = src.chargerWirelessOnline; + dst.maxChargingCurrentMicroamps = src.maxChargingCurrentMicroamps; + dst.maxChargingVoltageMicrovolts = src.maxChargingVoltageMicrovolts; + dst.batteryStatus = src.batteryStatus; + dst.batteryHealth = src.batteryHealth; + dst.batteryPresent = src.batteryPresent; + dst.batteryLevel = src.batteryLevel; + dst.batteryVoltageMillivolts = src.batteryVoltageMillivolts; + dst.batteryTemperatureTenthsCelsius = src.batteryTemperatureTenthsCelsius; + dst.batteryCurrentMicroamps = src.batteryCurrentMicroamps; + dst.batteryCycleCount = src.batteryCycleCount; + dst.batteryFullChargeUah = src.batteryFullChargeUah; + dst.batteryChargeCounterUah = src.batteryChargeCounterUah; + dst.batteryTechnology = src.batteryTechnology; + dst.batteryCurrentAverageMicroamps = src.batteryCurrentAverageMicroamps; + dst.batteryCapacityLevel = src.batteryCapacityLevel; + dst.batteryChargeTimeToFullNowSeconds = src.batteryChargeTimeToFullNowSeconds; + dst.batteryFullChargeDesignCapacityUah = src.batteryFullChargeDesignCapacityUah; + } +} diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index dc955337fdbc..3e52f5e07e62 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -2582,14 +2582,12 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } if (mCurToken != null) { - try { - if (DEBUG) { - Slog.v(TAG, "Removing window token: " + mCurToken + " for display: " - + mCurTokenDisplayId); - } - mIWindowManager.removeWindowToken(mCurToken, mCurTokenDisplayId); - } catch (RemoteException e) { + if (DEBUG) { + Slog.v(TAG, "Removing window token: " + mCurToken + " for display: " + + mCurTokenDisplayId); } + mWindowManagerInternal.removeWindowToken(mCurToken, false /* removeWindows */, + false /* animateExit */, mCurTokenDisplayId); // Set IME window status as invisible when unbind current method. mImeWindowVis = 0; mBackDisposition = InputMethodService.BACK_DISPOSITION_DEFAULT; diff --git a/services/core/java/com/android/server/inputmethod/OWNERS b/services/core/java/com/android/server/inputmethod/OWNERS index c09ade9e075f..00cd700541c0 100644 --- a/services/core/java/com/android/server/inputmethod/OWNERS +++ b/services/core/java/com/android/server/inputmethod/OWNERS @@ -5,3 +5,4 @@ yukawa@google.com tarandeep@google.com lumark@google.com roosa@google.com +wilsonwu@google.com diff --git a/services/core/java/com/android/server/net/OWNERS b/services/core/java/com/android/server/net/OWNERS index 28ae6a417bd3..a15fc3eef539 100644 --- a/services/core/java/com/android/server/net/OWNERS +++ b/services/core/java/com/android/server/net/OWNERS @@ -1,11 +1,7 @@ set noparent -codewiz@google.com -jchalard@google.com +include platform/packages/modules/Connectivity:/OWNERS + jsharkey@android.com -junyulai@google.com -lorenzo@google.com -reminv@google.com -satk@google.com sudheersai@google.com yamasani@google.com diff --git a/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java b/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java index 3019439a430b..5643873bef4d 100644 --- a/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java +++ b/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java @@ -215,7 +215,7 @@ public class DefaultCrossProfileIntentFiltersUtils { private static final DefaultCrossProfileIntentFilter RECOGNIZE_SPEECH = new DefaultCrossProfileIntentFilter.Builder( DefaultCrossProfileIntentFilter.Direction.TO_PARENT, - /* flags= */0, + /* flags= */ ONLY_IF_NO_MATCH_FOUND, /* letsPersonalDataIntoProfile= */ false) .addAction(ACTION_RECOGNIZE_SPEECH) .addCategory(Intent.CATEGORY_DEFAULT) diff --git a/services/core/java/com/android/server/pm/OWNERS b/services/core/java/com/android/server/pm/OWNERS index 3233819b543f..1bdc9f3cf850 100644 --- a/services/core/java/com/android/server/pm/OWNERS +++ b/services/core/java/com/android/server/pm/OWNERS @@ -3,27 +3,25 @@ hackbod@google.com jsharkey@android.com jsharkey@google.com narayan@google.com -patb@google.com svetoslavganov@android.com svetoslavganov@google.com -toddke@android.com -toddke@google.com +include /PACKAGE_MANAGER_OWNERS # apex support per-file ApexManager.java = dariofreni@google.com, ioffe@google.com, olilan@google.com per-file StagingManager.java = dariofreni@google.com, ioffe@google.com, olilan@google.com # dex -per-file AbstractStatsBase.java = calin@google.com, ngeoffray@google.com -per-file BackgroundDexOptService.java = calin@google.com, ngeoffray@google.com -per-file CompilerStats.java = calin@google.com, ngeoffray@google.com -per-file DynamicCodeLoggingService.java = alanstokes@google.com, calin@google.com, ngeoffray@google.com -per-file InstructionSets.java = calin@google.com, ngeoffray@google.com -per-file OtaDexoptService.java = calin@google.com, ngeoffray@google.com -per-file OtaDexoptShellCommand.java = calin@google.com, ngeoffray@google.com -per-file PackageDexOptimizer.java = calin@google.com, ngeoffray@google.com -per-file PackageManagerServiceCompilerMapping.java = calin@google.com, ngeoffray@google.com -per-file PackageUsage.java = calin@google.com, ngeoffray@google.com +per-file AbstractStatsBase.java = file:dex/OWNERS +per-file BackgroundDexOptService.java = file:dex/OWNERS +per-file CompilerStats.java = file:dex/OWNERS +per-file DynamicCodeLoggingService.java = file:dex/OWNERS +per-file InstructionSets.java = file:dex/OWNERS +per-file OtaDexoptService.java = file:dex/OWNERS +per-file OtaDexoptShellCommand.java = file:dex/OWNERS +per-file PackageDexOptimizer.java = file:dex/OWNERS +per-file PackageManagerServiceCompilerMapping.java = file:dex/OWNERS +per-file PackageUsage.java = file:dex/OWNERS # multi user / cross profile per-file CrossProfileAppsServiceImpl.java = omakoto@google.com, yamasani@google.com diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index f6acad0194c1..1a0a885d88b4 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -7337,9 +7337,16 @@ public class PackageManagerService extends IPackageManager.Stub // Parse overlay configuration files to set default enable state, mutability, and // priority of system overlays. + final ArrayMap<String, File> apkInApexPreInstalledPaths = new ArrayMap<>(); + for (ApexManager.ActiveApexInfo apexInfo : mApexManager.getActiveApexInfos()) { + for (String packageName : mApexManager.getApksInApex(apexInfo.apexModuleName)) { + apkInApexPreInstalledPaths.put(packageName, apexInfo.preInstalledApexPath); + } + } mOverlayConfig = OverlayConfig.initializeSystemInstance( consumer -> mPmInternal.forEachPackage( - pkg -> consumer.accept(pkg, pkg.isSystem()))); + pkg -> consumer.accept(pkg, pkg.isSystem(), + apkInApexPreInstalledPaths.get(pkg.getPackageName())))); // Prune any system packages that no longer exist. final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<>(); @@ -21911,7 +21918,7 @@ public class PackageManagerService extends IPackageManager.Stub for (int i = 0, size = SYSTEM_PARTITIONS.size(); i < size; i++) { ScanPartition sp = SYSTEM_PARTITIONS.get(i); if (apexInfo.preInstalledApexPath.getAbsolutePath().startsWith( - sp.getFolder().getAbsolutePath())) { + sp.getFolder().getAbsolutePath() + File.separator)) { return new ScanPartition(apexInfo.apexDirectory, sp, SCAN_AS_APK_IN_APEX); } } diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java index c2c35b736eb7..08a72151aa37 100644 --- a/services/core/java/com/android/server/pm/StagingManager.java +++ b/services/core/java/com/android/server/pm/StagingManager.java @@ -1255,6 +1255,9 @@ public class StagingManager { info.diskImagePath = ai.modulePath; info.versionCode = ai.versionCode; info.versionName = ai.versionName; + info.hasBootClassPathJars = ai.hasBootClassPathJars; + info.hasDex2OatBootClassPathJars = ai.hasDex2OatBootClassPathJars; + info.hasSystemServerClassPathJars = ai.hasSystemServerClassPathJars; return info; } } diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java index dab980a9e4b2..7bea01820a03 100644 --- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java +++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java @@ -213,6 +213,7 @@ final class DefaultPermissionGrantPolicy { NEARBY_DEVICES_PERMISSIONS.add(Manifest.permission.BLUETOOTH_CONNECT); NEARBY_DEVICES_PERMISSIONS.add(Manifest.permission.BLUETOOTH_SCAN); NEARBY_DEVICES_PERMISSIONS.add(Manifest.permission.UWB_RANGING); + NEARBY_DEVICES_PERMISSIONS.add(Manifest.permission.NEARBY_WIFI_DEVICES); } private static final int MSG_READ_DEFAULT_PERMISSION_EXCEPTIONS = 1; diff --git a/services/core/java/com/android/server/pm/permission/OWNERS b/services/core/java/com/android/server/pm/permission/OWNERS index 8c1a90c13513..fc0ee23c4859 100644 --- a/services/core/java/com/android/server/pm/permission/OWNERS +++ b/services/core/java/com/android/server/pm/permission/OWNERS @@ -1,7 +1,3 @@ include platform/frameworks/base:/core/java/android/permission/OWNERS -per-file DefaultPermissionGrantPolicy.java = hackbod@android.com -per-file DefaultPermissionGrantPolicy.java = jsharkey@android.com -per-file DefaultPermissionGrantPolicy.java = toddke@google.com -per-file DefaultPermissionGrantPolicy.java = yamasani@google.com -per-file DefaultPermissionGrantPolicy.java = patb@google.com +per-file DefaultPermissionGrantPolicy.java = file:platform/frameworks/base:/core/java/android/permission/DEFAULT_PERMISSION_GRANT_POLICY_OWNERS diff --git a/services/core/java/com/android/server/pm/permission/Permission.java b/services/core/java/com/android/server/pm/permission/Permission.java index cda48063e914..94e551a11dae 100644 --- a/services/core/java/com/android/server/pm/permission/Permission.java +++ b/services/core/java/com/android/server/pm/permission/Permission.java @@ -480,9 +480,10 @@ public final class Permission { r.append("DUP:"); r.append(permissionInfo.name); } - if (permission.isRuntime() && (ownerChanged || wasNonRuntime)) { - // If this is a runtime permission and the owner has changed, or this wasn't a runtime - // permission, then permission state should be cleaned up + if ((permission.isInternal() && ownerChanged) + || (permission.isRuntime() && (ownerChanged || wasNonRuntime))) { + // If this is an internal/runtime permission and the owner has changed, or this wasn't a + // runtime permission, then permission state should be cleaned up. permission.mDefinitionChanged = true; } if (PackageManagerService.DEBUG_PACKAGE_SCANNING && r != null) { diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java index 1133faabcf69..7b12709e4efd 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -1643,7 +1643,8 @@ public class PermissionManagerService extends IPermissionManager.Stub { isRolePermission = permission.isRole(); } final boolean mayRevokeRolePermission = isRolePermission - && mayManageRolePermission(callingUid); + // Allow ourselves to revoke role permissions due to definition changes. + && (callingUid == Process.myUid() || mayManageRolePermission(callingUid)); final boolean isRuntimePermission; synchronized (mLock) { @@ -2321,11 +2322,13 @@ public class PermissionManagerService extends IPermissionManager.Stub { for (int permNum = 0; permNum < numPermissions; permNum++) { final String permName = permissionsToRevoke.get(permNum); + final boolean isInternalPermission; synchronized (mLock) { final Permission bp = mRegistry.getPermission(permName); - if (bp == null || !bp.isRuntime()) { + if (bp == null || !(bp.isInternal() || bp.isRuntime())) { continue; } + isInternalPermission = bp.isInternal(); } mPackageManagerInt.forEachPackage(pkg -> { final String packageName = pkg.getPackageName(); @@ -2345,12 +2348,18 @@ public class PermissionManagerService extends IPermissionManager.Stub { if (permissionState == PackageManager.PERMISSION_GRANTED && (flags & flagMask) == 0) { final int uid = UserHandle.getUid(userId, appId); - EventLog.writeEvent(0x534e4554, "154505240", uid, - "Revoking permission " + permName + " from package " - + packageName + " due to definition change"); - EventLog.writeEvent(0x534e4554, "168319670", uid, - "Revoking permission " + permName + " from package " - + packageName + " due to definition change"); + if (isInternalPermission) { + EventLog.writeEvent(0x534e4554, "195338390", uid, + "Revoking permission " + permName + " from package " + + packageName + " due to definition change"); + } else { + EventLog.writeEvent(0x534e4554, "154505240", uid, + "Revoking permission " + permName + " from package " + + packageName + " due to definition change"); + EventLog.writeEvent(0x534e4554, "168319670", uid, + "Revoking permission " + permName + " from package " + + packageName + " due to definition change"); + } Slog.e(TAG, "Revoking permission " + permName + " from package " + packageName + " due to definition change"); try { diff --git a/services/core/java/com/android/server/security/OWNERS b/services/core/java/com/android/server/security/OWNERS index e6f5826557b5..5c2d5badfeee 100644 --- a/services/core/java/com/android/server/security/OWNERS +++ b/services/core/java/com/android/server/security/OWNERS @@ -1,3 +1,4 @@ # Bug component: 36824 +per-file *AttestationVerification* = file:/core/java/android/security/attestationverification/OWNERS per-file FileIntegrityService.java = victorhsieh@google.com diff --git a/services/core/java/com/android/server/soundtrigger_middleware/ConversionUtil.java b/services/core/java/com/android/server/soundtrigger_middleware/ConversionUtil.java index 6366280e1762..7ffff935128f 100644 --- a/services/core/java/com/android/server/soundtrigger_middleware/ConversionUtil.java +++ b/services/core/java/com/android/server/soundtrigger_middleware/ConversionUtil.java @@ -429,15 +429,7 @@ class ConversionUtil { private static @NonNull HidlMemory parcelFileDescriptorToHidlMemory(@Nullable ParcelFileDescriptor data, int dataSize) { if (dataSize > 0) { - // Extract a dup of the underlying FileDescriptor out of data. - FileDescriptor fd = new FileDescriptor(); - try { - ParcelFileDescriptor dup = data.dup(); - fd.setInt$(dup.detachFd()); - return HidlMemoryUtil.fileDescriptorToHidlMemory(fd, dataSize); - } catch (IOException e) { - throw new RuntimeException(e); - } + return HidlMemoryUtil.fileDescriptorToHidlMemory(data.getFileDescriptor(), dataSize); } else { return HidlMemoryUtil.fileDescriptorToHidlMemory(null, 0); } diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java index 61770ea1c1c2..1ef202511452 100644 --- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java +++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java @@ -29,6 +29,7 @@ import static android.net.NetworkIdentity.OEM_PAID; import static android.net.NetworkIdentity.OEM_PRIVATE; import static android.net.NetworkStats.DEFAULT_NETWORK_ALL; import static android.net.NetworkStats.METERED_ALL; +import static android.net.NetworkStats.METERED_YES; import static android.net.NetworkStats.ROAMING_ALL; import static android.net.NetworkTemplate.MATCH_ETHERNET; import static android.net.NetworkTemplate.MATCH_MOBILE_WILDCARD; @@ -91,7 +92,6 @@ import android.content.pm.UserInfo; import android.hardware.biometrics.BiometricsProtoEnums; import android.hardware.face.FaceManager; import android.hardware.fingerprint.FingerprintManager; -import android.hardware.health.V2_0.IHealth; import android.net.ConnectivityManager; import android.net.INetworkStatsService; import android.net.INetworkStatsSession; @@ -189,13 +189,13 @@ import com.android.internal.os.SystemServerCpuThreadReader.SystemServiceCpuThrea import com.android.internal.util.CollectionUtils; import com.android.internal.util.FrameworkStatsLog; import com.android.role.RoleManagerLocal; -import com.android.server.BatteryService; import com.android.server.BinderCallsStatsService; import com.android.server.LocalManagerRegistry; import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.SystemServiceManager; import com.android.server.am.MemoryStatUtil.MemoryStat; +import com.android.server.health.HealthServiceWrapper; import com.android.server.notification.NotificationManagerService; import com.android.server.stats.pull.IonMemoryUtil.IonAllocations; import com.android.server.stats.pull.ProcfsMemoryUtil.MemorySnapshot; @@ -225,6 +225,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.MissingResourceException; +import java.util.NoSuchElementException; import java.util.Random; import java.util.Set; import java.util.UUID; @@ -353,7 +354,7 @@ public class StatsPullAtomService extends SystemService { private File mBaseDir; @GuardedBy("mHealthHalLock") - private BatteryService.HealthServiceWrapper mHealthService; + private HealthServiceWrapper mHealthService; @Nullable @GuardedBy("mCpuTimePerThreadFreqLock") @@ -798,10 +799,9 @@ public class StatsPullAtomService extends SystemService { KernelCpuThreadReaderSettingsObserver.getSettingsModifiedReader(mContext); // Initialize HealthService - mHealthService = new BatteryService.HealthServiceWrapper(); try { - mHealthService.init(); - } catch (RemoteException e) { + mHealthService = HealthServiceWrapper.create(null); + } catch (RemoteException | NoSuchElementException e) { Slog.e(TAG, "failed to initialize healthHalWrapper"); } @@ -1340,7 +1340,7 @@ public class StatsPullAtomService extends SystemService { @Nullable private NetworkStats getUidNetworkStatsSnapshotForTransport(int transport) { final NetworkTemplate template = (transport == TRANSPORT_CELLULAR) ? NetworkTemplate.buildTemplateMobileWithRatType( - /*subscriptionId=*/null, NETWORK_TYPE_ALL) + /*subscriptionId=*/null, NETWORK_TYPE_ALL, METERED_YES) : NetworkTemplate.buildTemplateWifiWildcard(); return getUidNetworkStatsSnapshotForTemplate(template, /*includeTags=*/false); } @@ -1380,7 +1380,8 @@ public class StatsPullAtomService extends SystemService { final List<NetworkStatsExt> ret = new ArrayList<>(); for (final int ratType : getAllCollapsedRatTypes()) { final NetworkTemplate template = - buildTemplateMobileWithRatType(subInfo.subscriberId, ratType); + buildTemplateMobileWithRatType(subInfo.subscriberId, ratType, + METERED_YES); final NetworkStats stats = getUidNetworkStatsSnapshotForTemplate(template, /*includeTags=*/false); if (stats != null) { @@ -1601,7 +1602,7 @@ public class StatsPullAtomService extends SystemService { int pullBluetoothBytesTransferLocked(int atomTag, List<StatsEvent> pulledData) { BluetoothActivityEnergyInfo info = fetchBluetoothData(); - if (info == null || info.getUidTraffic() == null) { + if (info == null) { return StatsManager.PULL_SKIP; } for (UidTraffic traffic : info.getUidTraffic()) { @@ -2059,7 +2060,7 @@ public class StatsPullAtomService extends SystemService { if (info == null) { return StatsManager.PULL_SKIP; } - pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, info.getTimeStamp(), + pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, info.getTimestampMillis(), info.getBluetoothStackState(), info.getControllerTxTimeMillis(), info.getControllerRxTimeMillis(), info.getControllerIdleTimeMillis(), info.getControllerEnergyUsed())); @@ -3973,38 +3974,40 @@ public class StatsPullAtomService extends SystemService { } int pullHealthHalLocked(int atomTag, List<StatsEvent> pulledData) { - IHealth healthService = mHealthService.getLastService(); - if (healthService == null) { + if (mHealthService == null) { return StatsManager.PULL_SKIP; } + android.hardware.health.HealthInfo healthInfo; try { - healthService.getHealthInfo((result, value) -> { - int pulledValue; - switch(atomTag) { - case FrameworkStatsLog.BATTERY_LEVEL: - pulledValue = value.legacy.batteryLevel; - break; - case FrameworkStatsLog.REMAINING_BATTERY_CAPACITY: - pulledValue = value.legacy.batteryChargeCounter; - break; - case FrameworkStatsLog.FULL_BATTERY_CAPACITY: - pulledValue = value.legacy.batteryFullCharge; - break; - case FrameworkStatsLog.BATTERY_VOLTAGE: - pulledValue = value.legacy.batteryVoltage; - break; - case FrameworkStatsLog.BATTERY_CYCLE_COUNT: - pulledValue = value.legacy.batteryCycleCount; - break; - default: - throw new IllegalStateException("Invalid atomTag in healthHal puller: " - + atomTag); - } - pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, pulledValue)); - }); + healthInfo = mHealthService.getHealthInfo(); } catch (RemoteException | IllegalStateException e) { return StatsManager.PULL_SKIP; } + if (healthInfo == null) { + return StatsManager.PULL_SKIP; + } + + int pulledValue; + switch (atomTag) { + case FrameworkStatsLog.BATTERY_LEVEL: + pulledValue = healthInfo.batteryLevel; + break; + case FrameworkStatsLog.REMAINING_BATTERY_CAPACITY: + pulledValue = healthInfo.batteryChargeCounterUah; + break; + case FrameworkStatsLog.FULL_BATTERY_CAPACITY: + pulledValue = healthInfo.batteryFullChargeUah; + break; + case FrameworkStatsLog.BATTERY_VOLTAGE: + pulledValue = healthInfo.batteryVoltageMillivolts; + break; + case FrameworkStatsLog.BATTERY_CYCLE_COUNT: + pulledValue = healthInfo.batteryCycleCount; + break; + default: + return StatsManager.PULL_SKIP; + } + pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, pulledValue)); return StatsManager.PULL_SUCCESS; } diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java index 92e0845012de..f57a852fe8c5 100755 --- a/services/core/java/com/android/server/tv/TvInputHardwareManager.java +++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java @@ -1075,17 +1075,22 @@ class TvInputHardwareManager implements TvInputHal.Callback { } if (shouldRecreateAudioPatch) { mCommittedVolume = volume; - if (mAudioPatch != null) { - mAudioManager.releaseAudioPatch(mAudioPatch); - } - mAudioManager.createAudioPatch( + // only recreate if something was updated or audioPath is null + if (mAudioPatch == null || sinkUpdated ||sourceUpdated ) { + if (mAudioPatch != null) { + mAudioManager.releaseAudioPatch(mAudioPatch); + audioPatchArray[0] = null; + } + mAudioManager.createAudioPatch( audioPatchArray, new AudioPortConfig[] { sourceConfig }, sinkConfigs.toArray(new AudioPortConfig[sinkConfigs.size()])); - mAudioPatch = audioPatchArray[0]; - if (sourceGainConfig != null) { - mAudioManager.setAudioPortGain(mAudioSource, sourceGainConfig); + mAudioPatch = audioPatchArray[0]; } + } + + if (sourceGainConfig != null) { + mAudioManager.setAudioPortGain(mAudioSource, sourceGainConfig); } } diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java index 36a854e5374c..28947083854b 100755 --- a/services/core/java/com/android/server/tv/TvInputManagerService.java +++ b/services/core/java/com/android/server/tv/TvInputManagerService.java @@ -2304,10 +2304,9 @@ public final class TvInputManagerService extends SystemService { public void requestChannelBrowsable(Uri channelUri, int userId) throws RemoteException { final String callingPackageName = getCallingPackageName(); + final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), + Binder.getCallingUid(), userId, "requestChannelBrowsable"); final long identity = Binder.clearCallingIdentity(); - final int callingUid = Binder.getCallingUid(); - final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid, - userId, "requestChannelBrowsable"); try { Intent intent = new Intent(TvContract.ACTION_CHANNEL_BROWSABLE_REQUESTED); List<ResolveInfo> list = getContext().getPackageManager() diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java index 7dec4e785f5c..1c46ac8c4aa1 100644 --- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java +++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java @@ -98,6 +98,7 @@ import java.io.IOException; import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; +import java.net.NetworkInterface; import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -1663,8 +1664,6 @@ public class VcnGatewayConnection extends StateMachine { } /* validationStatusCallback */); agent.register(); - agent.setUnderlyingNetworks( - mUnderlying == null ? null : Collections.singletonList(mUnderlying.network)); agent.markConnected(); return agent; @@ -2039,6 +2038,7 @@ public class VcnGatewayConnection extends StateMachine { "Unknown transport type or missing TransportInfo/NetworkSpecifier for" + " non-null underlying network"); } + builder.setUnderlyingNetworks(List.of(underlying.network)); } else { Slog.wtf( TAG, @@ -2049,7 +2049,8 @@ public class VcnGatewayConnection extends StateMachine { return builder.build(); } - private static LinkProperties buildConnectedLinkProperties( + @VisibleForTesting(visibility = Visibility.PRIVATE) + LinkProperties buildConnectedLinkProperties( @NonNull VcnGatewayConnectionConfig gatewayConnectionConfig, @NonNull IpSecTunnelInterface tunnelIface, @NonNull VcnChildSessionConfiguration childConfig, @@ -2077,6 +2078,13 @@ public class VcnGatewayConnection extends StateMachine { lp.setTcpBufferSizes(underlyingLp.getTcpBufferSizes()); underlyingMtu = underlyingLp.getMtu(); + + // WiFi LinkProperties uses DHCP as the sole source of MTU information, and as a result + // often lists MTU as 0 (see b/184678973). Use the interface MTU as retrieved by + // NetworkInterface APIs. + if (underlyingMtu == 0 && underlyingLp.getInterfaceName() != null) { + underlyingMtu = mDeps.getUnderlyingIfaceMtu(underlyingLp.getInterfaceName()); + } } else { Slog.wtf( TAG, @@ -2418,6 +2426,17 @@ public class VcnGatewayConnection extends StateMachine { public long getElapsedRealTime() { return SystemClock.elapsedRealtime(); } + + /** Gets the MTU for the given underlying interface. */ + public int getUnderlyingIfaceMtu(String ifaceName) { + try { + final NetworkInterface underlyingIface = NetworkInterface.getByName(ifaceName); + return underlyingIface == null ? 0 : underlyingIface.getMTU(); + } catch (IOException e) { + Slog.d(TAG, "Could not get MTU of underlying network", e); + return 0; + } + } } /** diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 308df2f4e9a0..d1f21778177d 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -140,6 +140,7 @@ import static com.android.server.wm.ActivityRecordProto.IS_ANIMATING; import static com.android.server.wm.ActivityRecordProto.IS_WAITING_FOR_TRANSITION_START; import static com.android.server.wm.ActivityRecordProto.LAST_ALL_DRAWN; import static com.android.server.wm.ActivityRecordProto.LAST_SURFACE_SHOWING; +import static com.android.server.wm.ActivityRecordProto.MIN_ASPECT_RATIO; import static com.android.server.wm.ActivityRecordProto.NAME; import static com.android.server.wm.ActivityRecordProto.NUM_DRAWN_WINDOWS; import static com.android.server.wm.ActivityRecordProto.NUM_INTERESTING_WINDOWS; @@ -656,6 +657,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A boolean mLastImeShown; /** + * When set to true, the IME insets will be frozen until the next app becomes IME input target. + * @see InsetsPolicy#adjustVisibilityForIme + */ + boolean mImeInsetsFrozenUntilStartInput; + + /** * A flag to determine if this AR is in the process of closing or entering PIP. This is needed * to help AR know that the app is in the process of closing but hasn't yet started closing on * the WM side. @@ -1343,13 +1350,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } final Task rootTask = getRootTask(); - // If we reparent, make sure to remove ourselves from the old animation registry. - if (mAnimatingActivityRegistry != null) { - mAnimatingActivityRegistry.notifyFinished(this); - } - mAnimatingActivityRegistry = rootTask != null - ? rootTask.getAnimatingActivityRegistry() - : null; + updateAnimatingActivityRegistry(); if (task == mLastParentBeforePip) { // Activity's reparented back from pip, clear the links once established @@ -1363,6 +1364,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } if (newTask != null && isState(RESUMED)) { newTask.setResumedActivity(this, "onParentChanged"); + mImeInsetsFrozenUntilStartInput = false; } if (rootTask != null && rootTask.topRunningActivity() == this) { @@ -1373,6 +1375,20 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } } + void updateAnimatingActivityRegistry() { + final Task rootTask = getRootTask(); + final AnimatingActivityRegistry registry = rootTask != null + ? rootTask.getAnimatingActivityRegistry() + : null; + + // If we reparent, make sure to remove ourselves from the old animation registry. + if (mAnimatingActivityRegistry != null && mAnimatingActivityRegistry != registry) { + mAnimatingActivityRegistry.notifyFinished(this); + } + + mAnimatingActivityRegistry = registry; + } + /** * Sets {@link #mLastParentBeforePip} to the current parent Task, it's caller's job to ensure * {@link #getTask()} is set before this is called. @@ -4759,6 +4775,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A && imeInputTarget.getWindow().mActivityRecord == this && mDisplayContent.mInputMethodWindow != null && mDisplayContent.mInputMethodWindow.isVisible(); + mImeInsetsFrozenUntilStartInput = true; } final DisplayContent displayContent = getDisplayContent(); @@ -5877,6 +5894,14 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // closing activity having to wait until idle timeout to be stopped or destroyed if the // next activity won't report idle (e.g. repeated view animation). mTaskSupervisor.scheduleProcessStoppingAndFinishingActivitiesIfNeeded(); + + // If the activity is visible, but no windows are eligible to start input, unfreeze + // to avoid permanently frozen IME insets. + if (mImeInsetsFrozenUntilStartInput && getWindow( + win -> WindowManager.LayoutParams.mayUseInputMethod(win.mAttrs.flags)) + == null) { + mImeInsetsFrozenUntilStartInput = false; + } } } @@ -7792,6 +7817,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } } + @Override + void onResize() { + // Reset freezing IME insets flag when the activity resized. + mImeInsetsFrozenUntilStartInput = false; + super.onResize(); + } + /** Returns true if the configuration is compatible with this activity. */ boolean isConfigurationCompatible(Configuration config) { final int orientation = getRequestedOrientation(); @@ -8641,6 +8673,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } proto.write(PIP_AUTO_ENTER_ENABLED, pictureInPictureArgs.isAutoEnterEnabled()); proto.write(IN_SIZE_COMPAT_MODE, inSizeCompatMode()); + proto.write(MIN_ASPECT_RATIO, info.getMinAspectRatio()); } @Override diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index dbc1116ad389..9335846e7805 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -1165,10 +1165,10 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } } - WindowToken removeWindowToken(IBinder binder) { + WindowToken removeWindowToken(IBinder binder, boolean animateExit) { final WindowToken token = mTokenMap.remove(binder); if (token != null && token.asActivityRecord() == null) { - token.setExiting(); + token.setExiting(animateExit); } return token; } @@ -1252,7 +1252,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } void removeAppToken(IBinder binder) { - final WindowToken token = removeWindowToken(binder); + final WindowToken token = removeWindowToken(binder, true /* animateExit */); if (token == null) { Slog.w(TAG_WM, "removeAppToken: Attempted to remove non-existing token: " + binder); return; @@ -3971,6 +3971,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp void updateImeInputAndControlTarget(WindowState target) { if (mImeInputTarget != target) { ProtoLog.i(WM_DEBUG_IME, "setInputMethodInputTarget %s", target); + if (target != null && target.mActivityRecord != null) { + target.mActivityRecord.mImeInsetsFrozenUntilStartInput = false; + } setImeInputTarget(target); updateImeControlTarget(); } diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java index f2f192686ad5..a8e1c1cda72b 100644 --- a/services/core/java/com/android/server/wm/InsetsPolicy.java +++ b/services/core/java/com/android/server/wm/InsetsPolicy.java @@ -211,7 +211,7 @@ class InsetsPolicy { InsetsState getInsetsForWindow(WindowState target) { final InsetsState originalState = mStateController.getInsetsForWindow(target); final InsetsState state = adjustVisibilityForTransientTypes(originalState); - return target.mIsImWindow ? adjustVisibilityForIme(state, state == originalState) : state; + return adjustVisibilityForIme(target, state, state == originalState); } /** @@ -241,16 +241,37 @@ class InsetsPolicy { return state; } - // Navigation bar insets is always visible to IME. - private static InsetsState adjustVisibilityForIme(InsetsState originalState, + private InsetsState adjustVisibilityForIme(WindowState w, InsetsState originalState, boolean copyState) { - final InsetsSource originalNavSource = originalState.peekSource(ITYPE_NAVIGATION_BAR); - if (originalNavSource != null && !originalNavSource.isVisible()) { - final InsetsState state = copyState ? new InsetsState(originalState) : originalState; - final InsetsSource navSource = new InsetsSource(originalNavSource); - navSource.setVisible(true); - state.addSource(navSource); - return state; + if (w.mIsImWindow) { + // Navigation bar insets is always visible to IME. + final InsetsSource originalNavSource = originalState.peekSource(ITYPE_NAVIGATION_BAR); + if (originalNavSource != null && !originalNavSource.isVisible()) { + final InsetsState state = copyState ? new InsetsState(originalState) + : originalState; + final InsetsSource navSource = new InsetsSource(originalNavSource); + navSource.setVisible(true); + state.addSource(navSource); + return state; + } + } else if (w.mActivityRecord != null && w.mActivityRecord.mImeInsetsFrozenUntilStartInput) { + // During switching tasks with gestural navigation, if the IME is attached to + // one app window on that time, even the next app window is behind the IME window, + // conceptually the window should not receive the IME insets if the next window is + // not eligible IME requester and ready to show IME on top of it. + final boolean shouldImeAttachedToApp = mDisplayContent.shouldImeAttachedToApp(); + final InsetsSource originalImeSource = originalState.peekSource(ITYPE_IME); + + if (shouldImeAttachedToApp && originalImeSource != null) { + final boolean imeVisibility = + w.mActivityRecord.mLastImeShown || w.getRequestedVisibility(ITYPE_IME); + final InsetsState state = copyState ? new InsetsState(originalState) + : originalState; + final InsetsSource imeSource = new InsetsSource(originalImeSource); + imeSource.setVisible(imeVisibility); + state.addSource(imeSource); + return state; + } } return originalState; } diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java index fe1020c86041..a7216da9bed5 100644 --- a/services/core/java/com/android/server/wm/KeyguardController.java +++ b/services/core/java/com/android/server/wm/KeyguardController.java @@ -190,8 +190,7 @@ class KeyguardController { if (keyguardChanged) { // Irrelevant to AOD. - dismissMultiWindowModeForTaskIfNeeded(null /* currentTaskControllsingOcclusion */, - false /* turningScreenOn */); + dismissMultiWindowModeForTaskIfNeeded(null /* currentTaskControllsingOcclusion */); mKeyguardGoingAway = false; if (keyguardShowing) { mDismissalRequested = false; @@ -385,6 +384,8 @@ class KeyguardController { mService.continueWindowLayout(); } } + dismissMultiWindowModeForTaskIfNeeded(topActivity != null + ? topActivity.getRootTask() : null); } /** @@ -410,21 +411,6 @@ class KeyguardController { } } - /** - * Called when somebody wants to turn screen on. - */ - private void handleTurnScreenOn(int displayId) { - if (displayId != DEFAULT_DISPLAY) { - return; - } - - mTaskSupervisor.wakeUp("handleTurnScreenOn"); - if (mKeyguardShowing && canDismissKeyguard()) { - mWindowManager.dismissKeyguard(null /* callback */, null /* message */); - mDismissalRequested = true; - } - } - boolean isDisplayOccluded(int displayId) { return getDisplayState(displayId).mOccluded; } @@ -438,11 +424,9 @@ class KeyguardController { } private void dismissMultiWindowModeForTaskIfNeeded( - @Nullable Task currentTaskControllingOcclusion, boolean turningScreenOn) { - // If turningScreenOn is true, it means that the visibility state has changed from - // currentTaskControllingOcclusion and we should update windowing mode. + @Nullable Task currentTaskControllingOcclusion) { // TODO(b/113840485): Handle docked stack for individual display. - if (!turningScreenOn && (!mKeyguardShowing || !isDisplayOccluded(DEFAULT_DISPLAY))) { + if (!mKeyguardShowing || !isDisplayOccluded(DEFAULT_DISPLAY)) { return; } @@ -581,26 +565,17 @@ class KeyguardController { && controller.mWindowManager.isKeyguardSecure( controller.mService.getCurrentUserId()); - boolean occludingChange = false; - boolean turningScreenOn = false; if (mTopTurnScreenOnActivity != lastTurnScreenOnActivity && mTopTurnScreenOnActivity != null && !mService.mWindowManager.mPowerManager.isInteractive() - && (mRequestDismissKeyguard || occludedByActivity - || controller.canDismissKeyguard())) { - turningScreenOn = true; - controller.handleTurnScreenOn(mDisplayId); + && (mRequestDismissKeyguard || occludedByActivity)) { + controller.mTaskSupervisor.wakeUp("handleTurnScreenOn"); mTopTurnScreenOnActivity.setCurrentLaunchCanTurnScreenOn(false); } if (lastOccluded != mOccluded) { - occludingChange = true; controller.handleOccludedChanged(mDisplayId, mTopOccludesActivity); } - - if (occludingChange || turningScreenOn) { - controller.dismissMultiWindowModeForTaskIfNeeded(task, turningScreenOn); - } } /** diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 516be553d5f8..963485554b5e 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -1464,6 +1464,9 @@ class Task extends WindowContainer<WindowContainer> { adjustBoundsForDisplayChangeIfNeeded(getDisplayContent()); mRootWindowContainer.updateUIDsPresentOnDisplay(); + + // Ensure all animations are finished at same time in split-screen mode. + forAllActivities(ActivityRecord::updateAnimatingActivityRegistry); } void cleanUpActivityReferences(ActivityRecord r) { diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java index e74371036619..a518222c3bde 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotController.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java @@ -118,6 +118,11 @@ class TaskSnapshotController { */ private final boolean mIsRunningOnWear; + /** + * Flag indicating if device configuration has disabled app snapshots. + */ + private final boolean mConfigDisableTaskSnapshots; + TaskSnapshotController(WindowManagerService service) { mService = service; mPersister = new TaskSnapshotPersister(mService, Environment::getDataSystemCeDirectory); @@ -131,6 +136,8 @@ class TaskSnapshotController { PackageManager.FEATURE_WATCH); mHighResTaskSnapshotScale = mService.mContext.getResources().getFloat( com.android.internal.R.dimen.config_highResTaskSnapshotScale); + mConfigDisableTaskSnapshots = mService.mContext.getResources().getBoolean( + com.android.internal.R.bool.config_disableTaskSnapshots); } void systemReady() { @@ -488,7 +495,8 @@ class TaskSnapshotController { } boolean shouldDisableSnapshots() { - return mIsRunningOnWear || mIsRunningOnTv || mIsRunningOnIoT; + return mIsRunningOnWear || mIsRunningOnTv || mIsRunningOnIoT + || mConfigDisableTaskSnapshots; } /** diff --git a/services/core/java/com/android/server/wm/WallpaperWindowToken.java b/services/core/java/com/android/server/wm/WallpaperWindowToken.java index 194f48f57cc4..b54e8b7a7b4e 100644 --- a/services/core/java/com/android/server/wm/WallpaperWindowToken.java +++ b/services/core/java/com/android/server/wm/WallpaperWindowToken.java @@ -66,8 +66,8 @@ class WallpaperWindowToken extends WindowToken { } @Override - void setExiting() { - super.setExiting(); + void setExiting(boolean animateExit) { + super.setExiting(animateExit); mDisplayContent.mWallpaperController.removeWallpaperToken(this); } diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java index 47087cfbd147..4fac05c349c5 100644 --- a/services/core/java/com/android/server/wm/WindowManagerInternal.java +++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java @@ -445,8 +445,21 @@ public abstract class WindowManagerInternal { * @param removeWindows Whether to also remove the windows associated with the token. * @param displayId The display to remove the token from. */ + public final void removeWindowToken(android.os.IBinder token, boolean removeWindows, + int displayId) { + removeWindowToken(token, removeWindows, true /* animateExit */, displayId); + } + + /** + * Removes a window token. + * + * @param token The toke to remove. + * @param removeWindows Whether to also remove the windows associated with the token. + * @param animateExit Whether to play the windows exit animation after the token removal. + * @param displayId The display to remove the token from. + */ public abstract void removeWindowToken(android.os.IBinder token, boolean removeWindows, - int displayId); + boolean animateExit, int displayId); /** * Registers a listener to be notified about app transition events. diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 1ec9187d7a76..3421b28454f0 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -167,8 +167,10 @@ import android.graphics.Point; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Region; -import android.hardware.configstore.V1_0.ISurfaceFlingerConfigs; import android.hardware.configstore.V1_0.OptionalBool; +import android.hardware.configstore.V1_1.DisplayOrientation; +import android.hardware.configstore.V1_1.ISurfaceFlingerConfigs; +import android.hardware.configstore.V1_1.OptionalDisplayOrientation; import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManagerInternal; import android.hardware.input.InputManager; @@ -220,6 +222,7 @@ import android.util.TypedValue; import android.util.proto.ProtoOutputStream; import android.view.Choreographer; import android.view.Display; +import android.view.DisplayAddress; import android.view.DisplayInfo; import android.view.Gravity; import android.view.IAppTransitionAnimationSpecsFuture; @@ -465,6 +468,8 @@ public class WindowManagerService extends IWindowManager.Stub */ static final boolean ENABLE_FIXED_ROTATION_TRANSFORM = SystemProperties.getBoolean("persist.wm.fixed_rotation_transform", true); + private @Surface.Rotation int mPrimaryDisplayOrientation = Surface.ROTATION_0; + private DisplayAddress mPrimaryDisplayPhysicalAddress; // Enums for animation scale update types. @Retention(RetentionPolicy.SOURCE) @@ -2461,16 +2466,21 @@ public class WindowManagerService extends IWindowManager.Stub configChanged = displayContent.updateOrientation(); Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); - final DisplayInfo rotatedDisplayInfo = - win.mToken.getFixedRotationTransformDisplayInfo(); - if (rotatedDisplayInfo != null) { - outSurfaceControl.setTransformHint(rotatedDisplayInfo.rotation); - } else { - // We have to update the transform hint of display here, but we need to get if from - // SurfaceFlinger, so set it as rotation of display for most cases, then - // SurfaceFlinger would still update the transform hint of display in next frame. - outSurfaceControl.setTransformHint(displayContent.getDisplayInfo().rotation); - } + final DisplayInfo displayInfo = win.getDisplayInfo(); + int transformHint = displayInfo.rotation; + // If the window is on the primary display, use the panel orientation to adjust the + // transform hint + final boolean isPrimaryDisplay = displayInfo.address != null && + displayInfo.address.equals(mPrimaryDisplayPhysicalAddress); + if (isPrimaryDisplay) { + transformHint = (transformHint + mPrimaryDisplayOrientation) % 4; + } + outSurfaceControl.setTransformHint(transformHint); + ProtoLog.v(WM_DEBUG_ORIENTATION, + "Passing transform hint %d for window %s%s", + transformHint, win, + isPrimaryDisplay ? " on primary display with orientation " + + mPrimaryDisplayOrientation : ""); if (toBeDisplayed && win.mIsWallpaper) { displayContent.mWallpaperController.updateWallpaperOffset(win, false /* sync */); @@ -2816,6 +2826,31 @@ public class WindowManagerService extends IWindowManager.Stub } + void removeWindowToken(IBinder binder, boolean removeWindows, boolean animateExit, + int displayId) { + synchronized (mGlobalLock) { + final DisplayContent dc = mRoot.getDisplayContent(displayId); + + if (dc == null) { + ProtoLog.w(WM_ERROR, "removeWindowToken: Attempted to remove token: %s" + + " for non-exiting displayId=%d", binder, displayId); + return; + } + final WindowToken token = dc.removeWindowToken(binder, animateExit); + if (token == null) { + ProtoLog.w(WM_ERROR, + "removeWindowToken: Attempted to remove non-existing token: %s", + binder); + return; + } + + if (removeWindows) { + token.removeAllWindowsIfPossible(); + } + dc.getInputMonitor().updateInputWindowsLw(true /* force */); + } + } + @Override public void removeWindowToken(IBinder binder, int displayId) { if (!checkCallingPermission(MANAGE_APP_TOKENS, "removeWindowToken()")) { @@ -2823,23 +2858,7 @@ public class WindowManagerService extends IWindowManager.Stub } final long origId = Binder.clearCallingIdentity(); try { - synchronized (mGlobalLock) { - final DisplayContent dc = mRoot.getDisplayContent(displayId); - - if (dc == null) { - ProtoLog.w(WM_ERROR, "removeWindowToken: Attempted to remove token: %s" - + " for non-exiting displayId=%d", binder, displayId); - return; - } - final WindowToken token = dc.removeWindowToken(binder); - if (token == null) { - ProtoLog.w(WM_ERROR, - "removeWindowToken: Attempted to remove non-existing token: %s", - binder); - return; - } - dc.getInputMonitor().updateInputWindowsLw(true /*force*/); - } + removeWindowToken(binder, false /* removeWindows */, true /* animateExit */, displayId); } finally { Binder.restoreCallingIdentity(origId); } @@ -4859,6 +4878,9 @@ public class WindowManagerService extends IWindowManager.Stub mTaskSnapshotController.systemReady(); mHasWideColorGamutSupport = queryWideColorGamutSupport(); mHasHdrSupport = queryHdrSupport(); + mPrimaryDisplayOrientation = queryPrimaryDisplayOrientation(); + mPrimaryDisplayPhysicalAddress = + DisplayAddress.fromPhysicalDisplayId(SurfaceControl.getPrimaryPhysicalDisplayId()); UiThread.getHandler().post(mSettingsObserver::loadSettings); IVrManager vrManager = IVrManager.Stub.asInterface( ServiceManager.getService(Context.VR_SERVICE)); @@ -4878,6 +4900,9 @@ public class WindowManagerService extends IWindowManager.Stub } } + + // Keep logic in sync with SurfaceFlingerProperties.cpp + // Consider exposing properties via ISurfaceComposer instead. private static boolean queryWideColorGamutSupport() { boolean defaultValue = false; Optional<Boolean> hasWideColorProp = SurfaceFlingerProperties.has_wide_color_display(); @@ -4918,6 +4943,39 @@ public class WindowManagerService extends IWindowManager.Stub return false; } + private static @Surface.Rotation int queryPrimaryDisplayOrientation() { + Optional<SurfaceFlingerProperties.primary_display_orientation_values> prop = + SurfaceFlingerProperties.primary_display_orientation(); + if (prop.isPresent()) { + switch (prop.get()) { + case ORIENTATION_90: return Surface.ROTATION_90; + case ORIENTATION_180: return Surface.ROTATION_180; + case ORIENTATION_270: return Surface.ROTATION_270; + case ORIENTATION_0: + default: + return Surface.ROTATION_0; + } + } + try { + ISurfaceFlingerConfigs surfaceFlinger = ISurfaceFlingerConfigs.getService(); + OptionalDisplayOrientation primaryDisplayOrientation = + surfaceFlinger.primaryDisplayOrientation(); + if (primaryDisplayOrientation != null && primaryDisplayOrientation.specified) { + switch (primaryDisplayOrientation.value) { + case DisplayOrientation.ORIENTATION_90: return Surface.ROTATION_90; + case DisplayOrientation.ORIENTATION_180: return Surface.ROTATION_180; + case DisplayOrientation.ORIENTATION_270: return Surface.ROTATION_270; + case DisplayOrientation.ORIENTATION_0: + default: + return Surface.ROTATION_0; + } + } + } catch (Exception e) { + // Use default value if we can't talk to config store. + } + return Surface.ROTATION_0; + } + void reportFocusChanged(IBinder oldToken, IBinder newToken) { WindowState lastFocus; WindowState newFocus; @@ -7536,28 +7594,10 @@ public class WindowManagerService extends IWindowManager.Stub } @Override - public void removeWindowToken(IBinder binder, boolean removeWindows, int displayId) { - synchronized (mGlobalLock) { - if (removeWindows) { - final DisplayContent dc = mRoot.getDisplayContent(displayId); - if (dc == null) { - ProtoLog.w(WM_ERROR, "removeWindowToken: Attempted to remove token: %s" - + " for non-exiting displayId=%d", binder, displayId); - return; - } - - final WindowToken token = dc.removeWindowToken(binder); - if (token == null) { - ProtoLog.w(WM_ERROR, - "removeWindowToken: Attempted to remove non-existing token: %s", - binder); - return; - } - - token.removeAllWindowsIfPossible(); - } - WindowManagerService.this.removeWindowToken(binder, displayId); - } + public void removeWindowToken(IBinder binder, boolean removeWindows, boolean animateExit, + int displayId) { + WindowManagerService.this.removeWindowToken(binder, removeWindows, animateExit, + displayId); } @Override diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java index 5540cc567ed2..4857fb3faa76 100644 --- a/services/core/java/com/android/server/wm/WindowProcessController.java +++ b/services/core/java/com/android/server/wm/WindowProcessController.java @@ -1547,7 +1547,9 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio // activity as it could lead to incorrect display metrics. For ex, IME services // expect their config to match the config of the display with the IME window // showing. + // If the configuration has been overridden by previous activity, empty it. mIsActivityConfigOverrideAllowed = false; + unregisterActivityConfigurationListener(); break; default: break; diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index c3fc99554bcc..5e042efa2f11 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -2180,11 +2180,18 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } } - boolean onSetAppExiting() { + boolean onSetAppExiting(boolean animateExit) { final DisplayContent displayContent = getDisplayContent(); boolean changed = false; - if (isVisibleNow()) { + if (!animateExit) { + // Hide the window permanently if no window exist animation is performed, so we can + // avoid the window surface becoming visible again unexpectedly during the next + // relayout. + mPermanentlyHidden = true; + hide(false /* doAnimation */, false /* requestAnim */); + } + if (isVisibleNow() && animateExit) { mWinAnimator.applyAnimationLocked(TRANSIT_EXIT, false); if (mWmService.mAccessibilityController != null) { mWmService.mAccessibilityController.onWindowTransition(this, TRANSIT_EXIT); @@ -2197,7 +2204,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP for (int i = mChildren.size() - 1; i >= 0; --i) { final WindowState c = mChildren.get(i); - changed |= c.onSetAppExiting(); + changed |= c.onSetAppExiting(animateExit); } return changed; diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java index fbfa400ba852..3cbc67c004cd 100644 --- a/services/core/java/com/android/server/wm/WindowToken.java +++ b/services/core/java/com/android/server/wm/WindowToken.java @@ -24,6 +24,7 @@ import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_MOVEMENT; +import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION; import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN; import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS; import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION; @@ -232,7 +233,7 @@ class WindowToken extends WindowContainer<WindowState> { } } - void setExiting() { + void setExiting(boolean animateExit) { if (isEmpty()) { super.removeImmediately(); return; @@ -247,11 +248,12 @@ class WindowToken extends WindowContainer<WindowState> { final int count = mChildren.size(); boolean changed = false; - final boolean delayed = isAnimating(TRANSITION | PARENTS | CHILDREN); + final boolean delayed = isAnimating(TRANSITION | PARENTS) + || (isAnimating(CHILDREN, ANIMATION_TYPE_WINDOW_ANIMATION) && animateExit); for (int i = 0; i < count; i++) { final WindowState win = mChildren.get(i); - changed |= win.onSetAppExiting(); + changed |= win.onSetAppExiting(animateExit); } final ActivityRecord app = asActivityRecord(); @@ -353,7 +355,7 @@ class WindowToken extends WindowContainer<WindowState> { @Override void removeImmediately() { if (mDisplayContent != null) { - mDisplayContent.removeWindowToken(token); + mDisplayContent.removeWindowToken(token, true /* animateExit */); } // Needs to occur after the token is removed from the display above to avoid attempt at // duplicate removal of this window container from it's parent. diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp index 2722b8d04370..710a304545af 100644 --- a/services/core/jni/Android.bp +++ b/services/core/jni/Android.bp @@ -165,7 +165,7 @@ cc_defaults { "android.hardware.power@1.1", "android.hardware.power-V2-cpp", "android.hardware.power.stats@1.0", - "android.hardware.power.stats-V1-ndk_platform", + "android.hardware.power.stats-V1-ndk", "android.hardware.thermal@1.0", "android.hardware.tv.input@1.0", "android.hardware.vibrator-V2-cpp", @@ -178,7 +178,7 @@ cc_defaults { "android.frameworks.schedulerservice@1.0", "android.frameworks.sensorservice@1.0", "android.frameworks.stats@1.0", - "android.frameworks.stats-V1-ndk_platform", + "android.frameworks.stats-V1-ndk", "android.system.suspend.control-V1-cpp", "android.system.suspend.control.internal-cpp", "android.system.suspend-V1-ndk", diff --git a/services/java/com/android/server/SystemConfigService.java b/services/java/com/android/server/SystemConfigService.java index 3a9b2dca3921..cb52e5f72d5f 100644 --- a/services/java/com/android/server/SystemConfigService.java +++ b/services/java/com/android/server/SystemConfigService.java @@ -19,6 +19,7 @@ import static java.util.stream.Collectors.toList; import static java.util.stream.Collectors.toMap; import android.Manifest; +import android.content.ComponentName; import android.content.Context; import android.os.ISystemConfig; import android.util.ArrayMap; @@ -87,14 +88,14 @@ public class SystemConfigService extends SystemService { } @Override - public List<String> getEnabledComponentOverrides(String packageName) { + public List<ComponentName> getEnabledComponentOverrides(String packageName) { ArrayMap<String, Boolean> systemComponents = SystemConfig.getInstance() .getComponentsEnabledStates(packageName); - List<String> enabledComponent = new ArrayList<>(); + List<ComponentName> enabledComponent = new ArrayList<>(); if (systemComponents != null) { for (Map.Entry<String, Boolean> entry : systemComponents.entrySet()) { if (Boolean.TRUE.equals(entry.getValue())) { - enabledComponent.add(entry.getKey()); + enabledComponent.add(new ComponentName(packageName, entry.getKey())); } } } diff --git a/services/net/Android.bp b/services/net/Android.bp index 09a831e2b8c4..0c3f1dd3589d 100644 --- a/services/net/Android.bp +++ b/services/net/Android.bp @@ -41,6 +41,7 @@ java_library { sdk_version: "module_current", min_sdk_version: "30", libs: [ + "framework-annotations-lib", "unsupportedappusage", "framework-wifi-util-lib", "framework-connectivity", diff --git a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java index fdf23d3836ac..4fb801e188d0 100644 --- a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java +++ b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java @@ -23,7 +23,6 @@ import android.app.job.JobService; import android.content.ComponentName; import android.content.Context; import android.content.Intent; -import android.content.pm.ResolveInfo; import android.os.Handler; import android.os.IBinder.DeathRecipient; import android.os.Looper; @@ -32,8 +31,6 @@ import android.os.ServiceManager; import android.os.SystemProperties; import android.os.UpdateEngine; import android.os.UpdateEngineCallback; -import android.os.UserHandle; -import android.os.UserManager; import android.provider.DeviceConfig; import android.util.Log; @@ -45,9 +42,6 @@ import com.android.server.wm.ActivityMetricsLaunchObserver; import com.android.server.wm.ActivityMetricsLaunchObserverRegistry; import com.android.server.wm.ActivityTaskManagerInternal; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.List; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; @@ -306,79 +300,27 @@ public final class ProfcollectForwardingService extends SystemService { return; } - if (!getUploaderEnabledConfig(getContext())) { - return; - } - + Context context = getContext(); new Thread(() -> { try { - Context context = getContext(); - final String uploaderPkg = getUploaderPackageName(context); - final String uploaderAction = getUploaderActionName(context); - String reportUuid = mIProfcollect.report(); - - final int profileId = getBBProfileId(); - String reportDir = "/data/user/" + profileId - + "/com.google.android.apps.internal.betterbug/cache/"; - String reportPath = reportDir + reportUuid + ".zip"; - - if (!Files.exists(Paths.get(reportDir))) { - Log.i(LOG_TAG, "Destination directory does not exist, abort upload."); - return; - } + // Prepare profile report + String reportName = mIProfcollect.report() + ".zip"; - Intent uploadIntent = - new Intent(uploaderAction) - .setPackage(uploaderPkg) - .putExtra("EXTRA_DESTINATION", "PROFCOLLECT") - .putExtra("EXTRA_PACKAGE_NAME", getContext().getPackageName()) - .putExtra("EXTRA_PROFILE_PATH", reportPath) - .addFlags(Intent.FLAG_RECEIVER_FOREGROUND); - - List<ResolveInfo> receivers = - context.getPackageManager().queryBroadcastReceivers(uploadIntent, 0); - if (receivers == null || receivers.isEmpty()) { - Log.i(LOG_TAG, "No one to receive upload intent, abort upload."); + if (!context.getResources().getBoolean( + R.bool.config_profcollectReportUploaderEnabled)) { + Log.i(LOG_TAG, "Upload is not enabled."); return; } - mIProfcollect.copy_report_to_bb(profileId, reportUuid); - context.sendBroadcast(uploadIntent); - mIProfcollect.delete_report(reportUuid); + + // Upload the report + Intent intent = new Intent() + .setPackage("com.android.shell") + .setAction("com.android.shell.action.PROFCOLLECT_UPLOAD") + .putExtra("filename", reportName); + context.sendBroadcast(intent); } catch (RemoteException e) { Log.e(LOG_TAG, e.getMessage()); } }).start(); } - - /** - * Get BetterBug's profile ID. It is the work profile ID, if it exists. Otherwise the system - * user ID. - * - * @return BetterBug's profile ID. - */ - private int getBBProfileId() { - UserManager userManager = UserManager.get(getContext()); - int[] profiles = userManager.getProfileIds(UserHandle.USER_SYSTEM, false); - for (int p : profiles) { - if (userManager.getUserInfo(p).isManagedProfile()) { - return p; - } - } - return UserHandle.USER_SYSTEM; - } - - private boolean getUploaderEnabledConfig(Context context) { - return context.getResources().getBoolean( - R.bool.config_profcollectReportUploaderEnabled); - } - - private String getUploaderPackageName(Context context) { - return context.getResources().getString( - R.string.config_defaultProfcollectReportUploaderApp); - } - - private String getUploaderActionName(Context context) { - return context.getResources().getString( - R.string.config_defaultProfcollectReportUploaderAction); - } } diff --git a/services/tests/PackageManagerServiceTests/OWNERS b/services/tests/PackageManagerServiceTests/OWNERS index 182dfe8fca9e..86ae5818e91c 100644 --- a/services/tests/PackageManagerServiceTests/OWNERS +++ b/services/tests/PackageManagerServiceTests/OWNERS @@ -1,3 +1 @@ -chiuwinson@google.com -patb@google.com -toddke@google.com +include /PACKAGE_MANAGER_OWNERS diff --git a/services/tests/servicestests/src/com/android/server/BatteryServiceTest.java b/services/tests/servicestests/src/com/android/server/health/HealthServiceWrapperTest.java index cb12ba7d7679..c97a67bad590 100644 --- a/services/tests/servicestests/src/com/android/server/BatteryServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/health/HealthServiceWrapperTest.java @@ -14,19 +14,25 @@ * limitations under the License. */ -package com.android.server; +package com.android.server.health; -import static junit.framework.Assert.*; +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.fail; import static org.mockito.Mockito.*; import android.hardware.health.V2_0.IHealth; import android.hidl.manager.V1_0.IServiceManager; import android.hidl.manager.V1_0.IServiceNotification; -import android.test.AndroidTestCase; +import android.os.RemoteException; import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; import org.mockito.ArgumentMatcher; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -36,37 +42,39 @@ import java.util.Arrays; import java.util.Collection; import java.util.NoSuchElementException; -public class BatteryServiceTest extends AndroidTestCase { +@RunWith(AndroidJUnit4.class) +public class HealthServiceWrapperTest { @Mock IServiceManager mMockedManager; @Mock IHealth mMockedHal; @Mock IHealth mMockedHal2; - @Mock BatteryService.HealthServiceWrapper.Callback mCallback; - @Mock BatteryService.HealthServiceWrapper.IServiceManagerSupplier mManagerSupplier; - @Mock BatteryService.HealthServiceWrapper.IHealthSupplier mHealthServiceSupplier; - BatteryService.HealthServiceWrapper mWrapper; + @Mock HealthServiceWrapperHidl.Callback mCallback; + @Mock HealthServiceWrapperHidl.IServiceManagerSupplier mManagerSupplier; + @Mock HealthServiceWrapperHidl.IHealthSupplier mHealthServiceSupplier; + HealthServiceWrapper mWrapper; - private static final String HEALTHD = BatteryService.HealthServiceWrapper.INSTANCE_HEALTHD; - private static final String VENDOR = BatteryService.HealthServiceWrapper.INSTANCE_VENDOR; + private static final String VENDOR = HealthServiceWrapperHidl.INSTANCE_VENDOR; - @Override + @Before public void setUp() { MockitoAnnotations.initMocks(this); } - @Override + @After public void tearDown() { - if (mWrapper != null) - mWrapper.getHandlerThread().quitSafely(); + if (mWrapper != null) mWrapper.getHandlerThread().quitSafely(); } public static <T> ArgumentMatcher<T> isOneOf(Collection<T> collection) { return new ArgumentMatcher<T>() { - @Override public boolean matches(T e) { + @Override + public boolean matches(T e) { return collection.contains(e); } - @Override public String toString() { + + @Override + public String toString() { return collection.toString(); } }; @@ -74,27 +82,29 @@ public class BatteryServiceTest extends AndroidTestCase { private void initForInstances(String... instanceNamesArr) throws Exception { final Collection<String> instanceNames = Arrays.asList(instanceNamesArr); - doAnswer((invocation) -> { - // technically, preexisting is ignored by - // BatteryService.HealthServiceWrapper.Notification, but still call it correctly. - sendNotification(invocation, true); - sendNotification(invocation, true); - sendNotification(invocation, false); - return null; - }).when(mMockedManager).registerForNotifications( - eq(IHealth.kInterfaceName), - argThat(isOneOf(instanceNames)), - any(IServiceNotification.class)); + doAnswer( + (invocation) -> { + // technically, preexisting is ignored by + // HealthServiceWrapperHidl.Notification, but still call it correctly. + sendNotification(invocation, true); + sendNotification(invocation, true); + sendNotification(invocation, false); + return null; + }) + .when(mMockedManager) + .registerForNotifications( + eq(IHealth.kInterfaceName), + argThat(isOneOf(instanceNames)), + any(IServiceNotification.class)); doReturn(mMockedManager).when(mManagerSupplier).get(); - doReturn(mMockedHal) // init calls this - .doReturn(mMockedHal) // notification 1 - .doReturn(mMockedHal) // notification 2 - .doReturn(mMockedHal2) // notification 3 - .doThrow(new RuntimeException("Should not call getService for more than 4 times")) - .when(mHealthServiceSupplier).get(argThat(isOneOf(instanceNames))); - - mWrapper = new BatteryService.HealthServiceWrapper(); + doReturn(mMockedHal) // init calls this + .doReturn(mMockedHal) // notification 1 + .doReturn(mMockedHal) // notification 2 + .doReturn(mMockedHal2) // notification 3 + .doThrow(new RuntimeException("Should not call getService for more than 4 times")) + .when(mHealthServiceSupplier) + .get(argThat(isOneOf(instanceNames))); } private void waitHandlerThreadFinish() throws Exception { @@ -109,16 +119,20 @@ public class BatteryServiceTest extends AndroidTestCase { private static void sendNotification(InvocationOnMock invocation, boolean preexisting) throws Exception { - ((IServiceNotification)invocation.getArguments()[2]).onRegistration( - IHealth.kInterfaceName, - (String)invocation.getArguments()[1], - preexisting); + ((IServiceNotification) invocation.getArguments()[2]) + .onRegistration( + IHealth.kInterfaceName, (String) invocation.getArguments()[1], preexisting); + } + + private void createWrapper() throws RemoteException { + mWrapper = HealthServiceWrapper.create(mCallback, mManagerSupplier, mHealthServiceSupplier); } @SmallTest + @Test public void testWrapPreferVendor() throws Exception { - initForInstances(VENDOR, HEALTHD); - mWrapper.init(mCallback, mManagerSupplier, mHealthServiceSupplier); + initForInstances(VENDOR); + createWrapper(); waitHandlerThreadFinish(); verify(mCallback, times(1)).onRegistration(same(null), same(mMockedHal), eq(VENDOR)); verify(mCallback, never()).onRegistration(same(mMockedHal), same(mMockedHal), anyString()); @@ -126,20 +140,11 @@ public class BatteryServiceTest extends AndroidTestCase { } @SmallTest - public void testUseHealthd() throws Exception { - initForInstances(HEALTHD); - mWrapper.init(mCallback, mManagerSupplier, mHealthServiceSupplier); - waitHandlerThreadFinish(); - verify(mCallback, times(1)).onRegistration(same(null), same(mMockedHal), eq(HEALTHD)); - verify(mCallback, never()).onRegistration(same(mMockedHal), same(mMockedHal), anyString()); - verify(mCallback, times(1)).onRegistration(same(mMockedHal), same(mMockedHal2), eq(HEALTHD)); - } - - @SmallTest + @Test public void testNoService() throws Exception { initForInstances("unrelated"); try { - mWrapper.init(mCallback, mManagerSupplier, mHealthServiceSupplier); + createWrapper(); fail("Expect NoSuchElementException"); } catch (NoSuchElementException ex) { // expected diff --git a/services/tests/servicestests/src/com/android/server/health/OWNERS b/services/tests/servicestests/src/com/android/server/health/OWNERS new file mode 100644 index 000000000000..81522fcaa09f --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/health/OWNERS @@ -0,0 +1 @@ +file:platform/hardware/interfaces:/health/aidl/OWNERS diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityOptionsTest.java b/services/tests/wmtests/src/com/android/server/wm/ActivityOptionsTest.java index b4fbf5fe40eb..184ea521e828 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityOptionsTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityOptionsTest.java @@ -110,18 +110,20 @@ public class ActivityOptionsTest { @Override public void onTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) { try (SurfaceControl.Transaction t = new SurfaceControl.Transaction()) { - t.setVisibility(leash, true /* visible */).apply(); + t.show(leash).apply(); } int cookieIndex = -1; if (trampoline.equals(taskInfo.baseActivity)) { cookieIndex = 0; } else if (main.equals(taskInfo.baseActivity)) { cookieIndex = 1; - mainLatch.countDown(); } if (cookieIndex >= 0) { appearedCookies[cookieIndex] = taskInfo.launchCookies.isEmpty() ? null : taskInfo.launchCookies.get(0); + if (cookieIndex == 1) { + mainLatch.countDown(); + } } } }; diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java index 293e862a6b74..6f04f176afd8 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -39,6 +39,7 @@ import static android.os.Process.NOBODY_UID; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW; +import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD; import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; @@ -2816,6 +2817,73 @@ public class ActivityRecordTests extends WindowTestsBase { assertFalse(activity.mDisplayContent.mClosingApps.contains(activity)); } + @Test + public void testImeInsetsFrozenFlag_resetWhenReparented() { + final ActivityRecord activity = createActivityWithTask(); + final WindowState app = createWindow(null, TYPE_APPLICATION, activity, "app"); + final WindowState imeWindow = createWindow(null, TYPE_APPLICATION, "imeWindow"); + final Task newTask = new TaskBuilder(mSupervisor).build(); + makeWindowVisible(app, imeWindow); + mDisplayContent.mInputMethodWindow = imeWindow; + mDisplayContent.setImeLayeringTarget(app); + mDisplayContent.setImeInputTarget(app); + + // Simulate app is closing and expect the last IME is shown and IME insets is frozen. + app.mActivityRecord.commitVisibility(false, false); + assertTrue(app.mActivityRecord.mLastImeShown); + assertTrue(app.mActivityRecord.mImeInsetsFrozenUntilStartInput); + + // Expect IME insets frozen state will reset when the activity is reparent to the new task. + activity.setState(RESUMED, "test"); + activity.reparent(newTask, 0 /* top */, "test"); + assertFalse(app.mActivityRecord.mImeInsetsFrozenUntilStartInput); + } + + @UseTestDisplay(addWindows = W_INPUT_METHOD) + @Test + public void testImeInsetsFrozenFlag_resetWhenResized() { + final WindowState app = createWindow(null, TYPE_APPLICATION, "app"); + makeWindowVisibleAndDrawn(app, mImeWindow); + mDisplayContent.setImeLayeringTarget(app); + mDisplayContent.setImeInputTarget(app); + + // Simulate app is closing and expect the last IME is shown and IME insets is frozen. + app.mActivityRecord.commitVisibility(false, false); + assertTrue(app.mActivityRecord.mLastImeShown); + assertTrue(app.mActivityRecord.mImeInsetsFrozenUntilStartInput); + + // Expect IME insets frozen state will reset when the activity is reparent to the new task. + app.mActivityRecord.onResize(); + assertFalse(app.mActivityRecord.mImeInsetsFrozenUntilStartInput); + } + + @UseTestDisplay(addWindows = W_INPUT_METHOD) + @Test + public void testImeInsetsFrozenFlag_resetWhenNoImeFocusableInActivity() { + final WindowState app = createWindow(null, TYPE_APPLICATION, "app"); + makeWindowVisibleAndDrawn(app, mImeWindow); + mDisplayContent.setImeLayeringTarget(app); + mDisplayContent.setImeInputTarget(app); + + // Simulate app is closing and expect the last IME is shown and IME insets is frozen. + app.mActivityRecord.commitVisibility(false, false); + app.mActivityRecord.onWindowsGone(); + + assertTrue(app.mActivityRecord.mLastImeShown); + assertTrue(app.mActivityRecord.mImeInsetsFrozenUntilStartInput); + + // Expect IME insets frozen state will reset when the activity has no IME focusable window. + app.mActivityRecord.forAllWindowsUnchecked(w -> { + w.mAttrs.flags |= FLAG_ALT_FOCUSABLE_IM; + return true; + }, true); + + app.mActivityRecord.commitVisibility(true, false); + app.mActivityRecord.onWindowsVisible(); + + assertFalse(app.mActivityRecord.mImeInsetsFrozenUntilStartInput); + } + private void assertHasStartingWindow(ActivityRecord atoken) { assertNotNull(atoken.mStartingSurface); assertNotNull(atoken.mStartingData); diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java index a8e17534e6ed..8e7ba4bc3293 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java +++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java @@ -258,6 +258,7 @@ public class SystemServicesTestRule implements TestRule { final ActivityManagerInternal amInternal = mAmService.mInternal; spyOn(amInternal); doNothing().when(amInternal).trimApplications(); + doNothing().when(amInternal).scheduleAppGcs(); doNothing().when(amInternal).updateCpuStats(); doNothing().when(amInternal).updateOomAdj(); doNothing().when(amInternal).updateBatteryStats(any(), anyInt(), anyInt(), anyBoolean()); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java index 92b670ed9699..d88ac256be5c 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java @@ -891,6 +891,40 @@ public class WindowStateTests extends WindowTestsBase { assertTrue(mAppWindow.getInsetsState().getSourceOrDefaultVisibility(ITYPE_NAVIGATION_BAR)); } + @Test + public void testAdjustImeInsetsVisibilityWhenSwitchingApps() { + final WindowState app = createWindow(null, TYPE_APPLICATION, "app"); + final WindowState app2 = createWindow(null, TYPE_APPLICATION, "app2"); + final WindowState imeWindow = createWindow(null, TYPE_APPLICATION, "imeWindow"); + spyOn(imeWindow); + doReturn(true).when(imeWindow).isVisible(); + mDisplayContent.mInputMethodWindow = imeWindow; + + final InsetsStateController controller = mDisplayContent.getInsetsStateController(); + controller.getImeSourceProvider().setWindow(imeWindow, null, null); + + // Simulate app requests IME with updating all windows Insets State when IME is above app. + mDisplayContent.setImeLayeringTarget(app); + mDisplayContent.setImeInputTarget(app); + assertTrue(mDisplayContent.shouldImeAttachedToApp()); + controller.getImeSourceProvider().scheduleShowImePostLayout(app); + controller.getImeSourceProvider().getSource().setVisible(true); + controller.updateAboveInsetsState(imeWindow, false); + + // Expect all app windows behind IME can receive IME insets visible. + assertTrue(app.getInsetsState().getSource(ITYPE_IME).isVisible()); + assertTrue(app2.getInsetsState().getSource(ITYPE_IME).isVisible()); + + // Simulate app plays closing transition to app2. + app.mActivityRecord.commitVisibility(false, false); + assertTrue(app.mActivityRecord.mLastImeShown); + assertTrue(app.mActivityRecord.mImeInsetsFrozenUntilStartInput); + + // Verify the IME insets is visible on app, but not for app2 during app task switching. + assertTrue(app.getInsetsState().getSource(ITYPE_IME).isVisible()); + assertFalse(app2.getInsetsState().getSource(ITYPE_IME).isVisible()); + } + @UseTestDisplay(addWindows = { W_ACTIVITY }) @Test public void testUpdateImeControlTargetWhenLeavingMultiWindow() { diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java index d048f1842aa3..589f9134f227 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java @@ -24,6 +24,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; import static android.view.WindowManager.LayoutParams.TYPE_TOAST; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; +import static com.android.server.policy.WindowManagerPolicy.TRANSIT_EXIT; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -44,6 +45,7 @@ import androidx.test.filters.SmallTest; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mockito; import java.util.function.BiFunction; @@ -126,7 +128,7 @@ public class WindowTokenTests extends WindowTestsBase { final WindowState window1 = createWindow(null, TYPE_TOAST, token, "window1"); final WindowState window2 = createWindow(null, TYPE_TOAST, token, "window2"); - mDisplayContent.removeWindowToken(token.token); + mDisplayContent.removeWindowToken(token.token, true /* animateExit */); // Verify that the token is no longer mapped on the display assertNull(mDisplayContent.getWindowToken(token.token)); // Verify that the token is still attached to its parent @@ -261,4 +263,29 @@ public class WindowTokenTests extends WindowTestsBase { assertNotNull(app.getFrozenInsetsState()); assertNull(mDisplayContent.mInputMethodWindow.getFrozenInsetsState()); } + + @Test + public void testRemoveWindowToken_noAnimateExitWhenSet() { + final TestWindowToken token = createTestWindowToken(0, mDisplayContent); + final WindowState win = createWindow(null, TYPE_APPLICATION, token, "win"); + makeWindowVisible(win); + assertTrue(win.isOnScreen()); + spyOn(win); + spyOn(win.mWinAnimator); + spyOn(win.mToken); + + // Invoking removeWindowToken with setting no window exit animation and not remove window + // immediately. verify the window will hide without applying exit animation. + mWm.removeWindowToken(win.mToken.token, false /* removeWindows */, false /* animateExit */, + mDisplayContent.mDisplayId); + verify(win).onSetAppExiting(Mockito.eq(false) /* animateExit */); + verify(win).hide(false /* doAnimation */, false /* requestAnim */); + assertFalse(win.isOnScreen()); + verify(win.mWinAnimator, Mockito.never()).applyAnimationLocked(TRANSIT_EXIT, false); + assertTrue(win.mToken.hasChild()); + + // Even though the window is being removed afterwards, it won't apply exit animation. + win.removeIfPossible(); + verify(win.mWinAnimator, Mockito.never()).applyAnimationLocked(TRANSIT_EXIT, false); + } } diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java index 7f24c365237d..1579aaf9a571 100644 --- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java +++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java @@ -765,6 +765,8 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser // send a sticky broadcast containing USB accessory handshake information Intent intent = new Intent(UsbManager.ACTION_USB_ACCESSORY_HANDSHAKE) + .addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND + | Intent.FLAG_RECEIVER_FOREGROUND) .putExtra(UsbManager.EXTRA_ACCESSORY_UEVENT_TIME, mAccessoryConnectionStartTime) .putExtra(UsbManager.EXTRA_ACCESSORY_STRING_COUNT, diff --git a/telecomm/java/android/telecom/InCallService.java b/telecomm/java/android/telecom/InCallService.java index cac716efe78f..0ddd52dfc76d 100644 --- a/telecomm/java/android/telecom/InCallService.java +++ b/telecomm/java/android/telecom/InCallService.java @@ -69,7 +69,14 @@ import java.util.List; * them know that the app has crashed and that their call was continued using the pre-loaded dialer * app. * <p> - * Further, the pre-loaded dialer will ALWAYS be used when the user places an emergency call. + * The pre-loaded dialer will ALWAYS be used when the user places an emergency call, even if your + * app fills the {@link android.app.role.RoleManager#ROLE_DIALER} role. To ensure an optimal + * experience when placing an emergency call, the default dialer should ALWAYS use + * {@link android.telecom.TelecomManager#placeCall(Uri, Bundle)} to place calls (including + * emergency calls). This ensures that the platform is able to verify that the request came from + * the default dialer. If a non-preloaded dialer app uses {@link Intent#ACTION_CALL} to place an + * emergency call, it will be raised to the preloaded dialer app using {@link Intent#ACTION_DIAL} + * for confirmation; this is a suboptimal user experience. * <p> * Below is an example manifest registration for an {@code InCallService}. The meta-data * {@link TelecomManager#METADATA_IN_CALL_SERVICE_UI} indicates that this particular diff --git a/telephony/OWNERS b/telephony/OWNERS index 4df8a4bc6413..4016ba7de379 100644 --- a/telephony/OWNERS +++ b/telephony/OWNERS @@ -1,6 +1,5 @@ set noparent -amitmahajan@google.com breadley@google.com fionaxu@google.com jackyu@google.com @@ -8,10 +7,10 @@ rgreenwalt@google.com tgunn@google.com jminjie@google.com shuoq@google.com -nazaninb@google.com sarahchin@google.com xiaotonj@google.com huiwang@google.com jayachandranc@google.com chinmayd@google.com amruthr@google.com +sasindran@google.com diff --git a/telephony/java/android/telephony/AvailableNetworkInfo.java b/telephony/java/android/telephony/AvailableNetworkInfo.java index ae597e02f33c..2b355ae216e3 100644 --- a/telephony/java/android/telephony/AvailableNetworkInfo.java +++ b/telephony/java/android/telephony/AvailableNetworkInfo.java @@ -16,11 +16,14 @@ package android.telephony; +import android.annotation.IntDef; import android.annotation.NonNull; import android.os.Parcel; import android.os.Parcelable; import android.telephony.RadioAccessSpecifier; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -32,7 +35,6 @@ import java.util.Objects; * Network Service when passed through {@link TelephonyManager#updateAvailableNetworks} */ public final class AvailableNetworkInfo implements Parcelable { - /* * Defines number of priority level high. */ @@ -48,6 +50,14 @@ public final class AvailableNetworkInfo implements Parcelable { */ public static final int PRIORITY_LOW = 3; + /** @hide */ + @IntDef({ + PRIORITY_HIGH, + PRIORITY_MED, + PRIORITY_LOW, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface AvailableNetworkInfoPriority {} /** * subscription Id of the available network. This value must be one of the entry retrieved from * {@link SubscriptionManager#getOpportunisticSubscriptions} @@ -62,7 +72,7 @@ public final class AvailableNetworkInfo implements Parcelable { * for network selection. If there are more than one subId with highest priority then the * network with highest RSRP is chosen. */ - private int mPriority; + private @AvailableNetworkInfoPriority int mPriority; /** * Describes the List of PLMN ids (MCC-MNC) associated with mSubId. @@ -77,8 +87,7 @@ public final class AvailableNetworkInfo implements Parcelable { * Opportunistic network service will use these bands to scan. * * When no specific bands are specified (empty array or null) CBRS band - * {@link AccessNetworkConstants.EutranBand.BAND_48 - * } will be used for network scan. + * {@link AccessNetworkConstants.EutranBand.BAND_48} will be used for network scan. * * See {@link AccessNetworkConstants} for details. * @@ -94,7 +103,7 @@ public final class AvailableNetworkInfo implements Parcelable { * If this entry is left empty, {@link RadioAcccessSpecifier}s with {@link AccessNetworkType}s * of {@link AccessNetworkConstants.AccessNetworkType.EUTRAN} and {@link * AccessNetworkConstants.AccessNetworkType.NGRAN} with bands 48 and 71 on each will be assumed - * by Opportunistic network service. + * by Opportunistic network service for a network scan. */ private ArrayList<RadioAccessSpecifier> mRadioAccessSpecifiers; @@ -117,6 +126,7 @@ public final class AvailableNetworkInfo implements Parcelable { * network with highest RSRP is chosen. * @return priority level */ + @AvailableNetworkInfoPriority public int getPriority() { return mPriority; } @@ -149,15 +159,9 @@ public final class AvailableNetworkInfo implements Parcelable { * Returns a list of {@link RadioAccessSpecifier} associated with the available network. * Opportunistic network service will use this to determine which bands to scan for. * - * the returned value is one of {@link AccessNetworkConstants.AccessNetworkType}. When no - * specific access network type is specified, {@link RadioAccessSpecifier}s with {@link - * AccessNetworkType}s of {@link AccessNetworkConstants.AccessNetworkType.EUTRAN} and {@link - * AccessNetworkConstants.AccessNetworkType.NGRAN} with bands 48 and 71 on each will be assumed - * by Opportunistic network service. * @return the access network type associated with the available network. - * @hide */ - public List<RadioAccessSpecifier> getRadioAccessSpecifiers() { + public @NonNull List<RadioAccessSpecifier> getRadioAccessSpecifiers() { return (List<RadioAccessSpecifier>) mRadioAccessSpecifiers.clone(); } @@ -193,9 +197,9 @@ public final class AvailableNetworkInfo implements Parcelable { } /** @hide */ - private AvailableNetworkInfo(int subId, int priority, @NonNull List<String> mccMncs, - @NonNull List<Integer> bands, @NonNull List<RadioAccessSpecifier> - radioAccessSpecifiers) { + private AvailableNetworkInfo(int subId, @AvailableNetworkInfoPriority int priority, + @NonNull List<String> mccMncs, @NonNull List<Integer> bands, + @NonNull List<RadioAccessSpecifier> radioAccessSpecifiers) { mSubId = subId; mPriority = priority; mMccMncs = new ArrayList<String>(mccMncs); @@ -261,27 +265,39 @@ public final class AvailableNetworkInfo implements Parcelable { * * <pre><code> * - * AvailableNetworkInfo aNI = new AvailableNetworkInfo.Builder() - * .setSubId(1) + * AvailableNetworkInfo aNI = new AvailableNetworkInfo.Builder(subId) * .setPriority(AvailableNetworkInfo.PRIORITY_MED) + * .setRadioAccessSpecifiers(radioAccessSpecifiers) + * .setMccMncs(mccMncs) * .build(); * </code></pre> - * - * @hide */ public static final class Builder { private int mSubId = Integer.MIN_VALUE; - private int mPriority = AvailableNetworkInfo.PRIORITY_LOW; + private @AvailableNetworkInfoPriority int mPriority = AvailableNetworkInfo.PRIORITY_LOW; private ArrayList<String> mMccMncs = new ArrayList<>(); - private ArrayList<Integer> mBands = new ArrayList<>(); private ArrayList<RadioAccessSpecifier> mRadioAccessSpecifiers = new ArrayList<>(); - public @NonNull Builder setSubId(int subId) { + /** + * + */ + /** + * Creates an AvailableNetworkInfo Builder with specified subscription id. + * + * @param subId of the availableNetwork. + */ + public Builder(int subId) { mSubId = subId; - return this; } - public @NonNull Builder setPriority(int priority) { + /** + * Sets the priority for the subscription id. + * + * @param priority of the subscription id. See {@link AvailableNetworkInfo#getPriority} for + * more details + * @return the original Builder object. + */ + public @NonNull Builder setPriority(@AvailableNetworkInfoPriority int priority) { if (priority > AvailableNetworkInfo.PRIORITY_LOW || priority < AvailableNetworkInfo.PRIORITY_HIGH) { throw new IllegalArgumentException("A valid priority must be set"); @@ -290,30 +306,48 @@ public final class AvailableNetworkInfo implements Parcelable { return this; } - public @NonNull Builder setMccMncs(@NonNull ArrayList<String> mccMncs) { - Objects.requireNonNull(mccMncs, "A non-null ArrayList of mccmncs must be set. An empty " - + "list is still accepted. Please read documentation in " - + "AvailableNetworkService to see consequences of an empty Arraylist."); - mMccMncs = mccMncs; + /** + * Sets the list of mccmncs associated with the subscription id. + * + * @param mccMncs nonull list of mccmncs. An empty List is still accepted. Please read + * documentation in {@link AvailableNetworkInfo} to see consequences of an empty List. + * @return the original Builder object. + */ + public @NonNull Builder setMccMncs(@NonNull List<String> mccMncs) { + Objects.requireNonNull(mccMncs, "A non-null List of mccmncs must be set. An empty " + + "List is still accepted. Please read documentation in " + + "AvailableNetworkInfo to see consequences of an empty List."); + mMccMncs = new ArrayList<>(mccMncs); return this; } + /** + * Sets the list of mccmncs associated with the subscription id. + * + * @param radioAccessSpecifiers nonull list of radioAccessSpecifiers. An empty List is still + * accepted. Please read documentation in {@link AvailableNetworkInfo} to see + * consequences of an empty List. + * @return the original Builder object. + */ public @NonNull Builder setRadioAccessSpecifiers( - @NonNull ArrayList<RadioAccessSpecifier> radioAccessSpecifiers) { - Objects.requireNonNull(radioAccessSpecifiers, "A non-null ArrayList of " - + "RadioAccessSpecifiers must be set. An empty list is still accepted. Please " - + "read documentation in AvailableNetworkService to see consequences of an " - + "empty Arraylist."); - mRadioAccessSpecifiers = radioAccessSpecifiers; + @NonNull List<RadioAccessSpecifier> radioAccessSpecifiers) { + Objects.requireNonNull(radioAccessSpecifiers, "A non-null List of " + + "RadioAccessSpecifiers must be set. An empty List is still accepted. Please " + + "read documentation in AvailableNetworkInfo to see consequences of an " + + "empty List."); + mRadioAccessSpecifiers = new ArrayList<>(radioAccessSpecifiers); return this; } + /** + * @return an AvailableNetworkInfo object with all the fields previously set by the Builder. + */ public @NonNull AvailableNetworkInfo build() { if (mSubId == Integer.MIN_VALUE) { throw new IllegalArgumentException("A valid subId must be set"); } - return new AvailableNetworkInfo(mSubId, mPriority, mMccMncs, mBands, + return new AvailableNetworkInfo(mSubId, mPriority, mMccMncs, new ArrayList<>(), mRadioAccessSpecifiers); } } diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 73e6c76fe214..df1f13294961 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -21,6 +21,7 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; +import android.annotation.SuppressAutoDoc; import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.SystemService; @@ -1879,6 +1880,20 @@ public class CarrierConfigManager { "lte_plus_threshold_bandwidth_khz_int"; /** + * The combined channel bandwidth threshold (non-inclusive) in KHz required to display the + * NR advanced (i.e. 5G+) data icon. It is 0 by default, meaning minimum bandwidth check is + * not enabled. Other factors like bands or frequency can also determine whether the NR + * advanced data icon is shown or not. + * + * @see #KEY_ADDITIONAL_NR_ADVANCED_BANDS_INT_ARRAY + * @see #KEY_NR_ADVANCED_CAPABLE_PCO_ID_INT + * + * @hide + */ + public static final String KEY_NR_ADVANCED_THRESHOLD_BANDWIDTH_KHZ_INT = + "nr_advanced_threshold_bandwidth_khz_int"; + + /** * The string is used to filter redundant string from PLMN Network Name that's supplied by * specific carrier. * @@ -3543,6 +3558,17 @@ public class CarrierConfigManager { "nr_advanced_capable_pco_id_int"; /** + * Enabled NR advanced (i.e. 5G+) icon while roaming. The default value is {@code true}, meaming + * the same NR advanced logic used for home network will be used for roaming network as well. + * Set this to {@code false} will disable NR advanced icon while the device is roaming, + * regardless meeting NR advanced criteria or not. + * + * @hide + */ + public static final String KEY_ENABLE_NR_ADVANCED_WHILE_ROAMING_BOOL = + "enable_nr_advanced_for_roaming_bool"; + + /** * This configuration allows the framework to use user data communication to detect Idle state, * and this is used on the 5G icon. * @@ -3649,6 +3675,49 @@ public class CarrierConfigManager { "show_wifi_calling_icon_in_status_bar_bool"; /** + * Configuration to indicate that the carrier supports opportunistic data + * auto provisioning. Based on this flag, the device downloads and activates + * corresponding opportunistic profile. + */ + public static final String KEY_CARRIER_SUPPORTS_OPP_DATA_AUTO_PROVISIONING_BOOL = + "carrier_supports_opp_data_auto_provisioning_bool"; + + /** + * SMDP+ server address for downloading opportunistic eSIM profile. + * FQDN (Fully Qualified Domain Name) of the SM-DP+ (e.g., smdp.gsma.com) restricted to the + * Alphanumeric mode character set defined in table 5 of ISO/IEC 18004 [15] excluding '$'. + */ + public static final String KEY_SMDP_SERVER_ADDRESS_STRING = + "smdp_server_address_string"; + + /** + * This timer value is used in the eSIM Exponential Backoff download retry algorithm. + * Value should be in seconds. + * <OL> + * <LI>When the first download failure occurs, retry download after BACKOFF_TIMER_VALUE + * seconds.</LI> + * + * <LI>If download fails again then, retry after either BACKOFF_TIMER_VALUE, + * 2xBACKOFF_TIMER_VALUE, or 3xBACKOFF_TIMER_VALUE seconds.</LI> + * + * <LI>In general after the cth failed attempt, retry after k * BACKOFF_TIMER_VALUE + * seconds, where k is a random integer between 1 and 2^c − 1. Max c value is + * {@link #KEY_ESIM_MAX_DOWNLOAD_RETRY_ATTEMPTS_INT}</LI> + * </OL> + */ + public static final String KEY_ESIM_DOWNLOAD_RETRY_BACKOFF_TIMER_SEC_INT = + "esim_download_retry_backoff_timer_sec_int"; + + /** + * If eSIM profile download fails then, the number of retry attempts by UE + * will be based on this configuration. If download still fails even after the + * MAX attempts configured by this item then the retry is postponed until next + * device bootup. + */ + public static final String KEY_ESIM_MAX_DOWNLOAD_RETRY_ATTEMPTS_INT = + "esim_max_download_retry_attempts_int"; + + /** * Controls RSRP threshold at which OpportunisticNetworkService will decide whether * the opportunistic network is good enough for internet data. */ @@ -3858,6 +3927,30 @@ public class CarrierConfigManager { public static final String KEY_ENABLE_4G_OPPORTUNISTIC_NETWORK_SCAN_BOOL = "enabled_4g_opportunistic_network_scan_bool"; + /** + * Only relevant when the device supports opportunistic networks but does not support + * simultaneuous 5G+5G. Controls how long, in milliseconds, to wait before opportunistic network + * goes out of service before switching the 5G capability back to primary stack. The idea of + * waiting a few seconds is to minimize the calling of the expensive capability switching + * operation in the case where CBRS goes back into service shortly after going out of it. + * + * @hide + */ + public static final String KEY_TIME_TO_SWITCH_BACK_TO_PRIMARY_IF_OPPORTUNISTIC_OOS_LONG = + "time_to_switch_back_to_primary_if_opportunistic_oos_long"; + + /** + * Only relevant when the device supports opportunistic networks but does not support + * simultaneuous 5G+5G. Controls how long, in milliseconds, after 5G capability has switched back + * to primary stack due to opportunistic network being OOS. The idea is to minimizing the + * 'ping-ponging' effect where device is constantly witching capability back and forth between + * primary and opportunistic stack. + * + * @hide + */ + public static final String KEY_OPPORTUNISTIC_TIME_TO_SCAN_AFTER_CAPABILITY_SWITCH_TO_PRIMARY_LONG + = "opportunistic_time_to_scan_after_capability_switch_to_primary_long"; + /** * Indicates zero or more emergency number prefix(es), because some carrier requires * if users dial an emergency number address with a specific prefix, the combination of the @@ -5166,6 +5259,16 @@ public class CarrierConfigManager { "display_no_data_notification_on_permanent_failure_bool"; /** + * Boolean indicating if the VoNR setting is visible in the Call Settings menu. + * If true, the VoNR setting menu will be visible. If false, the menu will be gone. + * + * Disabled by default. + * + * @hide + */ + public static final String KEY_VONR_SETTING_VISIBILITY_BOOL = "vonr_setting_visibility_bool"; + + /** * Determine whether unthrottle data retry when tracking area code (TAC/LAC) from cell changes * * @hide @@ -5560,6 +5663,7 @@ public class CarrierConfigManager { sDefaults.putString(KEY_SHOW_CARRIER_DATA_ICON_PATTERN_STRING, ""); sDefaults.putBoolean(KEY_HIDE_LTE_PLUS_DATA_ICON_BOOL, true); sDefaults.putInt(KEY_LTE_PLUS_THRESHOLD_BANDWIDTH_KHZ_INT, 20000); + sDefaults.putInt(KEY_NR_ADVANCED_THRESHOLD_BANDWIDTH_KHZ_INT, 0); sDefaults.putIntArray(KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY, new int[]{CARRIER_NR_AVAILABILITY_NSA, CARRIER_NR_AVAILABILITY_SA}); sDefaults.putBoolean(KEY_LTE_ENABLED_BOOL, true); @@ -5655,6 +5759,7 @@ public class CarrierConfigManager { sDefaults.putLong(KEY_5G_WATCHDOG_TIME_MS_LONG, 3600000); sDefaults.putIntArray(KEY_ADDITIONAL_NR_ADVANCED_BANDS_INT_ARRAY, new int[0]); sDefaults.putInt(KEY_NR_ADVANCED_CAPABLE_PCO_ID_INT, 0); + sDefaults.putBoolean(KEY_ENABLE_NR_ADVANCED_WHILE_ROAMING_BOOL, true); sDefaults.putBoolean(KEY_LTE_ENDC_USING_USER_DATA_FOR_RRC_DETECTION_BOOL, false); sDefaults.putBoolean(KEY_UNMETERED_NR_NSA_BOOL, false); sDefaults.putBoolean(KEY_UNMETERED_NR_NSA_MMWAVE_BOOL, false); @@ -5665,6 +5770,10 @@ public class CarrierConfigManager { sDefaults.putBoolean(KEY_UNMETERED_NR_SA_SUB6_BOOL, false); sDefaults.putBoolean(KEY_ASCII_7_BIT_SUPPORT_FOR_LONG_MESSAGE_BOOL, false); sDefaults.putBoolean(KEY_SHOW_WIFI_CALLING_ICON_IN_STATUS_BAR_BOOL, false); + sDefaults.putBoolean(KEY_CARRIER_SUPPORTS_OPP_DATA_AUTO_PROVISIONING_BOOL, false); + sDefaults.putString(KEY_SMDP_SERVER_ADDRESS_STRING, ""); + sDefaults.putInt(KEY_ESIM_MAX_DOWNLOAD_RETRY_ATTEMPTS_INT, 5); + sDefaults.putInt(KEY_ESIM_DOWNLOAD_RETRY_BACKOFF_TIMER_SEC_INT, 60); /* Default value is minimum RSRP level needed for SIGNAL_STRENGTH_GOOD */ sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_RSRP_INT, -108); /* Default value is minimum RSRP level needed for SIGNAL_STRENGTH_MODERATE */ @@ -5708,6 +5817,10 @@ public class CarrierConfigManager { /* Default value is 2 seconds. */ sDefaults.putLong(KEY_OPPORTUNISTIC_NETWORK_5G_DATA_SWITCH_EXIT_HYSTERESIS_TIME_LONG, 2000); sDefaults.putBoolean(KEY_ENABLE_4G_OPPORTUNISTIC_NETWORK_SCAN_BOOL, true); + sDefaults.putInt(KEY_TIME_TO_SWITCH_BACK_TO_PRIMARY_IF_OPPORTUNISTIC_OOS_LONG, 60000); + sDefaults.putInt( + KEY_OPPORTUNISTIC_TIME_TO_SCAN_AFTER_CAPABILITY_SWITCH_TO_PRIMARY_LONG, + 120000); sDefaults.putAll(Gps.getDefaults()); sDefaults.putIntArray(KEY_CDMA_ENHANCED_ROAMING_INDICATOR_FOR_HOME_NETWORK_INT_ARRAY, new int[] { @@ -5779,6 +5892,7 @@ public class CarrierConfigManager { sDefaults.putString(KEY_CARRIER_PROVISIONING_APP_STRING, ""); sDefaults.putBoolean(KEY_DISPLAY_NO_DATA_NOTIFICATION_ON_PERMANENT_FAILURE_BOOL, false); sDefaults.putBoolean(KEY_UNTHROTTLE_DATA_RETRY_WHEN_TAC_CHANGES_BOOL, false); + sDefaults.putBoolean(KEY_VONR_SETTING_VISIBILITY_BOOL, false); } /** @@ -5847,12 +5961,15 @@ public class CarrierConfigManager { * any carrier specific configuration has been applied. * * <p>Requires Permission: - * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} + * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}, or the calling app + * has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges()}). * * @param subId the subscription ID, normally obtained from {@link SubscriptionManager}. * @return A {@link PersistableBundle} containing the config for the given subId, or default * values for an invalid subId. */ + @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges + @RequiresPermission(Manifest.permission.READ_PHONE_STATE) @Nullable public PersistableBundle getConfigForSubId(int subId) { try { @@ -5941,10 +6058,13 @@ public class CarrierConfigManager { * called to confirm whether any carrier specific configuration has been applied. * * <p>Requires Permission: - * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} + * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}, or the calling app + * has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges()}). * * @see #getConfigForSubId */ + @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges + @RequiresPermission(Manifest.permission.READ_PHONE_STATE) @Nullable public PersistableBundle getConfig() { return getConfigForSubId(SubscriptionManager.getDefaultSubscriptionId()); @@ -5953,8 +6073,8 @@ public class CarrierConfigManager { /** * Determines whether a configuration {@link PersistableBundle} obtained from * {@link #getConfig()} or {@link #getConfigForSubId(int)} corresponds to an identified carrier. - * <p> - * When an app receives the {@link CarrierConfigManager#ACTION_CARRIER_CONFIG_CHANGED} + * + * <p>When an app receives the {@link CarrierConfigManager#ACTION_CARRIER_CONFIG_CHANGED} * broadcast which informs it that the carrier configuration has changed, it is possible * that another reload of the carrier configuration has begun since the intent was sent. * In this case, the carrier configuration the app fetches (e.g. via {@link #getConfig()}) @@ -5963,14 +6083,12 @@ public class CarrierConfigManager { * return true because it may belong to another previous identified carrier. Users should * always call {@link #getConfig()} or {@link #getConfigForSubId(int)} after receiving the * broadcast {@link #ACTION_CARRIER_CONFIG_CHANGED}. - * </p> - * <p> - * After using {@link #getConfig()} or {@link #getConfigForSubId(int)} an app should always + * + * <p>After using {@link #getConfig()} or {@link #getConfigForSubId(int)} an app should always * use this method to confirm whether any carrier specific configuration has been applied. * Especially when an app misses the broadcast {@link #ACTION_CARRIER_CONFIG_CHANGED} but it * still needs to get the current configuration, it must use this method to verify whether the * configuration is default or carrier overridden. - * </p> * * @param bundle the configuration bundle to be checked. * @return boolean true if any carrier specific configuration bundle has been applied, false @@ -5982,19 +6100,20 @@ public class CarrierConfigManager { /** * Calling this method triggers telephony services to fetch the current carrier configuration. - * <p> - * Normally this does not need to be called because the platform reloads config on its own. + * + * <p>Normally this does not need to be called because the platform reloads config on its own. * This should be called by a carrier service app if it wants to update config at an arbitrary * moment. - * </p> - * <p>Requires that the calling app has carrier privileges. - * <p> - * This method returns before the reload has completed, and - * {@link android.service.carrier.CarrierService#onLoadConfig} will be called from an - * arbitrary thread. - * </p> - * @see TelephonyManager#hasCarrierPrivileges + * + * <p>Requires Permission: + * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}, or the calling app + * has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges()}). + * + * <p>This method returns before the reload has completed, and {@link + * android.service.carrier.CarrierService#onLoadConfig} will be called from an arbitrary thread. */ + @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges + @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void notifyConfigChangedForSubId(int subId) { try { ICarrierConfigLoader loader = getICarrierConfigLoader(); @@ -6010,11 +6129,10 @@ public class CarrierConfigManager { } /** - * Request the carrier config loader to update the cofig for phoneId. - * <p> - * Depending on simState, the config may be cleared or loaded from config app. This is only used - * by SubscriptionInfoUpdater. - * </p> + * Request the carrier config loader to update the config for phoneId. + * + * <p>Depending on simState, the config may be cleared or loaded from config app. This is only + * used by SubscriptionInfoUpdater. * * @hide */ @@ -6085,13 +6203,16 @@ public class CarrierConfigManager { * Gets the configuration values for a component using its prefix. * * <p>Requires Permission: - * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} + * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}, or the calling app + * has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges()}). * * @param prefix prefix of the component. * @param subId the subscription ID, normally obtained from {@link SubscriptionManager}. * * @see #getConfigForSubId */ + @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges + @RequiresPermission(Manifest.permission.READ_PHONE_STATE) @Nullable public PersistableBundle getConfigByComponentForSubId(@NonNull String prefix, int subId) { PersistableBundle configs = getConfigForSubId(subId); diff --git a/telephony/java/android/telephony/PhysicalChannelConfig.java b/telephony/java/android/telephony/PhysicalChannelConfig.java index d250088c2f10..95448c7807cc 100644 --- a/telephony/java/android/telephony/PhysicalChannelConfig.java +++ b/telephony/java/android/telephony/PhysicalChannelConfig.java @@ -242,6 +242,11 @@ public final class PhysicalChannelConfig implements Parcelable { } /** + * The physical cell ID which differentiates cells using the same radio channel. + * + * In GERAN, this value is the BSIC. The range is [0-63]. + * Reference: 3GPP TS 3.03 section 4.2.2. + * * In UTRAN, this value is primary scrambling code. The range is [0, 511]. * Reference: 3GPP TS 25.213 section 5.2.2. * diff --git a/telephony/java/android/telephony/SignalStrengthUpdateRequest.java b/telephony/java/android/telephony/SignalStrengthUpdateRequest.java index 41e24ddb3fa6..2ff4ac5e30d3 100644 --- a/telephony/java/android/telephony/SignalStrengthUpdateRequest.java +++ b/telephony/java/android/telephony/SignalStrengthUpdateRequest.java @@ -17,6 +17,8 @@ package android.telephony; import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.RequiresPermission; import android.os.Binder; import android.os.IBinder; import android.os.Parcel; @@ -66,10 +68,15 @@ public final class SignalStrengthUpdateRequest implements Parcelable { private final IBinder mLiveToken; private SignalStrengthUpdateRequest( - @NonNull List<SignalThresholdInfo> signalThresholdInfos, + @Nullable List<SignalThresholdInfo> signalThresholdInfos, boolean isReportingRequestedWhileIdle, boolean isSystemThresholdReportingRequestedWhileIdle) { - validate(signalThresholdInfos); + // System app (like Bluetooth) can specify the request to report system thresholds while + // device is idle (with permission protection). In this case, the request doesn't need to + // provide a non-empty list of SignalThresholdInfo which is only asked for public apps. + if (!isSystemThresholdReportingRequestedWhileIdle) { + validate(signalThresholdInfos); + } mSignalThresholdInfos = signalThresholdInfos; mIsReportingRequestedWhileIdle = isReportingRequestedWhileIdle; @@ -128,13 +135,15 @@ public final class SignalStrengthUpdateRequest implements Parcelable { /** * Set the builder object if require reporting on the system thresholds when device is idle. * - * This can only used by the system caller. + * <p>This can only used by the system caller. Requires permission + * {@link android.Manifest.permission#LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH}. * * @param isSystemThresholdReportingRequestedWhileIdle true if request reporting on the * system thresholds when device is idle * @return the builder to facilitate the chaining * @hide */ + @RequiresPermission(android.Manifest.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH) public @NonNull Builder setSystemThresholdReportingRequestedWhileIdle( boolean isSystemThresholdReportingRequestedWhileIdle) { mIsSystemThresholdReportingRequestedWhileIdle = diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 255a61266ebf..6ffdc6b1696d 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -2945,7 +2945,12 @@ public class TelephonyManager { * currently in use on the device for data transmission. * * If this object has been created with {@link #createForSubscriptionId}, applies to the given - * subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()} + * subId. Otherwise, applies to {@link SubscriptionManager#getActiveDataSubscriptionId()}. + * + * Note: Before {@link SubscriptionManager#getActiveDataSubscriptionId()} was introduced in API + * level 30, it was applied to {@link SubscriptionManager#getDefaultDataSubscriptionId()} which + * may be different now from {@link SubscriptionManager#getActiveDataSubscriptionId()}, e.g. + * when opportunistic network is providing cellular internet connection to the user. * * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}). @@ -12143,6 +12148,100 @@ public class TelephonyManager { } /** + * No error. Operation succeeded. + * @hide + */ + public static final int ENABLE_VONR_SUCCESS = 0; + + /** + * Radio is not available. + * @hide + */ + public static final int ENABLE_VONR_RADIO_NOT_AVAILABLE = 2; + + /** + * Internal Radio error. + * @hide + */ + public static final int ENABLE_VONR_RADIO_ERROR = 3; + + /** + * Voice over NR enable/disable request is received when system is in invalid state. + * @hide + */ + public static final int ENABLE_VONR_RADIO_INVALID_STATE = 4; + + /** + * Voice over NR enable/disable request is not supported. + * @hide + */ + public static final int ENABLE_VONR_REQUEST_NOT_SUPPORTED = 5; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = {"EnableVoNrResult"}, value = { + ENABLE_VONR_SUCCESS, + ENABLE_VONR_RADIO_NOT_AVAILABLE, + ENABLE_VONR_RADIO_ERROR, + ENABLE_VONR_RADIO_INVALID_STATE, + ENABLE_VONR_REQUEST_NOT_SUPPORTED}) + public @interface EnableVoNrResult {} + + /** + * Enable or disable Voice over NR (VoNR) + * + * <p>If this object has been created with {@link #createForSubscriptionId}, applies to the + * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()} + * + * <p>Requires Permission: + * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}. + * + * @param enabled enable or disable VoNR. + * @throws IllegalStateException if the Telephony process is not currently available. + * @hide + */ + @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + public @EnableVoNrResult int setVoNrEnabled(boolean enabled) { + try { + ITelephony service = getITelephony(); + if (service != null) { + return service.setVoNrEnabled( + getSubId(SubscriptionManager.getDefaultDataSubscriptionId()), enabled); + } else { + throw new IllegalStateException("telephony service is null."); + } + } catch (RemoteException e) { + Log.e(TAG, "Error calling ITelephony#setVoNrEnabled", e); + } + + return ENABLE_VONR_RADIO_INVALID_STATE; + } + + /** + * Is Voice over NR (VoNR) enabled. + * @return true if Voice over NR (VoNR) is enabled else false. Enabled state does not mean + * voice call over NR is active or voice ove NR is available. It means the device is allowed to + * register IMS over NR. + * @throws IllegalStateException if the Telephony process is not currently available. + * @hide + */ + @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + public boolean isVoNrEnabled() { + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + return telephony.isVoNrEnabled(getSubId()); + } else { + throw new IllegalStateException("telephony service is null."); + } + } catch (RemoteException ex) { + Rlog.e(TAG, "isVoNrEnabled RemoteException", ex); + ex.rethrowFromSystemServer(); + } + return false; + } + + /** * Carrier action to start or stop reporting default network available events. * * <p>If this object has been created with {@link #createForSubscriptionId}, applies to the @@ -12420,26 +12519,6 @@ public class TelephonyManager { } /** - * Enable or disable signal strength changes from radio will always be reported in any - * condition (e.g. screen is off). This is only allowed for System caller. - * - * @param isEnabled {@code true} for enabling; {@code false} for disabling. - * @hide - */ - @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) - public void setAlwaysReportSignalStrength(boolean isEnabled) { - try { - ITelephony telephony = getITelephony(); - if (telephony != null) { - telephony.setAlwaysReportSignalStrength(getSubId(), isEnabled); - } - } catch (RemoteException ex) { - Log.e(TAG, "setAlwaysReportSignalStrength RemoteException", ex); - ex.rethrowAsRuntimeException(); - } - } - - /** * Get the most recently available signal strength information. * * Get the most recent SignalStrength information reported by the modem. Due @@ -13542,15 +13621,18 @@ public class TelephonyManager { } /** - * It indicates whether modem is enabled or not per slot. - * It's the corresponding status of TelephonyManager.enableModemForSlot. + * Indicates whether or not there is a modem stack enabled for the given SIM slot. * * <p>Requires Permission: - * READ_PRIVILEGED_PHONE_STATE or - * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} + * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}, + * READ_PRIVILEGED_PHONE_STATE or that the calling app has carrier privileges (see + * {@link #hasCarrierPrivileges()}). + * * @param slotIndex which slot it's checking. */ - @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) + @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges + @RequiresPermission(anyOf = {android.Manifest.permission.READ_PHONE_STATE, + android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE}) public boolean isModemEnabledForSlot(int slotIndex) { try { ITelephony telephony = getITelephony(); diff --git a/telephony/java/android/telephony/TelephonyScanManager.java b/telephony/java/android/telephony/TelephonyScanManager.java index e890acb36b48..9572154ec773 100644 --- a/telephony/java/android/telephony/TelephonyScanManager.java +++ b/telephony/java/android/telephony/TelephonyScanManager.java @@ -36,6 +36,7 @@ import com.android.telephony.Rlog; import java.util.Arrays; import java.util.List; +import java.util.Objects; import java.util.concurrent.Executor; /** @@ -152,16 +153,9 @@ public final class TelephonyScanManager { throw new RuntimeException( "Failed to find NetworkScanInfo with id " + message.arg2); } - NetworkScanCallback callback = nsi.mCallback; - Executor executor = nsi.mExecutor; - if (callback == null) { - throw new RuntimeException( - "Failed to find NetworkScanCallback with id " + message.arg2); - } - if (executor == null) { - throw new RuntimeException( - "Failed to find Executor with id " + message.arg2); - } + + final NetworkScanCallback callback = nsi.mCallback; + final Executor executor = nsi.mExecutor; switch (message.what) { case CALLBACK_RESTRICTED_SCAN_RESULTS: @@ -246,17 +240,24 @@ public final class TelephonyScanManager { NetworkScanRequest request, Executor executor, NetworkScanCallback callback, String callingPackage, @Nullable String callingFeatureId) { try { + Objects.requireNonNull(request, "Request was null"); + Objects.requireNonNull(callback, "Callback was null"); + Objects.requireNonNull(executor, "Executor was null"); final ITelephony telephony = getITelephony(); if (telephony == null) return null; - int scanId = telephony.requestNetworkScan( - subId, request, mMessenger, new Binder(), callingPackage, - callingFeatureId); - if (scanId == INVALID_SCAN_ID) { - Rlog.e(TAG, "Failed to initiate network scan"); - return null; - } + // The lock must be taken before calling requestNetworkScan because the resulting + // scanId can be invoked asynchronously on another thread at any time after + // requestNetworkScan invoked, leaving a critical section between that call and adding + // the record to the ScanInfo cache. synchronized (mScanInfo) { + int scanId = telephony.requestNetworkScan( + subId, request, mMessenger, new Binder(), callingPackage, + callingFeatureId); + if (scanId == INVALID_SCAN_ID) { + Rlog.e(TAG, "Failed to initiate network scan"); + return null; + } // We link to death whenever a scan is started to ensure that we are linked // at the point that phone process death might matter. // We never unlink because: diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java index be1502ad49f2..1ef04be8f242 100644 --- a/telephony/java/android/telephony/data/ApnSetting.java +++ b/telephony/java/android/telephony/data/ApnSetting.java @@ -147,7 +147,12 @@ public class ApnSetting implements Parcelable { } // Possible values for authentication types. - /** No authentication type. */ + /** + * Authentication type is unknown. + * @hide + */ + public static final int AUTH_TYPE_UNKNOWN = -1; + /** Authentication is not required. */ public static final int AUTH_TYPE_NONE = 0; /** Authentication type for PAP. */ public static final int AUTH_TYPE_PAP = 1; @@ -357,6 +362,7 @@ public class ApnSetting implements Parcelable { /** @hide */ @IntDef(prefix = { "AUTH_TYPE_" }, value = { + AUTH_TYPE_UNKNOWN, AUTH_TYPE_NONE, AUTH_TYPE_PAP, AUTH_TYPE_CHAP, @@ -498,7 +504,8 @@ public class ApnSetting implements Parcelable { private final String mOperatorNumeric; private final int mProtocol; private final int mRoamingProtocol; - private final int mMtu; + private final int mMtuV4; + private final int mMtuV6; private final boolean mCarrierEnabled; @@ -522,13 +529,25 @@ public class ApnSetting implements Parcelable { private final int mSkip464Xlat; /** - * Returns the MTU size of the mobile interface to which the APN connected. + * Returns the MTU size of the IPv4 mobile interface to which the APN connected. Note this value + * is used only if MTU size is not provided in {@link DataCallResponse}. * * @return the MTU size of the APN * @hide */ - public int getMtu() { - return mMtu; + public int getMtuV4() { + return mMtuV4; + } + + /** + * Returns the MTU size of the IPv6 mobile interface to which the APN connected. Note this value + * is used only if MTU size is not provided in {@link DataCallResponse}. + * + * @return the MTU size of the APN + * @hide + */ + public int getMtuV6() { + return mMtuV6; } /** @@ -879,13 +898,18 @@ public class ApnSetting implements Parcelable { this.mMmsProxyPort = builder.mMmsProxyPort; this.mUser = builder.mUser; this.mPassword = builder.mPassword; - this.mAuthType = builder.mAuthType; + this.mAuthType = (builder.mAuthType != AUTH_TYPE_UNKNOWN) + ? builder.mAuthType + : TextUtils.isEmpty(builder.mUser) + ? AUTH_TYPE_NONE + : AUTH_TYPE_PAP_OR_CHAP; this.mApnTypeBitmask = builder.mApnTypeBitmask; this.mId = builder.mId; this.mOperatorNumeric = builder.mOperatorNumeric; this.mProtocol = builder.mProtocol; this.mRoamingProtocol = builder.mRoamingProtocol; - this.mMtu = builder.mMtu; + this.mMtuV4 = builder.mMtuV4; + this.mMtuV6 = builder.mMtuV6; this.mCarrierEnabled = builder.mCarrierEnabled; this.mNetworkTypeBitmask = builder.mNetworkTypeBitmask; this.mProfileId = builder.mProfileId; @@ -903,66 +927,6 @@ public class ApnSetting implements Parcelable { /** * @hide */ - public static ApnSetting makeApnSetting(int id, String operatorNumeric, String entryName, - String apnName, String proxyAddress, int proxyPort, Uri mmsc, - String mmsProxyAddress, int mmsProxyPort, String user, String password, - int authType, int mApnTypeBitmask, int protocol, int roamingProtocol, - boolean carrierEnabled, int networkTypeBitmask, int profileId, - boolean modemCognitive, int maxConns, int waitTime, int maxConnsTime, int mtu, - int mvnoType, String mvnoMatchData, int apnSetId, int carrierId, int skip464xlat) { - return new Builder() - .setId(id) - .setOperatorNumeric(operatorNumeric) - .setEntryName(entryName) - .setApnName(apnName) - .setProxyAddress(proxyAddress) - .setProxyPort(proxyPort) - .setMmsc(mmsc) - .setMmsProxyAddress(mmsProxyAddress) - .setMmsProxyPort(mmsProxyPort) - .setUser(user) - .setPassword(password) - .setAuthType(authType) - .setApnTypeBitmask(mApnTypeBitmask) - .setProtocol(protocol) - .setRoamingProtocol(roamingProtocol) - .setCarrierEnabled(carrierEnabled) - .setNetworkTypeBitmask(networkTypeBitmask) - .setProfileId(profileId) - .setModemCognitive(modemCognitive) - .setMaxConns(maxConns) - .setWaitTime(waitTime) - .setMaxConnsTime(maxConnsTime) - .setMtu(mtu) - .setMvnoType(mvnoType) - .setMvnoMatchData(mvnoMatchData) - .setApnSetId(apnSetId) - .setCarrierId(carrierId) - .setSkip464Xlat(skip464xlat) - .buildWithoutCheck(); - } - - /** - * @hide - */ - public static ApnSetting makeApnSetting(int id, String operatorNumeric, String entryName, - String apnName, String proxyAddress, int proxyPort, Uri mmsc, - String mmsProxyAddress, int mmsProxyPort, String user, String password, - int authType, int mApnTypeBitmask, int protocol, int roamingProtocol, - boolean carrierEnabled, int networkTypeBitmask, int profileId, boolean modemCognitive, - int maxConns, int waitTime, int maxConnsTime, int mtu, int mvnoType, - String mvnoMatchData) { - return makeApnSetting(id, operatorNumeric, entryName, apnName, proxyAddress, proxyPort, - mmsc, mmsProxyAddress, mmsProxyPort, user, password, authType, mApnTypeBitmask, - protocol, roamingProtocol, carrierEnabled, networkTypeBitmask, profileId, - modemCognitive, maxConns, waitTime, maxConnsTime, mtu, mvnoType, mvnoMatchData, - Carriers.NO_APN_SET_ID, TelephonyManager.UNKNOWN_CARRIER_ID, - Carriers.SKIP_464XLAT_DEFAULT); - } - - /** - * @hide - */ public static ApnSetting makeApnSetting(Cursor cursor) { final int apnTypesBitmask = getApnTypesBitmaskFromString( cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.TYPE))); @@ -975,272 +939,99 @@ public class ApnSetting implements Parcelable { ServiceState.convertBearerBitmaskToNetworkTypeBitmask(bearerBitmask); } - return makeApnSetting( - cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID)), - cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NUMERIC)), - cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NAME)), - cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.APN)), - cursor.getString( - cursor.getColumnIndexOrThrow(Telephony.Carriers.PROXY)), - portFromString(cursor.getString( - cursor.getColumnIndexOrThrow(Telephony.Carriers.PORT))), - UriFromString(cursor.getString( - cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSC))), - cursor.getString( - cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPROXY)), - portFromString(cursor.getString( - cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPORT))), - cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.USER)), - cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PASSWORD)), - cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.AUTH_TYPE)), - apnTypesBitmask, - getProtocolIntFromString( - cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROTOCOL))), - getProtocolIntFromString( - cursor.getString(cursor.getColumnIndexOrThrow( - Telephony.Carriers.ROAMING_PROTOCOL))), - cursor.getInt(cursor.getColumnIndexOrThrow( - Telephony.Carriers.CARRIER_ENABLED)) == 1, - networkTypeBitmask, - cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROFILE_ID)), - cursor.getInt(cursor.getColumnIndexOrThrow( - Telephony.Carriers.MODEM_PERSIST)) == 1, - cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MAX_CONNECTIONS)), - cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.WAIT_TIME_RETRY)), - cursor.getInt(cursor.getColumnIndexOrThrow( - Telephony.Carriers.TIME_LIMIT_FOR_MAX_CONNECTIONS)), - cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MTU)), - getMvnoTypeIntFromString( - cursor.getString(cursor.getColumnIndexOrThrow( - Telephony.Carriers.MVNO_TYPE))), - cursor.getString(cursor.getColumnIndexOrThrow( - Telephony.Carriers.MVNO_MATCH_DATA)), - cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.APN_SET_ID)), - cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.CARRIER_ID)), - cursor.getInt(cursor.getColumnIndexOrThrow(Carriers.SKIP_464XLAT))); + return new Builder() + .setId(cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID))) + .setOperatorNumeric(cursor.getString( + cursor.getColumnIndexOrThrow(Telephony.Carriers.NUMERIC))) + .setEntryName(cursor.getString( + cursor.getColumnIndexOrThrow(Telephony.Carriers.NAME))) + .setApnName(cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.APN))) + .setProxyAddress(cursor.getString( + cursor.getColumnIndexOrThrow(Telephony.Carriers.PROXY))) + .setProxyPort(portFromString(cursor.getString( + cursor.getColumnIndexOrThrow(Telephony.Carriers.PORT)))) + .setMmsc(UriFromString(cursor.getString( + cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSC)))) + .setMmsProxyAddress(cursor.getString( + cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPROXY))) + .setMmsProxyPort(portFromString(cursor.getString( + cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPORT)))) + .setUser(cursor.getString( + cursor.getColumnIndexOrThrow(Telephony.Carriers.USER))) + .setPassword(cursor.getString( + cursor.getColumnIndexOrThrow(Telephony.Carriers.PASSWORD))) + .setAuthType(cursor.getInt( + cursor.getColumnIndexOrThrow(Telephony.Carriers.AUTH_TYPE))) + .setApnTypeBitmask(apnTypesBitmask) + .setProtocol(getProtocolIntFromString( + cursor.getString( + cursor.getColumnIndexOrThrow(Telephony.Carriers.PROTOCOL)))) + .setRoamingProtocol(getProtocolIntFromString( + cursor.getString(cursor.getColumnIndexOrThrow( + Telephony.Carriers.ROAMING_PROTOCOL)))) + .setCarrierEnabled(cursor.getInt(cursor.getColumnIndexOrThrow( + Telephony.Carriers.CARRIER_ENABLED)) == 1) + .setNetworkTypeBitmask(networkTypeBitmask) + .setProfileId(cursor.getInt( + cursor.getColumnIndexOrThrow(Telephony.Carriers.PROFILE_ID))) + .setModemCognitive(cursor.getInt(cursor.getColumnIndexOrThrow( + Telephony.Carriers.MODEM_PERSIST)) == 1) + .setMaxConns(cursor.getInt( + cursor.getColumnIndexOrThrow(Telephony.Carriers.MAX_CONNECTIONS))) + .setWaitTime(cursor.getInt( + cursor.getColumnIndexOrThrow(Telephony.Carriers.WAIT_TIME_RETRY))) + .setMaxConnsTime(cursor.getInt(cursor.getColumnIndexOrThrow( + Telephony.Carriers.TIME_LIMIT_FOR_MAX_CONNECTIONS))) + .setMtuV4(cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MTU))) + .setMtuV6(UNSET_MTU) // TODO: Add corresponding support in telephony provider + .setMvnoType(getMvnoTypeIntFromString( + cursor.getString(cursor.getColumnIndexOrThrow( + Telephony.Carriers.MVNO_TYPE)))) + .setMvnoMatchData(cursor.getString(cursor.getColumnIndexOrThrow( + Telephony.Carriers.MVNO_MATCH_DATA))) + .setApnSetId(cursor.getInt( + cursor.getColumnIndexOrThrow(Telephony.Carriers.APN_SET_ID))) + .setCarrierId(cursor.getInt( + cursor.getColumnIndexOrThrow(Telephony.Carriers.CARRIER_ID))) + .setSkip464Xlat(cursor.getInt(cursor.getColumnIndexOrThrow(Carriers.SKIP_464XLAT))) + .buildWithoutCheck(); } /** * @hide */ public static ApnSetting makeApnSetting(ApnSetting apn) { - return makeApnSetting(apn.mId, apn.mOperatorNumeric, apn.mEntryName, apn.mApnName, - apn.mProxyAddress, apn.mProxyPort, apn.mMmsc, apn.mMmsProxyAddress, - apn.mMmsProxyPort, apn.mUser, apn.mPassword, apn.mAuthType, apn.mApnTypeBitmask, - apn.mProtocol, apn.mRoamingProtocol, apn.mCarrierEnabled, apn.mNetworkTypeBitmask, - apn.mProfileId, apn.mPersistent, apn.mMaxConns, apn.mWaitTime, - apn.mMaxConnsTime, apn.mMtu, apn.mMvnoType, apn.mMvnoMatchData, apn.mApnSetId, - apn.mCarrierId, apn.mSkip464Xlat); - } - - /** - * Creates an ApnSetting object from a string. - * - * @param data the string to read. - * - * The string must be in one of two formats (newlines added for clarity, - * spaces are optional): - * - * v1 format: - * <carrier>, <apn>, <proxy>, <port>, <user>, <password>, <server>, - * <mmsc>, <mmsproxy>, <mmsport>, <mcc>, <mnc>, <authtype>, - * <type>[| <type>...], - * - * v2 format: - * [ApnSettingV2] <carrier>, <apn>, <proxy>, <port>, <user>, <password>, <server>, - * <mmsc>, <mmsproxy>, <mmsport>, <mcc>, <mnc>, <authtype>, - * <type>[| <type>...], <protocol>, <roaming_protocol>, <carrierEnabled>, <bearerBitmask>, - * - * v3 format: - * [ApnSettingV3] <carrier>, <apn>, <proxy>, <port>, <user>, <password>, <server>, - * <mmsc>, <mmsproxy>, <mmsport>, <mcc>, <mnc>, <authtype>, - * <type>[| <type>...], <protocol>, <roaming_protocol>, <carrierEnabled>, <bearerBitmask>, - * <profileId>, <modemCognitive>, <maxConns>, <waitTime>, <maxConnsTime>, <mtu>, - * <mvnoType>, <mvnoMatchData> - * - * v4 format: - * [ApnSettingV4] <carrier>, <apn>, <proxy>, <port>, <user>, <password>, <server>, - * <mmsc>, <mmsproxy>, <mmsport>, <mcc>, <mnc>, <authtype>, - * <type>[| <type>...], <protocol>, <roaming_protocol>, <carrierEnabled>, <bearerBitmask>, - * <profileId>, <modemCognitive>, <maxConns>, <waitTime>, <maxConnsTime>, <mtu>, - * <mvnoType>, <mvnoMatchData>, <networkTypeBitmask> - * - * v5 format: - * [ApnSettingV5] <carrier>, <apn>, <proxy>, <port>, <user>, <password>, <server>, - * <mmsc>, <mmsproxy>, <mmsport>, <mcc>, <mnc>, <authtype>, - * <type>[| <type>...], <protocol>, <roaming_protocol>, <carrierEnabled>, <bearerBitmask>, - * <profileId>, <modemCognitive>, <maxConns>, <waitTime>, <maxConnsTime>, <mtu>, - * <mvnoType>, <mvnoMatchData>, <networkTypeBitmask>, <apnSetId> - * - * v6 format: - * [ApnSettingV6] <carrier>, <apn>, <proxy>, <port>, <user>, <password>, <server>, - * <mmsc>, <mmsproxy>, <mmsport>, <mcc>, <mnc>, <authtype>, - * <type>[| <type>...], <protocol>, <roaming_protocol>, <carrierEnabled>, <bearerBitmask>, - * <profileId>, <modemCognitive>, <maxConns>, <waitTime>, <maxConnsTime>, <mtu>, - * <mvnoType>, <mvnoMatchData>, <networkTypeBitmask>, <apnSetId>, <carrierId> - * - * v7 format: - * [ApnSettingV7] <carrier>, <apn>, <proxy>, <port>, <user>, <password>, <server>, - * <mmsc>, <mmsproxy>, <mmsport>, <mcc>, <mnc>, <authtype>, - * <type>[| <type>...], <protocol>, <roaming_protocol>, <carrierEnabled>, <bearerBitmask>, - * <profileId>, <modemCognitive>, <maxConns>, <waitTime>, <maxConnsTime>, <mtu>, - * <mvnoType>, <mvnoMatchData>, <networkTypeBitmask>, <apnSetId>, <carrierId>, <skip464xlat> - * - * Note that the strings generated by {@link #toString()} do not contain the username - * and password and thus cannot be read by this method. - * - * This method may return {@code null} if the input string is invalid. - * - * @hide - */ - public static ApnSetting fromString(String data) { - if (data == null) return null; - - int version; - // matches() operates on the whole string, so append .* to the regex. - if (data.matches(V7_FORMAT_REGEX + ".*")) { - version = 7; - data = data.replaceFirst(V7_FORMAT_REGEX, ""); - } else if (data.matches(V6_FORMAT_REGEX + ".*")) { - version = 6; - data = data.replaceFirst(V6_FORMAT_REGEX, ""); - } else if (data.matches(V5_FORMAT_REGEX + ".*")) { - version = 5; - data = data.replaceFirst(V5_FORMAT_REGEX, ""); - } else if (data.matches(V4_FORMAT_REGEX + ".*")) { - version = 4; - data = data.replaceFirst(V4_FORMAT_REGEX, ""); - } else if (data.matches(V3_FORMAT_REGEX + ".*")) { - version = 3; - data = data.replaceFirst(V3_FORMAT_REGEX, ""); - } else if (data.matches(V2_FORMAT_REGEX + ".*")) { - version = 2; - data = data.replaceFirst(V2_FORMAT_REGEX, ""); - } else { - version = 1; - } - - String[] a = data.split("\\s*,\\s*", -1); - if (a.length < 14) { - return null; - } - - int authType; - try { - authType = Integer.parseInt(a[12]); - } catch (NumberFormatException e) { - authType = 0; - } - - String[] typeArray; - String protocol, roamingProtocol; - boolean carrierEnabled; - int bearerBitmask = 0; - int networkTypeBitmask = 0; - int profileId = 0; - boolean modemCognitive = false; - int maxConns = 0; - int waitTime = 0; - int maxConnsTime = 0; - int mtu = UNSET_MTU; - String mvnoType = ""; - String mvnoMatchData = ""; - int apnSetId = Carriers.NO_APN_SET_ID; - int carrierId = TelephonyManager.UNKNOWN_CARRIER_ID; - int skip464xlat = Carriers.SKIP_464XLAT_DEFAULT; - if (version == 1) { - typeArray = new String[a.length - 13]; - System.arraycopy(a, 13, typeArray, 0, a.length - 13); - protocol = PROTOCOL_INT_MAP.get(PROTOCOL_IP); - roamingProtocol = PROTOCOL_INT_MAP.get(PROTOCOL_IP); - carrierEnabled = true; - } else { - if (a.length < 18) { - return null; - } - typeArray = a[13].split("\\s*\\|\\s*"); - protocol = a[14]; - roamingProtocol = a[15]; - carrierEnabled = Boolean.parseBoolean(a[16]); - - bearerBitmask = ServiceState.getBitmaskFromString(a[17]); - - if (a.length > 22) { - modemCognitive = Boolean.parseBoolean(a[19]); - try { - profileId = Integer.parseInt(a[18]); - maxConns = Integer.parseInt(a[20]); - waitTime = Integer.parseInt(a[21]); - maxConnsTime = Integer.parseInt(a[22]); - } catch (NumberFormatException e) { - } - } - if (a.length > 23) { - try { - mtu = Integer.parseInt(a[23]); - } catch (NumberFormatException e) { - } - } - if (a.length > 25) { - mvnoType = a[24]; - mvnoMatchData = a[25]; - } - if (a.length > 26) { - networkTypeBitmask = ServiceState.getBitmaskFromString(a[26]); - } - if (a.length > 27) { - apnSetId = Integer.parseInt(a[27]); - } - if (a.length > 28) { - carrierId = Integer.parseInt(a[28]); - } - if (a.length > 29) { - try { - skip464xlat = Integer.parseInt(a[29]); - } catch (NumberFormatException e) { - } - } - } - - // If both bearerBitmask and networkTypeBitmask were specified, bearerBitmask would be - // ignored. - if (networkTypeBitmask == 0) { - networkTypeBitmask = - ServiceState.convertBearerBitmaskToNetworkTypeBitmask(bearerBitmask); - } - return makeApnSetting(-1, a[10] + a[11], a[0], a[1], a[2], - portFromString(a[3]), UriFromString(a[7]), a[8], - portFromString(a[9]), a[4], a[5], authType, - getApnTypesBitmaskFromString(TextUtils.join(",", typeArray)), - getProtocolIntFromString(protocol), getProtocolIntFromString(roamingProtocol), - carrierEnabled, networkTypeBitmask, profileId, modemCognitive, maxConns, waitTime, - maxConnsTime, mtu, getMvnoTypeIntFromString(mvnoType), mvnoMatchData, apnSetId, - carrierId, skip464xlat); - } - - /** - * Creates an array of ApnSetting objects from a string. - * - * @param data the string to read. - * - * Builds on top of the same format used by fromString, but allows for multiple entries - * separated by ";". - * - * @hide - */ - public static List<ApnSetting> arrayFromString(String data) { - List<ApnSetting> retVal = new ArrayList<ApnSetting>(); - if (TextUtils.isEmpty(data)) { - return retVal; - } - String[] apnStrings = data.split("\\s*;\\s*"); - for (String apnString : apnStrings) { - ApnSetting apn = fromString(apnString); - if (apn != null) { - retVal.add(apn); - } - } - return retVal; + return new Builder() + .setId(apn.mId) + .setOperatorNumeric(apn.mOperatorNumeric) + .setEntryName(apn.mEntryName) + .setApnName(apn.mApnName) + .setProxyAddress(apn.mProxyAddress) + .setProxyPort(apn.mProxyPort) + .setMmsc(apn.mMmsc) + .setMmsProxyAddress(apn.mMmsProxyAddress) + .setMmsProxyPort(apn.mMmsProxyPort) + .setUser(apn.mUser) + .setPassword(apn.mPassword) + .setAuthType(apn.mAuthType) + .setApnTypeBitmask(apn.mApnTypeBitmask) + .setProtocol(apn.mProtocol) + .setRoamingProtocol(apn.mRoamingProtocol) + .setCarrierEnabled(apn.mCarrierEnabled) + .setNetworkTypeBitmask(apn.mNetworkTypeBitmask) + .setProfileId(apn.mProfileId) + .setModemCognitive(apn.mPersistent) + .setMaxConns(apn.mMaxConns) + .setWaitTime(apn.mWaitTime) + .setMaxConnsTime(apn.mMaxConnsTime) + .setMtuV4(apn.mMtuV4) + .setMtuV6(apn.mMtuV6) + .setMvnoType(apn.mMvnoType) + .setMvnoMatchData(apn.mMvnoMatchData) + .setApnSetId(apn.mApnSetId) + .setCarrierId(apn.mCarrierId) + .setSkip464Xlat(apn.mSkip464Xlat) + .buildWithoutCheck(); } /** @@ -1251,7 +1042,7 @@ public class ApnSetting implements Parcelable { */ public String toString() { StringBuilder sb = new StringBuilder(); - sb.append("[ApnSettingV7] ") + sb.append("[ApnSetting] ") .append(mEntryName) .append(", ").append(mId) .append(", ").append(mOperatorNumeric) @@ -1272,7 +1063,8 @@ public class ApnSetting implements Parcelable { sb.append(", ").append(mMaxConns); sb.append(", ").append(mWaitTime); sb.append(", ").append(mMaxConnsTime); - sb.append(", ").append(mMtu); + sb.append(", ").append(mMtuV4); + sb.append(", ").append(mMtuV6); sb.append(", ").append(MVNO_TYPE_INT_MAP.get(mMvnoType)); sb.append(", ").append(mMvnoMatchData); sb.append(", ").append(mPermanentFailed); @@ -1343,9 +1135,9 @@ public class ApnSetting implements Parcelable { public int hashCode() { return Objects.hash(mApnName, mProxyAddress, mProxyPort, mMmsc, mMmsProxyAddress, mMmsProxyPort, mUser, mPassword, mAuthType, mApnTypeBitmask, mId, mOperatorNumeric, - mProtocol, mRoamingProtocol, mMtu, mCarrierEnabled, mNetworkTypeBitmask, mProfileId, - mPersistent, mMaxConns, mWaitTime, mMaxConnsTime, mMvnoType, mMvnoMatchData, - mApnSetId, mCarrierId, mSkip464Xlat); + mProtocol, mRoamingProtocol, mMtuV4, mMtuV6, mCarrierEnabled, mNetworkTypeBitmask, + mProfileId, mPersistent, mMaxConns, mWaitTime, mMaxConnsTime, mMvnoType, + mMvnoMatchData, mApnSetId, mCarrierId, mSkip464Xlat); } @Override @@ -1357,33 +1149,34 @@ public class ApnSetting implements Parcelable { ApnSetting other = (ApnSetting) o; return mEntryName.equals(other.mEntryName) - && Objects.equals(mId, other.mId) - && Objects.equals(mOperatorNumeric, other.mOperatorNumeric) - && Objects.equals(mApnName, other.mApnName) - && Objects.equals(mProxyAddress, other.mProxyAddress) - && Objects.equals(mMmsc, other.mMmsc) - && Objects.equals(mMmsProxyAddress, other.mMmsProxyAddress) - && Objects.equals(mMmsProxyPort, other.mMmsProxyPort) - && Objects.equals(mProxyPort, other.mProxyPort) - && Objects.equals(mUser, other.mUser) - && Objects.equals(mPassword, other.mPassword) - && Objects.equals(mAuthType, other.mAuthType) - && Objects.equals(mApnTypeBitmask, other.mApnTypeBitmask) - && Objects.equals(mProtocol, other.mProtocol) - && Objects.equals(mRoamingProtocol, other.mRoamingProtocol) - && Objects.equals(mCarrierEnabled, other.mCarrierEnabled) - && Objects.equals(mProfileId, other.mProfileId) - && Objects.equals(mPersistent, other.mPersistent) - && Objects.equals(mMaxConns, other.mMaxConns) - && Objects.equals(mWaitTime, other.mWaitTime) - && Objects.equals(mMaxConnsTime, other.mMaxConnsTime) - && Objects.equals(mMtu, other.mMtu) - && Objects.equals(mMvnoType, other.mMvnoType) - && Objects.equals(mMvnoMatchData, other.mMvnoMatchData) - && Objects.equals(mNetworkTypeBitmask, other.mNetworkTypeBitmask) - && Objects.equals(mApnSetId, other.mApnSetId) - && Objects.equals(mCarrierId, other.mCarrierId) - && Objects.equals(mSkip464Xlat, other.mSkip464Xlat); + && Objects.equals(mId, other.mId) + && Objects.equals(mOperatorNumeric, other.mOperatorNumeric) + && Objects.equals(mApnName, other.mApnName) + && Objects.equals(mProxyAddress, other.mProxyAddress) + && Objects.equals(mMmsc, other.mMmsc) + && Objects.equals(mMmsProxyAddress, other.mMmsProxyAddress) + && Objects.equals(mMmsProxyPort, other.mMmsProxyPort) + && Objects.equals(mProxyPort, other.mProxyPort) + && Objects.equals(mUser, other.mUser) + && Objects.equals(mPassword, other.mPassword) + && Objects.equals(mAuthType, other.mAuthType) + && Objects.equals(mApnTypeBitmask, other.mApnTypeBitmask) + && Objects.equals(mProtocol, other.mProtocol) + && Objects.equals(mRoamingProtocol, other.mRoamingProtocol) + && Objects.equals(mCarrierEnabled, other.mCarrierEnabled) + && Objects.equals(mProfileId, other.mProfileId) + && Objects.equals(mPersistent, other.mPersistent) + && Objects.equals(mMaxConns, other.mMaxConns) + && Objects.equals(mWaitTime, other.mWaitTime) + && Objects.equals(mMaxConnsTime, other.mMaxConnsTime) + && Objects.equals(mMtuV4, other.mMtuV4) + && Objects.equals(mMtuV6, other.mMtuV6) + && Objects.equals(mMvnoType, other.mMvnoType) + && Objects.equals(mMvnoMatchData, other.mMvnoMatchData) + && Objects.equals(mNetworkTypeBitmask, other.mNetworkTypeBitmask) + && Objects.equals(mApnSetId, other.mApnSetId) + && Objects.equals(mCarrierId, other.mCarrierId) + && Objects.equals(mSkip464Xlat, other.mSkip464Xlat); } /** @@ -1406,31 +1199,32 @@ public class ApnSetting implements Parcelable { ApnSetting other = (ApnSetting) o; return mEntryName.equals(other.mEntryName) - && Objects.equals(mOperatorNumeric, other.mOperatorNumeric) - && Objects.equals(mApnName, other.mApnName) - && Objects.equals(mProxyAddress, other.mProxyAddress) - && Objects.equals(mMmsc, other.mMmsc) - && Objects.equals(mMmsProxyAddress, other.mMmsProxyAddress) - && Objects.equals(mMmsProxyPort, other.mMmsProxyPort) - && Objects.equals(mProxyPort, other.mProxyPort) - && Objects.equals(mUser, other.mUser) - && Objects.equals(mPassword, other.mPassword) - && Objects.equals(mAuthType, other.mAuthType) - && Objects.equals(mApnTypeBitmask, other.mApnTypeBitmask) - && (isDataRoaming || Objects.equals(mProtocol, other.mProtocol)) - && (!isDataRoaming || Objects.equals(mRoamingProtocol, other.mRoamingProtocol)) - && Objects.equals(mCarrierEnabled, other.mCarrierEnabled) - && Objects.equals(mProfileId, other.mProfileId) - && Objects.equals(mPersistent, other.mPersistent) - && Objects.equals(mMaxConns, other.mMaxConns) - && Objects.equals(mWaitTime, other.mWaitTime) - && Objects.equals(mMaxConnsTime, other.mMaxConnsTime) - && Objects.equals(mMtu, other.mMtu) - && Objects.equals(mMvnoType, other.mMvnoType) - && Objects.equals(mMvnoMatchData, other.mMvnoMatchData) - && Objects.equals(mApnSetId, other.mApnSetId) - && Objects.equals(mCarrierId, other.mCarrierId) - && Objects.equals(mSkip464Xlat, other.mSkip464Xlat); + && Objects.equals(mOperatorNumeric, other.mOperatorNumeric) + && Objects.equals(mApnName, other.mApnName) + && Objects.equals(mProxyAddress, other.mProxyAddress) + && Objects.equals(mMmsc, other.mMmsc) + && Objects.equals(mMmsProxyAddress, other.mMmsProxyAddress) + && Objects.equals(mMmsProxyPort, other.mMmsProxyPort) + && Objects.equals(mProxyPort, other.mProxyPort) + && Objects.equals(mUser, other.mUser) + && Objects.equals(mPassword, other.mPassword) + && Objects.equals(mAuthType, other.mAuthType) + && Objects.equals(mApnTypeBitmask, other.mApnTypeBitmask) + && (isDataRoaming || Objects.equals(mProtocol, other.mProtocol)) + && (!isDataRoaming || Objects.equals(mRoamingProtocol, other.mRoamingProtocol)) + && Objects.equals(mCarrierEnabled, other.mCarrierEnabled) + && Objects.equals(mProfileId, other.mProfileId) + && Objects.equals(mPersistent, other.mPersistent) + && Objects.equals(mMaxConns, other.mMaxConns) + && Objects.equals(mWaitTime, other.mWaitTime) + && Objects.equals(mMaxConnsTime, other.mMaxConnsTime) + && Objects.equals(mMtuV4, other.mMtuV4) + && Objects.equals(mMtuV6, other.mMtuV6) + && Objects.equals(mMvnoType, other.mMvnoType) + && Objects.equals(mMvnoMatchData, other.mMvnoMatchData) + && Objects.equals(mApnSetId, other.mApnSetId) + && Objects.equals(mCarrierId, other.mCarrierId) + && Objects.equals(mSkip464Xlat, other.mSkip464Xlat); } /** @@ -1732,7 +1526,7 @@ public class ApnSetting implements Parcelable { dest.writeString(mApnName); dest.writeString(mProxyAddress); dest.writeInt(mProxyPort); - dest.writeValue(mMmsc); + dest.writeParcelable(mMmsc, flags); dest.writeString(mMmsProxyAddress); dest.writeInt(mMmsProxyPort); dest.writeString(mUser); @@ -1742,40 +1536,53 @@ public class ApnSetting implements Parcelable { dest.writeInt(mProtocol); dest.writeInt(mRoamingProtocol); dest.writeBoolean(mCarrierEnabled); - dest.writeInt(mMvnoType); dest.writeInt(mNetworkTypeBitmask); + dest.writeInt(mProfileId); + dest.writeBoolean(mPersistent); + dest.writeInt(mMaxConns); + dest.writeInt(mWaitTime); + dest.writeInt(mMaxConnsTime); + dest.writeInt(mMtuV4); + dest.writeInt(mMtuV6); + dest.writeInt(mMvnoType); + dest.writeString(mMvnoMatchData); dest.writeInt(mApnSetId); dest.writeInt(mCarrierId); dest.writeInt(mSkip464Xlat); } private static ApnSetting readFromParcel(Parcel in) { - final int id = in.readInt(); - final String operatorNumeric = in.readString(); - final String entryName = in.readString(); - final String apnName = in.readString(); - final String proxy = in.readString(); - final int port = in.readInt(); - final Uri mmsc = (Uri) in.readValue(Uri.class.getClassLoader()); - final String mmsProxy = in.readString(); - final int mmsPort = in.readInt(); - final String user = in.readString(); - final String password = in.readString(); - final int authType = in.readInt(); - final int apnTypesBitmask = in.readInt(); - final int protocol = in.readInt(); - final int roamingProtocol = in.readInt(); - final boolean carrierEnabled = in.readBoolean(); - final int mvnoType = in.readInt(); - final int networkTypeBitmask = in.readInt(); - final int apnSetId = in.readInt(); - final int carrierId = in.readInt(); - final int skip464xlat = in.readInt(); - - return makeApnSetting(id, operatorNumeric, entryName, apnName, - proxy, port, mmsc, mmsProxy, mmsPort, user, password, authType, apnTypesBitmask, - protocol, roamingProtocol, carrierEnabled, networkTypeBitmask, 0, false, - 0, 0, 0, 0, mvnoType, null, apnSetId, carrierId, skip464xlat); + return new Builder() + .setId(in.readInt()) + .setOperatorNumeric(in.readString()) + .setEntryName(in.readString()) + .setApnName(in.readString()) + .setProxyAddress(in.readString()) + .setProxyPort(in.readInt()) + .setMmsc(in.readParcelable(Uri.class.getClassLoader())) + .setMmsProxyAddress(in.readString()) + .setMmsProxyPort(in.readInt()) + .setUser(in.readString()) + .setPassword(in.readString()) + .setAuthType(in.readInt()) + .setApnTypeBitmask(in.readInt()) + .setProtocol(in.readInt()) + .setRoamingProtocol(in.readInt()) + .setCarrierEnabled(in.readBoolean()) + .setNetworkTypeBitmask(in.readInt()) + .setProfileId(in.readInt()) + .setModemCognitive(in.readBoolean()) + .setMaxConns(in.readInt()) + .setWaitTime(in.readInt()) + .setMaxConnsTime(in.readInt()) + .setMtuV4(in.readInt()) + .setMtuV6(in.readInt()) + .setMvnoType(in.readInt()) + .setMvnoMatchData(in.readString()) + .setApnSetId(in.readInt()) + .setCarrierId(in.readInt()) + .setSkip464Xlat(in.readInt()) + .buildWithoutCheck(); } public static final @android.annotation.NonNull Parcelable.Creator<ApnSetting> CREATOR = @@ -1834,13 +1641,14 @@ public class ApnSetting implements Parcelable { private int mMmsProxyPort = UNSPECIFIED_INT; private String mUser; private String mPassword; - private int mAuthType; + private int mAuthType = AUTH_TYPE_UNKNOWN; private int mApnTypeBitmask; private int mId; private String mOperatorNumeric; private int mProtocol = UNSPECIFIED_INT; private int mRoamingProtocol = UNSPECIFIED_INT; - private int mMtu; + private int mMtuV4; + private int mMtuV6; private int mNetworkTypeBitmask; private boolean mCarrierEnabled; private int mProfileId; @@ -1863,20 +1671,34 @@ public class ApnSetting implements Parcelable { * Sets the unique database id for this entry. * * @param id the unique database id to set for this entry + * @hide */ - private Builder setId(int id) { + public Builder setId(int id) { this.mId = id; return this; } /** - * Set the MTU size of the mobile interface to which the APN connected. + * Set the MTU size of the IPv4 mobile interface to which the APN connected. Note this value + * is used only if MTU size is not provided in {@link DataCallResponse}. + * + * @param mtuV4 the MTU size to set for the APN + * @hide + */ + public Builder setMtuV4(int mtuV4) { + this.mMtuV4 = mtuV4; + return this; + } + + /** + * Set the MTU size of the IPv6 mobile interface to which the APN connected. Note this value + * is used only if MTU size is not provided in {@link DataCallResponse}. * - * @param mtu the MTU size to set for the APN + * @param mtuV6 the MTU size to set for the APN * @hide */ - public Builder setMtu(int mtu) { - this.mMtu = mtu; + public Builder setMtuV6(int mtuV6) { + this.mMtuV6 = mtuV6; return this; } @@ -2237,7 +2059,8 @@ public class ApnSetting implements Parcelable { | TYPE_FOTA | TYPE_IMS | TYPE_CBS | TYPE_IA | TYPE_EMERGENCY | TYPE_MCX | TYPE_XCAP | TYPE_VSIM | TYPE_BIP | TYPE_ENTERPRISE)) == 0 || TextUtils.isEmpty(mApnName) || TextUtils.isEmpty(mEntryName)) { - return null; + throw new IllegalArgumentException("mApName=" + mApnName + ", mEntryName=" + + mEntryName + ", mApnTypeBitmask=" + mApnTypeBitmask); } return new ApnSetting(this); } diff --git a/telephony/java/android/telephony/data/DataProfile.java b/telephony/java/android/telephony/data/DataProfile.java index f2a124901bc4..93903d2658cd 100644 --- a/telephony/java/android/telephony/data/DataProfile.java +++ b/telephony/java/android/telephony/data/DataProfile.java @@ -25,13 +25,11 @@ import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; import android.telephony.Annotation.ApnType; +import android.telephony.TelephonyManager; import android.telephony.TelephonyManager.NetworkTypeBitMask; import android.telephony.data.ApnSetting.AuthType; import android.text.TextUtils; -import com.android.internal.telephony.RILConstants; -import com.android.internal.telephony.util.TelephonyUtils; - import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Objects; @@ -62,152 +60,141 @@ public final class DataProfile implements Parcelable { /** 3GPP2 type data profile */ public static final int TYPE_3GPP2 = 2; - private final int mProfileId; - - private final String mApn; - - @ProtocolType - private final int mProtocolType; - - @AuthType - private final int mAuthType; - - private final String mUserName; - - private final String mPassword; - - @Type - private final int mType; - - private final int mMaxConnectionsTime; - - private final int mMaxConnections; - - private final int mWaitTime; - - private final boolean mEnabled; - - @ApnType - private final int mSupportedApnTypesBitmask; - - @ProtocolType - private final int mRoamingProtocolType; - - @NetworkTypeBitMask - private final int mBearerBitmask; + private final @Type int mType; - private final int mMtuV4; + private final @Nullable ApnSetting mApnSetting; - private final int mMtuV6; - - private final boolean mPersistent; + private final @Nullable TrafficDescriptor mTrafficDescriptor; private final boolean mPreferred; - /** @hide */ - private DataProfile(int profileId, String apn, @ProtocolType int protocolType, int authType, - String userName, String password, int type, int maxConnectionsTime, - int maxConnections, int waitTime, boolean enabled, - @ApnType int supportedApnTypesBitmask, @ProtocolType int roamingProtocolType, - @NetworkTypeBitMask int bearerBitmask, int mtuV4, int mtuV6, boolean persistent, - boolean preferred) { - this.mProfileId = profileId; - this.mApn = apn; - this.mProtocolType = protocolType; - if (authType == -1) { - authType = TextUtils.isEmpty(userName) ? RILConstants.SETUP_DATA_AUTH_NONE - : RILConstants.SETUP_DATA_AUTH_PAP_CHAP; - } - this.mAuthType = authType; - this.mUserName = userName; - this.mPassword = password; - this.mType = type; - this.mMaxConnectionsTime = maxConnectionsTime; - this.mMaxConnections = maxConnections; - this.mWaitTime = waitTime; - this.mEnabled = enabled; - this.mSupportedApnTypesBitmask = supportedApnTypesBitmask; - this.mRoamingProtocolType = roamingProtocolType; - this.mBearerBitmask = bearerBitmask; - this.mMtuV4 = mtuV4; - this.mMtuV6 = mtuV6; - this.mPersistent = persistent; - this.mPreferred = preferred; + private DataProfile(@NonNull Builder builder) { + mApnSetting = builder.mApnSetting; + mTrafficDescriptor = builder.mTrafficDescriptor; + mPreferred = builder.mPreferred; + + if (builder.mType != -1) { + mType = builder.mType; + } else if (mApnSetting != null) { + int networkTypes = mApnSetting.getNetworkTypeBitmask(); + + if (networkTypes == 0) { + mType = DataProfile.TYPE_COMMON; + } else if ((networkTypes & TelephonyManager.NETWORK_STANDARDS_FAMILY_BITMASK_3GPP2) + == networkTypes) { + mType = DataProfile.TYPE_3GPP2; + } else if ((networkTypes & TelephonyManager.NETWORK_STANDARDS_FAMILY_BITMASK_3GPP) + == networkTypes) { + mType = DataProfile.TYPE_3GPP; + } else { + mType = DataProfile.TYPE_COMMON; + } + } else { + mType = DataProfile.TYPE_COMMON; + } } private DataProfile(Parcel source) { - mProfileId = source.readInt(); - mApn = source.readString(); - mProtocolType = source.readInt(); - mAuthType = source.readInt(); - mUserName = source.readString(); - mPassword = source.readString(); mType = source.readInt(); - mMaxConnectionsTime = source.readInt(); - mMaxConnections = source.readInt(); - mWaitTime = source.readInt(); - mEnabled = source.readBoolean(); - mSupportedApnTypesBitmask = source.readInt(); - mRoamingProtocolType = source.readInt(); - mBearerBitmask = source.readInt(); - mMtuV4 = source.readInt(); - mMtuV6 = source.readInt(); - mPersistent = source.readBoolean(); + mApnSetting = source.readParcelable(ApnSetting.class.getClassLoader()); + mTrafficDescriptor = source.readParcelable(TrafficDescriptor.class.getClassLoader()); mPreferred = source.readBoolean(); } /** * @return Id of the data profile. */ - public int getProfileId() { return mProfileId; } + public int getProfileId() { + if (mApnSetting != null) { + return mApnSetting.getProfileId(); + } + return 0; + } /** * @return The APN (Access Point Name) to establish data connection. This is a string * specifically defined by the carrier. */ @NonNull - public String getApn() { return mApn; } + public String getApn() { + if (mApnSetting != null) { + return TextUtils.emptyIfNull(mApnSetting.getApnName()); + } + return ""; + } /** * @return The connection protocol defined in 3GPP TS 27.007 section 10.1.1. */ - public @ProtocolType int getProtocolType() { return mProtocolType; } + public @ProtocolType int getProtocolType() { + if (mApnSetting != null) { + return mApnSetting.getProtocol(); + } + return ApnSetting.PROTOCOL_IP; + } /** * @return The authentication protocol used for this PDP context. */ - public @AuthType int getAuthType() { return mAuthType; } + public @AuthType int getAuthType() { + if (mApnSetting != null) { + return mApnSetting.getAuthType(); + } + return ApnSetting.AUTH_TYPE_NONE; + } /** * @return The username for APN. Can be null. */ @Nullable - public String getUserName() { return mUserName; } + public String getUserName() { + if (mApnSetting != null) { + return mApnSetting.getUser(); + } + return null; + } /** * @return The password for APN. Can be null. */ @Nullable - public String getPassword() { return mPassword; } + public String getPassword() { + if (mApnSetting != null) { + return mApnSetting.getPassword(); + } + return null; + } /** * @return The profile type. */ - public @Type int getType() { return mType; } + public @Type int getType() { + return mType; + } /** * @return The period in seconds to limit the maximum connections. * * @hide */ - public int getMaxConnectionsTime() { return mMaxConnectionsTime; } + public int getMaxConnectionsTime() { + if (mApnSetting != null) { + return mApnSetting.getMaxConnsTime(); + } + return 0; + } /** * @return The maximum connections allowed. * * @hide */ - public int getMaxConnections() { return mMaxConnections; } + public int getMaxConnections() { + if (mApnSetting != null) { + return mApnSetting.getMaxConns(); + } + return 0; + } /** * @return The required wait time in seconds after a successful UE initiated disconnect of a @@ -216,57 +203,117 @@ public final class DataProfile implements Parcelable { * * @hide */ - public int getWaitTime() { return mWaitTime; } + public int getWaitTime() { + if (mApnSetting != null) { + return mApnSetting.getWaitTime(); + } + return 0; + } /** * @return True if the profile is enabled. */ - public boolean isEnabled() { return mEnabled; } + public boolean isEnabled() { + if (mApnSetting != null) { + return mApnSetting.isEnabled(); + } + return false; + } /** * @return The supported APN types bitmask. */ - public @ApnType int getSupportedApnTypesBitmask() { return mSupportedApnTypesBitmask; } + public @ApnType int getSupportedApnTypesBitmask() { + if (mApnSetting != null) { + return mApnSetting.getApnTypeBitmask(); + } + return ApnSetting.TYPE_NONE; + } /** * @return The connection protocol on roaming network defined in 3GPP TS 27.007 section 10.1.1. */ - public @ProtocolType int getRoamingProtocolType() { return mRoamingProtocolType; } + public @ProtocolType int getRoamingProtocolType() { + if (mApnSetting != null) { + return mApnSetting.getRoamingProtocol(); + } + return ApnSetting.PROTOCOL_IP; + } /** * @return The bearer bitmask indicating the applicable networks for this data profile. */ - public @NetworkTypeBitMask int getBearerBitmask() { return mBearerBitmask; } + public @NetworkTypeBitMask int getBearerBitmask() { + if (mApnSetting != null) { + return mApnSetting.getNetworkTypeBitmask(); + } + return (int) TelephonyManager.NETWORK_TYPE_BITMASK_UNKNOWN; + } /** * @return The maximum transmission unit (MTU) size in bytes. * @deprecated use {@link #getMtuV4} or {@link #getMtuV6} instead. */ @Deprecated - public int getMtu() { return mMtuV4; } + public int getMtu() { + return getMtuV4(); + } /** * This replaces the deprecated method getMtu. * @return The maximum transmission unit (MTU) size in bytes, for IPv4. */ - public int getMtuV4() { return mMtuV4; } + public int getMtuV4() { + if (mApnSetting != null) { + return mApnSetting.getMtuV4(); + } + return 0; + } /** * @return The maximum transmission unit (MTU) size in bytes, for IPv6. */ - public int getMtuV6() { return mMtuV6; } + public int getMtuV6() { + if (mApnSetting != null) { + return mApnSetting.getMtuV6(); + } + return 0; + } /** * @return {@code true} if modem must persist this data profile. */ - public boolean isPersistent() { return mPersistent; } + public boolean isPersistent() { + if (mApnSetting != null) { + return mApnSetting.isPersistent(); + } + return false; + } /** * @return {@code true} if this data profile was used to bring up the last default * (i.e internet) data connection successfully, or the one chosen by the user in Settings' * APN editor. For one carrier there can be only one profiled preferred. */ - public boolean isPreferred() { return mPreferred; } + public boolean isPreferred() { + return mPreferred; + } + + /** + * @return The APN setting + * @hide TODO: Remove before T is released. + */ + public @Nullable ApnSetting getApnSetting() { + return mApnSetting; + } + + /** + * @return The traffic descriptor + * @hide TODO: Remove before T is released. + */ + public @Nullable TrafficDescriptor getTrafficDescriptor() { + return mTrafficDescriptor; + } @Override public int describeContents() { @@ -276,34 +323,15 @@ public final class DataProfile implements Parcelable { @NonNull @Override public String toString() { - return "DataProfile=" + mProfileId + "/" + mProtocolType + "/" + mAuthType - + "/" + (TelephonyUtils.IS_USER ? "***/***/***" : - (mApn + "/" + mUserName + "/" + mPassword)) + "/" + mType + "/" - + mMaxConnectionsTime + "/" + mMaxConnections + "/" - + mWaitTime + "/" + mEnabled + "/" + mSupportedApnTypesBitmask + "/" - + mRoamingProtocolType + "/" + mBearerBitmask + "/" + mMtuV4 + "/" + mMtuV6 + "/" - + mPersistent + "/" + mPreferred; + return "DataProfile=" + mApnSetting + ", " + mTrafficDescriptor + ", preferred=" + + mPreferred; } @Override public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(mProfileId); - dest.writeString(mApn); - dest.writeInt(mProtocolType); - dest.writeInt(mAuthType); - dest.writeString(mUserName); - dest.writeString(mPassword); dest.writeInt(mType); - dest.writeInt(mMaxConnectionsTime); - dest.writeInt(mMaxConnections); - dest.writeInt(mWaitTime); - dest.writeBoolean(mEnabled); - dest.writeInt(mSupportedApnTypesBitmask); - dest.writeInt(mRoamingProtocolType); - dest.writeInt(mBearerBitmask); - dest.writeInt(mMtuV4); - dest.writeInt(mMtuV6); - dest.writeBoolean(mPersistent); + dest.writeParcelable(mApnSetting, flags); + dest.writeParcelable(mTrafficDescriptor, flags); dest.writeBoolean(mPreferred); } @@ -321,36 +349,18 @@ public final class DataProfile implements Parcelable { }; @Override - public boolean equals(@Nullable Object o) { + public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; DataProfile that = (DataProfile) o; - return mProfileId == that.mProfileId - && mProtocolType == that.mProtocolType - && mAuthType == that.mAuthType - && mType == that.mType - && mMaxConnectionsTime == that.mMaxConnectionsTime - && mMaxConnections == that.mMaxConnections - && mWaitTime == that.mWaitTime - && mEnabled == that.mEnabled - && mSupportedApnTypesBitmask == that.mSupportedApnTypesBitmask - && mRoamingProtocolType == that.mRoamingProtocolType - && mBearerBitmask == that.mBearerBitmask - && mMtuV4 == that.mMtuV4 - && mMtuV6 == that.mMtuV6 - && mPersistent == that.mPersistent - && mPreferred == that.mPreferred - && Objects.equals(mApn, that.mApn) - && Objects.equals(mUserName, that.mUserName) - && Objects.equals(mPassword, that.mPassword); + return mType == that.mType + && Objects.equals(mApnSetting, that.mApnSetting) + && Objects.equals(mTrafficDescriptor, that.mTrafficDescriptor); } @Override public int hashCode() { - return Objects.hash(mProfileId, mApn, mProtocolType, mAuthType, mUserName, mPassword, mType, - mMaxConnectionsTime, mMaxConnections, mWaitTime, mEnabled, - mSupportedApnTypesBitmask, mRoamingProtocolType, mBearerBitmask, mMtuV4, mMtuV6, - mPersistent, mPreferred); + return Objects.hash(mType, mApnSetting, mTrafficDescriptor); } /** @@ -383,13 +393,7 @@ public final class DataProfile implements Parcelable { private String mPassword; @Type - private int mType; - - private int mMaxConnectionsTime; - - private int mMaxConnections; - - private int mWaitTime; + private int mType = -1; private boolean mEnabled; @@ -410,6 +414,10 @@ public final class DataProfile implements Parcelable { private boolean mPreferred; + private ApnSetting mApnSetting; + + private TrafficDescriptor mTrafficDescriptor; + /** * Default constructor for Builder. */ @@ -496,48 +504,6 @@ public final class DataProfile implements Parcelable { } /** - * Set the period in seconds to limit the maximum connections. - * - * @param maxConnectionsTime The profile type - * @return The same instance of the builder. - * - * @hide - */ - public @NonNull Builder setMaxConnectionsTime(int maxConnectionsTime) { - mMaxConnectionsTime = maxConnectionsTime; - return this; - } - - /** - * Set the maximum connections allowed. - * - * @param maxConnections The maximum connections allowed. - * @return The same instance of the builder. - * - * @hide - */ - public @NonNull Builder setMaxConnections(int maxConnections) { - mMaxConnections = maxConnections; - return this; - } - - /** - * Set the period in seconds to limit the maximum connections. - * - * @param waitTime The required wait time in seconds after a successful UE initiated - * disconnect of a given PDN connection before the device can send a new PDN connection - * request for that given PDN. - * - * @return The same instance of the builder. - * - * @hide - */ - public @NonNull Builder setWaitTime(int waitTime) { - mWaitTime = waitTime; - return this; - } - - /** * Enable the data profile * * @param isEnabled {@code true} to enable the data profile, otherwise disable. @@ -587,8 +553,9 @@ public final class DataProfile implements Parcelable { * * @param mtu The maximum transmission unit (MTU) size in bytes. * @return The same instance of the builder. - * @deprecated use {@link #setMtuV4} or {@link #setMtuV6} instead. + * @deprecated use {@link #setApnSetting(ApnSetting)} instead. */ + @Deprecated public @NonNull Builder setMtu(int mtu) { mMtuV4 = mMtuV6 = mtu; return this; @@ -631,7 +598,7 @@ public final class DataProfile implements Parcelable { } /** - * Set data profile as persistent/non-persistent + * Set data profile as persistent/non-persistent. * * @param isPersistent {@code true} if this data profile was used to bring up the last * default (i.e internet) data connection successfully. @@ -643,15 +610,63 @@ public final class DataProfile implements Parcelable { } /** + * Set APN setting. + * + * @param apnSetting APN setting + * @return The same instance of the builder + * + * @hide // TODO: Remove before T is released. + */ + public @NonNull Builder setApnSetting(@NonNull ApnSetting apnSetting) { + mApnSetting = apnSetting; + return this; + } + + /** + * Set traffic descriptor. + * + * @param trafficDescriptor Traffic descriptor + * @return The same instance of the builder + * + * @hide // TODO: Remove before T is released. + */ + public @NonNull Builder setTrafficDescriptor(@NonNull TrafficDescriptor trafficDescriptor) { + mTrafficDescriptor = trafficDescriptor; + return this; + } + + /** * Build the DataProfile object * * @return The data profile object */ public @NonNull DataProfile build() { - return new DataProfile(mProfileId, mApn, mProtocolType, mAuthType, mUserName, mPassword, - mType, mMaxConnectionsTime, mMaxConnections, mWaitTime, mEnabled, - mSupportedApnTypesBitmask, mRoamingProtocolType, mBearerBitmask, mMtuV4, mMtuV6, - mPersistent, mPreferred); + if (mApnSetting == null && mApn != null) { + // This is for backwards compatibility. + mApnSetting = new ApnSetting.Builder() + .setEntryName(mApn) + .setApnName(mApn) + .setApnTypeBitmask(mSupportedApnTypesBitmask) + .setAuthType(mAuthType) + .setCarrierEnabled(mEnabled) + .setModemCognitive(mPersistent) + .setMtuV4(mMtuV4) + .setMtuV6(mMtuV6) + .setNetworkTypeBitmask(mBearerBitmask) + .setProfileId(mProfileId) + .setPassword(mPassword) + .setProtocol(mProtocolType) + .setRoamingProtocol(mRoamingProtocolType) + .setUser(mUserName) + .build(); + } + + if (mApnSetting == null && mTrafficDescriptor == null) { + throw new IllegalArgumentException("APN setting and traffic descriptor can't be " + + "both null."); + } + + return new DataProfile(this); } } } diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index 63732b5ee444..d586a4a38f73 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -1002,11 +1002,6 @@ interface ITelephony { boolean isManualNetworkSelectionAllowed(int subId); /** - * Enable or disable always reporting signal strength changes from radio. - */ - void setAlwaysReportSignalStrength(int subId, boolean isEnable); - - /** * Get P-CSCF address from PCO after data connection is established or modified. * @param apnType the apnType, "ims" for IMS APN, "emergency" for EMERGENCY APN * @param callingPackage The package making the call. @@ -2229,6 +2224,20 @@ interface ITelephony { List<String> getEquivalentHomePlmns(int subId, String callingPackage, String callingFeatureId); /** + * Enable or disable Voice over NR (VoNR) + * @param subId the subscription ID that this action applies to. + * @param enabled enable or disable VoNR. + * @return operation result. + */ + int setVoNrEnabled(int subId, boolean enabled); + + /** + * Is voice over NR enabled + * @return true if VoNR is enabled else false + */ + boolean isVoNrEnabled(int subId); + + /** * Enable/Disable E-UTRA-NR Dual Connectivity * @return operation result. See TelephonyManager.EnableNrDualConnectivityResult for * details diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java index b73f8271da1f..866fd2c7394e 100644 --- a/telephony/java/com/android/internal/telephony/RILConstants.java +++ b/telephony/java/com/android/internal/telephony/RILConstants.java @@ -528,6 +528,8 @@ public interface RILConstants { int RIL_REQUEST_SET_ALLOWED_NETWORK_TYPES_BITMAP = 222; int RIL_REQUEST_GET_ALLOWED_NETWORK_TYPES_BITMAP = 223; int RIL_REQUEST_GET_SLICING_CONFIG = 224; + int RIL_REQUEST_ENABLE_VONR = 225; + int RIL_REQUEST_IS_VONR_ENABLED = 226; /* Responses begin */ int RIL_RESPONSE_ACKNOWLEDGEMENT = 800; diff --git a/tests/DynamicCodeLoggerIntegrationTests/OWNERS b/tests/DynamicCodeLoggerIntegrationTests/OWNERS new file mode 100644 index 000000000000..d9eb1413cb1e --- /dev/null +++ b/tests/DynamicCodeLoggerIntegrationTests/OWNERS @@ -0,0 +1 @@ +file:/services/core/java/com/android/server/pm/dex/OWNERS diff --git a/tests/FlickerTests/OWNERS b/tests/FlickerTests/OWNERS index b5561010e7f9..c1221e3940d2 100644 --- a/tests/FlickerTests/OWNERS +++ b/tests/FlickerTests/OWNERS @@ -1,3 +1,4 @@ # Bug component: 909476 include /services/core/java/com/android/server/wm/OWNERS -natanieljr@google.com
\ No newline at end of file +natanieljr@google.com +pablogamito@google.com diff --git a/tests/SharedLibraryLoadingTest/Android.bp b/tests/SharedLibraryLoadingTest/Android.bp new file mode 100644 index 000000000000..088278d6ee89 --- /dev/null +++ b/tests/SharedLibraryLoadingTest/Android.bp @@ -0,0 +1,37 @@ +// Copyright (C) 2021 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + +java_test_host { + name: "SharedLibraryLoadingTests", + libs: [ + "tradefed", + "junit", + ], + test_suites: ["general-tests"], + data: [ + ":SharedLibraryLoadingTests_StandardSharedLibrary", + ":SharedLibraryLoadingTests_SharedLibraryLoadedAfter", + ":SharedLibraryLoadingTests_SharedLibraryClientTests", + ":SharedLibraryLoadingTests_Overlay", + ], +} diff --git a/tests/SharedLibraryLoadingTest/AndroidTest.xml b/tests/SharedLibraryLoadingTest/AndroidTest.xml new file mode 100644 index 000000000000..947453d07bd9 --- /dev/null +++ b/tests/SharedLibraryLoadingTest/AndroidTest.xml @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2021 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<configuration description="Host-driven test module config for SharedLibraryHostTests"> + <option name="test-tag" value="SharedLibraryLoadingTests" /> + <option name="test-suite-tag" value="apct" /> + <option name="test-suite-tag" value="apct-instrumentation" /> + + <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" /> + <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher"> + <option name="cleanup" value="false" /> + <option name="remount-system" value="true" /> + <option name="push" + value="SharedLibraryLoadingTests_StandardSharedLibrary.apk->/product/app/SharedLibraryLoadingTests_StandardSharedLibrary.apk" /> + <option name="push" + value="SharedLibraryLoadingTests_SharedLibraryLoadedAfter.apk->/product/app/SharedLibraryLoadingTests_SharedLibraryLoadedAfter.apk" /> + <option name="push" + value="SharedLibraryLoadingTests_Overlay.apk->/product/overlay/SharedLibraryLoadingTests_Overlay.apk" /> + </target_preparer> + + <target_preparer class="com.android.tradefed.targetprep.RebootTargetPreparer" /> + + <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup"> + <option name="cleanup-apks" value="true" /> + <option name="test-file-name" value="SharedLibraryLoadingTests_SharedLibraryClientTests.apk" /> + </target_preparer> + + <test class="com.android.tradefed.testtype.AndroidJUnitTest"> + <option name="package" value="com.android.sharedlibloadingtest.client" /> + </test> +</configuration>
\ No newline at end of file diff --git a/tests/SharedLibraryLoadingTest/OWNERS b/tests/SharedLibraryLoadingTest/OWNERS new file mode 100644 index 000000000000..d7b4569b6bc0 --- /dev/null +++ b/tests/SharedLibraryLoadingTest/OWNERS @@ -0,0 +1,2 @@ +stenning@google.com + diff --git a/tests/SharedLibraryLoadingTest/test-apps/Overlay/Android.bp b/tests/SharedLibraryLoadingTest/test-apps/Overlay/Android.bp new file mode 100644 index 000000000000..b2f4e8925b58 --- /dev/null +++ b/tests/SharedLibraryLoadingTest/test-apps/Overlay/Android.bp @@ -0,0 +1,29 @@ +// Copyright (C) 2021 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + +android_test_helper_app { + name: "SharedLibraryLoadingTests_Overlay", + platform_apis: true, + certificate: "platform", + aaptflags: ["--no-resource-removal"], +} diff --git a/tests/SharedLibraryLoadingTest/test-apps/Overlay/AndroidManifest.xml b/tests/SharedLibraryLoadingTest/test-apps/Overlay/AndroidManifest.xml new file mode 100644 index 000000000000..ae2784ca0904 --- /dev/null +++ b/tests/SharedLibraryLoadingTest/test-apps/Overlay/AndroidManifest.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2021 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.sharedlibloadingtest.overlay"> + <application android:hasCode="false" /> + <overlay android:targetPackage="android" + android:isStatic="true" + android:priority="1"/> +</manifest>
\ No newline at end of file diff --git a/tests/SharedLibraryLoadingTest/test-apps/Overlay/res/values/config.xml b/tests/SharedLibraryLoadingTest/test-apps/Overlay/res/values/config.xml new file mode 100644 index 000000000000..15da3dbafd84 --- /dev/null +++ b/tests/SharedLibraryLoadingTest/test-apps/Overlay/res/values/config.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* + * Copyright (C) 2020 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources> + <string-array name="config_sharedLibrariesLoadedAfterApp" translatable="false"> + <item>com.android.sharedlibloadingtest.shared_library_after</item> + </string-array> +</resources>
\ No newline at end of file diff --git a/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryClientTests/Android.bp b/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryClientTests/Android.bp new file mode 100644 index 000000000000..0d204979cb92 --- /dev/null +++ b/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryClientTests/Android.bp @@ -0,0 +1,35 @@ +// Copyright (C) 2021 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +android_test_helper_app { + name: "SharedLibraryLoadingTests_SharedLibraryClientTests", + srcs: ["**/*.java"], + resource_dirs: ["res"], + libs: [ + "SharedLibraryLoadingTests_StandardSharedLibrary", + "SharedLibraryLoadingTests_SharedLibraryLoadedAfter", + "android.test.base", + ], + static_libs: [ + "androidx.test.ext.junit", + "androidx.test.rules", + "androidx.test.core", + "testng", + ], + platform_apis: true, +} diff --git a/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryClientTests/AndroidManifest.xml b/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryClientTests/AndroidManifest.xml new file mode 100644 index 000000000000..e3a9b9bca78a --- /dev/null +++ b/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryClientTests/AndroidManifest.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2021 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.sharedlibloadingtest.client"> + <application> + <uses-library android:name="android.test.runner" /> + <uses-library android:name="com.android.sharedlibloadingtest.shared_library"/> + <uses-library android:name="com.android.sharedlibloadingtest.shared_library_after"/> + </application> + + <instrumentation + android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="com.android.sharedlibloadingtest.client" /> +</manifest>
\ No newline at end of file diff --git a/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryClientTests/res/values/values.xml b/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryClientTests/res/values/values.xml new file mode 100644 index 000000000000..5e0544eb8696 --- /dev/null +++ b/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryClientTests/res/values/values.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2021 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<resources> + <string name="identical_resource_key">client value</string> +</resources>
\ No newline at end of file diff --git a/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryClientTests/src/com/android/sharedlibloadingtest/ClientClass.java b/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryClientTests/src/com/android/sharedlibloadingtest/ClientClass.java new file mode 100644 index 000000000000..e48fb833bd76 --- /dev/null +++ b/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryClientTests/src/com/android/sharedlibloadingtest/ClientClass.java @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.sharedlibloadingtest; + +public class ClientClass { + @Override + public String toString() { + return "Client Code"; + } +} diff --git a/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryClientTests/src/com/android/sharedlibloadingtest/DuplicateClassA.java b/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryClientTests/src/com/android/sharedlibloadingtest/DuplicateClassA.java new file mode 100644 index 000000000000..4c771557e119 --- /dev/null +++ b/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryClientTests/src/com/android/sharedlibloadingtest/DuplicateClassA.java @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.sharedlibloadingtest; + +public class DuplicateClassA { + @Override + public String toString() { + return "Client's Version"; + } +} diff --git a/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryClientTests/src/com/android/sharedlibloadingtest/DuplicateClassB.java b/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryClientTests/src/com/android/sharedlibloadingtest/DuplicateClassB.java new file mode 100644 index 000000000000..86aa6a1a0901 --- /dev/null +++ b/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryClientTests/src/com/android/sharedlibloadingtest/DuplicateClassB.java @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.sharedlibloadingtest; + +public class DuplicateClassB { + @Override + public String toString() { + return "Client's Version B"; + } +} diff --git a/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryClientTests/src/com/android/sharedlibloadingtest/client/SharedLibraryLoadingOrderTest.java b/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryClientTests/src/com/android/sharedlibloadingtest/client/SharedLibraryLoadingOrderTest.java new file mode 100644 index 000000000000..43bcb1ad7d27 --- /dev/null +++ b/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryClientTests/src/com/android/sharedlibloadingtest/client/SharedLibraryLoadingOrderTest.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.sharedlibloadingtest.client; + +import static org.testng.Assert.assertEquals; + +import android.content.Context; +import android.content.res.Resources; + +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import com.android.internal.util.Preconditions; +import com.android.sharedlibloadingtest.ClientClass; +import com.android.sharedlibloadingtest.DuplicateClassA; +import com.android.sharedlibloadingtest.DuplicateClassB; +import com.android.sharedlibloadingtest.SharedClassAfter; +import com.android.sharedlibloadingtest.StdSharedClass; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.Collections; +import java.util.HashSet; + +@RunWith(AndroidJUnit4.class) +public class SharedLibraryLoadingOrderTest { + + @Test + public void testLoadingOfStdShareLibsShouldBeFirst() { + Preconditions.checkArgument(!getLibsLoadedAfter() + .contains("com.android.sharedlibloadingtest.shared_library")); + DuplicateClassA clazz = new DuplicateClassA(); + assertEquals(clazz.toString(), "Standard Shared Lib's Version"); + + StdSharedClass stdSharedClass = new StdSharedClass(); + assertEquals(stdSharedClass.toString(), "Nothing Special Lib"); + + ClientClass clientCode = new ClientClass(); + assertEquals(clientCode.toString(), "Client Code"); + } + + @Test + public void testLoadingOfShareLibsIsAfter() { + Preconditions.checkArgument(getLibsLoadedAfter() + .contains("com.android.sharedlibloadingtest.shared_library_after")); + DuplicateClassB clazz = new DuplicateClassB(); + assertEquals(clazz.toString(), "Client's Version B"); + + SharedClassAfter stdSharedClass = new SharedClassAfter(); + assertEquals(stdSharedClass.toString(), "Also Nothing Special"); + + ClientClass clientCode = new ClientClass(); + assertEquals(clientCode.toString(), "Client Code"); + } + + @Test + public void testLoadingOfResource() { + // aapt compiler gives each lib their own namespace so this test just confirming + // the resources can be loaded from the same context object + Context context = ApplicationProvider.getApplicationContext(); + String clientString = context.getResources().getString(R.string.identical_resource_key); + assertEquals(clientString, "client value"); + assertEquals(StdSharedClass.getResString(context), "std lib value"); + assertEquals(SharedClassAfter.getResString(context), "loaded after value"); + + } + + private HashSet<String> getLibsLoadedAfter() { + Resources systemR = Resources.getSystem(); + HashSet<String> libsToLoadAfter = new HashSet<>(); + Collections.addAll(libsToLoadAfter, systemR.getStringArray( + com.android.internal.R.array.config_sharedLibrariesLoadedAfterApp)); + return libsToLoadAfter; + } +} diff --git a/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryLoadedAfter/Android.bp b/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryLoadedAfter/Android.bp new file mode 100644 index 000000000000..db9b3edfe6a2 --- /dev/null +++ b/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryLoadedAfter/Android.bp @@ -0,0 +1,30 @@ +// Copyright (C) 2021 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + +android_test_helper_app { + name: "SharedLibraryLoadingTests_SharedLibraryLoadedAfter", + srcs: ["**/*.java"], + resource_dirs: ["res"], + sdk_version: "current", + aaptflags: ["--shared-lib"], +} diff --git a/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryLoadedAfter/AndroidManifest.xml b/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryLoadedAfter/AndroidManifest.xml new file mode 100644 index 000000000000..efedfcfeb515 --- /dev/null +++ b/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryLoadedAfter/AndroidManifest.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2021 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.sharedlibloadingtest.shared_library_after"> + <application> + <library android:name="com.android.sharedlibloadingtest.shared_library_after" /> + </application> +</manifest>
\ No newline at end of file diff --git a/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryLoadedAfter/res/values/values.xml b/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryLoadedAfter/res/values/values.xml new file mode 100644 index 000000000000..4525944b060c --- /dev/null +++ b/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryLoadedAfter/res/values/values.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2021 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<resources> + <string name="identical_resource_key">loaded after value</string> +</resources>
\ No newline at end of file diff --git a/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryLoadedAfter/src/com/android/sharedlibloadingtest/DuplicateClassB.java b/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryLoadedAfter/src/com/android/sharedlibloadingtest/DuplicateClassB.java new file mode 100644 index 000000000000..1e1f5aab5993 --- /dev/null +++ b/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryLoadedAfter/src/com/android/sharedlibloadingtest/DuplicateClassB.java @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.sharedlibloadingtest; + +public class DuplicateClassB { + @Override + public String toString() { + return "Loaded After Shared Lib's Version"; + } +} diff --git a/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryLoadedAfter/src/com/android/sharedlibloadingtest/SharedClassAfter.java b/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryLoadedAfter/src/com/android/sharedlibloadingtest/SharedClassAfter.java new file mode 100644 index 000000000000..9e5b40fc38d8 --- /dev/null +++ b/tests/SharedLibraryLoadingTest/test-apps/SharedLibraryLoadedAfter/src/com/android/sharedlibloadingtest/SharedClassAfter.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.sharedlibloadingtest; + +import android.content.Context; + +import com.android.sharedlibloadingtest.shared_library_after.R; + +public class SharedClassAfter { + @Override + public String toString() { + return "Also Nothing Special"; + } + + public static String getResString(Context context) { + return context.getResources().getString(R.string.identical_resource_key); + } +} diff --git a/tests/SharedLibraryLoadingTest/test-apps/StandardSharedLibrary/Android.bp b/tests/SharedLibraryLoadingTest/test-apps/StandardSharedLibrary/Android.bp new file mode 100644 index 000000000000..50456b0439c2 --- /dev/null +++ b/tests/SharedLibraryLoadingTest/test-apps/StandardSharedLibrary/Android.bp @@ -0,0 +1,30 @@ +// Copyright (C) 2021 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + +android_test_helper_app { + name: "SharedLibraryLoadingTests_StandardSharedLibrary", + srcs: ["**/*.java"], + resource_dirs: ["res"], + sdk_version: "current", + aaptflags: ["--shared-lib"], +} diff --git a/tests/SharedLibraryLoadingTest/test-apps/StandardSharedLibrary/AndroidManifest.xml b/tests/SharedLibraryLoadingTest/test-apps/StandardSharedLibrary/AndroidManifest.xml new file mode 100644 index 000000000000..f1a079feb316 --- /dev/null +++ b/tests/SharedLibraryLoadingTest/test-apps/StandardSharedLibrary/AndroidManifest.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2021 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.sharedlibloadingtest.shared_library"> + <application> + <library android:name="com.android.sharedlibloadingtest.shared_library" /> + </application> +</manifest>
\ No newline at end of file diff --git a/tests/SharedLibraryLoadingTest/test-apps/StandardSharedLibrary/res/values/values.xml b/tests/SharedLibraryLoadingTest/test-apps/StandardSharedLibrary/res/values/values.xml new file mode 100644 index 000000000000..941351aaea62 --- /dev/null +++ b/tests/SharedLibraryLoadingTest/test-apps/StandardSharedLibrary/res/values/values.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2021 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<resources> + <string name="identical_resource_key">std lib value</string> +</resources>
\ No newline at end of file diff --git a/tests/SharedLibraryLoadingTest/test-apps/StandardSharedLibrary/src/com/android/sharedlibloadingtest/DuplicateClassA.java b/tests/SharedLibraryLoadingTest/test-apps/StandardSharedLibrary/src/com/android/sharedlibloadingtest/DuplicateClassA.java new file mode 100644 index 000000000000..a3874aa3ad96 --- /dev/null +++ b/tests/SharedLibraryLoadingTest/test-apps/StandardSharedLibrary/src/com/android/sharedlibloadingtest/DuplicateClassA.java @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.sharedlibloadingtest; + +public class DuplicateClassA { + @Override + public String toString() { + return "Standard Shared Lib's Version"; + } +} diff --git a/tests/SharedLibraryLoadingTest/test-apps/StandardSharedLibrary/src/com/android/sharedlibloadingtest/StdSharedClass.java b/tests/SharedLibraryLoadingTest/test-apps/StandardSharedLibrary/src/com/android/sharedlibloadingtest/StdSharedClass.java new file mode 100644 index 000000000000..429d65ca2439 --- /dev/null +++ b/tests/SharedLibraryLoadingTest/test-apps/StandardSharedLibrary/src/com/android/sharedlibloadingtest/StdSharedClass.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.sharedlibloadingtest; + +import android.content.Context; + +import com.android.sharedlibloadingtest.shared_library.R; + +public class StdSharedClass { + @Override + public String toString() { + return "Nothing Special Lib"; + } + + public static String getResString(Context context) { + return context.getResources().getString(R.string.identical_resource_key); + } +} diff --git a/tests/StagedInstallTest/Android.bp b/tests/StagedInstallTest/Android.bp index 7a564fcaa99e..a5852b52ff19 100644 --- a/tests/StagedInstallTest/Android.bp +++ b/tests/StagedInstallTest/Android.bp @@ -31,6 +31,7 @@ android_test_helper_app { ], test_suites: ["general-tests"], java_resources: [ + ":apex.apexd_test_classpath", ":com.android.apex.apkrollback.test_v2", ":StagedInstallTestApexV2", ":StagedInstallTestApexV2_WrongSha", @@ -54,6 +55,7 @@ java_test_host { "cts-install-lib-host", ], data: [ + ":apex.apexd_test", ":com.android.apex.apkrollback.test_v1", ":StagedInstallTestApexV2", ":StagedInstallTestApexV2_WrongSha", diff --git a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java index c610641932df..f0ab63eb41b5 100644 --- a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java +++ b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java @@ -74,6 +74,11 @@ public class StagedInstallInternalTest { "ApexV2", SHIM_APEX_PACKAGE_NAME, 2, /* isApex= */ true, "com.android.apex.cts.shim.v2.apex"); + private static final String TEST_APEX_PACKAGE_NAME = "com.android.apex.test_package"; + private static final TestApp TEST_APEX_CLASSPATH = new TestApp("TestApex", + TEST_APEX_PACKAGE_NAME, 1, /*isApex=*/true, + "apex.apexd_test_classpath.apex"); + private File mTestStateFile = new File( InstrumentationRegistry.getInstrumentation().getContext().getFilesDir(), "stagedinstall_state"); @@ -439,11 +444,13 @@ public class StagedInstallInternalTest { StagedApexInfo result = getPackageManagerNative().getStagedApexInfo("not found"); assertThat(result).isNull(); // Stage an apex - int sessionId = Install.single(APEX_V2).setStaged().commit(); + int sessionId = Install.single(TEST_APEX_CLASSPATH).setStaged().commit(); waitForSessionReady(sessionId); // Query proper module name - result = getPackageManagerNative().getStagedApexInfo(SHIM_APEX_PACKAGE_NAME); - assertThat(result.moduleName).isEqualTo(SHIM_APEX_PACKAGE_NAME); + result = getPackageManagerNative().getStagedApexInfo(TEST_APEX_PACKAGE_NAME); + assertThat(result.moduleName).isEqualTo(TEST_APEX_PACKAGE_NAME); + assertThat(result.hasBootClassPathJars).isTrue(); + assertThat(result.hasSystemServerClassPathJars).isTrue(); InstallUtils.openPackageInstallerSession(sessionId).abandon(); } diff --git a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java index 31021031b47a..cd0078363c4b 100644 --- a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java +++ b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java @@ -61,6 +61,7 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test { private static final String APEX_WRONG_SHA = "com.android.apex.cts.shim.v2_wrong_sha.apex"; private static final String APK_A = "TestAppAv1.apk"; private static final String APK_IN_APEX_TESTAPEX_NAME = "com.android.apex.apkrollback.test"; + private static final String APEXD_TEST_APEX = "apex.apexd_test.apex"; private static final String TEST_VENDOR_APEX_ALLOW_LIST = "/vendor/etc/sysconfig/test-vendor-apex-allow-list.xml"; @@ -480,16 +481,29 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test { @Test public void testGetStagedModuleNames() throws Exception { + assumeTrue("Device does not support updating APEX", + mHostUtils.isApexUpdateSupported()); + runPhase("testGetStagedModuleNames"); } @Test + @LargeTest public void testGetStagedApexInfo() throws Exception { + assumeTrue("Device does not support updating APEX", + mHostUtils.isApexUpdateSupported()); + + pushTestApex(APEXD_TEST_APEX); + getDevice().reboot(); + runPhase("testGetStagedApexInfo"); } @Test public void testStagedApexObserver() throws Exception { + assumeTrue("Device does not support updating APEX", + mHostUtils.isApexUpdateSupported()); + runPhase("testStagedApexObserver"); } diff --git a/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java b/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java index f3851130c68a..3b201f9d20dd 100644 --- a/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java +++ b/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java @@ -135,11 +135,12 @@ public class IkeSessionParamsUtilsTest { } @Test - public void testEncodeRecodeParamsWithIkeOptions() throws Exception { + public void testEncodeDecodeParamsWithIkeOptions() throws Exception { final IkeSessionParams params = createBuilderMinimum() .addIkeOption(IkeSessionParams.IKE_OPTION_ACCEPT_ANY_REMOTE_ID) .addIkeOption(IkeSessionParams.IKE_OPTION_MOBIKE) + .addIkeOption(IkeSessionParams.IKE_OPTION_INITIAL_CONTACT) .build(); verifyPersistableBundleEncodeDecodeIsLossless(params); } diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index c9a8947ab5ef..937f9dc60a72 100644 --- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -297,8 +297,6 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection any(), any()); verify(mNetworkAgent).register(); - verify(mNetworkAgent) - .setUnderlyingNetworks(eq(singletonList(TEST_UNDERLYING_NETWORK_RECORD_1.network))); verify(mNetworkAgent).markConnected(); verify(mIpSecSvc) @@ -313,6 +311,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection final NetworkCapabilities nc = ncCaptor.getValue(); assertTrue(nc.hasTransport(TRANSPORT_CELLULAR)); assertFalse(nc.hasTransport(TRANSPORT_WIFI)); + assertEquals(List.of(TEST_UNDERLYING_NETWORK_RECORD_1.network), nc.getUnderlyingNetworks()); for (int cap : mConfig.getAllExposedCapabilities()) { assertTrue(nc.hasCapability(cap)); } diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java index a7001713533c..2b0037eaf8eb 100644 --- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java +++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java @@ -16,6 +16,7 @@ package com.android.server.vcn; +import static android.net.IpSecManager.IpSecTunnelInterface; import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN; import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; @@ -24,6 +25,8 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; +import static com.android.server.vcn.VcnGatewayConnection.DUMMY_ADDR; +import static com.android.server.vcn.VcnGatewayConnection.VcnChildSessionConfiguration; import static com.android.server.vcn.VcnGatewayConnection.VcnIkeSession; import static com.android.server.vcn.VcnGatewayConnection.VcnNetworkAgent; @@ -36,8 +39,11 @@ import static org.mockito.Matchers.eq; import static org.mockito.Mockito.CALLS_REAL_METHODS; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import android.net.IpSecManager; +import android.net.LinkAddress; import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; @@ -59,8 +65,11 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import java.net.InetAddress; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.UUID; @@ -70,6 +79,8 @@ import java.util.UUID; public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { private static final int TEST_UID = Process.myUid() + 1; + private static final String LOOPBACK_IFACE = "lo"; + private static final ParcelUuid TEST_PARCEL_UUID = new ParcelUuid(UUID.randomUUID()); private static final int TEST_SIM_SLOT_INDEX = 1; private static final int TEST_SUBSCRIPTION_ID_1 = 2; @@ -77,6 +88,12 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { private static final int TEST_SUBSCRIPTION_ID_2 = 3; private static final SubscriptionInfo TEST_SUBINFO_2 = mock(SubscriptionInfo.class); private static final Map<Integer, ParcelUuid> TEST_SUBID_TO_GROUP_MAP; + private static final String TEST_TCP_BUFFER_SIZES = "1,2,3,4,5,6"; + private static final int TEST_MTU = 1300; + private static final int TEST_MTU_DELTA = 64; + private static final List<LinkAddress> TEST_INTERNAL_ADDRESSES = + Arrays.asList(new LinkAddress(DUMMY_ADDR, 16)); + private static final List<InetAddress> TEST_DNS_ADDRESSES = Arrays.asList(DUMMY_ADDR); private static final int TEST_UPSTREAM_BANDWIDTH = 1234; private static final int TEST_DOWNSTREAM_BANDWIDTH = 2345; @@ -116,8 +133,9 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { capBuilder.setLinkUpstreamBandwidthKbps(TEST_UPSTREAM_BANDWIDTH); capBuilder.setLinkDownstreamBandwidthKbps(TEST_DOWNSTREAM_BANDWIDTH); capBuilder.setAdministratorUids(new int[] {TEST_UID}); + final Network underlyingNetwork = mock(Network.class, CALLS_REAL_METHODS); UnderlyingNetworkRecord record = new UnderlyingNetworkRecord( - mock(Network.class, CALLS_REAL_METHODS), + underlyingNetwork, capBuilder.build(), new LinkProperties(), false); final NetworkCapabilities vcnCaps = VcnGatewayConnection.buildNetworkCapabilities( @@ -128,6 +146,7 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { assertTrue(vcnCaps.hasTransport(TRANSPORT_CELLULAR)); assertTrue(vcnCaps.hasCapability(NET_CAPABILITY_NOT_METERED)); assertTrue(vcnCaps.hasCapability(NET_CAPABILITY_NOT_ROAMING)); + assertTrue(vcnCaps.getUnderlyingNetworks().equals(List.of(underlyingNetwork))); for (int cap : VcnGatewayConnectionConfigTest.EXPOSED_CAPS) { if (cap == NET_CAPABILITY_INTERNET || cap == NET_CAPABILITY_DUN) { @@ -166,6 +185,59 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { } @Test + public void testBuildLinkProperties() throws Exception { + final IpSecTunnelInterface tunnelIface = + mContext.getSystemService(IpSecManager.class) + .createIpSecTunnelInterface( + DUMMY_ADDR, DUMMY_ADDR, TEST_UNDERLYING_NETWORK_RECORD_1.network); + + final LinkProperties underlyingLp = new LinkProperties(); + underlyingLp.setInterfaceName(LOOPBACK_IFACE); + underlyingLp.setTcpBufferSizes(TEST_TCP_BUFFER_SIZES); + doReturn(TEST_MTU).when(mDeps).getUnderlyingIfaceMtu(LOOPBACK_IFACE); + + final VcnChildSessionConfiguration childSessionConfig = + mock(VcnChildSessionConfiguration.class); + doReturn(TEST_INTERNAL_ADDRESSES).when(childSessionConfig).getInternalAddresses(); + doReturn(TEST_DNS_ADDRESSES).when(childSessionConfig).getInternalDnsServers(); + + UnderlyingNetworkRecord record = + new UnderlyingNetworkRecord( + mock(Network.class, CALLS_REAL_METHODS), + new NetworkCapabilities.Builder().build(), + underlyingLp, + false); + + final LinkProperties vcnLp1 = + mGatewayConnection.buildConnectedLinkProperties( + VcnGatewayConnectionConfigTest.buildTestConfig(), + tunnelIface, + childSessionConfig, + record); + + verify(mDeps).getUnderlyingIfaceMtu(LOOPBACK_IFACE); + + // Instead of having to recalculate the final MTU (after accounting for IPsec overhead), + // calculate another set of Link Properties with a lower MTU, and calculate the delta. + doReturn(TEST_MTU - TEST_MTU_DELTA).when(mDeps).getUnderlyingIfaceMtu(LOOPBACK_IFACE); + + final LinkProperties vcnLp2 = + mGatewayConnection.buildConnectedLinkProperties( + VcnGatewayConnectionConfigTest.buildTestConfig(), + tunnelIface, + childSessionConfig, + record); + + verify(mDeps, times(2)).getUnderlyingIfaceMtu(LOOPBACK_IFACE); + + assertEquals(tunnelIface.getInterfaceName(), vcnLp1.getInterfaceName()); + assertEquals(TEST_INTERNAL_ADDRESSES, vcnLp1.getLinkAddresses()); + assertEquals(TEST_DNS_ADDRESSES, vcnLp1.getDnsServers()); + assertEquals(TEST_TCP_BUFFER_SIZES, vcnLp1.getTcpBufferSizes()); + assertEquals(TEST_MTU_DELTA, vcnLp1.getMtu() - vcnLp2.getMtu()); + } + + @Test public void testSubscriptionSnapshotUpdateNotifiesUnderlyingNetworkTracker() { verifyWakeLockSetUp(); diff --git a/tools/aapt2/OWNERS b/tools/aapt2/OWNERS index 69dfcc98340d..4f655e54a7c2 100644 --- a/tools/aapt2/OWNERS +++ b/tools/aapt2/OWNERS @@ -1,4 +1,4 @@ set noparent toddke@google.com -rtmitchell@google.com +zyy@google.com patb@google.com
\ No newline at end of file diff --git a/tools/aapt2/util/Files.cpp b/tools/aapt2/util/Files.cpp index 5d57de6a9fb1..be09545abb45 100644 --- a/tools/aapt2/util/Files.cpp +++ b/tools/aapt2/util/Files.cpp @@ -154,7 +154,7 @@ StringPiece GetFilename(const StringPiece& path) { const char* end = path.end(); const char* last_dir_sep = path.begin(); for (const char* c = path.begin(); c != end; ++c) { - if (*c == sDirSep) { + if (*c == sDirSep || *c == sInvariantDirSep) { last_dir_sep = c + 1; } } diff --git a/tools/aapt2/util/Files.h b/tools/aapt2/util/Files.h index 481a4cdb6ad0..e50cb505bf66 100644 --- a/tools/aapt2/util/Files.h +++ b/tools/aapt2/util/Files.h @@ -41,6 +41,8 @@ constexpr const char sDirSep = '/'; constexpr const char sPathSep = ':'; #endif +constexpr const char sInvariantDirSep = '/'; + enum class FileType { kUnknown = 0, kNonexistant, |