summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmds/idmap2/include/idmap2/FileUtils.h2
-rw-r--r--core/api/current.txt109
-rw-r--r--core/api/system-current.txt82
-rw-r--r--core/api/test-current.txt22
-rw-r--r--core/java/Android.bp21
-rw-r--r--core/java/android/annotation/SuppressLint.java38
-rw-r--r--core/java/android/annotation/TargetApi.java36
-rw-r--r--core/java/android/app/ActivityThread.java8
-rw-r--r--core/java/android/app/IntentService.java2
-rw-r--r--core/java/android/bluetooth/BluetoothAdapter.java9
-rw-r--r--core/java/android/bluetooth/BluetoothCsipSetCoordinator.java550
-rw-r--r--core/java/android/bluetooth/BluetoothDevice.java11
-rw-r--r--core/java/android/bluetooth/BluetoothHeadset.java7
-rw-r--r--core/java/android/content/pm/parsing/component/ParsedIntentInfo.java14
-rw-r--r--core/java/android/hardware/SensorManager.java4
-rw-r--r--core/java/android/net/NetworkTemplate.java23
-rw-r--r--core/java/android/os/ISystemConfig.aidl5
-rw-r--r--core/java/android/os/OutcomeReceiver.java42
-rw-r--r--core/java/android/os/Parcel.java38
-rw-r--r--core/java/android/os/ServiceManager.java9
-rw-r--r--core/java/android/os/SystemConfigManager.java18
-rw-r--r--core/java/android/os/connectivity/CellularBatteryStats.java2
-rw-r--r--core/java/android/text/Layout.java9
-rw-r--r--core/java/android/webkit/URLUtil.java2
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java69
-rw-r--r--core/java/com/android/internal/os/OWNERS2
-rw-r--r--core/java/com/android/internal/util/IState.java4
-rw-r--r--core/java/com/android/internal/util/State.java2
-rw-r--r--core/java/com/android/internal/util/StateMachine.java6
-rw-r--r--core/jni/OWNERS4
-rw-r--r--core/jni/android_os_Parcel.cpp13
-rw-r--r--core/jni/com_android_internal_os_Zygote.cpp6
-rw-r--r--core/res/AndroidManifest.xml3
-rw-r--r--core/res/res/values/public.xml3
-rw-r--r--core/res/res/xml/sms_short_codes.xml2
-rw-r--r--core/tests/coretests/src/android/app/activity/ActivityThreadTest.java5
-rw-r--r--core/tests/utiltests/src/com/android/internal/util/StateMachineTest.java78
-rw-r--r--identity/java/android/security/identity/IdentityCredential.java8
-rw-r--r--libs/hwui/jni/PaintFilter.cpp2
-rw-r--r--media/java/android/media/MediaCodecInfo.java6
-rw-r--r--media/java/android/media/MediaMetadataRetriever.java4
-rw-r--r--media/jni/audioeffect/android_media_AudioEffect.cpp50
-rw-r--r--media/jni/audioeffect/android_media_Visualizer.cpp92
-rw-r--r--media/tests/EffectsTest/AndroidManifest.xml4
-rw-r--r--media/tests/EffectsTest/res/layout/bassboosttest.xml5
-rw-r--r--media/tests/EffectsTest/res/layout/visualizertest.xml5
-rw-r--r--media/tests/EffectsTest/res/values/strings.xml2
-rw-r--r--media/tests/EffectsTest/src/com/android/effectstest/BassBoostTest.java80
-rw-r--r--media/tests/EffectsTest/src/com/android/effectstest/VisualizerTest.java60
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java3
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java20
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipSetCoordinatorProfile.java236
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java23
-rw-r--r--packages/Shell/AndroidManifest.xml2
-rw-r--r--services/OWNERS1
-rw-r--r--services/core/java/com/android/server/BluetoothManagerService.java48
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java103
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerConstants.java20
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerShellCommand.java12
-rw-r--r--services/core/java/com/android/server/am/BatteryExternalStatsWorker.java40
-rw-r--r--services/core/java/com/android/server/am/BatteryStatsService.java2
-rw-r--r--services/core/java/com/android/server/am/ServiceRecord.java6
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java35
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java12
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java12
-rw-r--r--services/core/java/com/android/server/role/RoleManagerService.java6
-rw-r--r--services/core/java/com/android/server/stats/pull/StatsPullAtomService.java45
-rwxr-xr-xservices/core/java/com/android/server/tv/TvInputHardwareManager.java6
-rw-r--r--services/core/java/com/android/server/vcn/Vcn.java14
-rw-r--r--services/core/java/com/android/server/vcn/VcnGatewayConnection.java6
-rw-r--r--services/java/com/android/server/SystemConfigService.java16
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java93
-rw-r--r--telecomm/java/android/telecom/InCallService.java7
-rw-r--r--telephony/java/android/telephony/ModemActivityInfo.java286
-rw-r--r--telephony/java/android/telephony/ServiceState.java4
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java237
-rw-r--r--telephony/java/android/telephony/data/NetworkSliceInfo.java135
-rw-r--r--telephony/java/android/telephony/data/RouteSelectionDescriptor.aidl19
-rw-r--r--telephony/java/android/telephony/data/RouteSelectionDescriptor.java263
-rw-r--r--telephony/java/android/telephony/data/SlicingConfig.aidl19
-rw-r--r--telephony/java/android/telephony/data/SlicingConfig.java137
-rw-r--r--telephony/java/android/telephony/data/TrafficDescriptor.java81
-rw-r--r--telephony/java/android/telephony/data/UrspRule.aidl19
-rw-r--r--telephony/java/android/telephony/data/UrspRule.java178
-rwxr-xr-xtelephony/java/android/telephony/ims/ImsCallSession.java10
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephony.aidl6
-rw-r--r--telephony/java/com/android/internal/telephony/RILConstants.java1
-rw-r--r--test-mock/Android.bp12
-rw-r--r--test-mock/jarjar-rules.txt7
-rw-r--r--tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java6
-rw-r--r--tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java9
-rw-r--r--tools/bit/print.cpp1
-rw-r--r--tools/bit/util.h2
-rw-r--r--tools/streaming_proto/Errors.cpp1
94 files changed, 3289 insertions, 490 deletions
diff --git a/cmds/idmap2/include/idmap2/FileUtils.h b/cmds/idmap2/include/idmap2/FileUtils.h
index c4e0e1fd8ef0..8fcaeb1f6b87 100644
--- a/cmds/idmap2/include/idmap2/FileUtils.h
+++ b/cmds/idmap2/include/idmap2/FileUtils.h
@@ -17,6 +17,8 @@
#ifndef IDMAP2_INCLUDE_IDMAP2_FILEUTILS_H_
#define IDMAP2_INCLUDE_IDMAP2_FILEUTILS_H_
+#include <sys/types.h>
+
#include <string>
namespace android::idmap2::utils {
diff --git a/core/api/current.txt b/core/api/current.txt
index bc61d15f4eb0..e4e7d4eec77d 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -954,7 +954,7 @@ package android {
field public static final int measureWithLargestChild = 16843476; // 0x10102d4
field public static final int mediaRouteButtonStyle = 16843693; // 0x10103ad
field public static final int mediaRouteTypes = 16843694; // 0x10103ae
- field public static final int memtagMode = 16844313; // 0x1010619
+ field public static final int memtagMode = 16844324; // 0x1010624
field public static final int menuCategory = 16843230; // 0x10101de
field public static final int mimeGroup = 16844309; // 0x1010615
field public static final int mimeType = 16842790; // 0x1010026
@@ -978,7 +978,7 @@ package android {
field public static final int multiArch = 16843918; // 0x101048e
field public static final int multiprocess = 16842771; // 0x1010013
field public static final int name = 16842755; // 0x1010003
- field public static final int nativeHeapZeroInitialized = 16844314; // 0x101061a
+ field public static final int nativeHeapZeroInitialized = 16844325; // 0x1010625
field public static final int navigationBarColor = 16843858; // 0x1010452
field public static final int navigationBarDividerColor = 16844141; // 0x101056d
field public static final int navigationContentDescription = 16843969; // 0x10104c1
@@ -8657,6 +8657,15 @@ package android.bluetooth {
field public static final int TELEPHONY = 4194304; // 0x400000
}
+ public final class BluetoothCsipSetCoordinator implements java.lang.AutoCloseable android.bluetooth.BluetoothProfile {
+ method public void close();
+ method protected void finalize();
+ method @NonNull public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
+ method public int getConnectionState(@Nullable android.bluetooth.BluetoothDevice);
+ method @NonNull public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(@NonNull int[]);
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH) public static final String ACTION_CSIS_CONNECTION_STATE_CHANGED = "android.bluetooth.action.CSIS_CONNECTION_STATE_CHANGED";
+ }
+
public final class BluetoothDevice implements android.os.Parcelable {
method public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback);
method public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback, int);
@@ -8703,6 +8712,7 @@ package android.bluetooth {
field public static final String EXTRA_BOND_STATE = "android.bluetooth.device.extra.BOND_STATE";
field public static final String EXTRA_CLASS = "android.bluetooth.device.extra.CLASS";
field public static final String EXTRA_DEVICE = "android.bluetooth.device.extra.DEVICE";
+ field public static final String EXTRA_IS_COORDINATED_SET_MEMBER = "android.bluetooth.extra.IS_COORDINATED_SET_MEMBER";
field public static final String EXTRA_NAME = "android.bluetooth.device.extra.NAME";
field public static final String EXTRA_PAIRING_KEY = "android.bluetooth.device.extra.PAIRING_KEY";
field public static final String EXTRA_PAIRING_VARIANT = "android.bluetooth.device.extra.PAIRING_VARIANT";
@@ -29936,6 +29946,11 @@ package android.os {
ctor public OperationCanceledException(String);
}
+ public interface OutcomeReceiver<R, E extends java.lang.Throwable> {
+ method public default void onError(@NonNull E);
+ method public void onResult(@NonNull R);
+ }
+
public final class Parcel {
method public void appendFrom(android.os.Parcel, int, int);
method @Nullable public android.os.IBinder[] createBinderArray();
@@ -41031,6 +41046,7 @@ package android.telephony {
method public String getNetworkOperator();
method public String getNetworkOperatorName();
method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public int getNetworkSelectionMode();
+ method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void getNetworkSlicingConfiguration(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.telephony.data.SlicingConfig,android.telephony.TelephonyManager.SlicingException>);
method public String getNetworkSpecifier();
method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int getNetworkType();
method @Deprecated public int getPhoneCount();
@@ -41264,6 +41280,13 @@ package android.telephony {
field public static final int ERROR_TIMEOUT = 1; // 0x1
}
+ public static class TelephonyManager.SlicingException extends java.lang.Exception {
+ ctor public TelephonyManager.SlicingException(int);
+ method public int getErrorCode();
+ field public static final int ERROR_MODEM_ERROR = 2; // 0x2
+ field public static final int ERROR_TIMEOUT = 1; // 0x1
+ }
+
public abstract static class TelephonyManager.UssdResponseCallback {
ctor public TelephonyManager.UssdResponseCallback();
method public void onReceiveUssdResponse(android.telephony.TelephonyManager, String, CharSequence);
@@ -41439,6 +41462,88 @@ package android.telephony.data {
method @NonNull public android.telephony.data.ApnSetting.Builder setUser(@Nullable String);
}
+ public final class NetworkSliceInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method @IntRange(from=0xffffffff, to=0xfffffe) public int getMappedHplmnSliceDifferentiator();
+ method public int getMappedHplmnSliceServiceType();
+ method @IntRange(from=0xffffffff, to=0xfffffe) public int getSliceDifferentiator();
+ method public int getSliceServiceType();
+ method public int getStatus();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.NetworkSliceInfo> CREATOR;
+ field public static final int SLICE_DIFFERENTIATOR_NO_SLICE = -1; // 0xffffffff
+ field public static final int SLICE_SERVICE_TYPE_EMBB = 1; // 0x1
+ field public static final int SLICE_SERVICE_TYPE_MIOT = 3; // 0x3
+ field public static final int SLICE_SERVICE_TYPE_NONE = 0; // 0x0
+ field public static final int SLICE_SERVICE_TYPE_URLLC = 2; // 0x2
+ field public static final int SLICE_STATUS_ALLOWED = 2; // 0x2
+ field public static final int SLICE_STATUS_CONFIGURED = 1; // 0x1
+ field public static final int SLICE_STATUS_DEFAULT_CONFIGURED = 5; // 0x5
+ field public static final int SLICE_STATUS_REJECTED_NOT_AVAILABLE_IN_PLMN = 3; // 0x3
+ field public static final int SLICE_STATUS_REJECTED_NOT_AVAILABLE_IN_REGISTERED_AREA = 4; // 0x4
+ field public static final int SLICE_STATUS_UNKNOWN = 0; // 0x0
+ }
+
+ public static final class NetworkSliceInfo.Builder {
+ ctor public NetworkSliceInfo.Builder();
+ method @NonNull public android.telephony.data.NetworkSliceInfo build();
+ method @NonNull public android.telephony.data.NetworkSliceInfo.Builder setMappedHplmnSliceDifferentiator(@IntRange(from=0xffffffff, to=0xfffffe) int);
+ method @NonNull public android.telephony.data.NetworkSliceInfo.Builder setMappedHplmnSliceServiceType(int);
+ method @NonNull public android.telephony.data.NetworkSliceInfo.Builder setSliceDifferentiator(@IntRange(from=0xffffffff, to=0xfffffe) int);
+ method @NonNull public android.telephony.data.NetworkSliceInfo.Builder setSliceServiceType(int);
+ method @NonNull public android.telephony.data.NetworkSliceInfo.Builder setStatus(int);
+ }
+
+ public final class RouteSelectionDescriptor implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public java.util.List<java.lang.String> getDataNetworkName();
+ method @IntRange(from=0x0, to=0xff) public int getPrecedence();
+ method public int getSessionType();
+ method @NonNull public java.util.List<android.telephony.data.NetworkSliceInfo> getSliceInfo();
+ method public int getSscMode();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.RouteSelectionDescriptor> CREATOR;
+ field public static final int ROUTE_SSC_MODE_1 = 1; // 0x1
+ field public static final int ROUTE_SSC_MODE_2 = 2; // 0x2
+ field public static final int ROUTE_SSC_MODE_3 = 3; // 0x3
+ field public static final int SESSION_TYPE_IPV4 = 0; // 0x0
+ field public static final int SESSION_TYPE_IPV4V6 = 2; // 0x2
+ field public static final int SESSION_TYPE_IPV6 = 1; // 0x1
+ }
+
+ public final class SlicingConfig implements android.os.Parcelable {
+ ctor public SlicingConfig();
+ method public int describeContents();
+ method @NonNull public java.util.List<android.telephony.data.NetworkSliceInfo> getSliceInfo();
+ method @NonNull public java.util.List<android.telephony.data.UrspRule> getUrspRules();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.SlicingConfig> CREATOR;
+ }
+
+ public final class TrafficDescriptor implements android.os.Parcelable {
+ method public int describeContents();
+ method @Nullable public String getDataNetworkName();
+ method @Nullable public String getOsAppId();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.TrafficDescriptor> CREATOR;
+ }
+
+ public static final class TrafficDescriptor.Builder {
+ ctor public TrafficDescriptor.Builder();
+ method @NonNull public android.telephony.data.TrafficDescriptor build();
+ method @NonNull public android.telephony.data.TrafficDescriptor.Builder setDataNetworkName(@NonNull String);
+ method @NonNull public android.telephony.data.TrafficDescriptor.Builder setOsAppId(@NonNull String);
+ }
+
+ public final class UrspRule implements android.os.Parcelable {
+ method public int describeContents();
+ method @IntRange(from=0x0, to=0xff) public int getPrecedence();
+ method @NonNull public java.util.List<android.telephony.data.RouteSelectionDescriptor> getRouteSelectionDescriptor();
+ method @NonNull public java.util.List<android.telephony.data.TrafficDescriptor> getTrafficDescriptors();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.UrspRule> CREATOR;
+ }
+
}
package android.telephony.emergency {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index cd41e58ba882..af103ab460cf 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -1507,6 +1507,21 @@ package android.bluetooth {
method public void onOobData(int, @NonNull android.bluetooth.OobData);
}
+ public final class BluetoothCsipSetCoordinator implements java.lang.AutoCloseable android.bluetooth.BluetoothProfile {
+ method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public java.util.List<java.lang.Integer> getAllGroupIds(@Nullable android.os.ParcelUuid);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getConnectionPolicy(@Nullable android.bluetooth.BluetoothDevice);
+ method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public java.util.Map getGroupUuidMapByDevice(@Nullable android.bluetooth.BluetoothDevice);
+ method @Nullable @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public java.util.UUID groupLock(int, @Nullable java.util.concurrent.Executor, @Nullable android.bluetooth.BluetoothCsipSetCoordinator.ClientLockCallback);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean groupUnlock(@NonNull java.util.UUID);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setConnectionPolicy(@Nullable android.bluetooth.BluetoothDevice, int);
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public static final String ACTION_CSIS_DEVICE_AVAILABLE = "android.bluetooth.action.CSIS_DEVICE_AVAILABLE";
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public static final String ACTION_CSIS_SET_MEMBER_AVAILABLE = "android.bluetooth.action.CSIS_SET_MEMBER_AVAILABLE";
+ }
+
+ public static interface BluetoothCsipSetCoordinator.ClientLockCallback {
+ method public void onGroupLockSet(int, int, boolean);
+ }
+
public final class BluetoothDevice implements android.os.Parcelable {
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean cancelBondProcess();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean createBondOutOfBand(int, @Nullable android.bluetooth.OobData, @Nullable android.bluetooth.OobData);
@@ -1560,7 +1575,10 @@ package android.bluetooth {
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean connect(android.bluetooth.BluetoothDevice);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean disconnect(android.bluetooth.BluetoothDevice);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean isInbandRingingEnabled();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean startScoUsingVirtualVoiceCall();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean stopScoUsingVirtualVoiceCall();
}
public final class BluetoothHearingAid implements android.bluetooth.BluetoothProfile {
@@ -7241,6 +7259,7 @@ 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);
}
@@ -9671,6 +9690,25 @@ package android.telephony {
field public static final String MBMS_STREAMING_SERVICE_ACTION = "android.telephony.action.EmbmsStreaming";
}
+ public final class ModemActivityInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public android.telephony.ModemActivityInfo getDelta(@NonNull android.telephony.ModemActivityInfo);
+ method public long getIdleTimeMillis();
+ method public static int getNumTxPowerLevels();
+ method public long getReceiveTimeMillis();
+ method public long getSleepTimeMillis();
+ method public long getTimestampMillis();
+ method public long getTransmitDurationMillisAtPowerLevel(int);
+ method @NonNull public android.util.Range<java.lang.Integer> getTransmitPowerRange(int);
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ModemActivityInfo> CREATOR;
+ field public static final int TX_POWER_LEVEL_0 = 0; // 0x0
+ field public static final int TX_POWER_LEVEL_1 = 1; // 0x1
+ field public static final int TX_POWER_LEVEL_2 = 2; // 0x2
+ field public static final int TX_POWER_LEVEL_3 = 3; // 0x3
+ field public static final int TX_POWER_LEVEL_4 = 4; // 0x4
+ }
+
public final class NetworkRegistrationInfo implements android.os.Parcelable {
method @Nullable public android.telephony.DataSpecificRegistrationInfo getDataSpecificInfo();
method public int getRegistrationState();
@@ -10337,6 +10375,7 @@ package android.telephony {
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean rebootRadio();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void reportDefaultNetworkStatus(boolean);
method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.MODIFY_PHONE_STATE}) public void requestCellInfoUpdate(@NonNull android.os.WorkSource, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CellInfoCallback);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void requestModemActivityInfo(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.telephony.ModemActivityInfo,android.telephony.TelephonyManager.ModemActivityInfoException>);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void requestNumberVerification(@NonNull android.telephony.PhoneNumberRange, long, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.NumberVerificationCallback);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void resetAllCarrierActions();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void resetCarrierKeysForImsiEncryption();
@@ -10509,6 +10548,14 @@ package android.telephony {
field public static final int RESULT_SUCCESS = 0; // 0x0
}
+ public static class TelephonyManager.ModemActivityInfoException extends java.lang.Exception {
+ method public int getErrorCode();
+ field public static final int ERROR_INVALID_INFO_RECEIVED = 2; // 0x2
+ field public static final int ERROR_MODEM_RESPONSE_ERROR = 3; // 0x3
+ field public static final int ERROR_PHONE_NOT_AVAILABLE = 1; // 0x1
+ field public static final int ERROR_UNKNOWN = 0; // 0x0
+ }
+
public final class ThermalMitigationRequest implements android.os.Parcelable {
method public int describeContents();
method @Nullable public android.telephony.DataThrottlingRequest getDataThrottlingRequest();
@@ -10772,32 +10819,6 @@ package android.telephony.data {
field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.EpsBearerQosSessionAttributes> CREATOR;
}
- public final class NetworkSliceInfo implements android.os.Parcelable {
- method public int describeContents();
- method @IntRange(from=android.telephony.data.NetworkSliceInfo.MIN_SLICE_DIFFERENTIATOR, to=android.telephony.data.NetworkSliceInfo.MAX_SLICE_DIFFERENTIATOR) public int getMappedHplmnSliceDifferentiator();
- method public int getMappedHplmnSliceServiceType();
- method @IntRange(from=android.telephony.data.NetworkSliceInfo.MIN_SLICE_DIFFERENTIATOR, to=android.telephony.data.NetworkSliceInfo.MAX_SLICE_DIFFERENTIATOR) public int getSliceDifferentiator();
- method public int getSliceServiceType();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.NetworkSliceInfo> CREATOR;
- field public static final int MAX_SLICE_DIFFERENTIATOR = 16777214; // 0xfffffe
- field public static final int MIN_SLICE_DIFFERENTIATOR = -1; // 0xffffffff
- field public static final int SLICE_DIFFERENTIATOR_NO_SLICE = -1; // 0xffffffff
- field public static final int SLICE_SERVICE_TYPE_EMBB = 1; // 0x1
- field public static final int SLICE_SERVICE_TYPE_MIOT = 3; // 0x3
- field public static final int SLICE_SERVICE_TYPE_NONE = 0; // 0x0
- field public static final int SLICE_SERVICE_TYPE_URLLC = 2; // 0x2
- }
-
- public static final class NetworkSliceInfo.Builder {
- ctor public NetworkSliceInfo.Builder();
- method @NonNull public android.telephony.data.NetworkSliceInfo build();
- method @NonNull public android.telephony.data.NetworkSliceInfo.Builder setMappedHplmnSliceDifferentiator(@IntRange(from=android.telephony.data.NetworkSliceInfo.MIN_SLICE_DIFFERENTIATOR, to=android.telephony.data.NetworkSliceInfo.MAX_SLICE_DIFFERENTIATOR) int);
- method @NonNull public android.telephony.data.NetworkSliceInfo.Builder setMappedHplmnSliceServiceType(int);
- method @NonNull public android.telephony.data.NetworkSliceInfo.Builder setSliceDifferentiator(@IntRange(from=android.telephony.data.NetworkSliceInfo.MIN_SLICE_DIFFERENTIATOR, to=android.telephony.data.NetworkSliceInfo.MAX_SLICE_DIFFERENTIATOR) int);
- method @NonNull public android.telephony.data.NetworkSliceInfo.Builder setSliceServiceType(int);
- }
-
public final class NrQosSessionAttributes implements android.os.Parcelable android.net.QosSessionAttributes {
method public int describeContents();
method @NonNull public java.time.Duration getBitRateWindowDuration();
@@ -10854,15 +10875,6 @@ package android.telephony.data {
method @NonNull public android.telephony.data.ThrottleStatus.Builder setTransportType(int);
}
- public final class TrafficDescriptor implements android.os.Parcelable {
- ctor public TrafficDescriptor(@Nullable String, @Nullable String);
- method public int describeContents();
- method @Nullable public String getDnn();
- method @Nullable public String getOsAppId();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.TrafficDescriptor> CREATOR;
- }
-
}
package android.telephony.euicc {
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 661394732a12..d905bbeba6b5 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -1649,6 +1649,28 @@ package android.telephony {
field public static final String MBMS_STREAMING_SERVICE_OVERRIDE_METADATA = "mbms-streaming-service-override";
}
+ public final class ModemActivityInfo implements android.os.Parcelable {
+ ctor public ModemActivityInfo(long, int, int, @NonNull int[], int);
+ method public int describeContents();
+ method @NonNull public android.telephony.ModemActivityInfo getDelta(@NonNull android.telephony.ModemActivityInfo);
+ method public long getIdleTimeMillis();
+ method public static int getNumTxPowerLevels();
+ method public long getReceiveTimeMillis();
+ method public long getSleepTimeMillis();
+ method public long getTimestampMillis();
+ method public long getTransmitDurationMillisAtPowerLevel(int);
+ method @NonNull public android.util.Range<java.lang.Integer> getTransmitPowerRange(int);
+ method public boolean isEmpty();
+ method public boolean isValid();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ModemActivityInfo> CREATOR;
+ field public static final int TX_POWER_LEVEL_0 = 0; // 0x0
+ field public static final int TX_POWER_LEVEL_1 = 1; // 0x1
+ field public static final int TX_POWER_LEVEL_2 = 2; // 0x2
+ field public static final int TX_POWER_LEVEL_3 = 3; // 0x3
+ field public static final int TX_POWER_LEVEL_4 = 4; // 0x4
+ }
+
public class PhoneNumberUtils {
method public static int getMinMatchForTest();
method public static void setMinMatchForTest(int);
diff --git a/core/java/Android.bp b/core/java/Android.bp
index eee696b0404c..675cea827216 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -341,6 +341,27 @@ filegroup {
],
}
+java_library {
+ name: "modules-utils-statemachine",
+ srcs: [
+ "com/android/internal/util/IState.java",
+ "com/android/internal/util/State.java",
+ "com/android/internal/util/StateMachine.java",
+ ],
+ libs: [
+ "framework-annotations-lib",
+ "unsupportedappusage",
+ ],
+ sdk_version: "module_current",
+ min_sdk_version: "29",
+
+ visibility: ["//visibility:public"],
+ apex_available: [
+ "//apex_available:anyapex",
+ "//apex_available:platform",
+ ],
+}
+
filegroup {
name: "framework-ims-common-shared-srcs",
srcs: [
diff --git a/core/java/android/annotation/SuppressLint.java b/core/java/android/annotation/SuppressLint.java
new file mode 100644
index 000000000000..2d3456b0ea46
--- /dev/null
+++ b/core/java/android/annotation/SuppressLint.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2012 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.annotation;
+
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.ElementType.TYPE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/** Indicates that Lint should ignore the specified warnings for the annotated element. */
+@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
+@Retention(RetentionPolicy.CLASS)
+public @interface SuppressLint {
+ /**
+ * The set of warnings (identified by the lint issue id) that should be
+ * ignored by lint. It is not an error to specify an unrecognized name.
+ */
+ String[] value();
+}
diff --git a/core/java/android/annotation/TargetApi.java b/core/java/android/annotation/TargetApi.java
new file mode 100644
index 000000000000..975318e4de67
--- /dev/null
+++ b/core/java/android/annotation/TargetApi.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2012 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.annotation;
+
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.TYPE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/** Indicates that Lint should treat this type as targeting a given API level, no matter what the
+ project target is. */
+@Target({TYPE, METHOD, CONSTRUCTOR, FIELD})
+@Retention(RetentionPolicy.CLASS)
+public @interface TargetApi {
+ /**
+ * This sets the target api level for the type..
+ */
+ int value();
+}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 41170a4c2749..749e8f548fab 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -6299,7 +6299,13 @@ public final class ActivityThread extends ClientTransactionHandler {
final File cacheDir = context.getCacheDir();
if (cacheDir != null) {
// Provide a usable directory for temporary files
- System.setProperty("java.io.tmpdir", cacheDir.getAbsolutePath());
+ String tmpdir = cacheDir.getAbsolutePath();
+ System.setProperty("java.io.tmpdir", tmpdir);
+ try {
+ android.system.Os.setenv("TMPDIR", tmpdir, true);
+ } catch (ErrnoException ex) {
+ Log.w(TAG, "Unable to initialize $TMPDIR", ex);
+ }
} else {
Log.v(TAG, "Unable to initialize \"java.io.tmpdir\" property "
+ "due to missing cache directory");
diff --git a/core/java/android/app/IntentService.java b/core/java/android/app/IntentService.java
index 71b28fba6019..6c435b9597f4 100644
--- a/core/java/android/app/IntentService.java
+++ b/core/java/android/app/IntentService.java
@@ -54,7 +54,7 @@ import android.os.Message;
* @see android.support.v4.app.JobIntentService
*
* @deprecated IntentService is subject to all the
- * <a href="/preview/features/background.html">background execution limits</a>
+ * <a href="{@docRoot}about/versions/oreo/background.html">background execution limits</a>
* imposed with Android 8.0 (API level 26). Consider using {@link androidx.work.WorkManager}
* or {@link androidx.core.app.JobIntentService}, which uses jobs
* instead of services when running on Android 8.0 or higher.
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index d487025631c7..313dd3e2bed0 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -2819,6 +2819,10 @@ public final class BluetoothAdapter {
} else if (profile == BluetoothProfile.VOLUME_CONTROL) {
BluetoothVolumeControl vcs = new BluetoothVolumeControl(context, listener, this);
return true;
+ } else if (profile == BluetoothProfile.CSIP_SET_COORDINATOR) {
+ BluetoothCsipSetCoordinator csipSetCoordinator =
+ new BluetoothCsipSetCoordinator(context, listener);
+ return true;
} else {
return false;
}
@@ -2908,6 +2912,11 @@ public final class BluetoothAdapter {
BluetoothVolumeControl vcs = (BluetoothVolumeControl) proxy;
vcs.close();
break;
+ case BluetoothProfile.CSIP_SET_COORDINATOR:
+ BluetoothCsipSetCoordinator csipSetCoordinator =
+ (BluetoothCsipSetCoordinator) proxy;
+ csipSetCoordinator.close();
+ break;
}
}
diff --git a/core/java/android/bluetooth/BluetoothCsipSetCoordinator.java b/core/java/android/bluetooth/BluetoothCsipSetCoordinator.java
new file mode 100644
index 000000000000..cb542e5ba388
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothCsipSetCoordinator.java
@@ -0,0 +1,550 @@
+/*
+ * Copyright 2021 HIMSA II K/S - www.himsa.com.
+ * Represented by EHIMA - www.ehima.com
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.Manifest;
+import android.annotation.CallbackExecutor;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SystemApi;
+import android.content.Context;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.ParcelUuid;
+import android.os.RemoteException;
+import android.util.CloseGuard;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.Executor;
+
+/**
+ * This class provides the public APIs to control the Bluetooth CSIP set coordinator.
+ *
+ * <p>BluetoothCsipSetCoordinator is a proxy object for controlling the Bluetooth VC
+ * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
+ * the BluetoothCsipSetCoordinator proxy object.
+ *
+ */
+public final class BluetoothCsipSetCoordinator implements BluetoothProfile, AutoCloseable {
+ private static final String TAG = "BluetoothCsipSetCoordinator";
+ private static final boolean DBG = false;
+ private static final boolean VDBG = false;
+
+ private CloseGuard mCloseGuard;
+
+ /**
+ * @hide
+ */
+ @SystemApi
+ public interface ClientLockCallback {
+ /**
+ * @hide
+ */
+ @SystemApi void onGroupLockSet(int groupId, int opStatus, boolean isLocked);
+ }
+
+ private static class BluetoothCsipSetCoordinatorLockCallbackDelegate
+ extends IBluetoothCsipSetCoordinatorLockCallback.Stub {
+ private final ClientLockCallback mCallback;
+ private final Executor mExecutor;
+
+ BluetoothCsipSetCoordinatorLockCallbackDelegate(
+ Executor executor, ClientLockCallback callback) {
+ mExecutor = executor;
+ mCallback = callback;
+ }
+
+ @Override
+ public void onGroupLockSet(int groupId, int opStatus, boolean isLocked) {
+ mExecutor.execute(() -> mCallback.onGroupLockSet(groupId, opStatus, isLocked));
+ }
+ };
+
+ /**
+ * Intent used to broadcast the change in connection state of the CSIS
+ * Client.
+ *
+ * <p>This intent will have 3 extras:
+ * <ul>
+ * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
+ * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li>
+ * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
+ * </ul>
+ *
+ * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
+ * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
+ * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
+ */
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH)
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_CSIS_CONNECTION_STATE_CHANGED =
+ "android.bluetooth.action.CSIS_CONNECTION_STATE_CHANGED";
+
+ /**
+ * Intent used to expose broadcast receiving device.
+ *
+ * <p>This intent will have 2 extras:
+ * <ul>
+ * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote Broadcast receiver device. </li>
+ * <li> {@link #EXTRA_CSIS_GROUP_ID} - Group identifier. </li>
+ * <li> {@link #EXTRA_CSIS_GROUP_SIZE} - Group size. </li>
+ * <li> {@link #EXTRA_CSIS_GROUP_TYPE_UUID} - Group type UUID. </li>
+ * </ul>
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_CSIS_DEVICE_AVAILABLE =
+ "android.bluetooth.action.CSIS_DEVICE_AVAILABLE";
+
+ /**
+ * Used as an extra field in {@link #ACTION_CSIS_DEVICE_AVAILABLE} intent.
+ * Contains the group id.
+ *
+ * @hide
+ */
+ public static final String EXTRA_CSIS_GROUP_ID = "android.bluetooth.extra.CSIS_GROUP_ID";
+
+ /**
+ * Group size as int extra field in {@link #ACTION_CSIS_DEVICE_AVAILABLE} intent.
+ *
+ * @hide
+ */
+ public static final String EXTRA_CSIS_GROUP_SIZE = "android.bluetooth.extra.CSIS_GROUP_SIZE";
+
+ /**
+ * Group type uuid extra field in {@link #ACTION_CSIS_DEVICE_AVAILABLE} intent.
+ *
+ * @hide
+ */
+ public static final String EXTRA_CSIS_GROUP_TYPE_UUID =
+ "android.bluetooth.extra.CSIS_GROUP_TYPE_UUID";
+
+ /**
+ * Intent used to broadcast information about identified set member
+ * ready to connect.
+ *
+ * <p>This intent will have one extra:
+ * <ul>
+ * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. It can
+ * be null if no device is active. </li>
+ * <li> {@link #EXTRA_CSIS_GROUP_ID} - Group identifier. </li>
+ * </ul>
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_CSIS_SET_MEMBER_AVAILABLE =
+ "android.bluetooth.action.CSIS_SET_MEMBER_AVAILABLE";
+
+ /**
+ * This represents an invalid group ID.
+ *
+ * @hide
+ */
+ public static final int GROUP_ID_INVALID = IBluetoothCsipSetCoordinator.CSIS_GROUP_ID_INVALID;
+
+ /**
+ * Indicating that group was locked with success.
+ *
+ * @hide
+ */
+ public static final int GROUP_LOCK_SUCCESS = 0;
+
+ /**
+ * Indicating that group locked failed due to invalid group ID.
+ *
+ * @hide
+ */
+ public static final int GROUP_LOCK_FAILED_INVALID_GROUP = 1;
+
+ /**
+ * Indicating that group locked failed due to empty group.
+ *
+ * @hide
+ */
+ public static final int GROUP_LOCK_FAILED_GROUP_EMPTY = 2;
+
+ /**
+ * Indicating that group locked failed due to group members being disconnected.
+ *
+ * @hide
+ */
+ public static final int GROUP_LOCK_FAILED_GROUP_NOT_CONNECTED = 3;
+
+ /**
+ * Indicating that group locked failed due to group member being already locked.
+ *
+ * @hide
+ */
+ public static final int GROUP_LOCK_FAILED_LOCKED_BY_OTHER = 4;
+
+ /**
+ * Indicating that group locked failed due to other reason.
+ *
+ * @hide
+ */
+ public static final int GROUP_LOCK_FAILED_OTHER_REASON = 5;
+
+ /**
+ * Indicating that group member in locked state was lost.
+ *
+ * @hide
+ */
+ public static final int LOCKED_GROUP_MEMBER_LOST = 6;
+
+ private BluetoothAdapter mAdapter;
+ private final BluetoothProfileConnector<IBluetoothCsipSetCoordinator> mProfileConnector =
+ new BluetoothProfileConnector(this, BluetoothProfile.CSIP_SET_COORDINATOR, TAG,
+ IBluetoothCsipSetCoordinator.class.getName()) {
+ @Override
+ public IBluetoothCsipSetCoordinator getServiceInterface(IBinder service) {
+ return IBluetoothCsipSetCoordinator.Stub.asInterface(
+ Binder.allowBlocking(service));
+ }
+ };
+
+ /**
+ * Create a BluetoothCsipSetCoordinator proxy object for interacting with the local
+ * Bluetooth CSIS service.
+ */
+ /*package*/ BluetoothCsipSetCoordinator(Context context, ServiceListener listener) {
+ mAdapter = BluetoothAdapter.getDefaultAdapter();
+ mProfileConnector.connect(context, listener);
+ mCloseGuard = new CloseGuard();
+ mCloseGuard.open("close");
+ }
+
+ /**
+ * @hide
+ */
+ protected void finalize() {
+ if (mCloseGuard != null) {
+ mCloseGuard.warnIfOpen();
+ }
+ close();
+ }
+
+ /**
+ * @hide
+ */
+ public void close() {
+ mProfileConnector.disconnect();
+ }
+
+ private IBluetoothCsipSetCoordinator getService() {
+ return mProfileConnector.getService();
+ }
+
+ /**
+ * Lock the set.
+ * @param groupId group ID to lock,
+ * @param executor callback executor,
+ * @param cb callback to report lock and unlock events - stays valid until the app unlocks
+ * using the returned lock identifier or the lock timeouts on the remote side,
+ * as per CSIS specification,
+ * @return unique lock identifier used for unlocking or null if lock has failed.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ public
+ @Nullable UUID groupLock(int groupId, @Nullable @CallbackExecutor Executor executor,
+ @Nullable ClientLockCallback cb) {
+ if (VDBG) {
+ log("groupLockSet()");
+ }
+ final IBluetoothCsipSetCoordinator service = getService();
+ try {
+ if (service != null && isEnabled()) {
+ IBluetoothCsipSetCoordinatorLockCallback delegate = null;
+ if ((executor != null) && (cb != null)) {
+ delegate = new BluetoothCsipSetCoordinatorLockCallbackDelegate(executor, cb);
+ }
+ return service.groupLock(groupId, delegate).getUuid();
+ }
+ if (service == null) {
+ Log.w(TAG, "Proxy not attached to service");
+ }
+ return null;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return null;
+ }
+ }
+
+ /**
+ * Unlock the set.
+ * @param lockUuid unique lock identifier
+ * @return true if unlocked, false on error
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ public boolean groupUnlock(@NonNull UUID lockUuid) {
+ if (VDBG) {
+ log("groupLockSet()");
+ }
+ if (lockUuid == null) {
+ return false;
+ }
+
+ final IBluetoothCsipSetCoordinator service = getService();
+ try {
+ if (service != null && isEnabled()) {
+ service.groupUnlock(new ParcelUuid(lockUuid));
+ return true;
+ }
+ if (service == null) {
+ Log.w(TAG, "Proxy not attached to service");
+ }
+ return false;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return false;
+ }
+ }
+
+ /**
+ * Get device's groups.
+ * @param device the active device
+ * @return Map of groups ids and related UUIDs
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ public @NonNull Map getGroupUuidMapByDevice(@Nullable BluetoothDevice device) {
+ if (VDBG) {
+ log("getGroupUuidMapByDevice()");
+ }
+ final IBluetoothCsipSetCoordinator service = getService();
+ try {
+ if (service != null && isEnabled()) {
+ return service.getGroupUuidMapByDevice(device);
+ }
+ if (service == null) {
+ Log.w(TAG, "Proxy not attached to service");
+ }
+ return new HashMap<>();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return new HashMap<>();
+ }
+ }
+
+ /**
+ * Get group id for the given UUID
+ * @param uuid
+ * @return list of group IDs
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ public @NonNull List<Integer> getAllGroupIds(@Nullable ParcelUuid uuid) {
+ if (VDBG) {
+ log("getAllGroupIds()");
+ }
+ final IBluetoothCsipSetCoordinator service = getService();
+ try {
+ if (service != null && isEnabled()) {
+ return service.getAllGroupIds(uuid);
+ }
+ if (service == null) {
+ Log.w(TAG, "Proxy not attached to service");
+ }
+ return new ArrayList<Integer>();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return new ArrayList<Integer>();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public @NonNull List<BluetoothDevice> getConnectedDevices() {
+ if (VDBG) {
+ log("getConnectedDevices()");
+ }
+ final IBluetoothCsipSetCoordinator service = getService();
+ if (service != null && isEnabled()) {
+ try {
+ return service.getConnectedDevices();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return new ArrayList<BluetoothDevice>();
+ }
+ }
+ if (service == null) {
+ Log.w(TAG, "Proxy not attached to service");
+ }
+ return new ArrayList<BluetoothDevice>();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public
+ @NonNull List<BluetoothDevice> getDevicesMatchingConnectionStates(
+ @NonNull int[] states) {
+ if (VDBG) {
+ log("getDevicesMatchingStates(states=" + Arrays.toString(states) + ")");
+ }
+ final IBluetoothCsipSetCoordinator service = getService();
+ if (service != null && isEnabled()) {
+ try {
+ return service.getDevicesMatchingConnectionStates(states);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return new ArrayList<BluetoothDevice>();
+ }
+ }
+ if (service == null) {
+ Log.w(TAG, "Proxy not attached to service");
+ }
+ return new ArrayList<BluetoothDevice>();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public
+ @BluetoothProfile.BtProfileState int getConnectionState(
+ @Nullable BluetoothDevice device) {
+ if (VDBG) {
+ log("getState(" + device + ")");
+ }
+ final IBluetoothCsipSetCoordinator service = getService();
+ if (service != null && isEnabled() && isValidDevice(device)) {
+ try {
+ return service.getConnectionState(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return BluetoothProfile.STATE_DISCONNECTED;
+ }
+ }
+ if (service == null) {
+ Log.w(TAG, "Proxy not attached to service");
+ }
+ return BluetoothProfile.STATE_DISCONNECTED;
+ }
+
+ /**
+ * Set connection policy of the profile
+ *
+ * <p> The device should already be paired.
+ * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED},
+ * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN}
+ *
+ * @param device Paired bluetooth device
+ * @param connectionPolicy is the connection policy to set to for this profile
+ * @return true if connectionPolicy is set, false on error
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ public boolean setConnectionPolicy(
+ @Nullable BluetoothDevice device, @ConnectionPolicy int connectionPolicy) {
+ if (DBG) {
+ log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
+ }
+ final IBluetoothCsipSetCoordinator service = getService();
+ try {
+ if (service != null && isEnabled() && isValidDevice(device)) {
+ if (connectionPolicy != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN
+ && connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
+ return false;
+ }
+ return service.setConnectionPolicy(device, connectionPolicy);
+ }
+ if (service == null) {
+ Log.w(TAG, "Proxy not attached to service");
+ }
+ return false;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return false;
+ }
+ }
+
+ /**
+ * Get the connection policy of the profile.
+ *
+ * <p> The connection policy can be any of:
+ * {@link #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN},
+ * {@link #CONNECTION_POLICY_UNKNOWN}
+ *
+ * @param device Bluetooth device
+ * @return connection policy of the device
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ public @ConnectionPolicy int getConnectionPolicy(@Nullable BluetoothDevice device) {
+ if (VDBG) {
+ log("getConnectionPolicy(" + device + ")");
+ }
+ final IBluetoothCsipSetCoordinator service = getService();
+ try {
+ if (service != null && isEnabled() && isValidDevice(device)) {
+ return service.getConnectionPolicy(device);
+ }
+ if (service == null) {
+ Log.w(TAG, "Proxy not attached to service");
+ }
+ return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+ }
+ }
+
+ private boolean isEnabled() {
+ return mAdapter.getState() == BluetoothAdapter.STATE_ON;
+ }
+
+ private static boolean isValidDevice(@Nullable BluetoothDevice device) {
+ return device != null && BluetoothAdapter.checkBluetoothAddress(device.getAddress());
+ }
+
+ private static void log(String msg) {
+ Log.d(TAG, msg);
+ }
+}
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 38fb90d9c4a7..b5ede8d1cdb6 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -106,7 +106,7 @@ public final class BluetoothDevice implements Parcelable {
* <p>Sent when a remote device is found during discovery.
* <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link
* #EXTRA_CLASS}. Can contain the extra fields {@link #EXTRA_NAME} and/or
- * {@link #EXTRA_RSSI} if they are available.
+ * {@link #EXTRA_RSSI} and/or {@link #EXTRA_IS_COORDINATED_SET_MEMBER} if they are available.
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} and
* {@link android.Manifest.permission#ACCESS_COARSE_LOCATION} to receive.
*/
@@ -257,6 +257,15 @@ public final class BluetoothDevice implements Parcelable {
public static final String EXTRA_RSSI = "android.bluetooth.device.extra.RSSI";
/**
+ * Used as an bool extra field in {@link #ACTION_FOUND} intents.
+ * It contains the information if device is discovered as member of a coordinated set or not.
+ * Pairing with device that belongs to a set would trigger pairing with the rest of set members.
+ * See Bluetooth CSIP specification for more details.
+ */
+ public static final String EXTRA_IS_COORDINATED_SET_MEMBER =
+ "android.bluetooth.extra.IS_COORDINATED_SET_MEMBER";
+
+ /**
* Used as a Parcelable {@link BluetoothClass} extra field in {@link
* #ACTION_FOUND} and {@link #ACTION_CLASS_CHANGED} intents.
*/
diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java
index 632572dea3c6..18aa23a07b87 100644
--- a/core/java/android/bluetooth/BluetoothHeadset.java
+++ b/core/java/android/bluetooth/BluetoothHeadset.java
@@ -1018,8 +1018,8 @@ public final class BluetoothHeadset implements BluetoothProfile {
* - binder is dead or Bluetooth is disabled or other error
* @hide
*/
+ @SystemApi
@RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
- @UnsupportedAppUsage
public boolean startScoUsingVirtualVoiceCall() {
if (DBG) log("startScoUsingVirtualVoiceCall()");
final IBluetoothHeadset service = mService;
@@ -1048,8 +1048,8 @@ public final class BluetoothHeadset implements BluetoothProfile {
* - binder is dead or Bluetooth is disabled or other error
* @hide
*/
+ @SystemApi
@RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
- @UnsupportedAppUsage
public boolean stopScoUsingVirtualVoiceCall() {
if (DBG) log("stopScoUsingVirtualVoiceCall()");
final IBluetoothHeadset service = mService;
@@ -1227,7 +1227,8 @@ public final class BluetoothHeadset implements BluetoothProfile {
* @return true if in-band ringing is enabled, false if in-band ringing is disabled
* @hide
*/
- @RequiresPermission(android.Manifest.permission.BLUETOOTH)
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
public boolean isInbandRingingEnabled() {
if (DBG) {
log("isInbandRingingEnabled()");
diff --git a/core/java/android/content/pm/parsing/component/ParsedIntentInfo.java b/core/java/android/content/pm/parsing/component/ParsedIntentInfo.java
index 0ba92cc4fef7..504a7bd5a320 100644
--- a/core/java/android/content/pm/parsing/component/ParsedIntentInfo.java
+++ b/core/java/android/content/pm/parsing/component/ParsedIntentInfo.java
@@ -19,7 +19,6 @@ package android.content.pm.parsing.component;
import android.annotation.Nullable;
import android.content.IntentFilter;
import android.os.Parcel;
-import android.os.Parcelable;
import android.util.Pair;
import com.android.internal.util.DataClass;
@@ -168,19 +167,6 @@ public final class ParsedIntentInfo extends IntentFilter {
+ '}';
}
- public static final Parcelable.Creator<ParsedIntentInfo> CREATOR =
- new Parcelable.Creator<ParsedIntentInfo>() {
- @Override
- public ParsedIntentInfo createFromParcel(Parcel source) {
- return new ParsedIntentInfo(source);
- }
-
- @Override
- public ParsedIntentInfo[] newArray(int size) {
- return new ParsedIntentInfo[size];
- }
- };
-
public boolean isHasDefault() {
return hasDefault;
}
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index 0a76a9c6bee3..9e78a6bb4760 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -1440,14 +1440,14 @@ public abstract class SensorManager {
* Assuming that the bottom edge of the device faces the
* user and that the screen is face-up, tilting the top edge
* of the device toward the ground creates a positive pitch
- * angle. The range of values is -&pi; to &pi;.</li>
+ * angle. The range of values is -&pi;/2 to &pi;/2.</li>
* <li>values[2]: <i>Roll</i>, angle of rotation about the y axis. This
* value represents the angle between a plane perpendicular
* to the device's screen and a plane perpendicular to the
* ground. Assuming that the bottom edge of the device faces
* the user and that the screen is face-up, tilting the left
* edge of the device toward the ground creates a positive
- * roll angle. The range of values is -&pi;/2 to &pi;/2.</li>
+ * roll angle. The range of values is -&pi; to &pi;.</li>
* </ul>
* <p>
* Applying these three rotations in the azimuth, pitch, roll order
diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
index 68917a82884b..08f75df5d82d 100644
--- a/core/java/android/net/NetworkTemplate.java
+++ b/core/java/android/net/NetworkTemplate.java
@@ -47,7 +47,6 @@ import android.text.TextUtils;
import android.util.BackupUtils;
import android.util.Log;
-import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import com.android.net.module.util.NetworkIdentityUtils;
@@ -151,24 +150,6 @@ public class NetworkTemplate implements Parcelable {
}
}
- private static boolean sForceAllNetworkTypes = false;
-
- /**
- * Results in matching against all mobile network types.
- *
- * <p>See {@link #matchesMobile} and {@link matchesMobileWildcard}.
- */
- @VisibleForTesting
- public static void forceAllNetworkTypes() {
- sForceAllNetworkTypes = true;
- }
-
- /** Resets the affect of {@link #forceAllNetworkTypes}. */
- @VisibleForTesting
- public static void resetForceAllNetworkTypes() {
- sForceAllNetworkTypes = false;
- }
-
/**
* Template to match {@link ConnectivityManager#TYPE_MOBILE} networks with
* the given IMSI.
@@ -611,7 +592,7 @@ public class NetworkTemplate implements Parcelable {
// 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 (sForceAllNetworkTypes || (ident.mType == TYPE_MOBILE && ident.mMetered))
+ return (ident.mType == TYPE_MOBILE && ident.mMetered)
&& !ArrayUtils.isEmpty(mMatchSubscriberIds)
&& ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId)
&& matchesCollapsedRatType(ident);
@@ -726,7 +707,7 @@ public class NetworkTemplate implements Parcelable {
if (ident.mType == TYPE_WIMAX) {
return true;
} else {
- return (sForceAllNetworkTypes || (ident.mType == TYPE_MOBILE && ident.mMetered))
+ return (ident.mType == TYPE_MOBILE && ident.mMetered)
&& matchesCollapsedRatType(ident);
}
}
diff --git a/core/java/android/os/ISystemConfig.aidl b/core/java/android/os/ISystemConfig.aidl
index 4d160da22ff8..d83d94a8ec77 100644
--- a/core/java/android/os/ISystemConfig.aidl
+++ b/core/java/android/os/ISystemConfig.aidl
@@ -40,4 +40,9 @@ interface ISystemConfig {
* @see SystemConfigManager#getSystemPermissionUids
*/
int[] getSystemPermissionUids(String permissionName);
+
+ /**
+ * @see SystemConfigManager#getEnabledComponentOverrides
+ */
+ List<String> getEnabledComponentOverrides(String packageName);
}
diff --git a/core/java/android/os/OutcomeReceiver.java b/core/java/android/os/OutcomeReceiver.java
new file mode 100644
index 000000000000..01b276411446
--- /dev/null
+++ b/core/java/android/os/OutcomeReceiver.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2020 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;
+
+/**
+ * Callback interface intended for use when an asynchronous operation may result in a failure.
+ *
+ * This interface may be used in cases where an asynchronous API may complete either with a value
+ * or with a {@link Throwable} that indicates an error.
+ * @param <R> The type of the result that's being sent.
+ * @param <E> The type of the {@link Throwable} that contains more information about the error.
+ */
+public interface OutcomeReceiver<R, E extends Throwable> {
+ /**
+ * Called when the asynchronous operation succeeds and delivers a result value.
+ * @param result The value delivered by the asynchronous operation.
+ */
+ void onResult(@NonNull R result);
+
+ /**
+ * Called when the asynchronous operation fails. The mode of failure is indicated by the
+ * {@link Throwable} passed as an argument to this method.
+ * @param error A subclass of {@link Throwable} with more details about the error that occurred.
+ */
+ default void onError(@NonNull E error) {}
+}
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 00db972bf709..a2716d211bbf 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -282,6 +282,8 @@ public final class Parcel {
@CriticalNative
private static native void nativeMarkSensitive(long nativePtr);
+ @FastNative
+ private static native void nativeMarkForBinder(long nativePtr, IBinder binder);
@CriticalNative
private static native int nativeDataSize(long nativePtr);
@CriticalNative
@@ -498,6 +500,16 @@ public final class Parcel {
/**
* Parcel data should be zero'd before realloc'd or deleted.
+ *
+ * Note: currently this feature requires multiple things to work in concert:
+ * - markSensitive must be called on every relative Parcel
+ * - FLAG_CLEAR_BUF must be passed into the kernel
+ * This requires having code which does the right thing in every method and in every backend
+ * of AIDL. Rather than exposing this API, it should be replaced with a single API on
+ * IBinder objects which can be called once, and the information should be fed into the
+ * Parcel using markForBinder APIs. In terms of code size and number of API calls, this is
+ * much more extensible.
+ *
* @hide
*/
public final void markSensitive() {
@@ -505,9 +517,23 @@ public final class Parcel {
}
/**
+ * Associate this parcel with a binder object. This marks the parcel as being prepared for a
+ * transaction on this specific binder object. Based on this, the format of the wire binder
+ * protocol may change. This should be called before any data is written to the parcel. If this
+ * is called multiple times, this will only be marked for the last binder. For future
+ * compatibility, it is recommended to call this on all parcels which are being sent over
+ * binder.
+ *
+ * @hide
+ */
+ public void markForBinder(@NonNull IBinder binder) {
+ nativeMarkForBinder(mNativePtr, binder);
+ }
+
+ /**
* Returns the total amount of data contained in the parcel.
*/
- public final int dataSize() {
+ public int dataSize() {
return nativeDataSize(mNativePtr);
}
@@ -3419,15 +3445,7 @@ public final class Parcel {
public void writeToParcel(Parcel out) {
if (mObject == null) {
- int restore = mSource.dataPosition();
- try {
- mSource.setDataPosition(mPosition);
- out.writeInt(mSource.readInt()); // Type
- out.writeInt(mSource.readInt()); // Length
- out.appendFrom(mSource, mSource.dataPosition(), mLength);
- } finally {
- mSource.setDataPosition(restore);
- }
+ out.appendFrom(mSource, mPosition, mLength + 8);
} else {
out.writeValue(mObject);
}
diff --git a/core/java/android/os/ServiceManager.java b/core/java/android/os/ServiceManager.java
index 06a2c875cf4f..4e8418bd60ec 100644
--- a/core/java/android/os/ServiceManager.java
+++ b/core/java/android/os/ServiceManager.java
@@ -29,7 +29,14 @@ import com.android.internal.util.StatLogger;
import java.util.Map;
-/** @hide */
+/**
+ * Manage binder services as registered with the binder context manager. These services must be
+ * declared statically on an Android device (SELinux access_vector service_manager, w/ service
+ * names in service_contexts files), and they do not follow the activity lifecycle. When
+ * building applications, android.app.Service should be preferred.
+ *
+ * @hide
+ **/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public final class ServiceManager {
private static final String TAG = "ServiceManager";
diff --git a/core/java/android/os/SystemConfigManager.java b/core/java/android/os/SystemConfigManager.java
index 9bfa8adc8571..a6316df0780c 100644
--- a/core/java/android/os/SystemConfigManager.java
+++ b/core/java/android/os/SystemConfigManager.java
@@ -17,6 +17,7 @@ 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;
@@ -129,4 +130,21 @@ public class SystemConfigManager {
throw e.rethrowFromSystemServer();
}
}
+
+ /**
+ * Get enabled component for a specific package
+ *
+ * @param packageName The target package.
+ * @return The enabled component
+ * {@hide}
+ */
+ @SystemApi
+ @NonNull
+ public List<String> getEnabledComponentOverrides(@NonNull String packageName) {
+ try {
+ return mInterface.getEnabledComponentOverrides(packageName);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/os/connectivity/CellularBatteryStats.java b/core/java/android/os/connectivity/CellularBatteryStats.java
index 121fd333d17f..fc17002ba056 100644
--- a/core/java/android/os/connectivity/CellularBatteryStats.java
+++ b/core/java/android/os/connectivity/CellularBatteryStats.java
@@ -109,7 +109,7 @@ public final class CellularBatteryStats implements Parcelable {
CellSignalStrength.getNumSignalStrengthLevels()));
mTxTimeMs = Arrays.copyOfRange(
txTimeMs, 0,
- Math.min(txTimeMs.length, ModemActivityInfo.TX_POWER_LEVELS));
+ Math.min(txTimeMs.length, ModemActivityInfo.getNumTxPowerLevels()));
mMonitoredRailChargeConsumedMaMs = monitoredRailChargeConsumedMaMs;
}
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index f0f0867d414b..505f400c60d2 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -2351,7 +2351,10 @@ public abstract class Layout {
final int ellipsisStringLen = ellipsisString.length();
// Use the ellipsis string only if there are that at least as many characters to replace.
final boolean useEllipsisString = ellipsisCount >= ellipsisStringLen;
- for (int i = 0; i < ellipsisCount; i++) {
+ final int min = Math.max(0, start - ellipsisStart - lineStart);
+ final int max = Math.min(ellipsisCount, end - ellipsisStart - lineStart);
+
+ for (int i = min; i < max; i++) {
final char c;
if (useEllipsisString && i < ellipsisStringLen) {
c = ellipsisString.charAt(i);
@@ -2360,9 +2363,7 @@ public abstract class Layout {
}
final int a = i + ellipsisStart + lineStart;
- if (start <= a && a < end) {
- dest[destoff + a - start] = c;
- }
+ dest[destoff + a - start] = c;
}
}
diff --git a/core/java/android/webkit/URLUtil.java b/core/java/android/webkit/URLUtil.java
index 844b156b84d3..c7609a6c18af 100644
--- a/core/java/android/webkit/URLUtil.java
+++ b/core/java/android/webkit/URLUtil.java
@@ -310,7 +310,7 @@ public final class URLUtil {
String extension = null;
// If we couldn't do anything with the hint, move toward the content disposition
- if (filename == null && contentDisposition != null) {
+ if (contentDisposition != null) {
filename = parseContentDisposition(contentDisposition);
if (filename != null) {
int index = filename.lastIndexOf('/') + 1;
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index dd2940f8c110..e8db609ee991 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -66,7 +66,6 @@ import android.provider.Settings;
import android.telephony.CellSignalStrength;
import android.telephony.DataConnectionRealTimeInfo;
import android.telephony.ModemActivityInfo;
-import android.telephony.ModemActivityInfo.TransmitPower;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.TelephonyManager;
@@ -7205,7 +7204,7 @@ public class BatteryStatsImpl extends BatteryStats {
public ControllerActivityCounterImpl getOrCreateModemControllerActivityLocked() {
if (mModemControllerActivity == null) {
mModemControllerActivity = new ControllerActivityCounterImpl(mBsi.mOnBatteryTimeBase,
- ModemActivityInfo.TX_POWER_LEVELS);
+ ModemActivityInfo.getNumTxPowerLevels());
}
return mModemControllerActivity;
}
@@ -8687,7 +8686,7 @@ public class BatteryStatsImpl extends BatteryStats {
if (in.readInt() != 0) {
mModemControllerActivity = new ControllerActivityCounterImpl(mBsi.mOnBatteryTimeBase,
- ModemActivityInfo.TX_POWER_LEVELS, in);
+ ModemActivityInfo.getNumTxPowerLevels(), in);
} else {
mModemControllerActivity = null;
}
@@ -9953,7 +9952,7 @@ public class BatteryStatsImpl extends BatteryStats {
mBluetoothActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
NUM_BT_TX_LEVELS);
mModemActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
- ModemActivityInfo.TX_POWER_LEVELS);
+ ModemActivityInfo.getNumTxPowerLevels());
mMobileRadioActiveTimer = new StopwatchTimer(mClocks, null, -400, null, mOnBatteryTimeBase);
mMobileRadioActivePerAppTimer = new StopwatchTimer(mClocks, null, -401, null,
mOnBatteryTimeBase);
@@ -11131,26 +11130,7 @@ public class BatteryStatsImpl extends BatteryStats {
}
}
- private ModemActivityInfo mLastModemActivityInfo =
- new ModemActivityInfo(0, 0, 0, new int[0], 0);
-
- private ModemActivityInfo getDeltaModemActivityInfo(ModemActivityInfo activityInfo) {
- if (activityInfo == null) {
- return null;
- }
- int[] txTimeMs = new int[ModemActivityInfo.TX_POWER_LEVELS];
- for (int i = 0; i < ModemActivityInfo.TX_POWER_LEVELS; i++) {
- txTimeMs[i] = activityInfo.getTransmitPowerInfo().get(i).getTimeInMillis()
- - mLastModemActivityInfo.getTransmitPowerInfo().get(i).getTimeInMillis();
- }
- ModemActivityInfo deltaInfo = new ModemActivityInfo(activityInfo.getTimestamp(),
- activityInfo.getSleepTimeMillis() - mLastModemActivityInfo.getSleepTimeMillis(),
- activityInfo.getIdleTimeMillis() - mLastModemActivityInfo.getIdleTimeMillis(),
- txTimeMs,
- activityInfo.getReceiveTimeMillis() - mLastModemActivityInfo.getReceiveTimeMillis());
- mLastModemActivityInfo = activityInfo;
- return deltaInfo;
- }
+ private ModemActivityInfo mLastModemActivityInfo = null;
/**
* Distribute Cell radio energy info and network traffic to apps.
@@ -11159,7 +11139,9 @@ public class BatteryStatsImpl extends BatteryStats {
if (DEBUG_ENERGY) {
Slog.d(TAG, "Updating mobile radio stats with " + activityInfo);
}
- ModemActivityInfo deltaInfo = getDeltaModemActivityInfo(activityInfo);
+ ModemActivityInfo deltaInfo = mLastModemActivityInfo == null ? activityInfo
+ : mLastModemActivityInfo.getDelta(activityInfo);
+ mLastModemActivityInfo = activityInfo;
// Add modem tx power to history.
addModemTxPowerToHistory(deltaInfo);
@@ -11191,10 +11173,9 @@ public class BatteryStatsImpl extends BatteryStats {
mModemActivity.getSleepTimeCounter().addCountLocked(
deltaInfo.getSleepTimeMillis());
mModemActivity.getRxTimeCounter().addCountLocked(deltaInfo.getReceiveTimeMillis());
- for (int lvl = 0; lvl < ModemActivityInfo.TX_POWER_LEVELS; lvl++) {
+ for (int lvl = 0; lvl < ModemActivityInfo.getNumTxPowerLevels(); lvl++) {
mModemActivity.getTxTimeCounters()[lvl]
- .addCountLocked(deltaInfo.getTransmitPowerInfo()
- .get(lvl).getTimeInMillis());
+ .addCountLocked(deltaInfo.getTransmitDurationMillisAtPowerLevel(lvl));
}
// POWER_MODEM_CONTROLLER_OPERATING_VOLTAGE is measured in mV, so convert to V.
@@ -11208,11 +11189,11 @@ public class BatteryStatsImpl extends BatteryStats {
mPowerProfile.getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_IDLE)
+ deltaInfo.getReceiveTimeMillis() *
mPowerProfile.getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_RX);
- List<TransmitPower> txPowerInfo = deltaInfo.getTransmitPowerInfo();
- for (int i = 0; i < Math.min(txPowerInfo.size(),
+ for (int i = 0; i < Math.min(ModemActivityInfo.getNumTxPowerLevels(),
CellSignalStrength.getNumSignalStrengthLevels()); i++) {
- energyUsed += txPowerInfo.get(i).getTimeInMillis() * mPowerProfile
- .getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_TX, i);
+ energyUsed += deltaInfo.getTransmitDurationMillisAtPowerLevel(i)
+ * mPowerProfile.getAveragePower(
+ PowerProfile.POWER_MODEM_CONTROLLER_TX, i);
}
// We store the power drain as mAms.
@@ -11307,10 +11288,10 @@ public class BatteryStatsImpl extends BatteryStats {
}
if (totalTxPackets > 0 && entry.txPackets > 0) {
- for (int lvl = 0; lvl < ModemActivityInfo.TX_POWER_LEVELS; lvl++) {
- long txMs =
- entry.txPackets * deltaInfo.getTransmitPowerInfo()
- .get(lvl).getTimeInMillis();
+ for (int lvl = 0; lvl < ModemActivityInfo.getNumTxPowerLevels();
+ lvl++) {
+ long txMs = entry.txPackets
+ * deltaInfo.getTransmitDurationMillisAtPowerLevel(lvl);
txMs /= totalTxPackets;
activityCounter.getTxTimeCounters()[lvl].addCountLocked(txMs);
}
@@ -11341,20 +11322,16 @@ public class BatteryStatsImpl extends BatteryStats {
if (activityInfo == null) {
return;
}
- List<TransmitPower> txPowerInfo = activityInfo.getTransmitPowerInfo();
- if (txPowerInfo == null || txPowerInfo.size() != ModemActivityInfo.TX_POWER_LEVELS) {
- return;
- }
final long elapsedRealtime = mClocks.elapsedRealtime();
final long uptime = mClocks.uptimeMillis();
int levelMaxTimeSpent = 0;
- for (int i = 1; i < txPowerInfo.size(); i++) {
- if (txPowerInfo.get(i).getTimeInMillis() > txPowerInfo.get(levelMaxTimeSpent)
- .getTimeInMillis()) {
+ for (int i = 1; i < ModemActivityInfo.getNumTxPowerLevels(); i++) {
+ if (activityInfo.getTransmitDurationMillisAtPowerLevel(i)
+ > activityInfo.getTransmitDurationMillisAtPowerLevel(levelMaxTimeSpent)) {
levelMaxTimeSpent = i;
}
}
- if (levelMaxTimeSpent == ModemActivityInfo.TX_POWER_LEVELS - 1) {
+ if (levelMaxTimeSpent == ModemActivityInfo.getNumTxPowerLevels() - 1) {
mHistoryCur.states2 |= HistoryItem.STATE2_CELLULAR_HIGH_TX_POWER_FLAG;
addHistoryRecordLocked(elapsedRealtime, uptime);
}
@@ -12771,7 +12748,7 @@ public class BatteryStatsImpl extends BatteryStats {
timeInRxSignalStrengthLevelMs[i]
= getPhoneSignalStrengthTime(i, rawRealTime, which) / 1000;
}
- long[] txTimeMs = new long[Math.min(ModemActivityInfo.TX_POWER_LEVELS,
+ long[] txTimeMs = new long[Math.min(ModemActivityInfo.getNumTxPowerLevels(),
counter.getTxTimeCounters().length)];
long totalTxTimeMs = 0;
for (int i = 0; i < txTimeMs.length; i++) {
@@ -14817,7 +14794,7 @@ public class BatteryStatsImpl extends BatteryStats {
mBluetoothActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
NUM_BT_TX_LEVELS, in);
mModemActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
- ModemActivityInfo.TX_POWER_LEVELS, in);
+ ModemActivityInfo.getNumTxPowerLevels(), in);
mHasWifiReporting = in.readInt() != 0;
mHasBluetoothReporting = in.readInt() != 0;
mHasModemReporting = in.readInt() != 0;
diff --git a/core/java/com/android/internal/os/OWNERS b/core/java/com/android/internal/os/OWNERS
index ea3b3a7b4056..7766b77ab3c6 100644
--- a/core/java/com/android/internal/os/OWNERS
+++ b/core/java/com/android/internal/os/OWNERS
@@ -10,4 +10,6 @@ per-file BatteryUsageStats* = file:/BATTERY_STATS_OWNERS
per-file *ChargeCalculator* = file:/BATTERY_STATS_OWNERS
per-file *PowerCalculator* = file:/BATTERY_STATS_OWNERS
per-file *PowerEstimator* = file:/BATTERY_STATS_OWNERS
+per-file *Kernel* = file:/BATTERY_STATS_OWNERS
+per-file *MultiState* = file:/BATTERY_STATS_OWNERS
diff --git a/core/java/com/android/internal/util/IState.java b/core/java/com/android/internal/util/IState.java
index 07837bf8f587..41b3d5e0a11f 100644
--- a/core/java/com/android/internal/util/IState.java
+++ b/core/java/com/android/internal/util/IState.java
@@ -27,12 +27,12 @@ import android.os.Message;
public interface IState {
/**
- * Returned by processMessage to indicate the the message was processed.
+ * Returned by processMessage to indicate the message was processed.
*/
static final boolean HANDLED = true;
/**
- * Returned by processMessage to indicate the the message was NOT processed.
+ * Returned by processMessage to indicate the message was NOT processed.
*/
static final boolean NOT_HANDLED = false;
diff --git a/core/java/com/android/internal/util/State.java b/core/java/com/android/internal/util/State.java
index 4613dad8cc67..d5c0f60f4b37 100644
--- a/core/java/com/android/internal/util/State.java
+++ b/core/java/com/android/internal/util/State.java
@@ -16,6 +16,7 @@
package com.android.internal.util;
+import android.annotation.SuppressLint;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
import android.os.Message;
@@ -25,6 +26,7 @@ import android.os.Message;
*
* The class for implementing states in a StateMachine
*/
+@SuppressLint("AndroidFrameworkRequiresPermission")
public class State implements IState {
/**
diff --git a/core/java/com/android/internal/util/StateMachine.java b/core/java/com/android/internal/util/StateMachine.java
index 4cff785cd671..cb8d9d127415 100644
--- a/core/java/com/android/internal/util/StateMachine.java
+++ b/core/java/com/android/internal/util/StateMachine.java
@@ -48,7 +48,7 @@ import java.util.Vector;
* in Object Oriented programming and are used to perform initialization and
* cleanup of the state respectively. The <code>getName</code> method returns the
* name of the state; the default implementation returns the class name. It may be
- * desirable to have <code>getName</code> return the the state instance name instead,
+ * desirable to have <code>getName</code> return the state instance name instead,
* in particular if a particular state class has multiple instances.</p>
*
* <p>When a state machine is created, <code>addState</code> is used to build the
@@ -433,14 +433,14 @@ public class StateMachine {
/**
* Convenience constant that maybe returned by processMessage
- * to indicate the the message was processed and is not to be
+ * to indicate the message was processed and is not to be
* processed by parent states
*/
public static final boolean HANDLED = true;
/**
* Convenience constant that maybe returned by processMessage
- * to indicate the the message was NOT processed and is to be
+ * to indicate the message was NOT processed and is to be
* processed by parent states
*/
public static final boolean NOT_HANDLED = false;
diff --git a/core/jni/OWNERS b/core/jni/OWNERS
index 701960eb4f11..6fb2904ab63c 100644
--- a/core/jni/OWNERS
+++ b/core/jni/OWNERS
@@ -75,3 +75,7 @@ per-file android_view_* = file:/graphics/java/android/graphics/OWNERS
# VINTF
per-file android_os_VintfObject* = file:platform/system/libvintf:/OWNERS
per-file android_os_VintfRuntimeInfo* = file:platform/system/libvintf:/OWNERS
+
+# Battery
+per-file com_android_internal_os_Kernel* = file:/BATTERY_STATS_OWNERS
+per-file com_android_internal_os_*MultiStateCounter* = file:/BATTERY_STATS_OWNERS
diff --git a/core/jni/android_os_Parcel.cpp b/core/jni/android_os_Parcel.cpp
index 241570a7f9d3..ac320386c3f3 100644
--- a/core/jni/android_os_Parcel.cpp
+++ b/core/jni/android_os_Parcel.cpp
@@ -98,6 +98,15 @@ static void android_os_Parcel_markSensitive(jlong nativePtr)
}
}
+static void android_os_Parcel_markForBinder(JNIEnv* env, jclass clazz, jlong nativePtr,
+ jobject binder)
+{
+ Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
+ if (parcel) {
+ parcel->markForBinder(ibinderForJavaObject(env, binder));
+ }
+}
+
static jint android_os_Parcel_dataSize(jlong nativePtr)
{
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
@@ -766,7 +775,9 @@ static jboolean android_os_Parcel_replaceCallingWorkSourceUid(jlong nativePtr, j
static const JNINativeMethod gParcelMethods[] = {
// @CriticalNative
- {"nativeMarkSensitive", "(J)V", (void*)android_os_Parcel_markSensitive},
+ {"nativeMarkSensitive", "(J)V", (void*)android_os_Parcel_markSensitive},
+ // @FastNative
+ {"nativeMarkForBinder", "(JLandroid/os/IBinder;)V", (void*)android_os_Parcel_markForBinder},
// @CriticalNative
{"nativeDataSize", "(J)I", (void*)android_os_Parcel_dataSize},
// @CriticalNative
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 515c08d8517e..288327ef61ba 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -1129,14 +1129,14 @@ static void isolateAppDataPerPackage(int userId, std::string_view package_name,
}
// Relabel directory
-static void relabelDir(const char* path, security_context_t context, fail_fn_t fail_fn) {
+static void relabelDir(const char* path, const char* context, fail_fn_t fail_fn) {
if (setfilecon(path, context) != 0) {
fail_fn(CREATE_ERROR("Failed to setfilecon %s %s", path, strerror(errno)));
}
}
// Relabel all directories under a path non-recursively.
-static void relabelAllDirs(const char* path, security_context_t context, fail_fn_t fail_fn) {
+static void relabelAllDirs(const char* path, const char* context, fail_fn_t fail_fn) {
DIR* dir = opendir(path);
if (dir == nullptr) {
fail_fn(CREATE_ERROR("Failed to opendir %s", path));
@@ -1211,7 +1211,7 @@ static void isolateAppData(JNIEnv* env, const std::vector<std::string>& merged_d
snprintf(internalDePath, PATH_MAX, "/data/user_de");
snprintf(externalPrivateMountPath, PATH_MAX, "/mnt/expand");
- security_context_t dataDataContext = nullptr;
+ char* dataDataContext = nullptr;
if (getfilecon(internalDePath, &dataDataContext) < 0) {
fail_fn(CREATE_ERROR("Unable to getfilecon on %s %s", internalDePath,
strerror(errno)));
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 0135e45c9b54..35a3cde2d8f9 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -196,6 +196,9 @@
android:name="android.bluetooth.hearingaid.profile.action.PLAYING_STATE_CHANGED" />
<protected-broadcast
android:name="android.bluetooth.hearingaid.profile.action.ACTIVE_DEVICE_CHANGED" />
+ <protected-broadcast android:name="android.bluetooth.action.CSIS_CONNECTION_STATE_CHANGED" />
+ <protected-broadcast android:name="android.bluetooth.action.CSIS_DEVICE_AVAILABLE" />
+ <protected-broadcast android:name="android.bluetooth.action.CSIS_SET_MEMBER_AVAILABLE" />
<protected-broadcast
android:name="android.bluetooth.volume-control.profile.action.CONNECTION_STATE_CHANGED" />
<protected-broadcast
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 6a4702be35c9..c1c185823d33 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3046,6 +3046,9 @@
<public name="canPauseRecording" />
<!-- attribute definitions go here -->
<public name="requireDeviceScreenOn" />
+ </public-group>
+
+ <public-group type="attr" first-id="0x01010624">
<public name="memtagMode" />
<public name="nativeHeapZeroInitialized" />
</public-group>
diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml
index 37d059a575f0..f1c66c5891f2 100644
--- a/core/res/res/xml/sms_short_codes.xml
+++ b/core/res/res/xml/sms_short_codes.xml
@@ -265,7 +265,7 @@
<!-- USA: 5-6 digits (premium codes from https://www.premiumsmsrefunds.com/ShortCodes.htm),
visual voicemail code for T-Mobile: 122 -->
- <shortcode country="us" pattern="\\d{5,6}" premium="20433|21(?:344|472)|22715|23(?:333|847)|24(?:15|28)0|25209|27(?:449|606|663)|28498|305(?:00|83)|32(?:340|941)|33(?:166|786|849)|34746|35(?:182|564)|37975|38(?:135|146|254)|41(?:366|463)|42335|43(?:355|500)|44(?:578|711|811)|45814|46(?:157|173|327)|46666|47553|48(?:221|277|669)|50(?:844|920)|51(?:062|368)|52944|54(?:723|892)|55928|56483|57370|59(?:182|187|252|342)|60339|61(?:266|982)|62478|64(?:219|898)|65(?:108|500)|69(?:208|388)|70877|71851|72(?:078|087|465)|73(?:288|588|882|909|997)|74(?:034|332|815)|76426|79213|81946|83177|84(?:103|685)|85797|86(?:234|236|666)|89616|90(?:715|842|938)|91(?:362|958)|94719|95297|96(?:040|666|835|969)|97(?:142|294|688)|99(?:689|796|807)" standard="44567|244444" free="122|87902|21696|24614|28003|30356|33669|40196|41064|41270|43753|44034|46645|52413|56139|57969|61785|66975|75136|76227|81398|83952|85140|86566|86799|95737|96684|99245" />
+ <shortcode country="us" pattern="\\d{5,6}" premium="20433|21(?:344|472)|22715|23(?:333|847)|24(?:15|28)0|25209|27(?:449|606|663)|28498|305(?:00|83)|32(?:340|941)|33(?:166|786|849)|34746|35(?:182|564)|37975|38(?:135|146|254)|41(?:366|463)|42335|43(?:355|500)|44(?:578|711|811)|45814|46(?:157|173|327)|46666|47553|48(?:221|277|669)|50(?:844|920)|51(?:062|368)|52944|54(?:723|892)|55928|56483|57370|59(?:182|187|252|342)|60339|61(?:266|982)|62478|64(?:219|898)|65(?:108|500)|69(?:208|388)|70877|71851|72(?:078|087|465)|73(?:288|588|882|909|997)|74(?:034|332|815)|76426|79213|81946|83177|84(?:103|685)|85797|86(?:234|236|666)|89616|90(?:715|842|938)|91(?:362|958)|94719|95297|96(?:040|666|835|969)|97(?:142|294|688)|99(?:689|796|807)" standard="44567|244444" free="122|87902|21696|24614|28003|30356|33669|40196|41064|41270|43753|44034|46645|52413|56139|57969|61785|66975|75136|76227|81398|83952|85140|86566|86799|95737|96684|99245|611611" />
<!-- Vietnam: 1-5 digits (standard system default, not country specific) -->
<shortcode country="vn" pattern="\\d{1,5}" free="5001|9055" />
diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
index 000e870369db..2d63351b8303 100644
--- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
+++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
@@ -88,6 +88,11 @@ public class ActivityThreadTest {
false /* launchActivity */);
@Test
+ public void testTemporaryDirectory() throws Exception {
+ assertEquals(System.getProperty("java.io.tmpdir"), System.getenv("TMPDIR"));
+ }
+
+ @Test
public void testDoubleRelaunch() throws Exception {
final Activity activity = mActivityTestRule.launchActivity(new Intent());
final IApplicationThread appThread = activity.getActivityThread().getApplicationThread();
diff --git a/core/tests/utiltests/src/com/android/internal/util/StateMachineTest.java b/core/tests/utiltests/src/com/android/internal/util/StateMachineTest.java
index edf473eac1b1..b85cb9cec47d 100644
--- a/core/tests/utiltests/src/com/android/internal/util/StateMachineTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/StateMachineTest.java
@@ -542,83 +542,83 @@ public class StateMachineTest extends TestCase {
public void testStateMachineEnterExitTransitionToTest() throws Exception {
//if (WAIT_FOR_DEBUGGER) Debug.waitForDebugger();
- StateMachineEnterExitTransitionToTest smEnterExitTranstionToTest =
- new StateMachineEnterExitTransitionToTest("smEnterExitTranstionToTest");
- smEnterExitTranstionToTest.start();
- if (smEnterExitTranstionToTest.isDbg()) {
+ StateMachineEnterExitTransitionToTest smEnterExitTransitionToTest =
+ new StateMachineEnterExitTransitionToTest("smEnterExitTransitionToTest");
+ smEnterExitTransitionToTest.start();
+ if (smEnterExitTransitionToTest.isDbg()) {
tlog("testStateMachineEnterExitTransitionToTest E");
}
- synchronized (smEnterExitTranstionToTest) {
- smEnterExitTranstionToTest.sendMessage(TEST_CMD_1);
+ synchronized (smEnterExitTransitionToTest) {
+ smEnterExitTransitionToTest.sendMessage(TEST_CMD_1);
try {
// wait for the messages to be handled
- smEnterExitTranstionToTest.wait();
+ smEnterExitTransitionToTest.wait();
} catch (InterruptedException e) {
tloge("testStateMachineEnterExitTransitionToTest: exception while waiting "
+ e.getMessage());
}
}
- dumpLogRecs(smEnterExitTranstionToTest);
+ dumpLogRecs(smEnterExitTransitionToTest);
- assertEquals(9, smEnterExitTranstionToTest.getLogRecCount());
+ assertEquals(9, smEnterExitTransitionToTest.getLogRecCount());
LogRec lr;
- lr = smEnterExitTranstionToTest.getLogRec(0);
+ lr = smEnterExitTransitionToTest.getLogRec(0);
assertEquals(ENTER, lr.getInfo());
- assertEquals(smEnterExitTranstionToTest.mS1, lr.getState());
+ assertEquals(smEnterExitTransitionToTest.mS1, lr.getState());
- lr = smEnterExitTranstionToTest.getLogRec(1);
+ lr = smEnterExitTransitionToTest.getLogRec(1);
assertEquals(EXIT, lr.getInfo());
- assertEquals(smEnterExitTranstionToTest.mS1, lr.getState());
+ assertEquals(smEnterExitTransitionToTest.mS1, lr.getState());
- lr = smEnterExitTranstionToTest.getLogRec(2);
+ lr = smEnterExitTransitionToTest.getLogRec(2);
assertEquals(ENTER, lr.getInfo());
- assertEquals(smEnterExitTranstionToTest.mS2, lr.getState());
+ assertEquals(smEnterExitTransitionToTest.mS2, lr.getState());
- lr = smEnterExitTranstionToTest.getLogRec(3);
+ lr = smEnterExitTransitionToTest.getLogRec(3);
assertEquals(TEST_CMD_1, lr.getWhat());
- assertEquals(smEnterExitTranstionToTest.mS2, lr.getState());
- assertEquals(smEnterExitTranstionToTest.mS2, lr.getOriginalState());
- assertEquals(smEnterExitTranstionToTest.mS3, lr.getDestState());
+ assertEquals(smEnterExitTransitionToTest.mS2, lr.getState());
+ assertEquals(smEnterExitTransitionToTest.mS2, lr.getOriginalState());
+ assertEquals(smEnterExitTransitionToTest.mS3, lr.getDestState());
- lr = smEnterExitTranstionToTest.getLogRec(4);
+ lr = smEnterExitTransitionToTest.getLogRec(4);
assertEquals(TEST_CMD_1, lr.getWhat());
- assertEquals(smEnterExitTranstionToTest.mS2, lr.getState());
- assertEquals(smEnterExitTranstionToTest.mS2, lr.getOriginalState());
- assertEquals(smEnterExitTranstionToTest.mS4, lr.getDestState());
+ assertEquals(smEnterExitTransitionToTest.mS2, lr.getState());
+ assertEquals(smEnterExitTransitionToTest.mS2, lr.getOriginalState());
+ assertEquals(smEnterExitTransitionToTest.mS4, lr.getDestState());
assertEquals(EXIT, lr.getInfo());
- lr = smEnterExitTranstionToTest.getLogRec(5);
+ lr = smEnterExitTransitionToTest.getLogRec(5);
assertEquals(TEST_CMD_1, lr.getWhat());
assertEquals(ENTER, lr.getInfo());
- assertEquals(smEnterExitTranstionToTest.mS3, lr.getState());
- assertEquals(smEnterExitTranstionToTest.mS3, lr.getOriginalState());
- assertEquals(smEnterExitTranstionToTest.mS4, lr.getDestState());
+ assertEquals(smEnterExitTransitionToTest.mS3, lr.getState());
+ assertEquals(smEnterExitTransitionToTest.mS3, lr.getOriginalState());
+ assertEquals(smEnterExitTransitionToTest.mS4, lr.getDestState());
- lr = smEnterExitTranstionToTest.getLogRec(6);
+ lr = smEnterExitTransitionToTest.getLogRec(6);
assertEquals(TEST_CMD_1, lr.getWhat());
assertEquals(EXIT, lr.getInfo());
- assertEquals(smEnterExitTranstionToTest.mS3, lr.getState());
- assertEquals(smEnterExitTranstionToTest.mS3, lr.getOriginalState());
- assertEquals(smEnterExitTranstionToTest.mS4, lr.getDestState());
+ assertEquals(smEnterExitTransitionToTest.mS3, lr.getState());
+ assertEquals(smEnterExitTransitionToTest.mS3, lr.getOriginalState());
+ assertEquals(smEnterExitTransitionToTest.mS4, lr.getDestState());
- lr = smEnterExitTranstionToTest.getLogRec(7);
+ lr = smEnterExitTransitionToTest.getLogRec(7);
assertEquals(TEST_CMD_1, lr.getWhat());
assertEquals(ENTER, lr.getInfo());
- assertEquals(smEnterExitTranstionToTest.mS4, lr.getState());
- assertEquals(smEnterExitTranstionToTest.mS4, lr.getOriginalState());
- assertEquals(smEnterExitTranstionToTest.mS4, lr.getDestState());
+ assertEquals(smEnterExitTransitionToTest.mS4, lr.getState());
+ assertEquals(smEnterExitTransitionToTest.mS4, lr.getOriginalState());
+ assertEquals(smEnterExitTransitionToTest.mS4, lr.getDestState());
- lr = smEnterExitTranstionToTest.getLogRec(8);
+ lr = smEnterExitTransitionToTest.getLogRec(8);
assertEquals(TEST_CMD_1, lr.getWhat());
assertEquals(EXIT, lr.getInfo());
- assertEquals(smEnterExitTranstionToTest.mS4, lr.getState());
- assertEquals(smEnterExitTranstionToTest.mS4, lr.getOriginalState());
+ assertEquals(smEnterExitTransitionToTest.mS4, lr.getState());
+ assertEquals(smEnterExitTransitionToTest.mS4, lr.getOriginalState());
- if (smEnterExitTranstionToTest.isDbg()) {
+ if (smEnterExitTransitionToTest.isDbg()) {
tlog("testStateMachineEnterExitTransitionToTest X");
}
}
diff --git a/identity/java/android/security/identity/IdentityCredential.java b/identity/java/android/security/identity/IdentityCredential.java
index 8f175bb63edb..1e685856d011 100644
--- a/identity/java/android/security/identity/IdentityCredential.java
+++ b/identity/java/android/security/identity/IdentityCredential.java
@@ -160,7 +160,7 @@ public abstract class IdentityCredential {
* not the case, the {@link SessionTranscriptMismatchException} exception is thrown.
*
* <p>If not {@code null} the {@code requestMessage} parameter must contain data for the request
- * from the verifier. The content can be defined in the way appropriate for the credential, byt
+ * from the verifier. The content can be defined in the way appropriate for the credential, but
* there are three requirements that must be met to work with this API:
* <ul>
* <li>The content must be a CBOR-encoded structure.</li>
@@ -205,9 +205,9 @@ public abstract class IdentityCredential {
* must appear somewhere in {@code sessionTranscript} and ditto for the 32 bytes for the Y
* coordinate.
*
- * <p>If {@code readerAuth} is not {@code null} it must be the bytes of a {@code COSE_Sign1}
- * structure as defined in RFC 8152. For the payload nil shall be used and the
- * detached payload is the ReaderAuthenticationBytes CBOR described below.
+ * <p>If {@code readerSignature} is not {@code null} it must be the bytes of a
+ * {@code COSE_Sign1} structure as defined in RFC 8152. For the payload nil shall be used and
+ * the detached payload is the ReaderAuthenticationBytes CBOR described below.
* <pre>
* ReaderAuthentication = [
* "ReaderAuthentication",
diff --git a/libs/hwui/jni/PaintFilter.cpp b/libs/hwui/jni/PaintFilter.cpp
index ec115b4e141c..86d4742b949e 100644
--- a/libs/hwui/jni/PaintFilter.cpp
+++ b/libs/hwui/jni/PaintFilter.cpp
@@ -74,7 +74,7 @@ int register_android_graphics_DrawFilter(JNIEnv* env) {
result |= RegisterMethodsOrDie(env, "android/graphics/PaintFlagsDrawFilter", paintflags_methods,
NELEM(paintflags_methods));
- return 0;
+ return result;
}
}
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index 9657b25e7c18..c7c503d64801 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -2178,12 +2178,6 @@ public final class MediaCodecInfo {
if (size == null || size.getWidth() * size.getHeight() <= 0) {
continue;
}
- if (size.getWidth() > SIZE_RANGE.getUpper()
- || size.getHeight() > SIZE_RANGE.getUpper()) {
- size = new Size(
- Math.min(size.getWidth(), SIZE_RANGE.getUpper()),
- Math.min(size.getHeight(), SIZE_RANGE.getUpper()));
- }
Range<Long> range = Utils.parseLongRange(map.get(key), null);
if (range == null || range.getLower() < 0 || range.getUpper() < 0) {
continue;
diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java
index 559a61daec38..0f9e89a497d2 100644
--- a/media/java/android/media/MediaMetadataRetriever.java
+++ b/media/java/android/media/MediaMetadataRetriever.java
@@ -900,7 +900,7 @@ public class MediaMetadataRetriever implements AutoCloseable {
private @NonNull List<Bitmap> getFramesAtIndexInternal(
int frameIndex, int numFrames, @Nullable BitmapParams params) {
if (!"yes".equals(extractMetadata(MediaMetadataRetriever.METADATA_KEY_HAS_VIDEO))) {
- throw new IllegalStateException("Does not contail video or image sequences");
+ throw new IllegalStateException("Does not contain video or image sequences");
}
int frameCount = Integer.parseInt(
extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_FRAME_COUNT));
@@ -1018,7 +1018,7 @@ public class MediaMetadataRetriever implements AutoCloseable {
private Bitmap getImageAtIndexInternal(int imageIndex, @Nullable BitmapParams params) {
if (!"yes".equals(extractMetadata(MediaMetadataRetriever.METADATA_KEY_HAS_IMAGE))) {
- throw new IllegalStateException("Does not contail still images");
+ throw new IllegalStateException("Does not contain still images");
}
String imageCount = extractMetadata(MediaMetadataRetriever.METADATA_KEY_IMAGE_COUNT);
diff --git a/media/jni/audioeffect/android_media_AudioEffect.cpp b/media/jni/audioeffect/android_media_AudioEffect.cpp
index 0d53ab152129..2691983a0e3a 100644
--- a/media/jni/audioeffect/android_media_AudioEffect.cpp
+++ b/media/jni/audioeffect/android_media_AudioEffect.cpp
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-
#include <stdio.h>
+#include <unordered_set>
//#define LOG_NDEBUG 0
#define LOG_TAG "AudioEffects-JNI"
@@ -58,22 +58,15 @@ static fields_t fields;
struct effect_callback_cookie {
jclass audioEffect_class; // AudioEffect class
jobject audioEffect_ref; // AudioEffect object instance
- };
+ bool busy;
+ Condition cond;
+};
// ----------------------------------------------------------------------------
-class AudioEffectJniStorage {
- public:
- effect_callback_cookie mCallbackData;
-
- AudioEffectJniStorage() {
- }
-
- ~AudioEffectJniStorage() {
- }
-
+struct AudioEffectJniStorage {
+ effect_callback_cookie mCallbackData{};
};
-
jint AudioEffectJni::translateNativeErrorToJava(int code) {
switch(code) {
case NO_ERROR:
@@ -101,6 +94,7 @@ jint AudioEffectJni::translateNativeErrorToJava(int code) {
}
static Mutex sLock;
+static std::unordered_set<effect_callback_cookie*> sAudioEffectCallBackCookies;
// ----------------------------------------------------------------------------
static void effectCallback(int event, void* user, void *info) {
@@ -121,7 +115,13 @@ static void effectCallback(int event, void* user, void *info) {
ALOGW("effectCallback error user %p, env %p", user, env);
return;
}
-
+ {
+ Mutex::Autolock l(sLock);
+ if (sAudioEffectCallBackCookies.count(callbackInfo) == 0) {
+ return;
+ }
+ callbackInfo->busy = true;
+ }
ALOGV("effectCallback: callbackInfo %p, audioEffect_ref %p audioEffect_class %p",
callbackInfo,
callbackInfo->audioEffect_ref,
@@ -188,6 +188,11 @@ effectCallback_Exit:
env->ExceptionDescribe();
env->ExceptionClear();
}
+ {
+ Mutex::Autolock l(sLock);
+ callbackInfo->busy = false;
+ callbackInfo->cond.broadcast();
+ }
}
// ----------------------------------------------------------------------------
@@ -396,6 +401,10 @@ android_media_AudioEffect_native_setup(JNIEnv *env, jobject thiz, jobject weak_t
setAudioEffect(env, thiz, lpAudioEffect);
}
+ {
+ Mutex::Autolock l(sLock);
+ sAudioEffectCallBackCookies.insert(&lpJniStorage->mCallbackData);
+ }
env->SetLongField(thiz, fields.fidJniData, (jlong)lpJniStorage);
return (jint) AUDIOEFFECT_SUCCESS;
@@ -427,6 +436,7 @@ setup_failure:
// ----------------------------------------------------------------------------
+#define CALLBACK_COND_WAIT_TIMEOUT_MS 1000
static void android_media_AudioEffect_native_release(JNIEnv *env, jobject thiz) {
sp<AudioEffect> lpAudioEffect = setAudioEffect(env, thiz, 0);
if (lpAudioEffect == 0) {
@@ -442,7 +452,17 @@ static void android_media_AudioEffect_native_release(JNIEnv *env, jobject thiz)
env->SetLongField(thiz, fields.fidJniData, 0);
if (lpJniStorage) {
- ALOGV("deleting pJniStorage: %p\n", lpJniStorage);
+ Mutex::Autolock l(sLock);
+ effect_callback_cookie *lpCookie = &lpJniStorage->mCallbackData;
+ ALOGV("deleting lpJniStorage: %p\n", lpJniStorage);
+ sAudioEffectCallBackCookies.erase(lpCookie);
+ while (lpCookie->busy) {
+ if (lpCookie->cond.waitRelative(sLock,
+ milliseconds(CALLBACK_COND_WAIT_TIMEOUT_MS)) !=
+ NO_ERROR) {
+ break;
+ }
+ }
env->DeleteGlobalRef(lpJniStorage->mCallbackData.audioEffect_class);
env->DeleteGlobalRef(lpJniStorage->mCallbackData.audioEffect_ref);
delete lpJniStorage;
diff --git a/media/jni/audioeffect/android_media_Visualizer.cpp b/media/jni/audioeffect/android_media_Visualizer.cpp
index 4c5970a30a05..609fafee4d6a 100644
--- a/media/jni/audioeffect/android_media_Visualizer.cpp
+++ b/media/jni/audioeffect/android_media_Visualizer.cpp
@@ -15,6 +15,7 @@
*/
#include <stdio.h>
+#include <unordered_set>
//#define LOG_NDEBUG 0
#define LOG_TAG "visualizers-JNI"
@@ -63,6 +64,12 @@ struct visualizer_callback_cookie {
jclass visualizer_class; // Visualizer class
jobject visualizer_ref; // Visualizer object instance
+ // 'busy_count' and 'cond' together with 'sLock' are used to serialize
+ // concurrent access to the callback cookie from 'setup'/'release'
+ // and the callback.
+ int busy_count;
+ Condition cond;
+
// Lazily allocated arrays used to hold callback data provided to java
// applications. These arrays are allocated during the first callback and
// reallocated when the size of the callback data changes. Allocating on
@@ -70,14 +77,12 @@ struct visualizer_callback_cookie {
// reference to the provided data (they need to make a copy if they want to
// hold onto outside of the callback scope), but it avoids GC thrash caused
// by constantly allocating and releasing arrays to hold callback data.
+ // 'callback_data_lock' must never be held at the same time with 'sLock'.
Mutex callback_data_lock;
jbyteArray waveform_data;
jbyteArray fft_data;
- visualizer_callback_cookie() {
- waveform_data = NULL;
- fft_data = NULL;
- }
+ // Assumes use of default initialization by the client.
~visualizer_callback_cookie() {
cleanupBuffers();
@@ -102,15 +107,8 @@ struct visualizer_callback_cookie {
};
// ----------------------------------------------------------------------------
-class VisualizerJniStorage {
- public:
- visualizer_callback_cookie mCallbackData;
-
- VisualizerJniStorage() {
- }
-
- ~VisualizerJniStorage() {
- }
+struct VisualizerJniStorage {
+ visualizer_callback_cookie mCallbackData{};
};
@@ -136,6 +134,7 @@ static jint translateError(int code) {
}
static Mutex sLock;
+static std::unordered_set<visualizer_callback_cookie*> sVisualizerCallBackCookies;
// ----------------------------------------------------------------------------
static void ensureArraySize(JNIEnv *env, jbyteArray *array, uint32_t size) {
@@ -173,11 +172,19 @@ static void captureCallback(void* user,
return;
}
+ {
+ Mutex::Autolock l(sLock);
+ if (sVisualizerCallBackCookies.count(callbackInfo) == 0) {
+ return;
+ }
+ callbackInfo->busy_count++;
+ }
ALOGV("captureCallback: callbackInfo %p, visualizer_ref %p visualizer_class %p",
callbackInfo,
callbackInfo->visualizer_ref,
callbackInfo->visualizer_class);
+ {
AutoMutex lock(&callbackInfo->callback_data_lock);
if (waveformSize != 0 && waveform != NULL) {
@@ -219,11 +226,17 @@ static void captureCallback(void* user,
jArray);
}
}
+ } // callback_data_lock scope
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
env->ExceptionClear();
}
+ {
+ Mutex::Autolock l(sLock);
+ callbackInfo->busy_count--;
+ callbackInfo->cond.broadcast();
+ }
}
// ----------------------------------------------------------------------------
@@ -332,16 +345,41 @@ static void android_media_visualizer_effect_callback(int32_t event,
void *info) {
if ((event == AudioEffect::EVENT_ERROR) &&
(*((status_t*)info) == DEAD_OBJECT)) {
- VisualizerJniStorage* lpJniStorage = (VisualizerJniStorage*)user;
- visualizer_callback_cookie* callbackInfo = &lpJniStorage->mCallbackData;
+ visualizer_callback_cookie* callbackInfo =
+ (visualizer_callback_cookie *)user;
JNIEnv *env = AndroidRuntime::getJNIEnv();
+ if (!user || !env) {
+ ALOGW("effectCallback error user %p, env %p", user, env);
+ return;
+ }
+ {
+ Mutex::Autolock l(sLock);
+ if (sVisualizerCallBackCookies.count(callbackInfo) == 0) {
+ return;
+ }
+ callbackInfo->busy_count++;
+ }
+ ALOGV("effectCallback: callbackInfo %p, visualizer_ref %p visualizer_class %p",
+ callbackInfo,
+ callbackInfo->visualizer_ref,
+ callbackInfo->visualizer_class);
+
env->CallStaticVoidMethod(
callbackInfo->visualizer_class,
fields.midPostNativeEvent,
callbackInfo->visualizer_ref,
NATIVE_EVENT_SERVER_DIED,
0, NULL);
+ if (env->ExceptionCheck()) {
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ }
+ {
+ Mutex::Autolock l(sLock);
+ callbackInfo->busy_count--;
+ callbackInfo->cond.broadcast();
+ }
}
}
@@ -389,7 +427,7 @@ android_media_visualizer_native_setup(JNIEnv *env, jobject thiz, jobject weak_th
}
lpVisualizer->set(0,
android_media_visualizer_effect_callback,
- lpJniStorage,
+ &lpJniStorage->mCallbackData,
(audio_session_t) sessionId);
lStatus = translateError(lpVisualizer->initCheck());
@@ -410,6 +448,10 @@ android_media_visualizer_native_setup(JNIEnv *env, jobject thiz, jobject weak_th
setVisualizer(env, thiz, lpVisualizer);
+ {
+ Mutex::Autolock l(sLock);
+ sVisualizerCallBackCookies.insert(&lpJniStorage->mCallbackData);
+ }
env->SetLongField(thiz, fields.fidJniData, (jlong)lpJniStorage);
return VISUALIZER_SUCCESS;
@@ -432,13 +474,15 @@ setup_failure:
}
// ----------------------------------------------------------------------------
+#define CALLBACK_COND_WAIT_TIMEOUT_MS 1000
static void android_media_visualizer_native_release(JNIEnv *env, jobject thiz) {
- { //limit scope so that lpVisualizer is deleted before JNI storage data.
+ {
sp<Visualizer> lpVisualizer = setVisualizer(env, thiz, 0);
if (lpVisualizer == 0) {
return;
}
lpVisualizer->release();
+ // Visualizer can still can be held by AudioEffect::EffectClient
}
// delete the JNI data
VisualizerJniStorage* lpJniStorage =
@@ -449,9 +493,22 @@ static void android_media_visualizer_native_release(JNIEnv *env, jobject thiz)
env->SetLongField(thiz, fields.fidJniData, 0);
if (lpJniStorage) {
+ {
+ Mutex::Autolock l(sLock);
+ visualizer_callback_cookie *lpCookie = &lpJniStorage->mCallbackData;
ALOGV("deleting pJniStorage: %p\n", lpJniStorage);
+ sVisualizerCallBackCookies.erase(lpCookie);
+ while (lpCookie->busy_count > 0) {
+ if (lpCookie->cond.waitRelative(sLock,
+ milliseconds(CALLBACK_COND_WAIT_TIMEOUT_MS)) !=
+ NO_ERROR) {
+ break;
+ }
+ }
+ ALOG_ASSERT(lpCookie->busy_count == 0, "Unbalanced busy_count inc/dec");
env->DeleteGlobalRef(lpJniStorage->mCallbackData.visualizer_class);
env->DeleteGlobalRef(lpJniStorage->mCallbackData.visualizer_ref);
+ } // sLock scope
delete lpJniStorage;
}
}
@@ -707,4 +764,3 @@ int register_android_media_visualizer(JNIEnv *env)
{
return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
}
-
diff --git a/media/tests/EffectsTest/AndroidManifest.xml b/media/tests/EffectsTest/AndroidManifest.xml
index 9b59891fb279..ad0c10ee3807 100644
--- a/media/tests/EffectsTest/AndroidManifest.xml
+++ b/media/tests/EffectsTest/AndroidManifest.xml
@@ -13,6 +13,10 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
+<!--
+Make sure to enable access to the mic in settings and run:
+adb shell am compat enable ALLOW_TEST_API_ACCESS com.android.effectstest
+-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.effectstest">
diff --git a/media/tests/EffectsTest/res/layout/bassboosttest.xml b/media/tests/EffectsTest/res/layout/bassboosttest.xml
index ac912c84d107..5f9132cb8cc7 100644
--- a/media/tests/EffectsTest/res/layout/bassboosttest.xml
+++ b/media/tests/EffectsTest/res/layout/bassboosttest.xml
@@ -187,6 +187,11 @@
android:layout_height="wrap_content"
android:scaleType="fitXY"/>
+ <Button android:id="@+id/hammer_on_release_bug"
+ android:layout_width="fill_parent" android:layout_height="wrap_content"
+ android:text="@string/hammer_on_release_bug_name">
+ </Button>
+
</LinearLayout>
</ScrollView>
diff --git a/media/tests/EffectsTest/res/layout/visualizertest.xml b/media/tests/EffectsTest/res/layout/visualizertest.xml
index 18d7a3648fbf..85dabbc115f3 100644
--- a/media/tests/EffectsTest/res/layout/visualizertest.xml
+++ b/media/tests/EffectsTest/res/layout/visualizertest.xml
@@ -175,6 +175,11 @@
</LinearLayout>
+ <Button android:id="@+id/hammer_on_release_bug"
+ android:layout_width="fill_parent" android:layout_height="wrap_content"
+ android:text="@string/hammer_on_release_bug_name">
+ </Button>
+
<ImageView
android:src="@android:drawable/divider_horizontal_dark"
android:layout_width="fill_parent"
diff --git a/media/tests/EffectsTest/res/values/strings.xml b/media/tests/EffectsTest/res/values/strings.xml
index 7c12da1274e3..a44c7e93382a 100644
--- a/media/tests/EffectsTest/res/values/strings.xml
+++ b/media/tests/EffectsTest/res/values/strings.xml
@@ -37,4 +37,6 @@
<string name="send_level_name">Send Level</string>
<!-- Toggles use of a multi-threaded client for an effect [CHAR LIMIT=24] -->
<string name="effect_multithreaded">Multithreaded Use</string>
+ <!-- Runs a stress test for a bug related to simultaneous release of multiple effect instances [CHAR LIMIT=24] -->
+ <string name="hammer_on_release_bug_name">Hammer on release()</string>
</resources>
diff --git a/media/tests/EffectsTest/src/com/android/effectstest/BassBoostTest.java b/media/tests/EffectsTest/src/com/android/effectstest/BassBoostTest.java
index cce2acc5869a..a207bf1d5359 100644
--- a/media/tests/EffectsTest/src/com/android/effectstest/BassBoostTest.java
+++ b/media/tests/EffectsTest/src/com/android/effectstest/BassBoostTest.java
@@ -17,29 +17,24 @@
package com.android.effectstest;
import android.app.Activity;
-import android.content.Context;
-import android.content.Intent;
+import android.media.audiofx.AudioEffect;
+import android.media.audiofx.BassBoost;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
-import android.view.Menu;
-import android.view.View.OnClickListener;
import android.view.View;
-import android.view.ViewGroup;
+import android.view.View.OnClickListener;
import android.widget.Button;
-import android.widget.TextView;
+import android.widget.CompoundButton;
+import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.EditText;
import android.widget.SeekBar;
+import android.widget.TextView;
import android.widget.ToggleButton;
-import android.widget.CompoundButton;
-import android.widget.CompoundButton.OnCheckedChangeListener;
-import java.nio.ByteOrder;
+
import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
import java.util.HashMap;
-import java.util.Map;
-
-import android.media.audiofx.BassBoost;
-import android.media.audiofx.AudioEffect;
public class BassBoostTest extends Activity implements OnCheckedChangeListener {
@@ -78,6 +73,9 @@ public class BassBoostTest extends Activity implements OnCheckedChangeListener {
mReleaseButton = (ToggleButton)findViewById(R.id.bbReleaseButton);
mOnOffButton = (ToggleButton)findViewById(R.id.bassboostOnOff);
+ final Button hammerReleaseTest = (Button) findViewById(R.id.hammer_on_release_bug);
+ hammerReleaseTest.setEnabled(false);
+
getEffect(sSession);
if (mBassBoost != null) {
@@ -93,6 +91,14 @@ public class BassBoostTest extends Activity implements OnCheckedChangeListener {
mStrength = new BassBoostParam(mBassBoost, 0, 1000, seekBar, textView);
seekBar.setOnSeekBarChangeListener(mStrength);
mStrength.setEnabled(mBassBoost.getStrengthSupported());
+
+ hammerReleaseTest.setEnabled(true);
+ hammerReleaseTest.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ runHammerReleaseTest(hammerReleaseTest);
+ }
+ });
}
}
@@ -273,4 +279,52 @@ public class BassBoostTest extends Activity implements OnCheckedChangeListener {
}
}
+ // Stress-tests releasing of AudioEffect by doing repeated creation
+ // and subsequent releasing. Also forces emission of callbacks from
+ // the AudioFlinger by setting a control status listener. Since all
+ // effect instances are bound to the same session, the AF will
+ // notify them about the change in their status. This can reveal racy
+ // behavior w.r.t. releasing.
+ class HammerReleaseTest extends Thread {
+ private static final int NUM_EFFECTS = 10;
+ private static final int NUM_ITERATIONS = 100;
+ private final int mSession;
+ private final Runnable mOnComplete;
+
+ HammerReleaseTest(int session, Runnable onComplete) {
+ mSession = session;
+ mOnComplete = onComplete;
+ }
+
+ @Override
+ public void run() {
+ Log.w(TAG, "HammerReleaseTest started");
+ BassBoost[] effects = new BassBoost[NUM_EFFECTS];
+ for (int i = 0; i < NUM_ITERATIONS; i++) {
+ for (int j = 0; j < NUM_EFFECTS; j++) {
+ effects[j] = new BassBoost(0, mSession);
+ effects[j].setControlStatusListener(mEffectListener);
+ yield();
+ }
+ for (int j = NUM_EFFECTS - 1; j >= 0; j--) {
+ Log.w(TAG, "HammerReleaseTest releasing effect " + (Object) effects[j]);
+ effects[j].release();
+ effects[j] = null;
+ yield();
+ }
+ }
+ Log.w(TAG, "HammerReleaseTest ended");
+ runOnUiThread(mOnComplete);
+ }
+ }
+
+ private void runHammerReleaseTest(Button controlButton) {
+ controlButton.setEnabled(false);
+ HammerReleaseTest thread = new HammerReleaseTest(sSession,
+ () -> {
+ controlButton.setEnabled(true);
+ });
+ thread.start();
+ }
+
}
diff --git a/media/tests/EffectsTest/src/com/android/effectstest/VisualizerTest.java b/media/tests/EffectsTest/src/com/android/effectstest/VisualizerTest.java
index 2e141c5ef7c8..dcfe11a79ef9 100644
--- a/media/tests/EffectsTest/src/com/android/effectstest/VisualizerTest.java
+++ b/media/tests/EffectsTest/src/com/android/effectstest/VisualizerTest.java
@@ -17,6 +17,7 @@
package com.android.effectstest;
import android.app.Activity;
+import android.media.audiofx.Visualizer;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
@@ -24,6 +25,8 @@ import android.os.Message;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.EditText;
@@ -74,11 +77,22 @@ public class VisualizerTest extends Activity implements OnCheckedChangeListener
mCallbackOn = false;
mCallbackButton.setChecked(mCallbackOn);
+ final Button hammerReleaseTest = (Button) findViewById(R.id.hammer_on_release_bug);
+ hammerReleaseTest.setEnabled(false);
+
mMultithreadedButton.setOnCheckedChangeListener(this);
if (getEffect(sSession) != null) {
mReleaseButton.setOnCheckedChangeListener(this);
mOnOffButton.setOnCheckedChangeListener(this);
mCallbackButton.setOnCheckedChangeListener(this);
+
+ hammerReleaseTest.setEnabled(true);
+ hammerReleaseTest.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ runHammerReleaseTest(hammerReleaseTest);
+ }
+ });
}
}
@@ -214,4 +228,50 @@ public class VisualizerTest extends Activity implements OnCheckedChangeListener
}
}
+ // Stress-tests releasing of AudioEffect by doing repeated creation
+ // and subsequent releasing. Unlike a similar class in BassBoostTest,
+ // this one doesn't sets a control status listener because Visualizer
+ // doesn't inherit from AudioEffect and doesn't implement this method
+ // by itself.
+ class HammerReleaseTest extends Thread {
+ private static final int NUM_EFFECTS = 10;
+ private static final int NUM_ITERATIONS = 100;
+ private final int mSession;
+ private final Runnable mOnComplete;
+
+ HammerReleaseTest(int session, Runnable onComplete) {
+ mSession = session;
+ mOnComplete = onComplete;
+ }
+
+ @Override
+ public void run() {
+ Log.w(TAG, "HammerReleaseTest started");
+ Visualizer[] effects = new Visualizer[NUM_EFFECTS];
+ for (int i = 0; i < NUM_ITERATIONS; i++) {
+ for (int j = 0; j < NUM_EFFECTS; j++) {
+ effects[j] = new Visualizer(mSession);
+ yield();
+ }
+ for (int j = NUM_EFFECTS - 1; j >= 0; j--) {
+ Log.w(TAG, "HammerReleaseTest releasing effect " + (Object) effects[j]);
+ effects[j].release();
+ effects[j] = null;
+ yield();
+ }
+ }
+ Log.w(TAG, "HammerReleaseTest ended");
+ runOnUiThread(mOnComplete);
+ }
+ }
+
+ private void runHammerReleaseTest(Button controlButton) {
+ controlButton.setEnabled(false);
+ HammerReleaseTest thread = new HammerReleaseTest(sSession,
+ () -> {
+ controlButton.setEnabled(true);
+ });
+ thread.start();
+ }
+
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
index 59d8acb82196..a0869189a5bd 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
@@ -293,6 +293,8 @@ public class BluetoothEventManager {
BluetoothDevice device) {
short rssi = intent.getShortExtra(BluetoothDevice.EXTRA_RSSI, Short.MIN_VALUE);
String name = intent.getStringExtra(BluetoothDevice.EXTRA_NAME);
+ final boolean isCoordinatedSetMember =
+ intent.getBooleanExtra(BluetoothDevice.EXTRA_IS_COORDINATED_SET_MEMBER, false);
// TODO Pick up UUID. They should be available for 2.1 devices.
// Skip for now, there's a bluez problem and we are not getting uuids even for 2.1.
CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
@@ -307,6 +309,7 @@ public class BluetoothEventManager {
}
cachedDevice.setRssi(rssi);
cachedDevice.setJustDiscovered(true);
+ cachedDevice.setIsCoordinatedSetMember(isCoordinatedSetMember);
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index 4c80b91f300d..6a590c2ff382 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -80,6 +80,8 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
boolean mJustDiscovered;
+ boolean mIsCoordinatedSetMember = false;
+
private final Collection<Callback> mCallbacks = new CopyOnWriteArrayList<>();
/**
@@ -297,6 +299,24 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
return mHiSyncId != BluetoothHearingAid.HI_SYNC_ID_INVALID;
}
+ /**
+ * Mark the discovered device as member of coordinated set.
+ *
+ * @param isCoordinatedSetMember {@code true}, if the device is a member of a coordinated set.
+ */
+ public void setIsCoordinatedSetMember(boolean isCoordinatedSetMember) {
+ mIsCoordinatedSetMember = isCoordinatedSetMember;
+ }
+
+ /**
+ * Check if the device is a CSIP member device.
+ *
+ * @return {@code true}, if this device supports CSIP, otherwise returns {@code false}.
+ */
+ public boolean isCoordinatedSetMemberDevice() {
+ return mIsCoordinatedSetMember;
+ }
+
void onBondingDockConnect() {
// Attempt to connect if UUIDs are available. Otherwise,
// we will connect when the ACTION_UUID intent arrives.
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipSetCoordinatorProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipSetCoordinatorProfile.java
new file mode 100644
index 000000000000..754914ff794f
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipSetCoordinatorProfile.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright 2021 HIMSA II K/S - www.himsa.com.
+ * Represented by EHIMA - www.ehima.com
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.bluetooth;
+
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED;
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothCsipSetCoordinator;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
+import android.content.Context;
+import android.util.Log;
+
+import androidx.annotation.RequiresApi;
+
+import com.android.settingslib.R;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * CSIP Set Coordinator handles Bluetooth CSIP Set Coordinator role profile.
+ */
+public class CsipSetCoordinatorProfile implements LocalBluetoothProfile {
+ private static final String TAG = "CsipSetCoordinatorProfile";
+ private static final boolean VDBG = true;
+
+ private Context mContext;
+
+ private BluetoothCsipSetCoordinator mService;
+ private boolean mIsProfileReady;
+
+ private final CachedBluetoothDeviceManager mDeviceManager;
+
+ static final String NAME = "CSIP Set Coordinator";
+ private final LocalBluetoothProfileManager mProfileManager;
+
+ // Order of this profile in device profiles list
+ private static final int ORDINAL = 1;
+
+ // These callbacks run on the main thread.
+ private final class CoordinatedSetServiceListener implements BluetoothProfile.ServiceListener {
+ @RequiresApi(32)
+ public void onServiceConnected(int profile, BluetoothProfile proxy) {
+ if (VDBG) {
+ Log.d(TAG, "Bluetooth service connected");
+ }
+ mService = (BluetoothCsipSetCoordinator) proxy;
+ // We just bound to the service, so refresh the UI for any connected CSIP devices.
+ List<BluetoothDevice> deviceList = mService.getConnectedDevices();
+ while (!deviceList.isEmpty()) {
+ BluetoothDevice nextDevice = deviceList.remove(0);
+ CachedBluetoothDevice device = mDeviceManager.findDevice(nextDevice);
+ // we may add a new device here, but generally this should not happen
+ if (device == null) {
+ if (VDBG) {
+ Log.d(TAG, "CsipSetCoordinatorProfile found new device: " + nextDevice);
+ }
+ device = mDeviceManager.addDevice(nextDevice);
+ }
+ device.onProfileStateChanged(
+ CsipSetCoordinatorProfile.this, BluetoothProfile.STATE_CONNECTED);
+ device.refresh();
+ }
+
+ mProfileManager.callServiceConnectedListeners();
+ mIsProfileReady = true;
+ }
+
+ public void onServiceDisconnected(int profile) {
+ if (VDBG) {
+ Log.d(TAG, "Bluetooth service disconnected");
+ }
+ mProfileManager.callServiceDisconnectedListeners();
+ mIsProfileReady = false;
+ }
+ }
+
+ CsipSetCoordinatorProfile(Context context, CachedBluetoothDeviceManager deviceManager,
+ LocalBluetoothProfileManager profileManager) {
+ mContext = context;
+ mDeviceManager = deviceManager;
+ mProfileManager = profileManager;
+
+ BluetoothAdapter.getDefaultAdapter().getProfileProxy(context,
+ new CoordinatedSetServiceListener(), BluetoothProfile.CSIP_SET_COORDINATOR);
+ }
+
+ /**
+ * Get CSIP devices matching connection states{
+ *
+ * @code BluetoothProfile.STATE_CONNECTED,
+ * @code BluetoothProfile.STATE_CONNECTING,
+ * @code BluetoothProfile.STATE_DISCONNECTING}
+ *
+ * @return Matching device list
+ */
+ public List<BluetoothDevice> getConnectedDevices() {
+ if (mService == null) {
+ return new ArrayList<BluetoothDevice>(0);
+ }
+ return mService.getDevicesMatchingConnectionStates(
+ new int[] {BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_CONNECTING,
+ BluetoothProfile.STATE_DISCONNECTING});
+ }
+
+ /**
+ * Gets the connection status of the device.
+ *
+ * @code BluetoothProfile.STATE_CONNECTED,
+ * @code BluetoothProfile.STATE_CONNECTING,
+ * @code BluetoothProfile.STATE_DISCONNECTING}
+ *
+ * @return Connection status, {@code BluetoothProfile.STATE_DISCONNECTED} if unknown.
+ */
+ public int getConnectionStatus(BluetoothDevice device) {
+ if (mService == null) {
+ return BluetoothProfile.STATE_DISCONNECTED;
+ }
+ return mService.getConnectionState(device);
+ }
+
+ @Override
+ public boolean isProfileReady() {
+ return mIsProfileReady;
+ }
+
+ @Override
+ public int getProfileId() {
+ return BluetoothProfile.CSIP_SET_COORDINATOR;
+ }
+
+ @Override
+ public boolean accessProfileEnabled() {
+ return false;
+ }
+
+ @Override
+ public boolean isAutoConnectable() {
+ return true;
+ }
+
+ @Override
+ public boolean isEnabled(BluetoothDevice device) {
+ if (mService == null || device == null) {
+ return false;
+ }
+ return mService.getConnectionPolicy(device) > CONNECTION_POLICY_FORBIDDEN;
+ }
+
+ @Override
+ public int getConnectionPolicy(BluetoothDevice device) {
+ if (mService == null || device == null) {
+ return CONNECTION_POLICY_FORBIDDEN;
+ }
+ return mService.getConnectionPolicy(device);
+ }
+
+ @Override
+ public boolean setEnabled(BluetoothDevice device, boolean enabled) {
+ boolean isEnabled = false;
+ if (mService == null || device == null) {
+ return false;
+ }
+ if (enabled) {
+ if (mService.getConnectionPolicy(device) < CONNECTION_POLICY_ALLOWED) {
+ isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
+ }
+ } else {
+ isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
+ }
+
+ return isEnabled;
+ }
+
+ @Override
+ public int getOrdinal() {
+ return ORDINAL;
+ }
+
+ @Override
+ public int getNameResource(BluetoothDevice device) {
+ return R.string.summary_empty;
+ }
+
+ @Override
+ public int getSummaryResourceForDevice(BluetoothDevice device) {
+ int state = getConnectionStatus(device);
+ return BluetoothUtils.getConnectionStateSummary(state);
+ }
+
+ @Override
+ public int getDrawableResource(BluetoothClass btClass) {
+ return 0;
+ }
+
+ /**
+ * Return the profile name as a string.
+ */
+ public String toString() {
+ return NAME;
+ }
+
+ @RequiresApi(32)
+ protected void finalize() {
+ if (VDBG) {
+ Log.d(TAG, "finalize()");
+ }
+ if (mService != null) {
+ try {
+ BluetoothAdapter.getDefaultAdapter().closeProfileProxy(
+ BluetoothProfile.CSIP_SET_COORDINATOR, mService);
+ mService = null;
+ } catch (Throwable t) {
+ Log.w(TAG, "Error cleaning up CSIP Set Coordinator proxy", t);
+ }
+ }
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
index c4cb6a1e7197..25fd430372f2 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
@@ -19,6 +19,7 @@ package com.android.settingslib.bluetooth;
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothA2dpSink;
import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothCsipSetCoordinator;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothHeadsetClient;
@@ -100,6 +101,7 @@ public class LocalBluetoothProfileManager {
private PbapClientProfile mPbapClientProfile;
private PbapServerProfile mPbapProfile;
private HearingAidProfile mHearingAidProfile;
+ private CsipSetCoordinatorProfile mCsipSetCoordinatorProfile;
private SapProfile mSapProfile;
private VolumeControlProfile mVolumeControlProfile;
@@ -230,7 +232,16 @@ public class LocalBluetoothProfileManager {
// Note: no event handler for VCP, only for being connectable.
mProfileNameMap.put(VolumeControlProfile.NAME, mVolumeControlProfile);
}
-
+ if (mCsipSetCoordinatorProfile == null
+ && supportedList.contains(BluetoothProfile.CSIP_SET_COORDINATOR)) {
+ if (DEBUG) {
+ Log.d(TAG, "Adding local CSIP set coordinator profile");
+ }
+ mCsipSetCoordinatorProfile =
+ new CsipSetCoordinatorProfile(mContext, mDeviceManager, this);
+ addProfile(mCsipSetCoordinatorProfile, mCsipSetCoordinatorProfile.NAME,
+ BluetoothCsipSetCoordinator.ACTION_CSIS_CONNECTION_STATE_CHANGED);
+ }
mEventManager.registerProfileIntentReceiver();
}
@@ -462,6 +473,10 @@ public class LocalBluetoothProfileManager {
return mHidDeviceProfile;
}
+ public CsipSetCoordinatorProfile getCsipSetCoordinatorProfile() {
+ return mCsipSetCoordinatorProfile;
+ }
+
/**
* Fill in a list of LocalBluetoothProfile objects that are supported by
* the local device and the remote device.
@@ -582,6 +597,12 @@ public class LocalBluetoothProfileManager {
removedProfiles.remove(mVolumeControlProfile);
}
+ if (mCsipSetCoordinatorProfile != null
+ && ArrayUtils.contains(uuids, BluetoothUuid.COORDINATED_SET)) {
+ profiles.add(mCsipSetCoordinatorProfile);
+ removedProfiles.remove(mCsipSetCoordinatorProfile);
+ }
+
if (DEBUG) {
Log.d(TAG,"New Profiles" + profiles.toString());
}
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 10600e37b220..0e9a51dbb63c 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -513,7 +513,7 @@
<provider android:name=".HeapDumpProvider"
android:authorities="com.android.shell.heapdump"
android:grantUriPermissions="true"
- android:exported="true" />
+ android:exported="false" />
<activity
android:name=".BugreportWarningActivity"
diff --git a/services/OWNERS b/services/OWNERS
index b7128a32fcee..a08331996556 100644
--- a/services/OWNERS
+++ b/services/OWNERS
@@ -4,3 +4,4 @@ per-file Android.bp = file:platform/build/soong:/OWNERS
per-file art-profile* = calin@google.com, ngeoffray@google.com, vmarko@google.com
per-file java/com/android/server/* = toddke@google.com,patb@google.com
+per-file tests/servicestests/src/com/android/server/systemconfig/* = patb@google.com
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 00cc75352633..bdeb4d56bfa4 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -175,8 +175,6 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
private final ReentrantReadWriteLock mBluetoothLock = new ReentrantReadWriteLock();
private boolean mBinding;
private boolean mUnbinding;
- private int mWaitForEnableRetry;
- private int mWaitForDisableRetry;
private BluetoothModeChangeHelper mBluetoothModeChangeHelper;
@@ -933,14 +931,15 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
if (mState == BluetoothAdapter.STATE_ON
|| mState == BluetoothAdapter.STATE_BLE_ON
|| mState == BluetoothAdapter.STATE_TURNING_ON
- || mState == BluetoothAdapter.STATE_TURNING_OFF) {
- Log.d(TAG, "enableBLE(): Bluetooth already enabled");
+ || mState == BluetoothAdapter.STATE_TURNING_OFF
+ || mState == BluetoothAdapter.STATE_BLE_TURNING_ON) {
+ Log.d(TAG, "enableBLE(): Bluetooth is already enabled or is turning on");
return true;
}
synchronized (mReceiver) {
// waive WRITE_SECURE_SETTINGS permission check
- sendEnableMsg(false,
- BluetoothProtoEnums.ENABLE_DISABLE_REASON_APPLICATION_REQUEST, packageName);
+ sendEnableMsg(false, BluetoothProtoEnums.ENABLE_DISABLE_REASON_APPLICATION_REQUEST,
+ packageName, true);
}
return true;
}
@@ -1734,6 +1733,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
private class BluetoothHandler extends Handler {
boolean mGetNameAddressOnly = false;
+ private int mWaitForEnableRetry;
+ private int mWaitForDisableRetry;
BluetoothHandler(Looper looper) {
super(looper);
@@ -1781,11 +1782,12 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
case MESSAGE_ENABLE:
int quietEnable = msg.arg1;
+ int isBle = msg.arg2;
if (mHandler.hasMessages(MESSAGE_HANDLE_DISABLE_DELAYED)
|| mHandler.hasMessages(MESSAGE_HANDLE_ENABLE_DELAYED)) {
// We are handling enable or disable right now, wait for it.
mHandler.sendMessageDelayed(mHandler.obtainMessage(MESSAGE_ENABLE,
- quietEnable, 0), ENABLE_DISABLE_DELAY_MS);
+ quietEnable, isBle), ENABLE_DISABLE_DELAY_MS);
break;
}
@@ -1800,13 +1802,28 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
try {
mBluetoothLock.readLock().lock();
if (mBluetooth != null) {
+ boolean isHandled = true;
int state = mBluetooth.getState();
- if (state == BluetoothAdapter.STATE_BLE_ON) {
- Slog.w(TAG, "BT Enable in BLE_ON State, going to ON");
- mBluetooth.onLeServiceUp();
- persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
- break;
+ switch (state) {
+ case BluetoothAdapter.STATE_BLE_ON:
+ if (isBle == 1) {
+ Slog.i(TAG, "Already at BLE_ON State");
+ } else {
+ Slog.w(TAG, "BT Enable in BLE_ON State, going to ON");
+ mBluetooth.onLeServiceUp();
+ persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
+ }
+ break;
+ case BluetoothAdapter.STATE_BLE_TURNING_ON:
+ case BluetoothAdapter.STATE_TURNING_ON:
+ case BluetoothAdapter.STATE_ON:
+ Slog.i(TAG, "MESSAGE_ENABLE: already enabled");
+ break;
+ default:
+ isHandled = false;
+ break;
}
+ if (isHandled) break;
}
} catch (RemoteException e) {
Slog.e(TAG, "", e);
@@ -2559,7 +2576,12 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
}
private void sendEnableMsg(boolean quietMode, int reason, String packageName) {
- mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE, quietMode ? 1 : 0, 0));
+ sendEnableMsg(quietMode, reason, packageName, false);
+ }
+
+ private void sendEnableMsg(boolean quietMode, int reason, String packageName, boolean isBle) {
+ mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE, quietMode ? 1 : 0,
+ isBle ? 1 : 0));
addActiveLog(reason, packageName, true);
mLastEnabledTime = SystemClock.elapsedRealtime();
}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index b1ffaeb50912..6d85273de142 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -734,11 +734,8 @@ public final class ActiveServices {
}
ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
- if (!r.mAllowWhileInUsePermissionInFgs) {
- r.mAllowWhileInUsePermissionInFgs =
- shouldAllowWhileInUsePermissionInFgsLocked(callingPackage, callingPid,
- callingUid, service, r, allowBackgroundActivityStarts);
- }
+ setFgsRestrictionLocked(callingPackage, callingPid, callingUid, r,
+ allowBackgroundActivityStarts);
return cmp;
}
@@ -1411,14 +1408,6 @@ public final class ActiveServices {
+ String.format("0x%08X", manifestType)
+ " in service element of manifest file");
}
- // If the foreground service is not started from TOP process, do not allow it to
- // have while-in-use location/camera/microphone access.
- if (!r.mAllowWhileInUsePermissionInFgs) {
- Slog.w(TAG,
- "Foreground service started from background can not have "
- + "location/camera/microphone access: service "
- + r.shortInstanceName);
- }
}
boolean alreadyStartedOp = false;
boolean stopProcStatsOp = false;
@@ -1466,6 +1455,57 @@ public final class ActiveServices {
ignoreForeground = true;
}
+ if (!ignoreForeground) {
+ if (r.mStartForegroundCount == 0) {
+ /*
+ If the service was started with startService(), not
+ startForegroundService(), and if startForeground() isn't called within
+ mFgsStartForegroundTimeoutMs, then we check the state of the app
+ (who owns the service, which is the app that called startForeground())
+ again. If the app is in the foreground, or in any other cases where
+ FGS-starts are allowed, then we still allow the FGS to be started.
+ Otherwise, startForeground() would fail.
+
+ If the service was started with startForegroundService(), then the service
+ must call startForeground() within a timeout anyway, so we don't need this
+ check.
+ */
+ if (!r.fgRequired) {
+ final long delayMs = SystemClock.elapsedRealtime() - r.createRealTime;
+ if (delayMs > mAm.mConstants.mFgsStartForegroundTimeoutMs) {
+ resetFgsRestrictionLocked(r);
+ setFgsRestrictionLocked(r.serviceInfo.packageName, r.app.pid,
+ r.appInfo.uid, r, false);
+ EventLog.writeEvent(0x534e4554, "183147114",
+ r.appInfo.uid,
+ "call setFgsRestrictionLocked again due to "
+ + "startForegroundTimeout");
+ }
+ }
+ } else if (r.mStartForegroundCount >= 1) {
+ // The second or later time startForeground() is called after service is
+ // started. Check for app state again.
+ final long delayMs = SystemClock.elapsedRealtime() -
+ r.mLastSetFgsRestrictionTime;
+ if (delayMs > mAm.mConstants.mFgsStartForegroundTimeoutMs) {
+ resetFgsRestrictionLocked(r);
+ setFgsRestrictionLocked(r.serviceInfo.packageName, r.app.pid,
+ r.appInfo.uid, r, false);
+ EventLog.writeEvent(0x534e4554, "183147114", r.appInfo.uid,
+ "call setFgsRestrictionLocked for "
+ + (r.mStartForegroundCount + 1) + "th startForeground");
+ }
+ }
+ // If the foreground service is not started from TOP process, do not allow it to
+ // have while-in-use location/camera/microphone access.
+ if (!r.mAllowWhileInUsePermissionInFgs) {
+ Slog.w(TAG,
+ "Foreground service started from background can not have "
+ + "location/camera/microphone access: service "
+ + r.shortInstanceName);
+ }
+ }
+
// Apps under strict background restrictions simply don't get to have foreground
// services, so now that we've enforced the startForegroundService() contract
// we only do the machinery of making the service foreground when the app
@@ -1501,6 +1541,7 @@ public final class ActiveServices {
active.mNumActive++;
}
r.isForeground = true;
+ r.mStartForegroundCount++;
if (!stopProcStatsOp) {
ServiceState stracker = r.getTracker();
if (stracker != null) {
@@ -1559,6 +1600,7 @@ public final class ActiveServices {
decActiveForegroundAppLocked(smap, r);
}
r.isForeground = false;
+ resetFgsRestrictionLocked(r);
ServiceState stracker = r.getTracker();
if (stracker != null) {
stracker.setForeground(false, mAm.mProcessStats.getMemFactorLocked(),
@@ -2118,12 +2160,7 @@ public final class ActiveServices {
}
}
- if (!s.mAllowWhileInUsePermissionInFgs) {
- s.mAllowWhileInUsePermissionInFgs =
- shouldAllowWhileInUsePermissionInFgsLocked(callingPackage,
- callingPid, callingUid,
- service, s, false);
- }
+ setFgsRestrictionLocked(callingPackage, callingPid, callingUid, s, false);
if (s.app != null) {
if ((flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) {
@@ -3419,7 +3456,7 @@ public final class ActiveServices {
r.isForeground = false;
r.foregroundId = 0;
r.foregroundNoti = null;
- r.mAllowWhileInUsePermissionInFgs = false;
+ resetFgsRestrictionLocked(r);
// Clear start entries.
r.clearDeliveredStartsLocked();
@@ -4900,7 +4937,7 @@ public final class ActiveServices {
* @return true if allow, false otherwise.
*/
private boolean shouldAllowWhileInUsePermissionInFgsLocked(String callingPackage,
- int callingPid, int callingUid, Intent intent, ServiceRecord r,
+ int callingPid, int callingUid, ServiceRecord r,
boolean allowBackgroundActivityStarts) {
// Is the background FGS start restriction turned on?
if (!mAm.mConstants.mFlagBackgroundFgsStartRestrictionEnabled) {
@@ -4986,6 +5023,28 @@ public final class ActiveServices {
boolean canAllowWhileInUsePermissionInFgsLocked(int callingPid, int callingUid,
String callingPackage) {
return shouldAllowWhileInUsePermissionInFgsLocked(
- callingPackage, callingPid, callingUid, null, null, false);
+ callingPackage, callingPid, callingUid, null, false);
+ }
+
+ /**
+ * In R, mAllowWhileInUsePermissionInFgs is to allow while-in-use permissions in foreground
+ * service or not. while-in-use permissions in FGS started from background might be restricted.
+ * @param callingPackage caller app's package name.
+ * @param callingUid caller app's uid.
+ * @param r the service to start.
+ * @return true if allow, false otherwise.
+ */
+ private void setFgsRestrictionLocked(String callingPackage,
+ int callingPid, int callingUid, ServiceRecord r,
+ boolean allowBackgroundActivityStarts) {
+ r.mLastSetFgsRestrictionTime = SystemClock.elapsedRealtime();
+ if (!r.mAllowWhileInUsePermissionInFgs) {
+ r.mAllowWhileInUsePermissionInFgs = shouldAllowWhileInUsePermissionInFgsLocked(
+ callingPackage, callingPid, callingUid, r, allowBackgroundActivityStarts);
+ }
+ }
+
+ private void resetFgsRestrictionLocked(ServiceRecord r) {
+ r.mAllowWhileInUsePermissionInFgs = false;
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index 7be843f17863..00d8208ea118 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -88,6 +88,7 @@ final class ActivityManagerConstants extends ContentObserver {
static final String KEY_PROCESS_START_ASYNC = "process_start_async";
static final String KEY_MEMORY_INFO_THROTTLE_TIME = "memory_info_throttle_time";
static final String KEY_TOP_TO_FGS_GRACE_DURATION = "top_to_fgs_grace_duration";
+ static final String KEY_FGS_START_FOREGROUND_TIMEOUT = "fgs_start_foreground_timeout";
static final String KEY_PENDINGINTENT_WARNING_THRESHOLD = "pendingintent_warning_threshold";
private static final int DEFAULT_MAX_CACHED_PROCESSES = 32;
@@ -121,6 +122,7 @@ final class ActivityManagerConstants extends ContentObserver {
private static final boolean DEFAULT_PROCESS_START_ASYNC = true;
private static final long DEFAULT_MEMORY_INFO_THROTTLE_TIME = 5*60*1000;
private static final long DEFAULT_TOP_TO_FGS_GRACE_DURATION = 15 * 1000;
+ private static final int DEFAULT_FGS_START_FOREGROUND_TIMEOUT_MS = 10 * 1000;
private static final int DEFAULT_PENDINGINTENT_WARNING_THRESHOLD = 2000;
// Flag stored in the DeviceConfig API.
@@ -273,6 +275,12 @@ final class ActivityManagerConstants extends ContentObserver {
// this long.
public long TOP_TO_FGS_GRACE_DURATION = DEFAULT_TOP_TO_FGS_GRACE_DURATION;
+ /**
+ * When service started from background, before the timeout it can be promoted to FGS by calling
+ * Service.startForeground().
+ */
+ volatile long mFgsStartForegroundTimeoutMs = DEFAULT_FGS_START_FOREGROUND_TIMEOUT_MS;
+
// Indicates whether the activity starts logging is enabled.
// Controlled by Settings.Global.ACTIVITY_STARTS_LOGGING_ENABLED
volatile boolean mFlagActivityStartsLoggingEnabled;
@@ -421,6 +429,9 @@ final class ActivityManagerConstants extends ContentObserver {
case KEY_MIN_ASSOC_LOG_DURATION:
updateMinAssocLogDuration();
break;
+ case KEY_FGS_START_FOREGROUND_TIMEOUT:
+ updateFgsStartForegroundTimeout();
+ break;
default:
break;
}
@@ -697,6 +708,13 @@ final class ActivityManagerConstants extends ContentObserver {
/* defaultValue */ DEFAULT_MIN_ASSOC_LOG_DURATION);
}
+ private void updateFgsStartForegroundTimeout() {
+ mFgsStartForegroundTimeoutMs = DeviceConfig.getLong(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ KEY_FGS_START_FOREGROUND_TIMEOUT,
+ DEFAULT_FGS_START_FOREGROUND_TIMEOUT_MS);
+ }
+
void dump(PrintWriter pw) {
pw.println("ACTIVITY MANAGER SETTINGS (dumpsys activity settings) "
+ Settings.Global.ACTIVITY_MANAGER_CONSTANTS + ":");
@@ -769,6 +787,8 @@ final class ActivityManagerConstants extends ContentObserver {
pw.println(Arrays.toString(IMPERCEPTIBLE_KILL_EXEMPT_PACKAGES.toArray()));
pw.print(" "); pw.print(KEY_MIN_ASSOC_LOG_DURATION); pw.print("=");
pw.println(MIN_ASSOC_LOG_DURATION);
+ pw.print(" "); pw.print(KEY_FGS_START_FOREGROUND_TIMEOUT); pw.print("=");
+ pw.println(mFgsStartForegroundTimeoutMs);
pw.println();
if (mOverrideMaxCachedProcesses >= 0) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index af8990778773..50f3520e6291 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -94,7 +94,6 @@ import com.android.internal.util.MemInfoReader;
import com.android.server.compat.PlatformCompat;
import java.io.BufferedReader;
-import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
@@ -787,8 +786,7 @@ final class ActivityManagerShellCommand extends ShellCommand {
return -1;
}
- File file = new File(filename);
- file.delete();
+ // Writes an error message to stderr on failure
ParcelFileDescriptor fd = openFileForSystem(filename, "w");
if (fd == null) {
return -1;
@@ -942,16 +940,16 @@ final class ActivityManagerShellCommand extends ShellCommand {
String logNameTimeString = LOG_NAME_TIME_FORMATTER.format(localDateTime);
heapFile = "/data/local/tmp/heapdump-" + logNameTimeString + ".prof";
}
- pw.println("File: " + heapFile);
- pw.flush();
- File file = new File(heapFile);
- file.delete();
+ // Writes an error message to stderr on failure
ParcelFileDescriptor fd = openFileForSystem(heapFile, "w");
if (fd == null) {
return -1;
}
+ pw.println("File: " + heapFile);
+ pw.flush();
+
final CountDownLatch latch = new CountDownLatch(1);
final RemoteCallback finishCallback = new RemoteCallback(new OnResultListener() {
diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
index 39f79ca2f13b..ef47b1ebc7ec 100644
--- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
+++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
@@ -22,6 +22,7 @@ import android.content.Context;
import android.net.wifi.WifiManager;
import android.os.BatteryStats;
import android.os.Bundle;
+import android.os.OutcomeReceiver;
import android.os.Parcelable;
import android.os.Process;
import android.os.ServiceManager;
@@ -40,6 +41,7 @@ import com.android.internal.os.BatteryStatsImpl;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.function.pooled.PooledLambda;
+import java.util.concurrent.ExecutionException;
import libcore.util.EmptyArray;
import java.util.concurrent.CompletableFuture;
@@ -405,7 +407,7 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
// We will request data from external processes asynchronously, and wait on a timeout.
SynchronousResultReceiver wifiReceiver = null;
SynchronousResultReceiver bluetoothReceiver = null;
- SynchronousResultReceiver modemReceiver = null;
+ CompletableFuture<ModemActivityInfo> modemFuture = CompletableFuture.completedFuture(null);
boolean railUpdated = false;
if ((updateFlags & BatteryStatsImpl.ExternalStatsSync.UPDATE_WIFI) != 0) {
@@ -460,8 +462,22 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
}
if (mTelephony != null) {
- modemReceiver = new SynchronousResultReceiver("telephony");
- mTelephony.requestModemActivityInfo(modemReceiver);
+ CompletableFuture<ModemActivityInfo> temp = new CompletableFuture<>();
+ mTelephony.requestModemActivityInfo(Runnable::run,
+ new OutcomeReceiver<ModemActivityInfo,
+ TelephonyManager.ModemActivityInfoException>() {
+ @Override
+ public void onResult(ModemActivityInfo result) {
+ temp.complete(result);
+ }
+
+ @Override
+ public void onError(TelephonyManager.ModemActivityInfoException e) {
+ Slog.w(TAG, "error reading modem stats:" + e);
+ temp.complete(null);
+ }
+ });
+ modemFuture = temp;
}
if (!railUpdated) {
synchronized (mStats) {
@@ -472,7 +488,17 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
final WifiActivityEnergyInfo wifiInfo = awaitControllerInfo(wifiReceiver);
final BluetoothActivityEnergyInfo bluetoothInfo = awaitControllerInfo(bluetoothReceiver);
- final ModemActivityInfo modemInfo = awaitControllerInfo(modemReceiver);
+ ModemActivityInfo modemInfo = null;
+ try {
+ modemInfo = modemFuture.get(EXTERNAL_STATS_SYNC_TIMEOUT_MILLIS,
+ TimeUnit.MILLISECONDS);
+ } catch (TimeoutException | InterruptedException e) {
+ Slog.w(TAG, "timeout or interrupt reading modem stats: " + e);
+ } catch (ExecutionException e) {
+ Slog.w(TAG, "exception reading modem stats: " + e.getCause());
+ }
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
+ final long uptime = SystemClock.uptimeMillis();
synchronized (mStats) {
mStats.addHistoryEventLocked(
@@ -519,11 +545,7 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
}
if (modemInfo != null) {
- if (modemInfo.isValid()) {
- mStats.updateMobileRadioState(modemInfo);
- } else {
- Slog.w(TAG, "modem info is invalid: " + modemInfo);
- }
+ mStats.updateMobileRadioState(modemInfo);
}
}
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 580ceca3b197..34ba3e078860 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -1208,7 +1208,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub
public void noteModemControllerActivity(ModemActivityInfo info) {
enforceCallingPermission();
- if (info == null || !info.isValid()) {
+ if (info == null) {
Slog.e(TAG, "invalid modem data given: " + info);
return;
}
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 1b65dbac2294..0e628289a09f 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -142,6 +142,10 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
// allow while-in-use permissions in foreground service or not.
// while-in-use permissions in FGS started from background might be restricted.
boolean mAllowWhileInUsePermissionInFgs;
+ // The number of times Service.startForeground() is called;
+ int mStartForegroundCount;
+ // Last time mAllowWhileInUsePermissionInFgs is set.
+ long mLastSetFgsRestrictionTime;
// the most recent package that start/bind this service.
String mRecentCallingPackage;
@@ -406,6 +410,8 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
}
pw.print(prefix); pw.print("allowWhileInUsePermissionInFgs=");
pw.println(mAllowWhileInUsePermissionInFgs);
+ pw.print(prefix); pw.print("startForegroundCount=");
+ pw.println(mStartForegroundCount);
pw.print(prefix); pw.print("recentCallingPackage=");
pw.println(mRecentCallingPackage);
if (delayed) {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 5babfeb08f76..f83d059ce212 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -123,6 +123,7 @@ import android.app.INotificationManager;
import android.app.ITransientNotification;
import android.app.ITransientNotificationCallback;
import android.app.IUriGrantsManager;
+import android.app.KeyguardManager;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationChannelGroup;
@@ -479,6 +480,8 @@ public class NotificationManagerService extends SystemService {
final ArrayMap<NotificationRecord, ArrayList<CancelNotificationRunnable>> mDelayedCancelations =
new ArrayMap<>();
+ private KeyguardManager mKeyguardManager;
+
// The last key in this list owns the hardware.
ArrayList<String> mLights = new ArrayList<>();
@@ -1726,6 +1729,11 @@ public class NotificationManagerService extends SystemService {
}
@VisibleForTesting
+ void setKeyguardManager(KeyguardManager keyguardManager) {
+ mKeyguardManager = keyguardManager;
+ }
+
+ @VisibleForTesting
ShortcutHelper getShortcutHelper() {
return mShortcutHelper;
}
@@ -2330,6 +2338,7 @@ public class NotificationManagerService extends SystemService {
mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
+ mKeyguardManager = getContext().getSystemService(KeyguardManager.class);
mZenModeHelper.onSystemReady();
mRoleObserver = new RoleObserver(getContext().getSystemService(RoleManager.class),
mPackageManager, getContext().getMainExecutor());
@@ -6902,7 +6911,6 @@ public class NotificationManagerService extends SystemService {
boolean beep = false;
boolean blink = false;
- final Notification notification = record.getSbn().getNotification();
final String key = record.getKey();
// Should this notification make noise, vibe, or use the LED?
@@ -6924,7 +6932,7 @@ public class NotificationManagerService extends SystemService {
if (!record.isUpdate
&& record.getImportance() > IMPORTANCE_MIN
&& !suppressedByDnd) {
- sendAccessibilityEvent(notification, record.getSbn().getPackageName());
+ sendAccessibilityEvent(record);
sentAccessibilityEvent = true;
}
@@ -6946,7 +6954,7 @@ public class NotificationManagerService extends SystemService {
boolean hasAudibleAlert = hasValidSound || hasValidVibrate;
if (hasAudibleAlert && !shouldMuteNotificationLocked(record)) {
if (!sentAccessibilityEvent) {
- sendAccessibilityEvent(notification, record.getSbn().getPackageName());
+ sendAccessibilityEvent(record);
sentAccessibilityEvent = true;
}
if (DBG) Slog.v(TAG, "Interrupting!");
@@ -7663,17 +7671,30 @@ public class NotificationManagerService extends SystemService {
return (x < low) ? low : ((x > high) ? high : x);
}
- void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
+ void sendAccessibilityEvent(NotificationRecord record) {
if (!mAccessibilityManager.isEnabled()) {
return;
}
- AccessibilityEvent event =
+ final Notification notification = record.getNotification();
+ final CharSequence packageName = record.getSbn().getPackageName();
+ final AccessibilityEvent event =
AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
event.setPackageName(packageName);
event.setClassName(Notification.class.getName());
- event.setParcelableData(notification);
- CharSequence tickerText = notification.tickerText;
+ final int visibilityOverride = record.getPackageVisibilityOverride();
+ final int notifVisibility = visibilityOverride == NotificationManager.VISIBILITY_NO_OVERRIDE
+ ? notification.visibility : visibilityOverride;
+ final int userId = record.getUser().getIdentifier();
+ final boolean needPublic = userId >= 0 && mKeyguardManager.isDeviceLocked(userId);
+ if (needPublic && notifVisibility != Notification.VISIBILITY_PUBLIC) {
+ // Emit the public version if we're on the lockscreen and this notification isn't
+ // publicly visible.
+ event.setParcelableData(notification.publicVersion);
+ } else {
+ event.setParcelableData(notification);
+ }
+ final CharSequence tickerText = notification.tickerText;
if (!TextUtils.isEmpty(tickerText)) {
event.getText().add(tickerText);
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 1173df629796..4767823c8963 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -14289,9 +14289,15 @@ public class PackageManagerService extends IPackageManager.Stub
return new ParceledListSlice<IntentFilter>(result) {
@Override
protected void writeElement(IntentFilter parcelable, Parcel dest, int callFlags) {
- // IntentFilter has final Parcelable methods, so redirect to the subclass
- ((ParsedIntentInfo) parcelable).writeIntentInfoToParcel(dest,
- callFlags);
+ parcelable.writeToParcel(dest, callFlags);
+ }
+
+ @Override
+ protected void writeParcelableCreator(IntentFilter parcelable, Parcel dest) {
+ // All Parcel#writeParcelableCreator does is serialize the class name to
+ // access via reflection to grab its CREATOR. This does that manually, pointing
+ // to the parent IntentFilter so that all of the subclass fields are ignored.
+ dest.writeString(IntentFilter.class.getName());
}
};
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 836e6150414c..ae940d0e3c1c 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -608,6 +608,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
private int mPowerButtonSuppressionDelayMillis = POWER_BUTTON_SUPPRESSION_DELAY_DEFAULT_MILLIS;
+ private boolean mLockNowPending = false;
+
private static final int MSG_DISPATCH_MEDIA_KEY_WITH_WAKE_LOCK = 3;
private static final int MSG_DISPATCH_MEDIA_KEY_REPEAT_WITH_WAKE_LOCK = 4;
private static final int MSG_KEYGUARD_DRAWN_COMPLETE = 5;
@@ -4941,6 +4943,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mKeyguardDelegate.doKeyguardTimeout(options);
}
mLockScreenTimerActive = false;
+ mLockNowPending = false;
options = null;
}
}
@@ -4950,7 +4953,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
- ScreenLockTimeout mScreenLockTimeout = new ScreenLockTimeout();
+ final ScreenLockTimeout mScreenLockTimeout = new ScreenLockTimeout();
@Override
public void lockNow(Bundle options) {
@@ -4962,6 +4965,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mScreenLockTimeout.setLockOptions(options);
}
mHandler.post(mScreenLockTimeout);
+ synchronized (mScreenLockTimeout) {
+ mLockNowPending = true;
+ }
}
// TODO (b/113840485): Move this logic to DisplayPolicy when lockscreen supports multi-display.
@@ -4977,6 +4983,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
private void updateLockScreenTimeout() {
synchronized (mScreenLockTimeout) {
+ if (mLockNowPending) {
+ Log.w(TAG, "lockNow pending, ignore updating lockscreen timeout");
+ return;
+ }
final boolean enable = !mAllowLockscreenWhenOnDisplays.isEmpty()
&& mDefaultDisplayPolicy.isAwake()
&& mKeyguardDelegate != null && mKeyguardDelegate.isSecure(mCurrentUserId);
diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java
index 392792dbae69..b75bce833e04 100644
--- a/services/core/java/com/android/server/role/RoleManagerService.java
+++ b/services/core/java/com/android/server/role/RoleManagerService.java
@@ -662,6 +662,12 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
@Override
public String getDefaultSmsPackage(int userId) {
+ userId = handleIncomingUser(userId, false, "getDefaultSmsPackage");
+ if (!mUserManagerInternal.exists(userId)) {
+ Slog.e(LOG_TAG, "user " + userId + " does not exist");
+ return null;
+ }
+
long identity = Binder.clearCallingIdentity();
try {
return CollectionUtils.firstOrNull(
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 03900150cfae..71b3e61a9844 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -102,6 +102,7 @@ import android.os.Environment;
import android.os.IStoraged;
import android.os.IThermalEventListener;
import android.os.IThermalService;
+import android.os.OutcomeReceiver;
import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
import android.os.RemoteException;
@@ -172,6 +173,7 @@ import com.android.server.stats.pull.netstats.SubInfo;
import com.android.server.storage.DiskStatsFileLogger;
import com.android.server.storage.DiskStatsLoggingService;
+import java.util.concurrent.ExecutionException;
import libcore.io.IoUtils;
import org.json.JSONArray;
@@ -1731,22 +1733,47 @@ public class StatsPullAtomService extends SystemService {
int pullModemActivityInfoLocked(int atomTag, List<StatsEvent> pulledData) {
long token = Binder.clearCallingIdentity();
try {
- SynchronousResultReceiver modemReceiver = new SynchronousResultReceiver("telephony");
- mTelephony.requestModemActivityInfo(modemReceiver);
- final ModemActivityInfo modemInfo = awaitControllerInfo(modemReceiver);
+ CompletableFuture<ModemActivityInfo> modemFuture = new CompletableFuture<>();
+ mTelephony.requestModemActivityInfo(Runnable::run,
+ new OutcomeReceiver<ModemActivityInfo,
+ TelephonyManager.ModemActivityInfoException>() {
+ @Override
+ public void onResult(ModemActivityInfo result) {
+ modemFuture.complete(result);
+ }
+
+ @Override
+ public void onError(TelephonyManager.ModemActivityInfoException e) {
+ Slog.w(TAG, "error reading modem stats:" + e);
+ modemFuture.complete(null);
+ }
+ });
+
+ ModemActivityInfo modemInfo;
+ try {
+ modemInfo = modemFuture.get(EXTERNAL_STATS_SYNC_TIMEOUT_MILLIS,
+ TimeUnit.MILLISECONDS);
+ } catch (TimeoutException | InterruptedException e) {
+ Slog.w(TAG, "timeout or interrupt reading modem stats: " + e);
+ return StatsManager.PULL_SKIP;
+ } catch (ExecutionException e) {
+ Slog.w(TAG, "exception reading modem stats: " + e.getCause());
+ return StatsManager.PULL_SKIP;
+ }
+
if (modemInfo == null) {
return StatsManager.PULL_SKIP;
}
StatsEvent e = StatsEvent.newBuilder()
.setAtomId(atomTag)
- .writeLong(modemInfo.getTimestamp())
+ .writeLong(modemInfo.getTimestampMillis())
.writeLong(modemInfo.getSleepTimeMillis())
.writeLong(modemInfo.getIdleTimeMillis())
- .writeLong(modemInfo.getTransmitPowerInfo().get(0).getTimeInMillis())
- .writeLong(modemInfo.getTransmitPowerInfo().get(1).getTimeInMillis())
- .writeLong(modemInfo.getTransmitPowerInfo().get(2).getTimeInMillis())
- .writeLong(modemInfo.getTransmitPowerInfo().get(3).getTimeInMillis())
- .writeLong(modemInfo.getTransmitPowerInfo().get(4).getTimeInMillis())
+ .writeLong(modemInfo.getTransmitDurationMillisAtPowerLevel(0))
+ .writeLong(modemInfo.getTransmitDurationMillisAtPowerLevel(1))
+ .writeLong(modemInfo.getTransmitDurationMillisAtPowerLevel(2))
+ .writeLong(modemInfo.getTransmitDurationMillisAtPowerLevel(3))
+ .writeLong(modemInfo.getTransmitDurationMillisAtPowerLevel(4))
.writeLong(modemInfo.getReceiveTimeMillis())
.build();
pulledData.add(e);
diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
index 277163a6e3ec..630317a150f6 100755
--- a/services/core/java/com/android/server/tv/TvInputHardwareManager.java
+++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
@@ -1265,12 +1265,14 @@ class TvInputHardwareManager implements TvInputHal.Callback {
if (inputId != null) {
if (connection.updateCableConnectionStatusLocked(cableConnectionStatus)) {
if (previousCableConnectionStatus != connection.getInputStateLocked()) {
- mListener.onStateChanged(inputId, connection.getInputStateLocked());
+ mHandler.obtainMessage(ListenerHandler.STATE_CHANGED,
+ connection.getInputStateLocked(), 0, inputId).sendToTarget();
}
} else {
if ((previousConfigsLength == 0)
!= (connection.getConfigsLengthLocked() == 0)) {
- mListener.onStateChanged(inputId, connection.getInputStateLocked());
+ mHandler.obtainMessage(ListenerHandler.STATE_CHANGED,
+ connection.getInputStateLocked(), 0, inputId).sendToTarget();
}
}
}
diff --git a/services/core/java/com/android/server/vcn/Vcn.java b/services/core/java/com/android/server/vcn/Vcn.java
index 382398a210bb..e0cc8e182079 100644
--- a/services/core/java/com/android/server/vcn/Vcn.java
+++ b/services/core/java/com/android/server/vcn/Vcn.java
@@ -352,7 +352,7 @@ public class Vcn extends Handler {
}
private void handleSafeModeStatusChanged() {
- logDbg("VcnGatewayConnection safe mode status changed");
+ logVdbg("VcnGatewayConnection safe mode status changed");
boolean hasSafeModeGatewayConnection = false;
// If any VcnGatewayConnection is in safe mode, mark the entire VCN as being in safe mode
@@ -368,7 +368,7 @@ public class Vcn extends Handler {
hasSafeModeGatewayConnection ? VCN_STATUS_CODE_SAFE_MODE : VCN_STATUS_CODE_ACTIVE;
if (oldStatus != mCurrentStatus) {
mVcnCallback.onSafeModeStatusChanged(hasSafeModeGatewayConnection);
- logDbg(
+ logInfo(
"Safe mode "
+ (mCurrentStatus == VCN_STATUS_CODE_SAFE_MODE ? "entered" : "exited"));
}
@@ -539,6 +539,16 @@ public class Vcn extends Handler {
Slog.d(TAG, getLogPrefix() + msg, tr);
}
+ private void logInfo(String msg) {
+ Slog.i(TAG, getLogPrefix() + msg);
+ LOCAL_LOG.log(getLogPrefix() + "INFO: " + msg);
+ }
+
+ private void logInfo(String msg, Throwable tr) {
+ Slog.i(TAG, getLogPrefix() + msg, tr);
+ LOCAL_LOG.log(getLogPrefix() + "INFO: " + msg + tr);
+ }
+
private void logErr(String msg) {
Slog.e(TAG, getLogPrefix() + msg);
LOCAL_LOG.log(getLogPrefix() + "ERR: " + msg);
diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
index 450257fcdecb..7dec4e785f5c 100644
--- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
+++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
@@ -1677,10 +1677,8 @@ public class VcnGatewayConnection extends StateMachine {
mFailedAttempts = 0;
cancelSafeModeAlarm();
- if (mIsInSafeMode) {
- mIsInSafeMode = false;
- mGatewayStatusCallback.onSafeModeStatusChanged();
- }
+ mIsInSafeMode = false;
+ mGatewayStatusCallback.onSafeModeStatusChanged();
}
protected void applyTransform(
diff --git a/services/java/com/android/server/SystemConfigService.java b/services/java/com/android/server/SystemConfigService.java
index a2768c637d79..3a9b2dca3921 100644
--- a/services/java/com/android/server/SystemConfigService.java
+++ b/services/java/com/android/server/SystemConfigService.java
@@ -21,6 +21,7 @@ import static java.util.stream.Collectors.toMap;
import android.Manifest;
import android.content.Context;
import android.os.ISystemConfig;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.SparseArray;
@@ -84,6 +85,21 @@ public class SystemConfigService extends SystemService {
}
return ArrayUtils.convertToIntArray(uids);
}
+
+ @Override
+ public List<String> getEnabledComponentOverrides(String packageName) {
+ ArrayMap<String, Boolean> systemComponents = SystemConfig.getInstance()
+ .getComponentsEnabledStates(packageName);
+ List<String> enabledComponent = new ArrayList<>();
+ if (systemComponents != null) {
+ for (Map.Entry<String, Boolean> entry : systemComponents.entrySet()) {
+ if (Boolean.TRUE.equals(entry.getValue())) {
+ enabledComponent.add(entry.getKey());
+ }
+ }
+ }
+ return enabledComponent;
+ }
};
public SystemConfigService(Context context) {
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
index ad15a99a0d78..11ea4a46b73b 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -46,6 +46,7 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.ActivityManager;
+import android.app.KeyguardManager;
import android.app.Notification;
import android.app.Notification.Builder;
import android.app.NotificationChannel;
@@ -103,6 +104,8 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
NotificationUsageStats mUsageStats;
@Mock
IAccessibilityManager mAccessibilityService;
+ @Mock
+ KeyguardManager mKeyguardManager;
NotificationRecordLoggerFake mNotificationRecordLogger = new NotificationRecordLoggerFake();
private InstanceIdSequence mNotificationInstanceIdSequence = new InstanceIdSequenceFake(
1 << 30);
@@ -147,6 +150,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
when(mAudioManager.getStreamVolume(anyInt())).thenReturn(10);
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL);
when(mUsageStats.isAlertRateLimited(any())).thenReturn(false);
+ when(mKeyguardManager.isDeviceLocked(anyInt())).thenReturn(false);
long serviceReturnValue = IntPair.of(
AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED,
@@ -168,6 +172,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
mService.setFallbackVibrationPattern(FALLBACK_VIBRATION_PATTERN);
mService.setUsageStats(mUsageStats);
mService.setAccessibilityManager(accessibilityManager);
+ mService.setKeyguardManager(mKeyguardManager);
mService.mScreenOn = false;
mService.mInCallStateOffHook = false;
mService.mNotificationPulseEnabled = true;
@@ -484,6 +489,94 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
}
@Test
+ public void testLockedPrivateA11yRedaction() throws Exception {
+ NotificationRecord r = getBeepyNotification();
+ r.setPackageVisibilityOverride(NotificationManager.VISIBILITY_NO_OVERRIDE);
+ r.getNotification().visibility = Notification.VISIBILITY_PRIVATE;
+ when(mKeyguardManager.isDeviceLocked(anyInt())).thenReturn(true);
+ AccessibilityManager accessibilityManager = Mockito.mock(AccessibilityManager.class);
+ when(accessibilityManager.isEnabled()).thenReturn(true);
+ mService.setAccessibilityManager(accessibilityManager);
+
+ mService.buzzBeepBlinkLocked(r);
+
+ ArgumentCaptor<AccessibilityEvent> eventCaptor =
+ ArgumentCaptor.forClass(AccessibilityEvent.class);
+
+ verify(accessibilityManager, times(1))
+ .sendAccessibilityEvent(eventCaptor.capture());
+
+ AccessibilityEvent event = eventCaptor.getValue();
+ assertEquals(r.getNotification().publicVersion, event.getParcelableData());
+ }
+
+ @Test
+ public void testLockedOverridePrivateA11yRedaction() throws Exception {
+ NotificationRecord r = getBeepyNotification();
+ r.setPackageVisibilityOverride(Notification.VISIBILITY_PRIVATE);
+ r.getNotification().visibility = Notification.VISIBILITY_PUBLIC;
+ when(mKeyguardManager.isDeviceLocked(anyInt())).thenReturn(true);
+ AccessibilityManager accessibilityManager = Mockito.mock(AccessibilityManager.class);
+ when(accessibilityManager.isEnabled()).thenReturn(true);
+ mService.setAccessibilityManager(accessibilityManager);
+
+ mService.buzzBeepBlinkLocked(r);
+
+ ArgumentCaptor<AccessibilityEvent> eventCaptor =
+ ArgumentCaptor.forClass(AccessibilityEvent.class);
+
+ verify(accessibilityManager, times(1))
+ .sendAccessibilityEvent(eventCaptor.capture());
+
+ AccessibilityEvent event = eventCaptor.getValue();
+ assertEquals(r.getNotification().publicVersion, event.getParcelableData());
+ }
+
+ @Test
+ public void testLockedPublicA11yNoRedaction() throws Exception {
+ NotificationRecord r = getBeepyNotification();
+ r.setPackageVisibilityOverride(NotificationManager.VISIBILITY_NO_OVERRIDE);
+ r.getNotification().visibility = Notification.VISIBILITY_PUBLIC;
+ when(mKeyguardManager.isDeviceLocked(anyInt())).thenReturn(true);
+ AccessibilityManager accessibilityManager = Mockito.mock(AccessibilityManager.class);
+ when(accessibilityManager.isEnabled()).thenReturn(true);
+ mService.setAccessibilityManager(accessibilityManager);
+
+ mService.buzzBeepBlinkLocked(r);
+
+ ArgumentCaptor<AccessibilityEvent> eventCaptor =
+ ArgumentCaptor.forClass(AccessibilityEvent.class);
+
+ verify(accessibilityManager, times(1))
+ .sendAccessibilityEvent(eventCaptor.capture());
+
+ AccessibilityEvent event = eventCaptor.getValue();
+ assertEquals(r.getNotification(), event.getParcelableData());
+ }
+
+ @Test
+ public void testUnlockedPrivateA11yNoRedaction() throws Exception {
+ NotificationRecord r = getBeepyNotification();
+ r.setPackageVisibilityOverride(NotificationManager.VISIBILITY_NO_OVERRIDE);
+ r.getNotification().visibility = Notification.VISIBILITY_PRIVATE;
+ when(mKeyguardManager.isDeviceLocked(anyInt())).thenReturn(false);
+ AccessibilityManager accessibilityManager = Mockito.mock(AccessibilityManager.class);
+ when(accessibilityManager.isEnabled()).thenReturn(true);
+ mService.setAccessibilityManager(accessibilityManager);
+
+ mService.buzzBeepBlinkLocked(r);
+
+ ArgumentCaptor<AccessibilityEvent> eventCaptor =
+ ArgumentCaptor.forClass(AccessibilityEvent.class);
+
+ verify(accessibilityManager, times(1))
+ .sendAccessibilityEvent(eventCaptor.capture());
+
+ AccessibilityEvent event = eventCaptor.getValue();
+ assertEquals(r.getNotification(), event.getParcelableData());
+ }
+
+ @Test
public void testBeepInsistently() throws Exception {
NotificationRecord r = getInsistentBeepyNotification();
diff --git a/telecomm/java/android/telecom/InCallService.java b/telecomm/java/android/telecom/InCallService.java
index 5e3d26a5179d..705b4918726e 100644
--- a/telecomm/java/android/telecom/InCallService.java
+++ b/telecomm/java/android/telecom/InCallService.java
@@ -81,7 +81,8 @@ import java.util.List;
* <pre>
* {@code
* <service android:name="your.package.YourInCallServiceImplementation"
- * android:permission="android.permission.BIND_INCALL_SERVICE">
+ * android:permission="android.permission.BIND_INCALL_SERVICE"
+ * android:exported="true">
* <meta-data android:name="android.telecom.IN_CALL_SERVICE_UI" android:value="true" />
* <meta-data android:name="android.telecom.IN_CALL_SERVICE_RINGING"
* android:value="true" />
@@ -91,6 +92,10 @@ import java.util.List;
* </service>
* }
* </pre>
+ *
+ * <em>Note: You should NOT mark your {@link InCallService} with the attribute
+ * {@code android:exported="false"}; doing so can result in a failure to bind to your implementation
+ * during calls.</em>
* <p>
* In addition to implementing the {@link InCallService} API, you must also declare an activity in
* your manifest which handles the {@link Intent#ACTION_DIAL} intent. The example below illustrates
diff --git a/telephony/java/android/telephony/ModemActivityInfo.java b/telephony/java/android/telephony/ModemActivityInfo.java
index debb119c94bc..0bf8ce620eb7 100644
--- a/telephony/java/android/telephony/ModemActivityInfo.java
+++ b/telephony/java/android/telephony/ModemActivityInfo.java
@@ -16,8 +16,12 @@
package android.telephony;
+import android.annotation.DurationMillisLong;
+import android.annotation.ElapsedRealtimeLong;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemClock;
@@ -25,46 +29,50 @@ import android.util.Range;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.Arrays;
+import java.util.Objects;
/**
- * Reports modem activity information.
+ * Contains information about the modem's activity. May be useful for power stats reporting.
* @hide
*/
+@SystemApi
+@TestApi
public final class ModemActivityInfo implements Parcelable {
+ private static final int TX_POWER_LEVELS = 5;
+
/**
- * Tx(transmit) power level. see power index below
- * <ul>
- * <li> index 0 = tx_power < 0dBm. </li>
- * <li> index 1 = 0dBm < tx_power < 5dBm. </li>
- * <li> index 2 = 5dBm < tx_power < 15dBm. </li>
- * <li> index 3 = 15dBm < tx_power < 20dBm. </li>
- * <li> index 4 = tx_power > 20dBm. </li>
- * </ul>
- */
- public static final int TX_POWER_LEVELS = 5;
- /**
- * Tx(transmit) power level 0: tx_power < 0dBm
+ * Corresponds to transmit power of less than 0dBm.
*/
public static final int TX_POWER_LEVEL_0 = 0;
+
/**
- * Tx(transmit) power level 1: 0dBm < tx_power < 5dBm
+ * Corresponds to transmit power between 0dBm and 5dBm.
*/
public static final int TX_POWER_LEVEL_1 = 1;
+
/**
- * Tx(transmit) power level 2: 5dBm < tx_power < 15dBm
+ * Corresponds to transmit power between 5dBm and 15dBm.
*/
public static final int TX_POWER_LEVEL_2 = 2;
+
/**
- * Tx(transmit) power level 3: 15dBm < tx_power < 20dBm.
+ * Corresponds to transmit power between 15dBm and 20dBm.
*/
public static final int TX_POWER_LEVEL_3 = 3;
+
/**
- * Tx(transmit) power level 4: tx_power > 20dBm
+ * Corresponds to transmit power above 20dBm.
*/
public static final int TX_POWER_LEVEL_4 = 4;
+ /**
+ * The number of transmit power levels. Fixed by HAL definition.
+ */
+ public static int getNumTxPowerLevels() {
+ return TX_POWER_LEVELS;
+ }
+
/** @hide */
@IntDef(prefix = {"TX_POWER_LEVEL_"}, value = {
TX_POWER_LEVEL_0,
@@ -82,34 +90,39 @@ public final class ModemActivityInfo implements Parcelable {
new Range<>(5, 15),
new Range<>(15, 20),
new Range<>(20, Integer.MAX_VALUE)
-
};
private long mTimestamp;
private int mSleepTimeMs;
private int mIdleTimeMs;
- private List<TransmitPower> mTransmitPowerInfo = new ArrayList<>(TX_POWER_LEVELS);
+ private int[] mTxTimeMs;
private int mRxTimeMs;
+ /**
+ * @hide
+ */
+ @TestApi
public ModemActivityInfo(long timestamp, int sleepTimeMs, int idleTimeMs,
@NonNull int[] txTimeMs, int rxTimeMs) {
+ Objects.requireNonNull(txTimeMs);
+ if (txTimeMs.length != TX_POWER_LEVELS) {
+ throw new IllegalArgumentException("txTimeMs must have length == TX_POWER_LEVELS");
+ }
mTimestamp = timestamp;
mSleepTimeMs = sleepTimeMs;
mIdleTimeMs = idleTimeMs;
- populateTransmitPowerRange(txTimeMs);
+ mTxTimeMs = txTimeMs;
mRxTimeMs = rxTimeMs;
}
- /** helper API to populate tx power range for each bucket **/
- private void populateTransmitPowerRange(@NonNull int[] transmitPowerMs) {
- int i = 0;
- for ( ; i < Math.min(transmitPowerMs.length, TX_POWER_LEVELS); i++) {
- mTransmitPowerInfo.add(i, new TransmitPower(TX_POWER_RANGES[i], transmitPowerMs[i]));
- }
- // Make sure that mTransmitPowerInfo is fully initialized.
- for ( ; i < TX_POWER_LEVELS; i++) {
- mTransmitPowerInfo.add(i, new TransmitPower(TX_POWER_RANGES[i], 0));
- }
+ /**
+ * Provided for convenience in manipulation since the API exposes long values but internal
+ * representations are ints.
+ * @hide
+ */
+ public ModemActivityInfo(long timestamp, long sleepTimeMs, long idleTimeMs,
+ @NonNull int[] txTimeMs, long rxTimeMs) {
+ this(timestamp, (int) sleepTimeMs, (int) idleTimeMs, txTimeMs, (int) rxTimeMs);
}
@Override
@@ -118,7 +131,7 @@ public final class ModemActivityInfo implements Parcelable {
+ " mTimestamp=" + mTimestamp
+ " mSleepTimeMs=" + mSleepTimeMs
+ " mIdleTimeMs=" + mIdleTimeMs
- + " mTransmitPowerInfo[]=" + mTransmitPowerInfo.toString()
+ + " mTxTimeMs[]=" + Arrays.toString(mTxTimeMs)
+ " mRxTimeMs=" + mRxTimeMs
+ "}";
}
@@ -129,14 +142,12 @@ public final class ModemActivityInfo implements Parcelable {
public static final @android.annotation.NonNull Parcelable.Creator<ModemActivityInfo> CREATOR =
new Parcelable.Creator<ModemActivityInfo>() {
- public ModemActivityInfo createFromParcel(Parcel in) {
+ public ModemActivityInfo createFromParcel(@NonNull Parcel in) {
long timestamp = in.readLong();
int sleepTimeMs = in.readInt();
int idleTimeMs = in.readInt();
int[] txTimeMs = new int[TX_POWER_LEVELS];
- for (int i = 0; i < TX_POWER_LEVELS; i++) {
- txTimeMs[i] = in.readInt();
- }
+ in.readIntArray(txTimeMs);
int rxTimeMs = in.readInt();
return new ModemActivityInfo(timestamp, sleepTimeMs, idleTimeMs,
txTimeMs, rxTimeMs);
@@ -147,21 +158,25 @@ public final class ModemActivityInfo implements Parcelable {
}
};
- public void writeToParcel(Parcel dest, int flags) {
+ /**
+ * @param dest The Parcel in which the object should be written.
+ * @param flags Additional flags about how the object should be written.
+ */
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeLong(mTimestamp);
dest.writeInt(mSleepTimeMs);
dest.writeInt(mIdleTimeMs);
- for (int i = 0; i < TX_POWER_LEVELS; i++) {
- dest.writeInt(mTransmitPowerInfo.get(i).getTimeInMillis());
- }
+ dest.writeIntArray(mTxTimeMs);
dest.writeInt(mRxTimeMs);
}
/**
- * @return milliseconds since boot, including mTimeInMillis spent in sleep.
- * @see SystemClock#elapsedRealtime()
+ * Gets the timestamp at which this modem activity info was recorded.
+ *
+ * @return The timestamp, as returned by {@link SystemClock#elapsedRealtime()}, when this
+ * {@link ModemActivityInfo} was recorded.
*/
- public long getTimestamp() {
+ public @ElapsedRealtimeLong long getTimestampMillis() {
return mTimestamp;
}
@@ -171,35 +186,48 @@ public final class ModemActivityInfo implements Parcelable {
}
/**
- * @return an arrayList of {@link TransmitPower} with each element representing the total time where
- * transmitter is awake time (in ms) for a given power range (in dbm).
+ * Gets the amount of time the modem spent transmitting at a certain power level.
*
- * @see #TX_POWER_LEVELS
+ * @param powerLevel The power level to query.
+ * @return The amount of time, in milliseconds, that the modem spent transmitting at the
+ * given power level.
*/
- @NonNull
- public List<TransmitPower> getTransmitPowerInfo() {
- return mTransmitPowerInfo;
+ public @DurationMillisLong long getTransmitDurationMillisAtPowerLevel(
+ @TxPowerLevel int powerLevel) {
+ return mTxTimeMs[powerLevel];
+ }
+
+ /**
+ * Gets the range of transmit powers corresponding to a certain power level.
+ *
+ * @param powerLevel The power level to query
+ * @return A {@link Range} object representing the range of intensities (in dBm) to which this
+ * power level corresponds.
+ */
+ public @NonNull Range<Integer> getTransmitPowerRange(@TxPowerLevel int powerLevel) {
+ return TX_POWER_RANGES[powerLevel];
}
/** @hide */
public void setTransmitTimeMillis(int[] txTimeMs) {
- populateTransmitPowerRange(txTimeMs);
+ mTxTimeMs = Arrays.copyOf(txTimeMs, TX_POWER_LEVELS);
}
- /** @hide */
+ /**
+ * @return The raw array of transmit power durations
+ * @hide
+ */
@NonNull
public int[] getTransmitTimeMillis() {
- int[] transmitTimeMillis = new int[TX_POWER_LEVELS];
- for (int i = 0; i < transmitTimeMillis.length; i++) {
- transmitTimeMillis[i] = mTransmitPowerInfo.get(i).getTimeInMillis();
- }
- return transmitTimeMillis;
+ return mTxTimeMs;
}
/**
- * @return total mTimeInMillis (in ms) when modem is in a low power or sleep state.
+ * Gets the amount of time (in milliseconds) when the modem is in a low power or sleep state.
+ *
+ * @return Time in milliseconds.
*/
- public int getSleepTimeMillis() {
+ public @DurationMillisLong long getSleepTimeMillis() {
return mSleepTimeMs;
}
@@ -209,10 +237,44 @@ public final class ModemActivityInfo implements Parcelable {
}
/**
- * @return total mTimeInMillis (in ms) when modem is awake but neither the transmitter nor receiver are
- * active.
+ * Provided for convenience, since the API surface needs to return longs but internal
+ * representations are ints.
+ * @hide
*/
- public int getIdleTimeMillis() {
+ public void setSleepTimeMillis(long sleepTimeMillis) {
+ mSleepTimeMs = (int) sleepTimeMillis;
+ }
+
+ /**
+ * Computes the difference between this instance of {@link ModemActivityInfo} and another
+ * instance.
+ *
+ * This method should be used to compute the amount of activity that has happened between two
+ * samples of modem activity taken at separate times. The sample passed in as an argument to
+ * this method should be the one that's taken later in time (and therefore has more activity).
+ * @param other The other instance of {@link ModemActivityInfo} to diff against.
+ * @return An instance of {@link ModemActivityInfo} representing the difference in modem
+ * activity.
+ */
+ public @NonNull ModemActivityInfo getDelta(@NonNull ModemActivityInfo other) {
+ int[] txTimeMs = new int[ModemActivityInfo.TX_POWER_LEVELS];
+ for (int i = 0; i < ModemActivityInfo.TX_POWER_LEVELS; i++) {
+ txTimeMs[i] = other.mTxTimeMs[i] - mTxTimeMs[i];
+ }
+ return new ModemActivityInfo(other.getTimestampMillis(),
+ other.getSleepTimeMillis() - getSleepTimeMillis(),
+ other.getIdleTimeMillis() - getIdleTimeMillis(),
+ txTimeMs,
+ other.getReceiveTimeMillis() - getReceiveTimeMillis());
+ }
+
+ /**
+ * Gets the amount of time (in milliseconds) when the modem is awake but neither transmitting
+ * nor receiving.
+ *
+ * @return Time in milliseconds.
+ */
+ public @DurationMillisLong long getIdleTimeMillis() {
return mIdleTimeMs;
}
@@ -222,9 +284,20 @@ public final class ModemActivityInfo implements Parcelable {
}
/**
- * @return rx(receive) mTimeInMillis in ms.
+ * Provided for convenience, since the API surface needs to return longs but internal
+ * representations are ints.
+ * @hide
+ */
+ public void setIdleTimeMillis(long idleTimeMillis) {
+ mIdleTimeMs = (int) idleTimeMillis;
+ }
+
+ /**
+ * Gets the amount of time (in milliseconds) when the modem is awake and receiving data.
+ *
+ * @return Time in milliseconds.
*/
- public int getReceiveTimeMillis() {
+ public @DurationMillisLong long getReceiveTimeMillis() {
return mRxTimeMs;
}
@@ -234,71 +307,56 @@ public final class ModemActivityInfo implements Parcelable {
}
/**
+ * Provided for convenience, since the API surface needs to return longs but internal
+ * representations are ints.
+ * @hide
+ */
+ public void setReceiveTimeMillis(long receiveTimeMillis) {
+ mRxTimeMs = (int) receiveTimeMillis;
+ }
+
+ /**
* Indicates if the modem has reported valid {@link ModemActivityInfo}.
*
* @return {@code true} if this {@link ModemActivityInfo} record is valid,
* {@code false} otherwise.
+ * @hide
*/
+ @TestApi
public boolean isValid() {
- for (TransmitPower powerInfo : getTransmitPowerInfo()) {
- if(powerInfo.getTimeInMillis() < 0) {
- return false;
- }
- }
+ boolean isTxPowerValid = Arrays.stream(mTxTimeMs).allMatch((i) -> i >= 0);
- return ((getIdleTimeMillis() >= 0) && (getSleepTimeMillis() >= 0)
+ return isTxPowerValid && ((getIdleTimeMillis() >= 0) && (getSleepTimeMillis() >= 0)
&& (getReceiveTimeMillis() >= 0) && !isEmpty());
}
- private boolean isEmpty() {
- for (TransmitPower txVal : getTransmitPowerInfo()) {
- if(txVal.getTimeInMillis() != 0) {
- return false;
- }
- }
+ /** @hide */
+ @TestApi
+ public boolean isEmpty() {
+ boolean isTxPowerEmpty = mTxTimeMs == null || mTxTimeMs.length == 0
+ || Arrays.stream(mTxTimeMs).allMatch((i) -> i == 0);
- return ((getIdleTimeMillis() == 0) && (getSleepTimeMillis() == 0)
+ return isTxPowerEmpty && ((getIdleTimeMillis() == 0) && (getSleepTimeMillis() == 0)
&& (getReceiveTimeMillis() == 0));
}
- /**
- * Transmit power Information, including the power range in dbm and the total time (in ms) where
- * the transmitter is active/awake for this power range.
- * e.g, range: 0dbm(lower) ~ 5dbm(upper)
- * time: 5ms
- */
- public class TransmitPower {
- private int mTimeInMillis;
- private Range<Integer> mPowerRangeInDbm;
- /** @hide */
- public TransmitPower(@NonNull Range<Integer> range, int time) {
- this.mTimeInMillis = time;
- this.mPowerRangeInDbm = range;
- }
-
- /**
- * @return the total time in ms where the transmitter is active/wake for this power range
- * {@link #getPowerRangeInDbm()}.
- */
- public int getTimeInMillis() {
- return mTimeInMillis;
- }
- /**
- * @return the power range in dbm. e.g, range: 0dbm(lower) ~ 5dbm(upper)
- */
- @NonNull
- public Range<Integer> getPowerRangeInDbm() {
- return mPowerRangeInDbm;
- }
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ ModemActivityInfo that = (ModemActivityInfo) o;
+ return mTimestamp == that.mTimestamp
+ && mSleepTimeMs == that.mSleepTimeMs
+ && mIdleTimeMs == that.mIdleTimeMs
+ && mRxTimeMs == that.mRxTimeMs
+ && Arrays.equals(mTxTimeMs, that.mTxTimeMs);
+ }
- @Override
- public String toString() {
- return "TransmitPower{"
- + " mTimeInMillis=" + mTimeInMillis
- + " mPowerRangeInDbm={" + mPowerRangeInDbm.getLower()
- + "," + mPowerRangeInDbm.getUpper()
- + "}}";
- }
+ @Override
+ public int hashCode() {
+ int result = Objects.hash(mTimestamp, mSleepTimeMs, mIdleTimeMs, mRxTimeMs);
+ result = 31 * result + Arrays.hashCode(mTxTimeMs);
+ return result;
}
}
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 6da61b712916..1677c61eb9cf 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -444,7 +444,9 @@ public class ServiceState implements Parcelable {
mArfcnRsrpBoost = s.mArfcnRsrpBoost;
synchronized (mNetworkRegistrationInfos) {
mNetworkRegistrationInfos.clear();
- mNetworkRegistrationInfos.addAll(s.getNetworkRegistrationInfoList());
+ for (NetworkRegistrationInfo nri : s.getNetworkRegistrationInfoList()) {
+ mNetworkRegistrationInfos.add(new NetworkRegistrationInfo(nri));
+ }
}
mNrFrequencyRange = s.mNrFrequencyRange;
mOperatorAlphaLongRaw = s.mOperatorAlphaLongRaw;
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 4189784bf5e0..f55dc8b6f8f1 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -57,7 +57,9 @@ import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
+import android.os.OutcomeReceiver;
import android.os.ParcelFileDescriptor;
+import android.os.Parcelable;
import android.os.PersistableBundle;
import android.os.RemoteException;
import android.os.ResultReceiver;
@@ -84,6 +86,7 @@ import android.telephony.CallForwardingInfo.CallForwardingReason;
import android.telephony.VisualVoicemailService.VisualVoicemailTask;
import android.telephony.data.ApnSetting;
import android.telephony.data.ApnSetting.MvnoType;
+import android.telephony.data.SlicingConfig;
import android.telephony.emergency.EmergencyNumber;
import android.telephony.emergency.EmergencyNumber.EmergencyServiceCategories;
import android.telephony.gba.UaSecurityProtocolIdentifier;
@@ -176,6 +179,9 @@ public class TelephonyManager {
*/
public static final String MODEM_ACTIVITY_RESULT_KEY = "controller_activity";
+ /** @hide */
+ public static final String EXCEPTION_RESULT_KEY = "exception";
+
/**
* The process name of the Phone app as well as many other apps that use this process name, such
* as settings and vendor components.
@@ -10855,26 +10861,149 @@ public class TelephonyManager {
return null;
}
+ /**
+ * Exception that may be supplied to the callback provided in {@link #requestModemActivityInfo}.
+ * @hide
+ */
+ @SystemApi
+ public static class ModemActivityInfoException extends Exception {
+ /** Indicates that an unknown error occurred */
+ public static final int ERROR_UNKNOWN = 0;
+
+ /**
+ * Indicates that the modem or phone processes are not available (such as when the device
+ * is in airplane mode).
+ */
+ public static final int ERROR_PHONE_NOT_AVAILABLE = 1;
+
+ /**
+ * Indicates that the modem supplied an invalid instance of {@link ModemActivityInfo}
+ */
+ public static final int ERROR_INVALID_INFO_RECEIVED = 2;
+
+ /**
+ * Indicates that the modem encountered an internal failure when processing the request
+ * for activity info.
+ */
+ public static final int ERROR_MODEM_RESPONSE_ERROR = 3;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"ERROR_"},
+ value = {
+ ERROR_UNKNOWN,
+ ERROR_PHONE_NOT_AVAILABLE,
+ ERROR_INVALID_INFO_RECEIVED,
+ ERROR_MODEM_RESPONSE_ERROR,
+ })
+ public @interface ModemActivityInfoError {}
+
+ private final int mErrorCode;
+
+ /** @hide */
+ public ModemActivityInfoException(@ModemActivityInfoError int errorCode) {
+ mErrorCode = errorCode;
+ }
+
+ public @ModemActivityInfoError int getErrorCode() {
+ return mErrorCode;
+ }
+
+ @Override
+ public String toString() {
+ switch (mErrorCode) {
+ case ERROR_UNKNOWN: return "ERROR_UNKNOWN";
+ case ERROR_PHONE_NOT_AVAILABLE: return "ERROR_PHONE_NOT_AVAILABLE";
+ case ERROR_INVALID_INFO_RECEIVED: return "ERROR_INVALID_INFO_RECEIVED";
+ case ERROR_MODEM_RESPONSE_ERROR: return "ERROR_MODEM_RESPONSE_ERROR";
+ default: return "UNDEFINED";
+ }
+ }
+ }
/**
- * Requests the modem activity info. The recipient will place the result
- * in `result`.
- * @param result The object on which the recipient will send the resulting
- * {@link android.telephony.ModemActivityInfo} object with key of
- * {@link #MODEM_ACTIVITY_RESULT_KEY}.
+ * Requests the current modem activity info.
+ *
+ * The provided instance of {@link ModemActivityInfo} represents the cumulative activity since
+ * the last restart of the phone process.
+ *
+ * @param callback A callback object to which the result will be delivered. If there was an
+ * error processing the request, {@link OutcomeReceiver#onError} will be called
+ * with more details about the error.
* @hide
*/
- public void requestModemActivityInfo(@NonNull ResultReceiver result) {
+ @SystemApi
+ @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
+ public void requestModemActivityInfo(@NonNull @CallbackExecutor Executor executor,
+ @NonNull OutcomeReceiver<ModemActivityInfo, ModemActivityInfoException> callback) {
+ Objects.requireNonNull(executor);
+ Objects.requireNonNull(callback);
+
+ // Pass no handler into the receiver, since we're going to be trampolining the call to the
+ // listener onto the provided executor.
+ ResultReceiver wrapperResultReceiver = new ResultReceiver(null) {
+ @Override
+ protected void onReceiveResult(int resultCode, Bundle data) {
+ if (data == null) {
+ Log.w(TAG, "requestModemActivityInfo: received null bundle");
+ sendErrorToListener(ModemActivityInfoException.ERROR_UNKNOWN);
+ return;
+ }
+ data.setDefusable(true);
+ if (data.containsKey(EXCEPTION_RESULT_KEY)) {
+ int receivedErrorCode = data.getInt(EXCEPTION_RESULT_KEY);
+ sendErrorToListener(receivedErrorCode);
+ return;
+ }
+
+ if (!data.containsKey(MODEM_ACTIVITY_RESULT_KEY)) {
+ Log.w(TAG, "requestModemActivityInfo: Bundle did not contain expected key");
+ sendErrorToListener(ModemActivityInfoException.ERROR_UNKNOWN);
+ return;
+ }
+ Parcelable receivedResult = data.getParcelable(MODEM_ACTIVITY_RESULT_KEY);
+ if (!(receivedResult instanceof ModemActivityInfo)) {
+ Log.w(TAG, "requestModemActivityInfo: Bundle contained something that wasn't "
+ + "a ModemActivityInfo.");
+ sendErrorToListener(ModemActivityInfoException.ERROR_UNKNOWN);
+ return;
+ }
+ ModemActivityInfo modemActivityInfo = (ModemActivityInfo) receivedResult;
+ if (!modemActivityInfo.isValid()) {
+ Log.w(TAG, "requestModemActivityInfo: Received an invalid ModemActivityInfo");
+ sendErrorToListener(ModemActivityInfoException.ERROR_INVALID_INFO_RECEIVED);
+ return;
+ }
+ Log.d(TAG, "requestModemActivityInfo: Sending result to app: " + modemActivityInfo);
+ sendResultToListener(modemActivityInfo);
+ }
+
+ private void sendResultToListener(ModemActivityInfo info) {
+ Binder.withCleanCallingIdentity(() ->
+ executor.execute(() ->
+ callback.onResult(info)));
+ }
+
+ private void sendErrorToListener(int code) {
+ ModemActivityInfoException e = new ModemActivityInfoException(code);
+ Binder.withCleanCallingIdentity(() ->
+ executor.execute(() ->
+ callback.onError(e)));
+ }
+ };
+
try {
ITelephony service = getITelephony();
if (service != null) {
- service.requestModemActivityInfo(result);
+ service.requestModemActivityInfo(wrapperResultReceiver);
return;
}
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelephony#getModemActivityInfo", e);
}
- result.send(0, null);
+ executor.execute(() -> callback.onError(
+ new ModemActivityInfoException(
+ ModemActivityInfoException.ERROR_PHONE_NOT_AVAILABLE)));
}
/**
@@ -15093,4 +15222,96 @@ public class TelephonyManager {
return PhoneCapability.DEFAULT_SSSS_CAPABILITY;
}
}
+
+ /**
+ * Exception that may be supplied to the callback in {@link #getNetworkSlicingConfiguration} if
+ * something goes awry.
+ */
+ public static class SlicingException extends Exception {
+ /**
+ * Getting the current slicing configuration successfully. Used internally only.
+ * @hide
+ */
+ public static final int SUCCESS = 0;
+
+ /**
+ * The system timed out waiting for a response from the Radio.
+ */
+ public static final int ERROR_TIMEOUT = 1;
+
+ /**
+ * The modem returned a failure.
+ */
+ public static final int ERROR_MODEM_ERROR = 2;
+
+ /** @hide */
+ @IntDef(prefix = {"ERROR_"}, value = {
+ ERROR_TIMEOUT,
+ ERROR_MODEM_ERROR,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SlicingError {}
+
+ private final int mErrorCode;
+
+ public SlicingException(@SlicingError int errorCode) {
+ mErrorCode = errorCode;
+ }
+
+ /**
+ * Fetches the error code associated with this exception.
+ * @return An error code.
+ */
+ public @SlicingError int getErrorCode() {
+ return mErrorCode;
+ }
+ }
+
+ /** @hide */
+ public static final String KEY_SLICING_CONFIG_HANDLE = "slicing_config_handle";
+
+ /**
+ * Request to get the current slicing configuration including URSP rules and
+ * NSSAIs (configured, allowed and rejected).
+ *
+ * This method can be invoked if one of the following requirements is met:
+ * <ul>
+ * <li>If the calling app has been granted the READ_PRIVILEGED_PHONE_STATE permission; this
+ * is a privileged permission that can only be granted to apps preloaded on the device.
+ * <li>If the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+ * </ul>
+ *
+ * @param executor the executor on which callback will be invoked.
+ * @param callback a callback to receive the current slicing configuration.
+ */
+ @SuppressAutoDoc // No support for carrier privileges (b/72967236).
+ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public void getNetworkSlicingConfiguration(
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull OutcomeReceiver<SlicingConfig, SlicingException> callback) {
+ Objects.requireNonNull(executor);
+ Objects.requireNonNull(callback);
+
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony == null) {
+ throw new IllegalStateException("telephony service is null.");
+ }
+ telephony.getSlicingConfig(new ResultReceiver(null) {
+ @Override
+ protected void onReceiveResult(int resultCode, Bundle result) {
+ if (resultCode != SlicingException.SUCCESS) {
+ executor.execute(() -> callback.onError(
+ new SlicingException(resultCode)));
+ return;
+ }
+ SlicingConfig slicingConfig =
+ result.getParcelable(KEY_SLICING_CONFIG_HANDLE);
+ executor.execute(() -> callback.onResult(slicingConfig));
+ }
+ });
+ } catch (RemoteException ex) {
+ ex.rethrowAsRuntimeException();
+ }
+ }
}
diff --git a/telephony/java/android/telephony/data/NetworkSliceInfo.java b/telephony/java/android/telephony/data/NetworkSliceInfo.java
index 1d9009533685..232a93012f4b 100644
--- a/telephony/java/android/telephony/data/NetworkSliceInfo.java
+++ b/telephony/java/android/telephony/data/NetworkSliceInfo.java
@@ -19,8 +19,6 @@ package android.telephony.data;
import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
-import android.annotation.SuppressLint;
-import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -35,10 +33,7 @@ import java.util.Objects;
* SliceServiceType defines the type of service provided by the slice, and SliceDifferentiator is
* used to differentiate between multiple slices of the same type. If the devices is not on HPLMN,
* the mappedHplmn versions of these 2 fields indicate the corresponding values in HPLMN.
- *
- * @hide
*/
-@SystemApi
public final class NetworkSliceInfo implements Parcelable {
/**
* When set on a Slice Differentiator, this value indicates that there is no corresponding
@@ -68,14 +63,14 @@ public final class NetworkSliceInfo implements Parcelable {
/**
* The min acceptable value for a Slice Differentiator
+ * @hide
*/
- @SuppressLint("MinMaxConstant")
public static final int MIN_SLICE_DIFFERENTIATOR = -1;
/**
* The max acceptable value for a Slice Differentiator
+ * @hide
*/
- @SuppressLint("MinMaxConstant")
public static final int MAX_SLICE_DIFFERENTIATOR = 0xFFFFFE;
/** @hide */
@@ -88,6 +83,62 @@ public final class NetworkSliceInfo implements Parcelable {
@Retention(RetentionPolicy.SOURCE)
public @interface SliceServiceType {}
+ /**
+ * The slice status is unknown. This can happen during IWLAN->cellular handover when the
+ * NetworkSliceInfo is received over IWLAN.
+ */
+ public static final int SLICE_STATUS_UNKNOWN = 0;
+
+ /**
+ * The slice is configured but not allowed or rejected yet.
+ */
+ public static final int SLICE_STATUS_CONFIGURED = 1;
+
+ /**
+ * The slice is allowed to be used.
+ */
+ public static final int SLICE_STATUS_ALLOWED = 2;
+
+ /**
+ * The slice is rejected because not available in PLMN.
+ */
+ public static final int SLICE_STATUS_REJECTED_NOT_AVAILABLE_IN_PLMN = 3;
+
+ /**
+ * The slice is rejected because not available in registered area.
+ */
+ public static final int SLICE_STATUS_REJECTED_NOT_AVAILABLE_IN_REGISTERED_AREA = 4;
+
+ /**
+ * The slice is configured by home operator(HPLMN) in default and is used if configured/allowed
+ * slices are not available for the serving PLMN.
+ */
+ public static final int SLICE_STATUS_DEFAULT_CONFIGURED = 5;
+
+ /**
+ * The min acceptable value for a slice status.
+ * @hide
+ */
+ public static final int MIN_SLICE_STATUS = SLICE_STATUS_UNKNOWN;
+
+ /**
+ * The max acceptable value for a slice status.
+ * @hide
+ */
+ public static final int MAX_SLICE_STATUS = SLICE_STATUS_DEFAULT_CONFIGURED;
+
+ /** @hide */
+ @IntDef(prefix = { "SLICE_STATUS_" }, value = {
+ SLICE_STATUS_UNKNOWN,
+ SLICE_STATUS_CONFIGURED,
+ SLICE_STATUS_ALLOWED,
+ SLICE_STATUS_REJECTED_NOT_AVAILABLE_IN_PLMN,
+ SLICE_STATUS_REJECTED_NOT_AVAILABLE_IN_REGISTERED_AREA,
+ SLICE_STATUS_DEFAULT_CONFIGURED,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SliceStatus {}
+
@SliceServiceType
private final int mSliceServiceType;
@@ -97,14 +148,18 @@ public final class NetworkSliceInfo implements Parcelable {
private final int mMappedHplmnSliceServiceType;
@IntRange(from = MIN_SLICE_DIFFERENTIATOR, to = MAX_SLICE_DIFFERENTIATOR)
private final int mMappedHplmnSliceDifferentiator;
+ @SliceStatus
+ @IntRange(from = MIN_SLICE_STATUS, to = MAX_SLICE_STATUS)
+ private final int mStatus;
private NetworkSliceInfo(@SliceServiceType int sliceServiceType,
int sliceDifferentiator, int mappedHplmnSliceServiceType,
- int mappedHplmnSliceDifferentiator) {
+ int mappedHplmnSliceDifferentiator, int status) {
mSliceServiceType = sliceServiceType;
mSliceDifferentiator = sliceDifferentiator;
mMappedHplmnSliceDifferentiator = mappedHplmnSliceDifferentiator;
mMappedHplmnSliceServiceType = mappedHplmnSliceServiceType;
+ mStatus = status;
}
/**
@@ -157,11 +212,21 @@ public final class NetworkSliceInfo implements Parcelable {
return mMappedHplmnSliceDifferentiator;
}
+ /**
+ * Field to indicate the current status of the slice.
+ * @return the current status for this slice info.
+ */
+ @SliceStatus
+ public int getStatus() {
+ return mStatus;
+ }
+
private NetworkSliceInfo(@NonNull Parcel in) {
mSliceServiceType = in.readInt();
mSliceDifferentiator = in.readInt();
mMappedHplmnSliceServiceType = in.readInt();
mMappedHplmnSliceDifferentiator = in.readInt();
+ mStatus = in.readInt();
}
@Override
@@ -175,6 +240,7 @@ public final class NetworkSliceInfo implements Parcelable {
dest.writeInt(mSliceDifferentiator);
dest.writeInt(mMappedHplmnSliceServiceType);
dest.writeInt(mMappedHplmnSliceDifferentiator);
+ dest.writeInt(mStatus);
}
public static final @android.annotation.NonNull Parcelable.Creator<NetworkSliceInfo> CREATOR =
@@ -200,6 +266,7 @@ public final class NetworkSliceInfo implements Parcelable {
+ ", mMappedHplmnSliceServiceType="
+ sliceServiceTypeToString(mMappedHplmnSliceServiceType)
+ ", mMappedHplmnSliceDifferentiator=" + mMappedHplmnSliceDifferentiator
+ + ", mStatus=" + sliceStatusToString(mStatus)
+ '}';
}
@@ -218,6 +285,25 @@ public final class NetworkSliceInfo implements Parcelable {
}
}
+ private static String sliceStatusToString(@SliceStatus int sliceStatus) {
+ switch(sliceStatus) {
+ case SLICE_STATUS_UNKNOWN:
+ return "UNKNOWN";
+ case SLICE_STATUS_CONFIGURED:
+ return "CONFIGURED";
+ case SLICE_STATUS_ALLOWED:
+ return "ALLOWED";
+ case SLICE_STATUS_REJECTED_NOT_AVAILABLE_IN_PLMN:
+ return "REJECTED_NOT_AVAILABLE_IN_PLMN";
+ case SLICE_STATUS_REJECTED_NOT_AVAILABLE_IN_REGISTERED_AREA:
+ return "REJECTED_NOT_AVAILABLE_IN_REGISTERED_AREA";
+ case SLICE_STATUS_DEFAULT_CONFIGURED:
+ return "DEFAULT_CONFIGURED";
+ default:
+ return Integer.toString(sliceStatus);
+ }
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) return true;
@@ -226,13 +312,14 @@ public final class NetworkSliceInfo implements Parcelable {
return mSliceServiceType == sliceInfo.mSliceServiceType
&& mSliceDifferentiator == sliceInfo.mSliceDifferentiator
&& mMappedHplmnSliceServiceType == sliceInfo.mMappedHplmnSliceServiceType
- && mMappedHplmnSliceDifferentiator == sliceInfo.mMappedHplmnSliceDifferentiator;
+ && mMappedHplmnSliceDifferentiator == sliceInfo.mMappedHplmnSliceDifferentiator
+ && mStatus == sliceInfo.mStatus;
}
@Override
public int hashCode() {
return Objects.hash(mSliceServiceType, mSliceDifferentiator, mMappedHplmnSliceServiceType,
- mMappedHplmnSliceDifferentiator);
+ mMappedHplmnSliceDifferentiator, mStatus);
}
/**
@@ -257,6 +344,9 @@ public final class NetworkSliceInfo implements Parcelable {
private int mMappedHplmnSliceServiceType = SLICE_SERVICE_TYPE_NONE;
@IntRange(from = MIN_SLICE_DIFFERENTIATOR, to = MAX_SLICE_DIFFERENTIATOR)
private int mMappedHplmnSliceDifferentiator = SLICE_DIFFERENTIATOR_NO_SLICE;
+ @SliceStatus
+ @IntRange(from = MIN_SLICE_STATUS, to = MAX_SLICE_STATUS)
+ private int mStatus = SLICE_STATUS_UNKNOWN;
/**
* Default constructor for Builder.
@@ -281,8 +371,7 @@ public final class NetworkSliceInfo implements Parcelable {
* A value of {@link #SLICE_DIFFERENTIATOR_NO_SLICE} indicates that there is no
* corresponding Slice.
*
- * @throws IllegalArgumentException if the parameter is not between
- * {@link #MIN_SLICE_DIFFERENTIATOR} and {@link #MAX_SLICE_DIFFERENTIATOR}.
+ * @throws IllegalArgumentException if the parameter is not in the expected range.
*
* @return The same instance of the builder.
*/
@@ -316,8 +405,7 @@ public final class NetworkSliceInfo implements Parcelable {
* A value of {@link #SLICE_DIFFERENTIATOR_NO_SLICE} indicates that there is no
* corresponding Slice of the HPLMN.
*
- * @throws IllegalArgumentException if the parameter is not between
- * {@link #MIN_SLICE_DIFFERENTIATOR} and {@link #MAX_SLICE_DIFFERENTIATOR}.
+ * @throws IllegalArgumentException if the parameter is not in the expected range.
*
* @return The same instance of the builder.
*/
@@ -334,6 +422,22 @@ public final class NetworkSliceInfo implements Parcelable {
}
/**
+ * Set the slice status.
+ *
+ * @throws IllegalArgumentException if the status is invalid.
+ *
+ * @return The same instance of the builder.
+ */
+ @NonNull
+ public Builder setStatus(@SliceStatus int status) {
+ if (status < MIN_SLICE_STATUS || status > MAX_SLICE_STATUS) {
+ throw new IllegalArgumentException("The slice status is not valid");
+ }
+ this.mStatus = status;
+ return this;
+ }
+
+ /**
* Build the {@link NetworkSliceInfo}.
*
* @return the {@link NetworkSliceInfo} object.
@@ -341,7 +445,8 @@ public final class NetworkSliceInfo implements Parcelable {
@NonNull
public NetworkSliceInfo build() {
return new NetworkSliceInfo(this.mSliceServiceType, this.mSliceDifferentiator,
- this.mMappedHplmnSliceServiceType, this.mMappedHplmnSliceDifferentiator);
+ this.mMappedHplmnSliceServiceType, this.mMappedHplmnSliceDifferentiator,
+ this.mStatus);
}
}
}
diff --git a/telephony/java/android/telephony/data/RouteSelectionDescriptor.aidl b/telephony/java/android/telephony/data/RouteSelectionDescriptor.aidl
new file mode 100644
index 000000000000..563a00e5d177
--- /dev/null
+++ b/telephony/java/android/telephony/data/RouteSelectionDescriptor.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.data;
+
+parcelable RouteSelectionDescriptor;
diff --git a/telephony/java/android/telephony/data/RouteSelectionDescriptor.java b/telephony/java/android/telephony/data/RouteSelectionDescriptor.java
new file mode 100644
index 000000000000..c2457f21f5ef
--- /dev/null
+++ b/telephony/java/android/telephony/data/RouteSelectionDescriptor.java
@@ -0,0 +1,263 @@
+/**
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.data;
+
+import android.annotation.IntDef;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Represents a single route selection descriptor as defined in
+ * 3GPP TS 24.526.
+ */
+public final class RouteSelectionDescriptor implements Parcelable {
+ /**
+ * The min acceptable value for the precedence of a route selection descriptor.
+ * @hide
+ */
+ public static final int MIN_ROUTE_PRECEDENCE = 0;
+
+ /**
+ * The max acceptable value for the precedence of a route selection descriptor.
+ * @hide
+ */
+ public static final int MAX_ROUTE_PRECEDENCE = 255;
+
+ /**
+ * The route selection descriptor is for the session with IPV4 type.
+ */
+ public static final int SESSION_TYPE_IPV4 = 0;
+
+ /**
+ * The route selection descriptor is for the session with IPV6 type.
+ */
+ public static final int SESSION_TYPE_IPV6 = 1;
+
+ /**
+ * The route selection descriptor is for the session with both IP and IPV6 types.
+ */
+ public static final int SESSION_TYPE_IPV4V6 = 2;
+
+ /** @hide */
+ @IntDef(prefix = { "SESSION_TYPE_" }, value = {
+ SESSION_TYPE_IPV4,
+ SESSION_TYPE_IPV6,
+ SESSION_TYPE_IPV4V6,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface RouteSessionType {}
+
+ /**
+ * The route selection descriptor is using SSC mode 1. The session will provide continual
+ * support when UE's location is updated.
+ */
+ public static final int ROUTE_SSC_MODE_1 = 1;
+
+ /**
+ * The route selection descriptor is using SSC mode 2. The new session for the same network
+ * will be established after releasing the old session when UE's location is updated.
+ */
+ public static final int ROUTE_SSC_MODE_2 = 2;
+
+ /**
+ * The route selection descriptor is using SSC mode 3. The new session for the same network is
+ * allowed to be established before releasing the old session when UE's location is updated.
+ */
+ public static final int ROUTE_SSC_MODE_3 = 3;
+
+ /**
+ * The min acceptable value for the SSC mode of a route selection descriptor.
+ * @hide
+ */
+ public static final int MIN_ROUTE_SSC_MODE = ROUTE_SSC_MODE_1;
+
+ /**
+ * The max acceptable value for the SSC mode of a route selection descriptor.
+ * @hide
+ */
+ public static final int MAX_ROUTE_SSC_MODE = ROUTE_SSC_MODE_3;
+
+ /** @hide */
+ @IntDef(prefix = { "ROUTE_SSC_MODE_" }, value = {
+ ROUTE_SSC_MODE_1,
+ ROUTE_SSC_MODE_2,
+ ROUTE_SSC_MODE_3,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface RouteSscMode {}
+
+ @IntRange(from = MIN_ROUTE_PRECEDENCE, to = MAX_ROUTE_PRECEDENCE)
+ private final int mPrecedence;
+ @RouteSessionType
+ private final int mSessionType;
+ @RouteSscMode
+ @IntRange(from = MIN_ROUTE_SSC_MODE, to = MAX_ROUTE_SSC_MODE)
+ private final int mSscMode;
+ private final List<NetworkSliceInfo> mSliceInfo;
+ private final List<String> mDnn;
+
+ /** @hide */
+ RouteSelectionDescriptor(android.hardware.radio.V1_6.RouteSelectionDescriptor rsd) {
+ this(rsd.precedence, rsd.sessionType.value(), rsd.sscMode.value(), rsd.sliceInfo,
+ rsd.dnn);
+ }
+
+ /** @hide */
+ public RouteSelectionDescriptor(int precedence, int sessionType, int sscMode,
+ List<android.hardware.radio.V1_6.SliceInfo> sliceInfo, List<String> dnn) {
+ mPrecedence = precedence;
+ mSessionType = sessionType;
+ mSscMode = sscMode;
+ mSliceInfo = new ArrayList<NetworkSliceInfo>();
+ for (android.hardware.radio.V1_6.SliceInfo si : sliceInfo) {
+ mSliceInfo.add(sliceInfoBuilder(si));
+ }
+ mDnn = new ArrayList<String>();
+ mDnn.addAll(dnn);
+ }
+
+ private NetworkSliceInfo sliceInfoBuilder(android.hardware.radio.V1_6.SliceInfo si) {
+ NetworkSliceInfo.Builder builder = new NetworkSliceInfo.Builder()
+ .setSliceServiceType(si.sst)
+ .setMappedHplmnSliceServiceType(si.mappedHplmnSst);
+ if (si.sliceDifferentiator != NetworkSliceInfo.SLICE_DIFFERENTIATOR_NO_SLICE) {
+ builder
+ .setSliceDifferentiator(si.sliceDifferentiator)
+ .setMappedHplmnSliceDifferentiator(si.mappedHplmnSD);
+ }
+ return builder.build();
+ }
+
+ private RouteSelectionDescriptor(Parcel p) {
+ mPrecedence = p.readInt();
+ mSessionType = p.readInt();
+ mSscMode = p.readInt();
+ mSliceInfo = p.createTypedArrayList(NetworkSliceInfo.CREATOR);
+ mDnn = new ArrayList<String>();
+ p.readStringList(mDnn);
+ }
+
+ /**
+ * Precedence value in the range of 0 to 255. Higher value has lower precedence.
+ * @return the precedence value for this route selection descriptor.
+ */
+ @IntRange(from = MIN_ROUTE_PRECEDENCE, to = MAX_ROUTE_PRECEDENCE)
+ public int getPrecedence() {
+ return mPrecedence;
+ }
+
+ /**
+ * This is used for checking which session type defined in 3GPP TS 23.501 is allowed for the
+ * route in a route selection descriptor.
+ * @return the session type for this route selection descriptor.
+ */
+ @RouteSessionType
+ public int getSessionType() {
+ return mSessionType;
+ }
+
+ /**
+ * SSC mode stands for Session and Service Continuity mode (which specifies the IP continuity
+ * mode) as defined in 3GPP TS 23.501.
+ * @return the SSC mode for this route selection descriptor.
+ */
+ @RouteSscMode
+ public int getSscMode() {
+ return mSscMode;
+ }
+
+ /**
+ * This is the list of all the slices available in the route selection descriptor as indicated
+ * by the network. These are the slices that can be used by the device if this route selection
+ * descriptor is used based the traffic (see 3GPP TS 23.501 for details).
+ * @return the list of all the slices available in the route selection descriptor.
+ */
+ public @NonNull List<NetworkSliceInfo> getSliceInfo() {
+ return mSliceInfo;
+ }
+
+ /**
+ * DNN stands for Data Network Name and represents an APN as defined in 3GPP TS 23.003. There
+ * can be 0 or more DNNs specified in a route selection descriptor.
+ * @return the list of DNN for this route selection descriptor.
+ */
+ public @NonNull List<String> getDataNetworkName() {
+ return mDnn;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mPrecedence);
+ dest.writeInt(mSessionType);
+ dest.writeInt(mSscMode);
+ dest.writeTypedList(mSliceInfo, flags);
+ dest.writeStringList(mDnn);
+ }
+
+ public static final @NonNull Parcelable.Creator<RouteSelectionDescriptor> CREATOR =
+ new Parcelable.Creator<RouteSelectionDescriptor>() {
+ @Override
+ public RouteSelectionDescriptor createFromParcel(Parcel source) {
+ return new RouteSelectionDescriptor(source);
+ }
+
+ @Override
+ public RouteSelectionDescriptor[] newArray(int size) {
+ return new RouteSelectionDescriptor[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ RouteSelectionDescriptor that = (RouteSelectionDescriptor) o;
+ return mPrecedence == that.mPrecedence
+ && mSessionType == that.mSessionType
+ && mSscMode == that.mSscMode
+ && mSliceInfo.size() == that.mSliceInfo.size()
+ && mSliceInfo.containsAll(that.mSliceInfo)
+ && mDnn.size() == that.mDnn.size()
+ && mDnn.containsAll(that.mDnn);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mPrecedence, mSessionType, mSscMode, mSliceInfo, mDnn);
+ }
+
+ @Override
+ public String toString() {
+ return "{.precedence = " + mPrecedence + ", .sessionType = " + mSessionType
+ + ", .sscMode = " + mSscMode + ", .sliceInfo = " + mSliceInfo
+ + ", .dnn = " + mDnn + "}";
+ }
+}
diff --git a/telephony/java/android/telephony/data/SlicingConfig.aidl b/telephony/java/android/telephony/data/SlicingConfig.aidl
new file mode 100644
index 000000000000..ad93d8cafeba
--- /dev/null
+++ b/telephony/java/android/telephony/data/SlicingConfig.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.data;
+
+parcelable SlicingConfig;
diff --git a/telephony/java/android/telephony/data/SlicingConfig.java b/telephony/java/android/telephony/data/SlicingConfig.java
new file mode 100644
index 000000000000..990e4d218930
--- /dev/null
+++ b/telephony/java/android/telephony/data/SlicingConfig.java
@@ -0,0 +1,137 @@
+/**
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.data;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Represents a slicing configuration
+ */
+public final class SlicingConfig implements Parcelable {
+ private final List<UrspRule> mUrspRules;
+ private final List<NetworkSliceInfo> mSliceInfo;
+
+ public SlicingConfig() {
+ mUrspRules = new ArrayList<UrspRule>();
+ mSliceInfo = new ArrayList<NetworkSliceInfo>();
+ }
+
+ /** @hide */
+ public SlicingConfig(android.hardware.radio.V1_6.SlicingConfig sc) {
+ this(sc.urspRules, sc.sliceInfo);
+ }
+
+ /** @hide */
+ public SlicingConfig(List<android.hardware.radio.V1_6.UrspRule> urspRules,
+ List<android.hardware.radio.V1_6.SliceInfo> sliceInfo) {
+ mUrspRules = new ArrayList<UrspRule>();
+ for (android.hardware.radio.V1_6.UrspRule ur : urspRules) {
+ mUrspRules.add(new UrspRule(ur.precedence, ur.trafficDescriptors,
+ ur.routeSelectionDescriptor));
+ }
+ mSliceInfo = new ArrayList<NetworkSliceInfo>();
+ for (android.hardware.radio.V1_6.SliceInfo si : sliceInfo) {
+ mSliceInfo.add(sliceInfoBuilder(si));
+ }
+ }
+
+ private NetworkSliceInfo sliceInfoBuilder(android.hardware.radio.V1_6.SliceInfo si) {
+ NetworkSliceInfo.Builder builder = new NetworkSliceInfo.Builder()
+ .setSliceServiceType(si.sst)
+ .setMappedHplmnSliceServiceType(si.mappedHplmnSst);
+ if (si.sliceDifferentiator != NetworkSliceInfo.SLICE_DIFFERENTIATOR_NO_SLICE) {
+ builder
+ .setSliceDifferentiator(si.sliceDifferentiator)
+ .setMappedHplmnSliceDifferentiator(si.mappedHplmnSD);
+ }
+ return builder.build();
+ }
+
+ /** @hide */
+ public SlicingConfig(Parcel p) {
+ mUrspRules = p.createTypedArrayList(UrspRule.CREATOR);
+ mSliceInfo = p.createTypedArrayList(NetworkSliceInfo.CREATOR);
+ }
+
+ /**
+ * This list contains the current URSP rules. Empty list represents that no rules are
+ * configured.
+ * @return the current URSP rules for this slicing configuration.
+ */
+ public @NonNull List<UrspRule> getUrspRules() {
+ return mUrspRules;
+ }
+
+ /**
+ * @return the list of all slices for this slicing configuration.
+ */
+ public @NonNull List<NetworkSliceInfo> getSliceInfo() {
+ return mSliceInfo;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeTypedList(mUrspRules, flags);
+ dest.writeTypedList(mSliceInfo, flags);
+ }
+
+ public static final @NonNull Parcelable.Creator<SlicingConfig> CREATOR =
+ new Parcelable.Creator<SlicingConfig>() {
+ @Override
+ public SlicingConfig createFromParcel(Parcel source) {
+ return new SlicingConfig(source);
+ }
+
+ @Override
+ public SlicingConfig[] newArray(int size) {
+ return new SlicingConfig[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ SlicingConfig that = (SlicingConfig) o;
+ return mUrspRules.size() == that.mUrspRules.size()
+ && mUrspRules.containsAll(that.mUrspRules)
+ && mSliceInfo.size() == that.mSliceInfo.size()
+ && mSliceInfo.containsAll(that.mSliceInfo);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mUrspRules, mSliceInfo);
+ }
+
+ @Override
+ public String toString() {
+ return "{.urspRules = " + mUrspRules + ", .sliceInfo = " + mSliceInfo + "}";
+ }
+}
diff --git a/telephony/java/android/telephony/data/TrafficDescriptor.java b/telephony/java/android/telephony/data/TrafficDescriptor.java
index 480379d641b6..d813bc58fe6f 100644
--- a/telephony/java/android/telephony/data/TrafficDescriptor.java
+++ b/telephony/java/android/telephony/data/TrafficDescriptor.java
@@ -18,20 +18,17 @@ package android.telephony.data;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
import java.util.Objects;
/**
- * A traffic descriptor, as defined in 3GPP TS 24.526 Section 5.2. It is used for URSP traffic
- * matching as described in 3GPP TS 24.526 Section 4.2.2. It includes an optional DNN, which,
- * if present, must be used for traffic matching; it does not specify the end point to be used for
- * the data call.
- * @hide
+ * A traffic descriptor, as defined in 3GPP TS 24.526 Section 5.2. It is used for UE Route Selection
+ * Policy(URSP) traffic matching as described in 3GPP TS 24.526 Section 4.2.2. It includes an
+ * optional Data Network Name(DNN), which, if present, must be used for traffic matching; it does
+ * not specify the end point to be used for the data call.
*/
-@SystemApi
public final class TrafficDescriptor implements Parcelable {
private final String mDnn;
private final String mOsAppId;
@@ -45,8 +42,10 @@ public final class TrafficDescriptor implements Parcelable {
* Create a traffic descriptor, as defined in 3GPP TS 24.526 Section 5.2
* @param dnn optional DNN, which must be used for traffic matching, if present
* @param osAppId OsId + osAppId of the traffic descriptor
+ *
+ * @hide
*/
- public TrafficDescriptor(@Nullable String dnn, @Nullable String osAppId) {
+ public TrafficDescriptor(String dnn, String osAppId) {
mDnn = dnn;
mOsAppId = osAppId;
}
@@ -55,12 +54,13 @@ public final class TrafficDescriptor implements Parcelable {
* DNN stands for Data Network Name and represents an APN as defined in 3GPP TS 23.003.
* @return the DNN of this traffic descriptor.
*/
- public @Nullable String getDnn() {
+ public @Nullable String getDataNetworkName() {
return mDnn;
}
/**
- * OsAppId represents the OsId + OsAppId as defined in 3GPP TS 24.526 Section 5.2.
+ * OsAppId is the app id as defined in 3GPP TS 24.526 Section 5.2, and it identifies a traffic
+ * category.
* @return the OS App ID of this traffic descriptor.
*/
public @Nullable String getOsAppId() {
@@ -108,4 +108,65 @@ public final class TrafficDescriptor implements Parcelable {
public int hashCode() {
return Objects.hash(mDnn, mOsAppId);
}
+
+ /**
+ * Provides a convenient way to set the fields of a {@link TrafficDescriptor} when creating a
+ * new instance.
+ *
+ * <p>The example below shows how you might create a new {@code TrafficDescriptor}:
+ *
+ * <pre><code>
+ *
+ * TrafficDescriptor response = new TrafficDescriptor.Builder()
+ * .setDnn("")
+ * .build();
+ * </code></pre>
+ */
+ public static final class Builder {
+ private String mDnn = null;
+ private String mOsAppId = null;
+
+ /**
+ * Default constructor for Builder.
+ */
+ public Builder() {
+ }
+
+ /**
+ * Set the Data Network Name(DNN).
+ *
+ * @return The same instance of the builder.
+ */
+ @NonNull
+ public Builder setDataNetworkName(@NonNull String dnn) {
+ this.mDnn = dnn;
+ return this;
+ }
+
+ /**
+ * Set the OS App ID.
+ *
+ * @return The same instance of the builder.
+ */
+ @NonNull
+ public Builder setOsAppId(@NonNull String osAppId) {
+ this.mOsAppId = osAppId;
+ return this;
+ }
+
+ /**
+ * Build the {@link TrafficDescriptor}.
+ *
+ * @throws IllegalArgumentException if DNN and OS App ID are null.
+ *
+ * @return the {@link TrafficDescriptor} object.
+ */
+ @NonNull
+ public TrafficDescriptor build() {
+ if (this.mDnn == null && this.mOsAppId == null) {
+ throw new IllegalArgumentException("DNN and OS App ID are null");
+ }
+ return new TrafficDescriptor(this.mDnn, this.mOsAppId);
+ }
+ }
}
diff --git a/telephony/java/android/telephony/data/UrspRule.aidl b/telephony/java/android/telephony/data/UrspRule.aidl
new file mode 100644
index 000000000000..2bed583c750e
--- /dev/null
+++ b/telephony/java/android/telephony/data/UrspRule.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.data;
+
+parcelable UrspRule;
diff --git a/telephony/java/android/telephony/data/UrspRule.java b/telephony/java/android/telephony/data/UrspRule.java
new file mode 100644
index 000000000000..e2c47fd86b4b
--- /dev/null
+++ b/telephony/java/android/telephony/data/UrspRule.java
@@ -0,0 +1,178 @@
+/**
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.data;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.hardware.radio.V1_6.OptionalDnn;
+import android.hardware.radio.V1_6.OptionalOsAppId;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Represents a single URSP rule as defined in 3GPP TS 24.526. URSP stands for UE Route Selection
+ * Policy. In 5G, network can provide URSP information to devices which provides information on
+ * what connection parameters should be used for what traffic.
+ */
+public final class UrspRule implements Parcelable {
+ /**
+ * The min acceptable value for the precedence of a URSP rule.
+ * @hide
+ */
+ public static final int MIN_URSP_PRECEDENCE = 0;
+
+ /**
+ * The max acceptable value for the precedence of a URSP rule.
+ * @hide
+ */
+ public static final int MAX_URSP_PRECEDENCE = 255;
+
+ @IntRange(from = MIN_URSP_PRECEDENCE, to = MAX_URSP_PRECEDENCE)
+ private final int mPrecedence;
+ private final List<TrafficDescriptor> mTrafficDescriptors;
+ private final List<RouteSelectionDescriptor> mRouteSelectionDescriptor;
+
+ UrspRule(android.hardware.radio.V1_6.UrspRule ur) {
+ this(ur.precedence, ur.trafficDescriptors, ur.routeSelectionDescriptor);
+ }
+
+ /** @hide */
+ public UrspRule(int precedence,
+ List<android.hardware.radio.V1_6.TrafficDescriptor> trafficDescriptors,
+ List<android.hardware.radio.V1_6.RouteSelectionDescriptor> routeSelectionDescriptor) {
+ mPrecedence = precedence;
+ mTrafficDescriptors = new ArrayList<TrafficDescriptor>();
+ for (android.hardware.radio.V1_6.TrafficDescriptor td : trafficDescriptors) {
+ mTrafficDescriptors.add(convertToTrafficDescriptor(td));
+ }
+ mRouteSelectionDescriptor = new ArrayList<RouteSelectionDescriptor>();
+ for (android.hardware.radio.V1_6.RouteSelectionDescriptor rsd : routeSelectionDescriptor) {
+ mRouteSelectionDescriptor.add(new RouteSelectionDescriptor(rsd));
+ }
+ }
+
+ /** Convert an ArrayList of Bytes to an exactly-sized primitive array */
+ private byte[] arrayListToPrimitiveArray(ArrayList<Byte> bytes) {
+ byte[] ret = new byte[bytes.size()];
+ for (int i = 0; i < ret.length; i++) {
+ ret[i] = bytes.get(i);
+ }
+ return ret;
+ }
+
+ private TrafficDescriptor convertToTrafficDescriptor(
+ android.hardware.radio.V1_6.TrafficDescriptor td) {
+ String dnn = td.dnn.getDiscriminator() == OptionalDnn.hidl_discriminator.noinit
+ ? null : td.dnn.value();
+ String osAppId = td.osAppId.getDiscriminator() == OptionalOsAppId.hidl_discriminator.noinit
+ ? null : new String(arrayListToPrimitiveArray(td.osAppId.value().osAppId));
+ TrafficDescriptor.Builder builder = new TrafficDescriptor.Builder();
+ if (dnn != null) {
+ builder.setDataNetworkName(dnn);
+ }
+ if (osAppId != null) {
+ builder.setOsAppId(osAppId);
+ }
+ return builder.build();
+ }
+
+ private UrspRule(Parcel p) {
+ mPrecedence = p.readInt();
+ mTrafficDescriptors = p.createTypedArrayList(TrafficDescriptor.CREATOR);
+ mRouteSelectionDescriptor = p.createTypedArrayList(RouteSelectionDescriptor.CREATOR);
+ }
+
+ /**
+ * Precedence value in the range of 0 to 255. Higher value has lower precedence.
+ * @return the precedence value for this URSP rule.
+ */
+ @IntRange(from = MIN_URSP_PRECEDENCE, to = MAX_URSP_PRECEDENCE)
+ public int getPrecedence() {
+ return mPrecedence;
+ }
+
+ /**
+ * These traffic descriptors are used as a matcher for network requests.
+ * @return the traffic descriptors which are associated to this URSP rule.
+ */
+ public @NonNull List<TrafficDescriptor> getTrafficDescriptors() {
+ return mTrafficDescriptors;
+ }
+
+ /**
+ * List of routes (connection parameters) that must be used by the device for requests matching
+ * a traffic descriptor.
+ * @return the route selection descriptors which are associated to this URSP rule.
+ */
+ public @NonNull List<RouteSelectionDescriptor> getRouteSelectionDescriptor() {
+ return mRouteSelectionDescriptor;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mPrecedence);
+ dest.writeTypedList(mTrafficDescriptors, flags);
+ dest.writeTypedList(mRouteSelectionDescriptor, flags);
+ }
+
+ public static final @NonNull Parcelable.Creator<UrspRule> CREATOR =
+ new Parcelable.Creator<UrspRule>() {
+ @Override
+ public UrspRule createFromParcel(Parcel source) {
+ return new UrspRule(source);
+ }
+
+ @Override
+ public UrspRule[] newArray(int size) {
+ return new UrspRule[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ UrspRule that = (UrspRule) o;
+ return mPrecedence == that.mPrecedence
+ && mTrafficDescriptors.size() == that.mTrafficDescriptors.size()
+ && mTrafficDescriptors.containsAll(that.mTrafficDescriptors)
+ && mRouteSelectionDescriptor.size() == that.mRouteSelectionDescriptor.size()
+ && mRouteSelectionDescriptor.containsAll(that.mRouteSelectionDescriptor);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mPrecedence, mTrafficDescriptors, mRouteSelectionDescriptor);
+ }
+
+ @Override
+ public String toString() {
+ return "{.precedence = " + mPrecedence + ", .trafficDescriptors = " + mTrafficDescriptors
+ + ", .routeSelectionDescriptor = " + mRouteSelectionDescriptor + "}";
+ }
+}
diff --git a/telephony/java/android/telephony/ims/ImsCallSession.java b/telephony/java/android/telephony/ims/ImsCallSession.java
index 0aff99709a52..dfe5e6c93f53 100755
--- a/telephony/java/android/telephony/ims/ImsCallSession.java
+++ b/telephony/java/android/telephony/ims/ImsCallSession.java
@@ -766,7 +766,10 @@ public class ImsCallSession {
* The method is only valid to call when the session state is in
* {@link ImsCallSession.State#IDLE}.
*
- * @param callee dialed string to make the call to
+ * @param callee dial string to make the call to. The platform passes the dialed number
+ * entered by the user as-is. The {@link ImsService} should ensure that the
+ * number is formatted in SIP messages appropriately (e.g. using
+ * {@link android.telephony.PhoneNumberUtils#formatNumberToE164(String, String)}).
* @param profile call profile to make the call with the specified service type,
* call type and media information
* @see Listener#callSessionStarted, Listener#callSessionStartFailed
@@ -788,7 +791,10 @@ public class ImsCallSession {
* The method is only valid to call when the session state is in
* {@link ImsCallSession.State#IDLE}.
*
- * @param participants participant list to initiate an IMS conference call
+ * @param participants participant list to initiate an IMS conference call. The platform passes
+ * the dialed numbers entered by the user as-is. The {@link ImsService} should
+ * ensure that the number is formatted in SIP messages appropriately (e.g. using
+ * {@link android.telephony.PhoneNumberUtils#formatNumberToE164(String, String)}).
* @param profile call profile to make the call with the specified service type,
* call type and media information
* @see Listener#callSessionStarted, Listener#callSessionStartFailed
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index ae5f997360cd..d812b4641748 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -2447,4 +2447,10 @@ interface ITelephony {
* Gets the current phone capability.
*/
PhoneCapability getPhoneCapability();
+
+ /**
+ * Request to get the current slicing configuration including URSP rules and
+ * NSSAIs (configured, allowed and rejected).
+ */
+ void getSlicingConfig(in ResultReceiver callback);
}
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 822fc44146d6..fe8e6715fe35 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -527,6 +527,7 @@ public interface RILConstants {
int RIL_REQUEST_SET_DATA_THROTTLING = 221;
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;
/* Responses begin */
int RIL_RESPONSE_ACKNOWLEDGEMENT = 800;
diff --git a/test-mock/Android.bp b/test-mock/Android.bp
index 460a26d63cd6..0bb61987a514 100644
--- a/test-mock/Android.bp
+++ b/test-mock/Android.bp
@@ -32,7 +32,9 @@ java_sdk_library {
":android-test-mock-sources",
// Note: Below are NOT APIs of this library. We only take APIs under
// the android.test.mock package. They however provide private APIs that
- // android.test.mock APIs references to.
+ // android.test.mock APIs references to. We need to have the classes in
+ // source code form to have access to the @hide comment which disappears
+ // when the classes are compiled into a Jar library.
":framework-core-sources-for-test-mock",
":framework_native_aidl",
],
@@ -46,6 +48,14 @@ java_sdk_library {
api_packages: [
"android.test.mock",
],
+ // Only include android.test.mock.* classes. Jarjar rules below removes
+ // classes in other packages like android.content. In order to keep the
+ // list up-to-date, permitted_packages ensures that the library contains
+ // clases under android.test.mock after the jarjar rules are applied.
+ jarjar_rules: "jarjar-rules.txt",
+ permitted_packages: [
+ "android.test.mock",
+ ],
compile_dex: true,
default_to_stubs: true,
dist_group: "android",
diff --git a/test-mock/jarjar-rules.txt b/test-mock/jarjar-rules.txt
new file mode 100644
index 000000000000..4420a4413f5b
--- /dev/null
+++ b/test-mock/jarjar-rules.txt
@@ -0,0 +1,7 @@
+zap android.accounts.**
+zap android.app.**
+zap android.content.**
+zap android.database.**
+zap android.os.**
+zap android.util.**
+zap android.view.**
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
index 0f84f6ebe522..c9a8947ab5ef 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
@@ -322,6 +322,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection
triggerValidation(NetworkAgent.VALIDATION_STATUS_VALID);
verify(mSafeModeTimeoutAlarm).cancel();
assertFalse(mGatewayConnection.isInSafeMode());
+ verifySafeModeStateAndCallbackFired(1 /* invocationCount */, false /* isInSafeMode */);
}
@Test
@@ -391,6 +392,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection
triggerValidation(NetworkAgent.VALIDATION_STATUS_VALID);
+ verifySafeModeStateAndCallbackFired(2 /* invocationCount */, false /* isInSafeMode */);
assertFalse(mGatewayConnection.isInSafeMode());
}
@@ -400,7 +402,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection
mTestLooper.dispatchAll();
triggerValidation(NetworkAgent.VALIDATION_STATUS_VALID);
- assertFalse(mGatewayConnection.isInSafeMode());
+ verifySafeModeStateAndCallbackFired(1 /* invocationCount */, false /* isInSafeMode */);
// Trigger a failed validation, and the subsequent safemode timeout.
triggerValidation(NetworkAgent.VALIDATION_STATUS_NOT_VALID);
@@ -416,7 +418,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection
runnableCaptor.getValue().run();
mTestLooper.dispatchAll();
- assertTrue(mGatewayConnection.isInSafeMode());
+ verifySafeModeStateAndCallbackFired(2 /* invocationCount */, true /* isInSafeMode */);
}
private Consumer<VcnNetworkAgent> setupNetworkAndGetUnwantedCallback() {
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
index a696b3ae28f7..64d0bca15ce9 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
@@ -23,7 +23,6 @@ import static com.android.server.vcn.VcnTestUtils.setupIpSecManager;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.CALLS_REAL_METHODS;
@@ -301,6 +300,11 @@ public class VcnGatewayConnectionTestBase {
expectCanceled);
}
+ protected void verifySafeModeStateAndCallbackFired(int invocationCount, boolean isInSafeMode) {
+ verify(mGatewayStatusCallback, times(invocationCount)).onSafeModeStatusChanged();
+ assertEquals(isInSafeMode, mGatewayConnection.isInSafeMode());
+ }
+
protected void verifySafeModeTimeoutNotifiesCallbackAndUnregistersNetworkAgent(
@NonNull State expectedState) {
// Set a VcnNetworkAgent, and expect it to be unregistered and cleared
@@ -314,9 +318,8 @@ public class VcnGatewayConnectionTestBase {
delayedEvent.run();
mTestLooper.dispatchAll();
- verify(mGatewayStatusCallback).onSafeModeStatusChanged();
assertEquals(expectedState, mGatewayConnection.getCurrentState());
- assertTrue(mGatewayConnection.isInSafeMode());
+ verifySafeModeStateAndCallbackFired(1, true);
verify(mockNetworkAgent).unregister();
assertNull(mGatewayConnection.getNetworkAgent());
diff --git a/tools/bit/print.cpp b/tools/bit/print.cpp
index 35feda11ec29..8bc6f167bd7f 100644
--- a/tools/bit/print.cpp
+++ b/tools/bit/print.cpp
@@ -17,6 +17,7 @@
#include "print.h"
#include <sys/ioctl.h>
+#include <stdarg.h>
#include <stdio.h>
#include <unistd.h>
diff --git a/tools/bit/util.h b/tools/bit/util.h
index 7ccdab103d9a..8c66911b3c48 100644
--- a/tools/bit/util.h
+++ b/tools/bit/util.h
@@ -17,6 +17,8 @@
#ifndef UTIL_H
#define UTIL_H
+#include <sys/types.h>
+
#include <map>
#include <string>
#include <vector>
diff --git a/tools/streaming_proto/Errors.cpp b/tools/streaming_proto/Errors.cpp
index 0cd9037dcb55..6890d99b104c 100644
--- a/tools/streaming_proto/Errors.cpp
+++ b/tools/streaming_proto/Errors.cpp
@@ -1,5 +1,6 @@
#include "Errors.h"
+#include <stdarg.h>
#include <stdlib.h>
namespace android {