diff options
213 files changed, 5517 insertions, 2407 deletions
diff --git a/Android.bp b/Android.bp index 92f79d1fbef4..8e17f5524a38 100644 --- a/Android.bp +++ b/Android.bp @@ -769,7 +769,6 @@ filegroup { name: "framework-services-net-module-wifi-shared-srcs", srcs: [ "core/java/android/net/DhcpResults.java", - "core/java/android/net/util/IpUtils.java", "core/java/android/util/LocalLog.java", ], } diff --git a/StubLibraries.bp b/StubLibraries.bp index 9e087f020246..39aa732d929b 100644 --- a/StubLibraries.bp +++ b/StubLibraries.bp @@ -55,7 +55,24 @@ stubs_defaults { aidl: { local_include_dirs: ["telephony/java"], }, - libs: ["framework-internal-utils"], + // These are libs from framework-internal-utils that are required (i.e. being referenced) + // from framework-non-updatable-sources. Add more here when there's a need. + // DO NOT add the entire framework-internal-utils. It might cause unnecessary circular + // dependencies gets bigger. + libs: [ + "android.hardware.cas-V1.2-java", + "android.hardware.health-V1.0-java-constants", + "android.hardware.radio-V1.5-java", + "android.hardware.thermal-V1.0-java-constants", + "android.hardware.thermal-V2.0-java", + "android.hardware.tv.input-V1.0-java-constants", + "android.hardware.tv.tuner-V1.0-java-constants", + "android.hardware.usb-V1.0-java-constants", + "android.hardware.usb-V1.1-java-constants", + "android.hardware.usb.gadget-V1.0-java", + "android.hardware.vibrator-V1.3-java", + "framework-protos", + ], installable: false, annotations_enabled: true, previous_api: ":android.api.public.latest", @@ -101,7 +118,6 @@ stubs_defaults { droidstubs { name: "api-stubs-docs", defaults: ["metalava-full-api-stubs-default"], - removed_dex_api_filename: "removed-dex.txt", arg_files: [ "core/res/AndroidManifest.xml", ], @@ -122,12 +138,6 @@ droidstubs { baseline_file: "api/lint-baseline.txt", }, }, - dist: { - targets: ["sdk", "win_sdk"], - dir: "apistubs/android/public/api", - dest: "android.txt", - }, - jdiff_enabled: true, } droidstubs { @@ -140,6 +150,11 @@ droidstubs { api_file: "non-updatable-api/current.txt", removed_api_file: "non-updatable-api/removed.txt", }, + last_released: { + api_file: ":android-non-updatable.api.public.latest", + removed_api_file: ":android-non-updatable-removed.api.public.latest", + baseline_file: ":public-api-incompatibilities-with-last-released", + }, api_lint: { enabled: true, new_since: ":android-non-updatable.api.public.latest", @@ -163,7 +178,6 @@ module_libs = " " + droidstubs { name: "system-api-stubs-docs", defaults: ["metalava-full-api-stubs-default"], - removed_dex_api_filename: "system-removed-dex.txt", arg_files: [ "core/res/AndroidManifest.xml", ], @@ -184,12 +198,6 @@ droidstubs { baseline_file: "api/system-lint-baseline.txt", }, }, - dist: { - targets: ["sdk", "win_sdk"], - dir: "apistubs/android/system/api", - dest: "android.txt", - }, - jdiff_enabled: true, } droidstubs { @@ -202,6 +210,11 @@ droidstubs { api_file: "non-updatable-api/system-current.txt", removed_api_file: "non-updatable-api/system-removed.txt", }, + last_released: { + api_file: ":android-non-updatable.api.system.latest", + removed_api_file: ":android-non-updatable-removed.api.system.latest", + baseline_file: ":system-api-incompatibilities-with-last-released" + }, api_lint: { enabled: true, new_since: ":android-non-updatable.api.system.latest", @@ -212,11 +225,15 @@ droidstubs { droidstubs { name: "test-api-stubs-docs", - defaults: ["metalava-full-api-stubs-default"], + defaults: ["metalava-non-updatable-api-stubs-default"], arg_files: [ "core/res/AndroidManifest.xml", ], - args: metalava_framework_docs_args + " --show-annotation android.annotation.TestApi", + args: metalava_framework_docs_args + + " --show-annotation android.annotation.TestApi" + + " --show-for-stub-purposes-annotation android.annotation.SystemApi\\(" + + "client=android.annotation.SystemApi.Client.PRIVILEGED_APPS" + + "\\)", check_api: { current: { api_file: "api/test-current.txt", @@ -264,11 +281,6 @@ droidstubs { baseline_file: "api/module-lib-lint-baseline.txt", }, }, - dist: { - targets: ["sdk", "win_sdk"], - dir: "apistubs/android/module-lib/api", - dest: "android.txt", - }, } droidstubs { @@ -281,6 +293,10 @@ droidstubs { api_file: "non-updatable-api/module-lib-current.txt", removed_api_file: "non-updatable-api/module-lib-removed.txt", }, + last_released: { + api_file: ":android-non-updatable.api.module-lib.latest", + removed_api_file: ":android-non-updatable-removed.api.module-lib.latest", + }, api_lint: { enabled: true, new_since: ":android-non-updatable.api.module-lib.latest", @@ -398,7 +414,19 @@ java_library_static { java_library_static { name: "android_test_stubs_current", srcs: [ ":test-api-stubs-docs" ], - static_libs: [ "private-stub-annotations-jar" ], + static_libs: [ + // Modules do not have test APIs, but we want to include their SystemApis, like we include + // the SystemApi of framework-non-updatable-sources. + "conscrypt.module.public.api.stubs", + "framework-media.stubs.system", + "framework-mediaprovider.stubs.system", + "framework-permission.stubs.system", + "framework-sdkextensions.stubs.system", + "framework-statsd.stubs.system", + "framework-tethering.stubs.system", + "framework-wifi.stubs.system", + "private-stub-annotations-jar", + ], defaults: [ "android_defaults_stubs_current", "android_stubs_dists_default", diff --git a/apex/statsd/aidl/android/os/IStatsCompanionService.aidl b/apex/statsd/aidl/android/os/IStatsCompanionService.aidl index 5cdb3249501b..d56a4bd0a8e5 100644 --- a/apex/statsd/aidl/android/os/IStatsCompanionService.aidl +++ b/apex/statsd/aidl/android/os/IStatsCompanionService.aidl @@ -27,17 +27,6 @@ interface IStatsCompanionService { oneway void statsdReady(); /** - * Register an alarm for anomaly detection to fire at the given timestamp (ms since epoch). - * If anomaly alarm had already been registered, it will be replaced with the new timestamp. - * Uses AlarmManager.set API, so if the timestamp is in the past, alarm fires immediately, and - * alarm is inexact. - */ - oneway void setAnomalyAlarm(long timestampMs); - - /** Cancel any anomaly detection alarm. */ - oneway void cancelAnomalyAlarm(); - - /** * Register a repeating alarm for pulling to fire at the given timestamp and every * intervalMs thereafter (in ms since epoch). * If polling alarm had already been registered, it will be replaced by new one. diff --git a/apex/statsd/aidl/android/os/IStatsd.aidl b/apex/statsd/aidl/android/os/IStatsd.aidl index 0d3f4208a2ab..066412a9f157 100644 --- a/apex/statsd/aidl/android/os/IStatsd.aidl +++ b/apex/statsd/aidl/android/os/IStatsd.aidl @@ -42,13 +42,6 @@ interface IStatsd { void statsCompanionReady(); /** - * Tells statsd that an anomaly may have occurred, so statsd can check whether this is so and - * act accordingly. - * Two-way binder call so that caller's method (and corresponding wakelocks) will linger. - */ - void informAnomalyAlarmFired(); - - /** * Tells statsd that it is time to poll some stats. Statsd will be responsible for determing * what stats to poll and initiating the polling. * Two-way binder call so that caller's method (and corresponding wakelocks) will linger. diff --git a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java index cbc8ed636ff2..b5e72247a4a3 100644 --- a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java +++ b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java @@ -100,7 +100,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { private static IStatsd sStatsd; private static final Object sStatsdLock = new Object(); - private final OnAlarmListener mAnomalyAlarmListener; private final OnAlarmListener mPullingAlarmListener; private final OnAlarmListener mPeriodicAlarmListener; @@ -124,7 +123,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { handlerThread.start(); mHandler = new CompanionHandler(handlerThread.getLooper()); - mAnomalyAlarmListener = new AnomalyAlarmListener(context); mPullingAlarmListener = new PullingAlarmListener(context); mPeriodicAlarmListener = new PeriodicAlarmListener(context); } @@ -336,41 +334,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { } } - public static final class AnomalyAlarmListener implements OnAlarmListener { - private final Context mContext; - - AnomalyAlarmListener(Context context) { - mContext = context; - } - - @Override - public void onAlarm() { - if (DEBUG) { - Log.i(TAG, "StatsCompanionService believes an anomaly has occurred at time " - + System.currentTimeMillis() + "ms."); - } - IStatsd statsd = getStatsdNonblocking(); - if (statsd == null) { - Log.w(TAG, "Could not access statsd to inform it of anomaly alarm firing"); - return; - } - - // Wakelock needs to be retained while calling statsd. - Thread thread = new WakelockThread(mContext, - AnomalyAlarmListener.class.getCanonicalName(), new Runnable() { - @Override - public void run() { - try { - statsd.informAnomalyAlarmFired(); - } catch (RemoteException e) { - Log.w(TAG, "Failed to inform statsd of anomaly alarm firing", e); - } - } - }); - thread.start(); - } - } - public final static class PullingAlarmListener implements OnAlarmListener { private final Context mContext; @@ -469,34 +432,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { } @Override // Binder call - public void setAnomalyAlarm(long timestampMs) { - StatsCompanion.enforceStatsdCallingUid(); - if (DEBUG) Log.d(TAG, "Setting anomaly alarm for " + timestampMs); - final long callingToken = Binder.clearCallingIdentity(); - try { - // using ELAPSED_REALTIME, not ELAPSED_REALTIME_WAKEUP, so if device is asleep, will - // only fire when it awakens. - // AlarmManager will automatically cancel any previous mAnomalyAlarmListener alarm. - mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME, timestampMs, TAG + ".anomaly", - mAnomalyAlarmListener, mHandler); - } finally { - Binder.restoreCallingIdentity(callingToken); - } - } - - @Override // Binder call - public void cancelAnomalyAlarm() { - StatsCompanion.enforceStatsdCallingUid(); - if (DEBUG) Log.d(TAG, "Cancelling anomaly alarm"); - final long callingToken = Binder.clearCallingIdentity(); - try { - mAlarmManager.cancel(mAnomalyAlarmListener); - } finally { - Binder.restoreCallingIdentity(callingToken); - } - } - - @Override // Binder call public void setAlarmForSubscriberTriggering(long timestampMs) { StatsCompanion.enforceStatsdCallingUid(); if (DEBUG) { @@ -666,7 +601,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { // instead of in binder death because statsd can come back and set different alarms, or not // want to set an alarm when it had been set. This guarantees that when we get a new statsd, // we cancel any alarms before it is able to set them. - cancelAnomalyAlarm(); cancelPullingAlarm(); cancelAlarmForSubscriberTriggering(); diff --git a/api/Android.bp b/api/Android.bp index cb6d448caf63..fd0303b31de9 100644 --- a/api/Android.bp +++ b/api/Android.bp @@ -60,6 +60,29 @@ genrule { out: ["current.txt"], tools: ["metalava"], cmd: "$(location metalava) --no-banner --format=v2 $(in) --api $(out)", + dist: { + targets: ["sdk", "win_sdk"], + dir: "apistubs/android/public/api", + dest: "android.txt", + }, +} + +genrule { + name: "frameworks-base-api-removed-merged.txt", + srcs: [ + ":conscrypt.module.public.api{.public.removed-api.txt}", + ":framework-media{.public.removed-api.txt}", + ":framework-mediaprovider{.public.removed-api.txt}", + ":framework-permission{.public.removed-api.txt}", + ":framework-sdkextensions{.public.removed-api.txt}", + ":framework-statsd{.public.removed-api.txt}", + ":framework-tethering{.public.removed-api.txt}", + ":framework-wifi{.public.removed-api.txt}", + ":non-updatable-removed.txt", + ], + out: ["removed.txt"], + tools: ["metalava"], + cmd: "$(location metalava) --no-banner --format=v2 $(in) --api $(out)", } genrule { @@ -77,6 +100,28 @@ genrule { out: ["system-current.txt"], tools: ["metalava"], cmd: "$(location metalava) --no-banner --format=v2 $(in) --api $(out)", + dist: { + targets: ["sdk", "win_sdk"], + dir: "apistubs/android/system/api", + dest: "android.txt", + }, +} + +genrule { + name: "frameworks-base-api-system-removed-merged.txt", + srcs: [ + ":framework-media{.system.removed-api.txt}", + ":framework-mediaprovider{.system.removed-api.txt}", + ":framework-permission{.system.removed-api.txt}", + ":framework-sdkextensions{.system.removed-api.txt}", + ":framework-statsd{.system.removed-api.txt}", + ":framework-tethering{.system.removed-api.txt}", + ":framework-wifi{.system.removed-api.txt}", + ":non-updatable-system-removed.txt", + ], + out: ["system-removed.txt"], + tools: ["metalava"], + cmd: "$(location metalava) --no-banner --format=v2 $(in) --api $(out)", } genrule { @@ -94,4 +139,40 @@ genrule { out: ["module-lib-current.txt"], tools: ["metalava"], cmd: "$(location metalava) --no-banner --format=v2 $(in) --api $(out)", + dist: { + targets: ["sdk", "win_sdk"], + dir: "apistubs/android/module-lib/api", + dest: "android.txt", + }, +} + +genrule { + name: "frameworks-base-api-module-lib-removed-merged.txt", + srcs: [ + ":framework-media{.module-lib.removed-api.txt}", + ":framework-mediaprovider{.module-lib.removed-api.txt}", + ":framework-permission{.module-lib.removed-api.txt}", + ":framework-sdkextensions{.module-lib.removed-api.txt}", + ":framework-statsd{.module-lib.removed-api.txt}", + ":framework-tethering{.module-lib.removed-api.txt}", + ":framework-wifi{.module-lib.removed-api.txt}", + ":non-updatable-module-lib-removed.txt", + ], + out: ["module-lib-removed.txt"], + tools: ["metalava"], + cmd: "$(location metalava) --no-banner --format=v2 $(in) --api $(out)", +} + +genrule { + name: "combined-removed-dex", + srcs: [ + ":frameworks-base-api-removed-merged.txt", + ":frameworks-base-api-system-removed-merged.txt", + ":android.car-stubs-docs{.removed-api.txt}", + ":android.car-system-stubs-docs{.removed-api.txt}", + ], + tool_files: ["gen_combined_removed_dex.sh"], + tools: ["metalava"], + out: ["combined-removed-dex.txt"], + cmd: "$(location gen_combined_removed_dex.sh) $(location metalava) $(genDir) $(in) > $(out)", } diff --git a/api/current.txt b/api/current.txt index 17413475451e..22b8c456f655 100644 --- a/api/current.txt +++ b/api/current.txt @@ -9126,6 +9126,7 @@ package android.bluetooth.le { method public boolean getIncludeTxPowerLevel(); method public android.util.SparseArray<byte[]> getManufacturerSpecificData(); method public java.util.Map<android.os.ParcelUuid,byte[]> getServiceData(); + method @Nullable public java.util.List<android.os.ParcelUuid> getServiceSolicitationUuids(); method public java.util.List<android.os.ParcelUuid> getServiceUuids(); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.le.AdvertiseData> CREATOR; @@ -9135,6 +9136,7 @@ package android.bluetooth.le { ctor public AdvertiseData.Builder(); method public android.bluetooth.le.AdvertiseData.Builder addManufacturerData(int, byte[]); method public android.bluetooth.le.AdvertiseData.Builder addServiceData(android.os.ParcelUuid, byte[]); + method @NonNull public android.bluetooth.le.AdvertiseData.Builder addServiceSolicitationUuid(@NonNull android.os.ParcelUuid); method public android.bluetooth.le.AdvertiseData.Builder addServiceUuid(android.os.ParcelUuid); method public android.bluetooth.le.AdvertiseData build(); method public android.bluetooth.le.AdvertiseData.Builder setIncludeDeviceName(boolean); @@ -30049,9 +30051,12 @@ package android.net { method public int describeContents(); method @NonNull public byte[] getKey(); method @NonNull public String getName(); + method @NonNull public static java.util.Set<java.lang.String> getSupportedAlgorithms(); method public int getTruncationLengthBits(); method public void writeToParcel(android.os.Parcel, int); + field public static final String AUTH_AES_XCBC = "xcbc(aes)"; field public static final String AUTH_CRYPT_AES_GCM = "rfc4106(gcm(aes))"; + field public static final String AUTH_CRYPT_CHACHA20_POLY1305 = "rfc7539esp(chacha20,poly1305)"; field public static final String AUTH_HMAC_MD5 = "hmac(md5)"; field public static final String AUTH_HMAC_SHA1 = "hmac(sha1)"; field public static final String AUTH_HMAC_SHA256 = "hmac(sha256)"; @@ -30059,6 +30064,7 @@ package android.net { field public static final String AUTH_HMAC_SHA512 = "hmac(sha512)"; field @NonNull public static final android.os.Parcelable.Creator<android.net.IpSecAlgorithm> CREATOR; field public static final String CRYPT_AES_CBC = "cbc(aes)"; + field public static final String CRYPT_AES_CTR = "rfc3686(ctr(aes))"; } public final class IpSecManager { @@ -36464,7 +36470,7 @@ package android.os { method public int dataCapacity(); method public int dataPosition(); method public int dataSize(); - method public void enforceInterface(String); + method public void enforceInterface(@NonNull String); method public boolean hasFileDescriptors(); method public byte[] marshall(); method @NonNull public static android.os.Parcel obtain(); @@ -36535,7 +36541,7 @@ package android.os { method public void writeFloatArray(@Nullable float[]); method public void writeInt(int); method public void writeIntArray(@Nullable int[]); - method public void writeInterfaceToken(String); + method public void writeInterfaceToken(@NonNull String); method public void writeList(@Nullable java.util.List); method public void writeLong(long); method public void writeLongArray(@Nullable long[]); @@ -47039,9 +47045,9 @@ package android.telephony { field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CellInfoWcdma> CREATOR; } - public abstract class CellLocation { - ctor public CellLocation(); - method public static android.telephony.CellLocation getEmpty(); + @Deprecated public abstract class CellLocation { + ctor @Deprecated public CellLocation(); + method @Deprecated public static android.telephony.CellLocation getEmpty(); method @Deprecated public static void requestLocationUpdate(); } @@ -47910,6 +47916,7 @@ package android.telephony { method @NonNull public android.os.Bundle getCarrierConfigValues(); method public static android.telephony.SmsManager getDefault(); method public static int getDefaultSmsSubscriptionId(); + method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int getSmsCapacityOnIcc(); method public static android.telephony.SmsManager getSmsManagerForSubscriptionId(int); method @RequiresPermission(android.Manifest.permission.SMS_FINANCIAL_TRANSACTIONS) public void getSmsMessagesForFinancialApp(android.os.Bundle, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.SmsManager.FinancialSmsCallback); method @Nullable @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getSmscAddress(); @@ -48252,6 +48259,7 @@ package android.telephony { method @Nullable @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getDeviceSoftwareVersion(); method @NonNull @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public java.util.Map<java.lang.Integer,java.util.List<android.telephony.emergency.EmergencyNumber>> getEmergencyNumberList(); method @NonNull @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public java.util.Map<java.lang.Integer,java.util.List<android.telephony.emergency.EmergencyNumber>> getEmergencyNumberList(int); + method @NonNull @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public java.util.List<java.lang.String> getEquivalentHomePlmns(); method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String[] getForbiddenPlmns(); method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getGroupIdLevel1(); method public String getIccAuthentication(int, int, String); @@ -48276,7 +48284,7 @@ package android.telephony { method @Deprecated public int getPhoneCount(); method public int getPhoneType(); method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PHONE_STATE}) public int getPreferredOpportunisticDataSubscription(); - method @RequiresPermission(allOf={android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.ACCESS_COARSE_LOCATION}) public android.telephony.ServiceState getServiceState(); + method @Nullable @RequiresPermission(allOf={android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.ACCESS_COARSE_LOCATION}) public android.telephony.ServiceState getServiceState(); method @Nullable public android.telephony.SignalStrength getSignalStrength(); method public int getSimCarrierId(); method @Nullable public CharSequence getSimCarrierIdName(); @@ -48299,7 +48307,7 @@ package android.telephony { method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getVoiceMailAlphaTag(); method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getVoiceMailNumber(); method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int getVoiceNetworkType(); - method public android.net.Uri getVoicemailRingtoneUri(android.telecom.PhoneAccountHandle); + method @Nullable public android.net.Uri getVoicemailRingtoneUri(android.telecom.PhoneAccountHandle); method public boolean hasCarrierPrivileges(); method public boolean hasIccCard(); method @Deprecated public boolean iccCloseLogicalChannel(int); @@ -48549,19 +48557,19 @@ package android.telephony { package android.telephony.cdma { - public class CdmaCellLocation extends android.telephony.CellLocation { - ctor public CdmaCellLocation(); - ctor public CdmaCellLocation(android.os.Bundle); - method public static double convertQuartSecToDecDegrees(int); - method public void fillInNotifierBundle(android.os.Bundle); - method public int getBaseStationId(); - method public int getBaseStationLatitude(); - method public int getBaseStationLongitude(); - method public int getNetworkId(); - method public int getSystemId(); - method public void setCellLocationData(int, int, int); - method public void setCellLocationData(int, int, int, int, int); - method public void setStateInvalid(); + @Deprecated public class CdmaCellLocation extends android.telephony.CellLocation { + ctor @Deprecated public CdmaCellLocation(); + ctor @Deprecated public CdmaCellLocation(android.os.Bundle); + method @Deprecated public static double convertQuartSecToDecDegrees(int); + method @Deprecated public void fillInNotifierBundle(android.os.Bundle); + method @Deprecated public int getBaseStationId(); + method @Deprecated public int getBaseStationLatitude(); + method @Deprecated public int getBaseStationLongitude(); + method @Deprecated public int getNetworkId(); + method @Deprecated public int getSystemId(); + method @Deprecated public void setCellLocationData(int, int, int); + method @Deprecated public void setCellLocationData(int, int, int, int, int); + method @Deprecated public void setStateInvalid(); } } @@ -48761,15 +48769,15 @@ package android.telephony.euicc { package android.telephony.gsm { - public class GsmCellLocation extends android.telephony.CellLocation { - ctor public GsmCellLocation(); - ctor public GsmCellLocation(android.os.Bundle); - method public void fillInNotifierBundle(android.os.Bundle); - method public int getCid(); - method public int getLac(); - method public int getPsc(); - method public void setLacAndCid(int, int); - method public void setStateInvalid(); + @Deprecated public class GsmCellLocation extends android.telephony.CellLocation { + ctor @Deprecated public GsmCellLocation(); + ctor @Deprecated public GsmCellLocation(android.os.Bundle); + method @Deprecated public void fillInNotifierBundle(android.os.Bundle); + method @Deprecated public int getCid(); + method @Deprecated public int getLac(); + method @Deprecated public int getPsc(); + method @Deprecated public void setLacAndCid(int, int); + method @Deprecated public void setStateInvalid(); } @Deprecated public final class SmsManager { @@ -49105,6 +49113,7 @@ package android.telephony.ims.feature { } public static class MmTelFeature.MmTelCapabilities { + method public final boolean isCapable(int); field public static final int CAPABILITY_TYPE_SMS = 8; // 0x8 field public static final int CAPABILITY_TYPE_UT = 4; // 0x4 field public static final int CAPABILITY_TYPE_VIDEO = 2; // 0x2 diff --git a/api/gen_combined_removed_dex.sh b/api/gen_combined_removed_dex.sh new file mode 100755 index 000000000000..9225fe8dfe85 --- /dev/null +++ b/api/gen_combined_removed_dex.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +metalava_path="$1" +tmp_dir="$2" +shift 2 + +# Convert each removed.txt to the "dex format" equivalent, and print all output. +for f in "$@"; do + "$metalava_path" --no-banner "$f" --dex-api "${tmp_dir}/tmp" + cat "${tmp_dir}/tmp" +done diff --git a/api/system-current.txt b/api/system-current.txt index 6d13582bb49d..8db99aa097a7 100755 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -11075,7 +11075,6 @@ package android.telephony { method public boolean disableCellBroadcastRange(int, int, int); method public boolean enableCellBroadcastRange(int, int, int); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getPremiumSmsConsent(@NonNull String); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getSmsCapacityOnIcc(); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void sendMultipartTextMessageWithoutPersisting(String, String, java.util.List<java.lang.String>, java.util.List<android.app.PendingIntent>, java.util.List<android.app.PendingIntent>); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setPremiumSmsConsent(@NonNull String, int); field public static final int PREMIUM_SMS_CONSENT_ALWAYS_ALLOW = 3; // 0x3 @@ -12249,7 +12248,6 @@ package android.telephony.ims.feature { ctor @Deprecated public MmTelFeature.MmTelCapabilities(android.telephony.ims.feature.ImsFeature.Capabilities); ctor public MmTelFeature.MmTelCapabilities(int); method public final void addCapabilities(int); - method public final boolean isCapable(int); method public final void removeCapabilities(int); } diff --git a/api/test-current.txt b/api/test-current.txt index 415ed034f176..912f33c763cd 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -19,6 +19,7 @@ package android { field public static final String NETWORK_STACK = "android.permission.NETWORK_STACK"; field public static final String OVERRIDE_DISPLAY_MODE_REQUESTS = "android.permission.OVERRIDE_DISPLAY_MODE_REQUESTS"; field public static final String READ_CELL_BROADCASTS = "android.permission.READ_CELL_BROADCASTS"; + field public static final String READ_PRIVILEGED_PHONE_STATE = "android.permission.READ_PRIVILEGED_PHONE_STATE"; field public static final String REMOVE_TASKS = "android.permission.REMOVE_TASKS"; field public static final String SUSPEND_APPS = "android.permission.SUSPEND_APPS"; field public static final String TEST_MANAGE_ROLLBACKS = "android.permission.TEST_MANAGE_ROLLBACKS"; @@ -84,7 +85,7 @@ package android.app { method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public void removeOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener); method public static void resumeAppSwitches() throws android.os.RemoteException; method @RequiresPermission(android.Manifest.permission.CHANGE_CONFIGURATION) public void scheduleApplicationInfoChanged(java.util.List<java.lang.String>, int); - method @RequiresPermission("android.permission.MANAGE_USERS") public boolean switchUser(@NonNull android.os.UserHandle); + method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean switchUser(@NonNull android.os.UserHandle); field public static final int PROCESS_CAPABILITY_ALL = 7; // 0x7 field public static final int PROCESS_CAPABILITY_ALL_EXPLICIT = 1; // 0x1 field public static final int PROCESS_CAPABILITY_ALL_IMPLICIT = 6; // 0x6 @@ -184,12 +185,12 @@ package android.app { public class AppOpsManager { method @RequiresPermission("android.permission.MANAGE_APPOPS") public void addHistoricalOps(@NonNull android.app.AppOpsManager.HistoricalOps); method @RequiresPermission("android.permission.MANAGE_APPOPS") public void clearHistory(); - method @Nullable @RequiresPermission("android.permission.GET_APP_OPS_STATS") public android.app.RuntimeAppOpAccessMessage collectRuntimeAppOpAccessMessage(); - method @RequiresPermission("android.permission.GET_APP_OPS_STATS") public void getHistoricalOps(@NonNull android.app.AppOpsManager.HistoricalOpsRequest, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.AppOpsManager.HistoricalOps>); + method @Nullable @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) public android.app.RuntimeAppOpAccessMessage collectRuntimeAppOpAccessMessage(); + method @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) public void getHistoricalOps(@NonNull android.app.AppOpsManager.HistoricalOpsRequest, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.AppOpsManager.HistoricalOps>); method @RequiresPermission("android.permission.MANAGE_APPOPS") public void getHistoricalOpsFromDiskRaw(@NonNull android.app.AppOpsManager.HistoricalOpsRequest, @Nullable java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.AppOpsManager.HistoricalOps>); method public static int getNumOps(); method public static String[] getOpStrs(); - method @NonNull @RequiresPermission("android.permission.GET_APP_OPS_STATS") public java.util.List<android.app.AppOpsManager.PackageOps> getOpsForPackage(int, @NonNull String, @Nullable java.lang.String...); + method @NonNull @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) public java.util.List<android.app.AppOpsManager.PackageOps> getOpsForPackage(int, @NonNull String, @Nullable java.lang.String...); method public boolean isOperationActive(int, int, String); method @RequiresPermission("android.permission.MANAGE_APPOPS") public void offsetHistory(long); method public static int opToDefaultMode(@NonNull String); @@ -434,10 +435,10 @@ package android.app { } public class DreamManager { - method @RequiresPermission("android.permission.READ_DREAM_STATE") public boolean isDreaming(); - method @RequiresPermission("android.permission.WRITE_DREAM_STATE") public void setActiveDream(@NonNull android.content.ComponentName); - method @RequiresPermission("android.permission.WRITE_DREAM_STATE") public void startDream(@NonNull android.content.ComponentName); - method @RequiresPermission("android.permission.WRITE_DREAM_STATE") public void stopDream(); + method @RequiresPermission(android.Manifest.permission.READ_DREAM_STATE) public boolean isDreaming(); + method @RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE) public void setActiveDream(@NonNull android.content.ComponentName); + method @RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE) public void startDream(@NonNull android.content.ComponentName); + method @RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE) public void stopDream(); } public final class NotificationChannel implements android.os.Parcelable { @@ -527,14 +528,14 @@ package android.app { } public class UiModeManager { - method @RequiresPermission("android.permission.ENTER_CAR_MODE_PRIORITIZED") public void enableCarMode(@IntRange(from=0) int, int); + method @RequiresPermission(android.Manifest.permission.ENTER_CAR_MODE_PRIORITIZED) public void enableCarMode(@IntRange(from=0) int, int); method public boolean isNightModeLocked(); method public boolean isUiModeLocked(); } public class WallpaperManager { method @Nullable public android.graphics.Bitmap getBitmap(); - method @RequiresPermission("android.permission.SET_WALLPAPER_COMPONENT") public boolean setWallpaperComponent(android.content.ComponentName); + method @RequiresPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT) public boolean setWallpaperComponent(android.content.ComponentName); method public boolean shouldEnableWideColorGamut(); method @RequiresPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE) public boolean wallpaperSupportsWcg(int); } @@ -608,11 +609,11 @@ package android.app.assist { package android.app.backup { public class BackupManager { - method @RequiresPermission("android.permission.BACKUP") public android.content.Intent getConfigurationIntent(String); - method @RequiresPermission("android.permission.BACKUP") public android.content.Intent getDataManagementIntent(String); - method @Nullable @RequiresPermission("android.permission.BACKUP") public CharSequence getDataManagementIntentLabel(@NonNull String); - method @Deprecated @Nullable @RequiresPermission("android.permission.BACKUP") public String getDataManagementLabel(@NonNull String); - method @RequiresPermission("android.permission.BACKUP") public String getDestinationString(String); + method @RequiresPermission(android.Manifest.permission.BACKUP) public android.content.Intent getConfigurationIntent(String); + method @RequiresPermission(android.Manifest.permission.BACKUP) public android.content.Intent getDataManagementIntent(String); + method @Nullable @RequiresPermission(android.Manifest.permission.BACKUP) public CharSequence getDataManagementIntentLabel(@NonNull String); + method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.BACKUP) public String getDataManagementLabel(@NonNull String); + method @RequiresPermission(android.Manifest.permission.BACKUP) public String getDestinationString(String); } } @@ -737,20 +738,20 @@ package android.app.role { } public class RoleControllerManager { - method @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public void isApplicationVisibleForRole(@NonNull String, @NonNull String, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>); - method @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public void isRoleVisible(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>); + method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void isApplicationVisibleForRole(@NonNull String, @NonNull String, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>); + method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void isRoleVisible(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>); } public final class RoleManager { - method @RequiresPermission("android.permission.OBSERVE_ROLE_HOLDERS") public void addOnRoleHoldersChangedListenerAsUser(@NonNull java.util.concurrent.Executor, @NonNull android.app.role.OnRoleHoldersChangedListener, @NonNull android.os.UserHandle); - method @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public void addRoleHolderAsUser(@NonNull String, @NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>); + method @RequiresPermission(android.Manifest.permission.OBSERVE_ROLE_HOLDERS) public void addOnRoleHoldersChangedListenerAsUser(@NonNull java.util.concurrent.Executor, @NonNull android.app.role.OnRoleHoldersChangedListener, @NonNull android.os.UserHandle); + method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void addRoleHolderAsUser(@NonNull String, @NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>); method @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public boolean addRoleHolderFromController(@NonNull String, @NonNull String); - method @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public void clearRoleHoldersAsUser(@NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>); + method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void clearRoleHoldersAsUser(@NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>); method @NonNull @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public java.util.List<java.lang.String> getHeldRolesFromController(@NonNull String); - method @NonNull @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public java.util.List<java.lang.String> getRoleHolders(@NonNull String); - method @NonNull @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public java.util.List<java.lang.String> getRoleHoldersAsUser(@NonNull String, @NonNull android.os.UserHandle); - method @RequiresPermission("android.permission.OBSERVE_ROLE_HOLDERS") public void removeOnRoleHoldersChangedListenerAsUser(@NonNull android.app.role.OnRoleHoldersChangedListener, @NonNull android.os.UserHandle); - method @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public void removeRoleHolderAsUser(@NonNull String, @NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>); + method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public java.util.List<java.lang.String> getRoleHolders(@NonNull String); + method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public java.util.List<java.lang.String> getRoleHoldersAsUser(@NonNull String, @NonNull android.os.UserHandle); + method @RequiresPermission(android.Manifest.permission.OBSERVE_ROLE_HOLDERS) public void removeOnRoleHoldersChangedListenerAsUser(@NonNull android.app.role.OnRoleHoldersChangedListener, @NonNull android.os.UserHandle); + method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void removeRoleHolderAsUser(@NonNull String, @NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>); method @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public boolean removeRoleHolderFromController(@NonNull String, @NonNull String); method @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public void setRoleNamesFromController(@NonNull java.util.List<java.lang.String>); field public static final int MANAGE_HOLDERS_FLAG_DONT_KILL_APP = 1; // 0x1 @@ -857,7 +858,7 @@ package android.content { method public int getUserId(); method public void setAutofillOptions(@Nullable android.content.AutofillOptions); method public void setContentCaptureOptions(@Nullable android.content.ContentCaptureOptions); - method @RequiresPermission("android.permission.INTERACT_ACROSS_USERS") public void startActivityAsUser(@NonNull @RequiresPermission android.content.Intent, @NonNull android.os.UserHandle); + method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public void startActivityAsUser(@NonNull @RequiresPermission android.content.Intent, @NonNull android.os.UserHandle); field public static final String APP_INTEGRITY_SERVICE = "app_integrity"; field public static final String BUGREPORT_SERVICE = "bugreport"; field public static final String CONTENT_CAPTURE_MANAGER_SERVICE = "content_capture"; @@ -876,7 +877,7 @@ package android.content { } public class Intent implements java.lang.Cloneable android.os.Parcelable { - field @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public static final String ACTION_MANAGE_DEFAULT_APP = "android.intent.action.MANAGE_DEFAULT_APP"; + field @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public static final String ACTION_MANAGE_DEFAULT_APP = "android.intent.action.MANAGE_DEFAULT_APP"; field public static final String ACTION_ROLLBACK_COMMITTED = "android.intent.action.ROLLBACK_COMMITTED"; field public static final String EXTRA_ORIGINATING_UID = "android.intent.extra.ORIGINATING_UID"; field public static final String EXTRA_ROLE_NAME = "android.intent.extra.ROLE_NAME"; @@ -975,7 +976,7 @@ package android.content.pm { public static class PackageInstaller.SessionParams implements android.os.Parcelable { method public void setEnableRollback(boolean); method public void setEnableRollback(boolean, int); - method @RequiresPermission("android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS") public void setGrantedRuntimePermissions(String[]); + method @RequiresPermission(android.Manifest.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS) public void setGrantedRuntimePermissions(String[]); method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void setInstallAsApex(); method public void setInstallerPackageName(@Nullable String); method public void setRequestDowngrade(boolean); @@ -986,24 +987,24 @@ package android.content.pm { method @RequiresPermission("android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS") public abstract void addOnPermissionsChangeListener(@NonNull android.content.pm.PackageManager.OnPermissionsChangedListener); method public abstract boolean arePermissionsIndividuallyControlled(); method @Nullable public String getContentCaptureServicePackageName(); - method @Nullable @RequiresPermission("android.permission.INTERACT_ACROSS_USERS_FULL") public abstract String getDefaultBrowserPackageNameAsUser(int); + method @Nullable @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public abstract String getDefaultBrowserPackageNameAsUser(int); method @Nullable public String getDefaultTextClassifierPackageName(); method @Nullable public String getIncidentReportApproverPackageName(); method public abstract int getInstallReason(@NonNull String, @NonNull android.os.UserHandle); method @NonNull public abstract java.util.List<android.content.pm.ApplicationInfo> getInstalledApplicationsAsUser(int, int); - method @NonNull @RequiresPermission("android.permission.INTERACT_ACROSS_USERS_FULL") public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackagesAsUser(int, int); + method @NonNull @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackagesAsUser(int, int); method @Nullable public abstract String[] getNamesForUids(int[]); method @NonNull public abstract String getPermissionControllerPackageName(); - method @RequiresPermission(anyOf={"android.permission.GRANT_RUNTIME_PERMISSIONS", "android.permission.REVOKE_RUNTIME_PERMISSIONS", "android.permission.GET_RUNTIME_PERMISSIONS"}) public abstract int getPermissionFlags(@NonNull String, @NonNull String, @NonNull android.os.UserHandle); + method @android.content.pm.PackageManager.PermissionFlags @RequiresPermission(anyOf={android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS, android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS, android.Manifest.permission.GET_RUNTIME_PERMISSIONS}) public abstract int getPermissionFlags(@NonNull String, @NonNull String, @NonNull android.os.UserHandle); method @NonNull public abstract String getServicesSystemSharedLibraryPackageName(); method @NonNull public abstract String getSharedSystemSharedLibraryPackageName(); method @Nullable public String getSystemTextClassifierPackageName(); method @Nullable public String getWellbeingPackageName(); - method @RequiresPermission("android.permission.GRANT_RUNTIME_PERMISSIONS") public abstract void grantRuntimePermission(@NonNull String, @NonNull String, @NonNull android.os.UserHandle); + method @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS) public abstract void grantRuntimePermission(@NonNull String, @NonNull String, @NonNull android.os.UserHandle); method @RequiresPermission("android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS") public abstract void removeOnPermissionsChangeListener(@NonNull android.content.pm.PackageManager.OnPermissionsChangedListener); - method @RequiresPermission("android.permission.REVOKE_RUNTIME_PERMISSIONS") public abstract void revokeRuntimePermission(@NonNull String, @NonNull String, @NonNull android.os.UserHandle); - method @RequiresPermission("android.permission.REVOKE_RUNTIME_PERMISSIONS") public void revokeRuntimePermission(@NonNull String, @NonNull String, @NonNull android.os.UserHandle, @NonNull String); - method @RequiresPermission(anyOf={"android.permission.GRANT_RUNTIME_PERMISSIONS", "android.permission.REVOKE_RUNTIME_PERMISSIONS"}) public abstract void updatePermissionFlags(@NonNull String, @NonNull String, int, int, @NonNull android.os.UserHandle); + method @RequiresPermission(android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS) public abstract void revokeRuntimePermission(@NonNull String, @NonNull String, @NonNull android.os.UserHandle); + method @RequiresPermission(android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS) public void revokeRuntimePermission(@NonNull String, @NonNull String, @NonNull android.os.UserHandle, @NonNull String); + method @RequiresPermission(anyOf={android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS, android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS}) public abstract void updatePermissionFlags(@NonNull String, @NonNull String, @android.content.pm.PackageManager.PermissionFlags int, @android.content.pm.PackageManager.PermissionFlags int, @NonNull android.os.UserHandle); field public static final String FEATURE_ADOPTABLE_STORAGE = "android.software.adoptable_storage"; field public static final String FEATURE_FILE_BASED_ENCRYPTION = "android.software.file_based_encryption"; field public static final int FLAG_PERMISSION_APPLY_RESTRICTION = 16384; // 0x4000 @@ -1290,7 +1291,7 @@ package android.hardware.display { } public final class DisplayManager { - method @RequiresPermission("android.permission.ACCESS_AMBIENT_LIGHT_STATS") public java.util.List<android.hardware.display.AmbientBrightnessDayStats> getAmbientBrightnessStats(); + method @RequiresPermission(android.Manifest.permission.ACCESS_AMBIENT_LIGHT_STATS) public java.util.List<android.hardware.display.AmbientBrightnessDayStats> getAmbientBrightnessStats(); method @RequiresPermission(android.Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS) public android.hardware.display.BrightnessConfiguration getBrightnessConfiguration(); method @RequiresPermission(android.Manifest.permission.BRIGHTNESS_SLIDER_USAGE) public java.util.List<android.hardware.display.BrightnessChangeEvent> getBrightnessEvents(); method @Nullable @RequiresPermission(android.Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS) public android.hardware.display.BrightnessConfiguration getDefaultBrightnessConfiguration(); @@ -1305,7 +1306,7 @@ package android.hardware.hdmi { public final class HdmiControlManager { method @Nullable public android.hardware.hdmi.HdmiSwitchClient getSwitchClient(); - method @RequiresPermission("android.permission.HDMI_CEC") public void setStandbyMode(boolean); + method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void setStandbyMode(boolean); field public static final String ACTION_OSD_MESSAGE = "android.hardware.hdmi.action.OSD_MESSAGE"; field public static final int AVR_VOLUME_MUTED = 101; // 0x65 field public static final int CLEAR_TIMER_STATUS_CEC_DISABLE = 162; // 0xa2 @@ -1416,11 +1417,9 @@ package android.hardware.hdmi { field public static final int PORT_OUTPUT = 1; // 0x1 } - public class HdmiSwitchClient { + public class HdmiSwitchClient extends android.hardware.hdmi.HdmiClient { method public int getDeviceType(); method @NonNull public java.util.List<android.hardware.hdmi.HdmiPortInfo> getPortInfo(); - method public void sendKeyEvent(int, boolean); - method public void sendVendorCommand(int, byte[], boolean); } } @@ -1679,7 +1678,7 @@ package android.location { method @NonNull public String[] getBackgroundThrottlingWhitelist(); method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void getCurrentLocation(@NonNull android.location.LocationRequest, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.location.Location>); method @NonNull public String[] getIgnoreSettingsWhitelist(); - method @Nullable @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public java.util.List<java.lang.String> getProviderPackages(@NonNull String); + method @Nullable @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public java.util.List<java.lang.String> getProviderPackages(@NonNull String); method @NonNull public java.util.List<android.location.LocationRequest> getTestProviderCurrentRequests(String); method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.location.LocationListener, @Nullable android.os.Looper); method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener); @@ -1747,12 +1746,12 @@ package android.media { } public class AudioManager { - method @RequiresPermission("android.permission.MODIFY_AUDIO_ROUTING") public int dispatchAudioFocusChange(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy); + method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int dispatchAudioFocusChange(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy); method public boolean hasRegisteredDynamicPolicy(); - method @RequiresPermission("android.permission.MODIFY_AUDIO_ROUTING") public int registerAudioPolicy(@NonNull android.media.audiopolicy.AudioPolicy); - method @RequiresPermission("android.permission.MODIFY_AUDIO_ROUTING") public void setFocusRequestResult(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy); - method @RequiresPermission("android.permission.MODIFY_AUDIO_ROUTING") public void unregisterAudioPolicy(@NonNull android.media.audiopolicy.AudioPolicy); - method @RequiresPermission("android.permission.MODIFY_AUDIO_ROUTING") public void unregisterAudioPolicyAsync(@NonNull android.media.audiopolicy.AudioPolicy); + method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int registerAudioPolicy(@NonNull android.media.audiopolicy.AudioPolicy); + method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setFocusRequestResult(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy); + method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void unregisterAudioPolicy(@NonNull android.media.audiopolicy.AudioPolicy); + method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void unregisterAudioPolicyAsync(@NonNull android.media.audiopolicy.AudioPolicy); field public static final int SUCCESS = 0; // 0x0 } @@ -2129,15 +2128,15 @@ package android.net { method @NonNull public android.net.NetworkCapabilities build(); method @NonNull public android.net.NetworkCapabilities.Builder removeCapability(int); method @NonNull public android.net.NetworkCapabilities.Builder removeTransportType(int); - method @NonNull @RequiresPermission("android.permission.NETWORK_FACTORY") public android.net.NetworkCapabilities.Builder setAdministratorUids(@NonNull int[]); + method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setAdministratorUids(@NonNull int[]); method @NonNull public android.net.NetworkCapabilities.Builder setLinkDownstreamBandwidthKbps(int); method @NonNull public android.net.NetworkCapabilities.Builder setLinkUpstreamBandwidthKbps(int); method @NonNull public android.net.NetworkCapabilities.Builder setNetworkSpecifier(@Nullable android.net.NetworkSpecifier); - method @NonNull @RequiresPermission("android.permission.NETWORK_FACTORY") public android.net.NetworkCapabilities.Builder setOwnerUid(int); - method @NonNull @RequiresPermission("android.permission.NETWORK_FACTORY") public android.net.NetworkCapabilities.Builder setRequestorPackageName(@Nullable String); - method @NonNull @RequiresPermission("android.permission.NETWORK_FACTORY") public android.net.NetworkCapabilities.Builder setRequestorUid(int); - method @NonNull @RequiresPermission("android.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP") public android.net.NetworkCapabilities.Builder setSignalStrength(int); - method @NonNull @RequiresPermission("android.permission.NETWORK_FACTORY") public android.net.NetworkCapabilities.Builder setSsid(@Nullable String); + method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setOwnerUid(int); + method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setRequestorPackageName(@Nullable String); + method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setRequestorUid(int); + method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP) public android.net.NetworkCapabilities.Builder setSignalStrength(int); + method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setSsid(@Nullable String); method @NonNull public android.net.NetworkCapabilities.Builder setTransportInfo(@Nullable android.net.TransportInfo); } @@ -2195,100 +2194,6 @@ package android.net { method public void teardownTestNetwork(@NonNull android.net.Network); } - public final class TetheredClient implements android.os.Parcelable { - ctor public TetheredClient(@NonNull android.net.MacAddress, @NonNull java.util.Collection<android.net.TetheredClient.AddressInfo>, int); - method public int describeContents(); - method @NonNull public java.util.List<android.net.TetheredClient.AddressInfo> getAddresses(); - method @NonNull public android.net.MacAddress getMacAddress(); - method public int getTetheringType(); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.net.TetheredClient> CREATOR; - } - - public static final class TetheredClient.AddressInfo implements android.os.Parcelable { - method public int describeContents(); - method @NonNull public android.net.LinkAddress getAddress(); - method @Nullable public String getHostname(); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.net.TetheredClient.AddressInfo> CREATOR; - } - - public class TetheringManager { - method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.TetheringEventCallback); - method @RequiresPermission(anyOf={"android.permission.TETHER_PRIVILEGED", android.Manifest.permission.WRITE_SETTINGS}) public void requestLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.OnTetheringEntitlementResultListener); - method @RequiresPermission(anyOf={"android.permission.TETHER_PRIVILEGED", android.Manifest.permission.WRITE_SETTINGS}) public void startTethering(@NonNull android.net.TetheringManager.TetheringRequest, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.StartTetheringCallback); - method @RequiresPermission(anyOf={"android.permission.TETHER_PRIVILEGED", android.Manifest.permission.WRITE_SETTINGS}) public void stopAllTethering(); - method @RequiresPermission(anyOf={"android.permission.TETHER_PRIVILEGED", android.Manifest.permission.WRITE_SETTINGS}) public void stopTethering(int); - method @RequiresPermission(anyOf={"android.permission.TETHER_PRIVILEGED", android.Manifest.permission.ACCESS_NETWORK_STATE}) public void unregisterTetheringEventCallback(@NonNull android.net.TetheringManager.TetheringEventCallback); - field public static final String ACTION_TETHER_STATE_CHANGED = "android.net.conn.TETHER_STATE_CHANGED"; - field public static final String EXTRA_ACTIVE_LOCAL_ONLY = "android.net.extra.ACTIVE_LOCAL_ONLY"; - field public static final String EXTRA_ACTIVE_TETHER = "tetherArray"; - field public static final String EXTRA_AVAILABLE_TETHER = "availableArray"; - field public static final String EXTRA_ERRORED_TETHER = "erroredArray"; - field public static final int TETHERING_BLUETOOTH = 2; // 0x2 - field public static final int TETHERING_ETHERNET = 5; // 0x5 - field public static final int TETHERING_INVALID = -1; // 0xffffffff - field public static final int TETHERING_NCM = 4; // 0x4 - field public static final int TETHERING_USB = 1; // 0x1 - field public static final int TETHERING_WIFI = 0; // 0x0 - field public static final int TETHERING_WIFI_P2P = 3; // 0x3 - field public static final int TETHER_ERROR_DHCPSERVER_ERROR = 12; // 0xc - field public static final int TETHER_ERROR_DISABLE_FORWARDING_ERROR = 9; // 0x9 - field public static final int TETHER_ERROR_ENABLE_FORWARDING_ERROR = 8; // 0x8 - field public static final int TETHER_ERROR_ENTITLEMENT_UNKNOWN = 13; // 0xd - field public static final int TETHER_ERROR_IFACE_CFG_ERROR = 10; // 0xa - field public static final int TETHER_ERROR_INTERNAL_ERROR = 5; // 0x5 - field public static final int TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION = 15; // 0xf - field public static final int TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION = 14; // 0xe - field public static final int TETHER_ERROR_NO_ERROR = 0; // 0x0 - field public static final int TETHER_ERROR_PROVISIONING_FAILED = 11; // 0xb - field public static final int TETHER_ERROR_SERVICE_UNAVAIL = 2; // 0x2 - field public static final int TETHER_ERROR_TETHER_IFACE_ERROR = 6; // 0x6 - field public static final int TETHER_ERROR_UNAVAIL_IFACE = 4; // 0x4 - field public static final int TETHER_ERROR_UNKNOWN_IFACE = 1; // 0x1 - field public static final int TETHER_ERROR_UNKNOWN_TYPE = 16; // 0x10 - field public static final int TETHER_ERROR_UNSUPPORTED = 3; // 0x3 - field public static final int TETHER_ERROR_UNTETHER_IFACE_ERROR = 7; // 0x7 - field public static final int TETHER_HARDWARE_OFFLOAD_FAILED = 2; // 0x2 - field public static final int TETHER_HARDWARE_OFFLOAD_STARTED = 1; // 0x1 - field public static final int TETHER_HARDWARE_OFFLOAD_STOPPED = 0; // 0x0 - } - - public static interface TetheringManager.OnTetheringEntitlementResultListener { - method public void onTetheringEntitlementResult(int); - } - - public static interface TetheringManager.StartTetheringCallback { - method public default void onTetheringFailed(int); - method public default void onTetheringStarted(); - } - - public static interface TetheringManager.TetheringEventCallback { - method public default void onClientsChanged(@NonNull java.util.Collection<android.net.TetheredClient>); - method public default void onError(@NonNull String, int); - method public default void onOffloadStatusChanged(int); - method public default void onTetherableInterfacesChanged(@NonNull java.util.List<java.lang.String>); - method public default void onTetheredInterfacesChanged(@NonNull java.util.List<java.lang.String>); - method public default void onTetheringSupported(boolean); - method public default void onUpstreamChanged(@Nullable android.net.Network); - } - - public static class TetheringManager.TetheringRequest { - method @Nullable public android.net.LinkAddress getClientStaticIpv4Address(); - method @Nullable public android.net.LinkAddress getLocalIpv4Address(); - method public boolean getShouldShowEntitlementUi(); - method public int getTetheringType(); - method public boolean isExemptFromEntitlementCheck(); - } - - public static class TetheringManager.TetheringRequest.Builder { - ctor public TetheringManager.TetheringRequest.Builder(int); - method @NonNull public android.net.TetheringManager.TetheringRequest build(); - method @NonNull @RequiresPermission("android.permission.TETHER_PRIVILEGED") public android.net.TetheringManager.TetheringRequest.Builder setExemptFromEntitlementCheck(boolean); - method @NonNull @RequiresPermission("android.permission.TETHER_PRIVILEGED") public android.net.TetheringManager.TetheringRequest.Builder setShouldShowEntitlementUi(boolean); - method @NonNull @RequiresPermission("android.permission.TETHER_PRIVILEGED") public android.net.TetheringManager.TetheringRequest.Builder setStaticIpv4Addresses(@NonNull android.net.LinkAddress, @NonNull android.net.LinkAddress); - } - public class TrafficStats { method public static long getLoopbackRxBytes(); method public static long getLoopbackRxPackets(); @@ -2488,7 +2393,7 @@ package android.net.util { package android.os { public class BatteryManager { - method @RequiresPermission("android.permission.POWER_SAVER") public boolean setChargingStateUpdateDelayMillis(int); + method @RequiresPermission(android.Manifest.permission.POWER_SAVER) public boolean setChargingStateUpdateDelayMillis(int); } public final class BugreportManager { @@ -2784,18 +2689,18 @@ package android.os { } public final class PowerManager { - method @RequiresPermission("android.permission.POWER_SAVER") public int getPowerSaveModeTrigger(); - method @RequiresPermission("android.permission.POWER_SAVER") public boolean setDynamicPowerSaveHint(boolean, int); - method @RequiresPermission(anyOf={"android.permission.DEVICE_POWER", "android.permission.POWER_SAVER"}) public boolean setPowerSaveModeEnabled(boolean); + method @RequiresPermission(android.Manifest.permission.POWER_SAVER) public int getPowerSaveModeTrigger(); + method @RequiresPermission(android.Manifest.permission.POWER_SAVER) public boolean setDynamicPowerSaveHint(boolean, int); + method @RequiresPermission(anyOf={android.Manifest.permission.DEVICE_POWER, android.Manifest.permission.POWER_SAVER}) public boolean setPowerSaveModeEnabled(boolean); field public static final int POWER_SAVE_MODE_TRIGGER_DYNAMIC = 1; // 0x1 field public static final int POWER_SAVE_MODE_TRIGGER_PERCENTAGE = 0; // 0x0 } public class PowerWhitelistManager { - method @RequiresPermission("android.permission.DEVICE_POWER") public void addToWhitelist(@NonNull String); - method @RequiresPermission("android.permission.DEVICE_POWER") public void addToWhitelist(@NonNull java.util.List<java.lang.String>); - method @RequiresPermission("android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST") public void whitelistAppTemporarily(@NonNull String, long); - method @RequiresPermission("android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST") public long whitelistAppTemporarilyForEvent(@NonNull String, int, @NonNull String); + method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void addToWhitelist(@NonNull String); + method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void addToWhitelist(@NonNull java.util.List<java.lang.String>); + method @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public void whitelistAppTemporarily(@NonNull String, long); + method @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public long whitelistAppTemporarilyForEvent(@NonNull String, int, @NonNull String); field public static final int EVENT_MMS = 2; // 0x2 field public static final int EVENT_SMS = 1; // 0x1 field public static final int EVENT_UNSPECIFIED = 0; // 0x0 @@ -2861,8 +2766,8 @@ package android.os { } public class SystemConfigManager { - method @NonNull @RequiresPermission("android.permission.READ_CARRIER_APP_INFO") public java.util.Set<java.lang.String> getDisabledUntilUsedPreinstalledCarrierApps(); - method @NonNull @RequiresPermission("android.permission.READ_CARRIER_APP_INFO") public java.util.Map<java.lang.String,java.util.List<java.lang.String>> getDisabledUntilUsedPreinstalledCarrierAssociatedApps(); + 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(); } public class SystemProperties { @@ -2891,7 +2796,7 @@ package android.os { } public class UserManager { - method @RequiresPermission(anyOf={"android.permission.MANAGE_USERS", "android.permission.CREATE_USERS"}) public boolean hasBaseUserRestriction(@NonNull String, @NonNull android.os.UserHandle); + method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public boolean hasBaseUserRestriction(@NonNull String, @NonNull android.os.UserHandle); method public static boolean isSplitSystemUser(); field public static final String ACTION_USER_RESTRICTIONS_CHANGED = "android.os.action.USER_RESTRICTIONS_CHANGED"; } @@ -2957,10 +2862,10 @@ package android.os { } public abstract class Vibrator { - method @RequiresPermission("android.permission.ACCESS_VIBRATOR_STATE") public void addVibratorStateListener(@NonNull android.os.Vibrator.OnVibratorStateChangedListener); - method @RequiresPermission("android.permission.ACCESS_VIBRATOR_STATE") public void addVibratorStateListener(@NonNull java.util.concurrent.Executor, @NonNull android.os.Vibrator.OnVibratorStateChangedListener); - method @RequiresPermission("android.permission.ACCESS_VIBRATOR_STATE") public boolean isVibrating(); - method @RequiresPermission("android.permission.ACCESS_VIBRATOR_STATE") public void removeVibratorStateListener(@NonNull android.os.Vibrator.OnVibratorStateChangedListener); + method @RequiresPermission(android.Manifest.permission.ACCESS_VIBRATOR_STATE) public void addVibratorStateListener(@NonNull android.os.Vibrator.OnVibratorStateChangedListener); + method @RequiresPermission(android.Manifest.permission.ACCESS_VIBRATOR_STATE) public void addVibratorStateListener(@NonNull java.util.concurrent.Executor, @NonNull android.os.Vibrator.OnVibratorStateChangedListener); + method @RequiresPermission(android.Manifest.permission.ACCESS_VIBRATOR_STATE) public boolean isVibrating(); + method @RequiresPermission(android.Manifest.permission.ACCESS_VIBRATOR_STATE) public void removeVibratorStateListener(@NonNull android.os.Vibrator.OnVibratorStateChangedListener); } public static interface Vibrator.OnVibratorStateChangedListener { @@ -3059,12 +2964,12 @@ package android.os.image { public class DynamicSystemClient { ctor public DynamicSystemClient(@NonNull android.content.Context); - method @RequiresPermission("android.permission.INSTALL_DYNAMIC_SYSTEM") public void bind(); + method @RequiresPermission(android.Manifest.permission.INSTALL_DYNAMIC_SYSTEM) public void bind(); method public void setOnStatusChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.os.image.DynamicSystemClient.OnStatusChangedListener); method public void setOnStatusChangedListener(@NonNull android.os.image.DynamicSystemClient.OnStatusChangedListener); - method @RequiresPermission("android.permission.INSTALL_DYNAMIC_SYSTEM") public void start(@NonNull android.net.Uri, long); - method @RequiresPermission("android.permission.INSTALL_DYNAMIC_SYSTEM") public void start(@NonNull android.net.Uri, long, long); - method @RequiresPermission("android.permission.INSTALL_DYNAMIC_SYSTEM") public void unbind(); + method @RequiresPermission(android.Manifest.permission.INSTALL_DYNAMIC_SYSTEM) public void start(@NonNull android.net.Uri, long); + method @RequiresPermission(android.Manifest.permission.INSTALL_DYNAMIC_SYSTEM) public void start(@NonNull android.net.Uri, long, long); + method @RequiresPermission(android.Manifest.permission.INSTALL_DYNAMIC_SYSTEM) public void unbind(); field public static final int CAUSE_ERROR_EXCEPTION = 6; // 0x6 field public static final int CAUSE_ERROR_INVALID_URL = 4; // 0x4 field public static final int CAUSE_ERROR_IO = 3; // 0x3 @@ -3118,13 +3023,13 @@ package android.os.strictmode { package android.permission { public final class PermissionControllerManager { - method @RequiresPermission(anyOf={"android.permission.GRANT_RUNTIME_PERMISSIONS", "android.permission.RESTORE_RUNTIME_PERMISSIONS"}) public void applyStagedRuntimePermissionBackup(@NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>); - method @RequiresPermission("android.permission.GET_RUNTIME_PERMISSIONS") public void countPermissionApps(@NonNull java.util.List<java.lang.String>, int, @NonNull android.permission.PermissionControllerManager.OnCountPermissionAppsResultCallback, @Nullable android.os.Handler); - method @RequiresPermission("android.permission.GET_RUNTIME_PERMISSIONS") public void getAppPermissions(@NonNull String, @NonNull android.permission.PermissionControllerManager.OnGetAppPermissionResultCallback, @Nullable android.os.Handler); - method @RequiresPermission("android.permission.GET_RUNTIME_PERMISSIONS") public void getRuntimePermissionBackup(@NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<byte[]>); - method @RequiresPermission("android.permission.REVOKE_RUNTIME_PERMISSIONS") public void revokeRuntimePermission(@NonNull String, @NonNull String); - method @RequiresPermission("android.permission.REVOKE_RUNTIME_PERMISSIONS") public void revokeRuntimePermissions(@NonNull java.util.Map<java.lang.String,java.util.List<java.lang.String>>, boolean, int, @NonNull java.util.concurrent.Executor, @NonNull android.permission.PermissionControllerManager.OnRevokeRuntimePermissionsCallback); - method @RequiresPermission(anyOf={"android.permission.GRANT_RUNTIME_PERMISSIONS", "android.permission.RESTORE_RUNTIME_PERMISSIONS"}) public void stageAndApplyRuntimePermissionsBackup(@NonNull byte[], @NonNull android.os.UserHandle); + method @RequiresPermission(anyOf={android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS, android.Manifest.permission.RESTORE_RUNTIME_PERMISSIONS}) public void applyStagedRuntimePermissionBackup(@NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>); + method @RequiresPermission(android.Manifest.permission.GET_RUNTIME_PERMISSIONS) public void countPermissionApps(@NonNull java.util.List<java.lang.String>, int, @NonNull android.permission.PermissionControllerManager.OnCountPermissionAppsResultCallback, @Nullable android.os.Handler); + method @RequiresPermission(android.Manifest.permission.GET_RUNTIME_PERMISSIONS) public void getAppPermissions(@NonNull String, @NonNull android.permission.PermissionControllerManager.OnGetAppPermissionResultCallback, @Nullable android.os.Handler); + method @RequiresPermission(android.Manifest.permission.GET_RUNTIME_PERMISSIONS) public void getRuntimePermissionBackup(@NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<byte[]>); + method @RequiresPermission(android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS) public void revokeRuntimePermission(@NonNull String, @NonNull String); + method @RequiresPermission(android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS) public void revokeRuntimePermissions(@NonNull java.util.Map<java.lang.String,java.util.List<java.lang.String>>, boolean, int, @NonNull java.util.concurrent.Executor, @NonNull android.permission.PermissionControllerManager.OnRevokeRuntimePermissionsCallback); + method @RequiresPermission(anyOf={android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS, android.Manifest.permission.RESTORE_RUNTIME_PERMISSIONS}) public void stageAndApplyRuntimePermissionsBackup(@NonNull byte[], @NonNull android.os.UserHandle); field public static final int COUNT_ONLY_WHEN_GRANTED = 1; // 0x1 field public static final int COUNT_WHEN_SYSTEM = 2; // 0x2 field public static final int REASON_INSTALLER_POLICY_VIOLATION = 2; // 0x2 @@ -3145,9 +3050,9 @@ package android.permission { } public final class PermissionManager { - method @IntRange(from=0) @RequiresPermission(anyOf={"android.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY", android.Manifest.permission.UPGRADE_RUNTIME_PERMISSIONS}) public int getRuntimePermissionsVersion(); + method @IntRange(from=0) @RequiresPermission(anyOf={android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY, android.Manifest.permission.UPGRADE_RUNTIME_PERMISSIONS}) public int getRuntimePermissionsVersion(); method @NonNull public java.util.List<android.permission.PermissionManager.SplitPermissionInfo> getSplitPermissions(); - method @RequiresPermission(anyOf={"android.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY", android.Manifest.permission.UPGRADE_RUNTIME_PERMISSIONS}) public void setRuntimePermissionsVersion(@IntRange(from=0) int); + method @RequiresPermission(anyOf={android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY, android.Manifest.permission.UPGRADE_RUNTIME_PERMISSIONS}) public void setRuntimePermissionsVersion(@IntRange(from=0) int); } public static final class PermissionManager.SplitPermissionInfo { @@ -3213,14 +3118,14 @@ package android.provider { } public final class DeviceConfig { - method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static void addOnPropertiesChangedListener(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.provider.DeviceConfig.OnPropertiesChangedListener); - method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static boolean getBoolean(@NonNull String, @NonNull String, boolean); - method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static float getFloat(@NonNull String, @NonNull String, float); - method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static int getInt(@NonNull String, @NonNull String, int); - method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static long getLong(@NonNull String, @NonNull String, long); - method @NonNull @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static android.provider.DeviceConfig.Properties getProperties(@NonNull String, @NonNull java.lang.String...); - method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static String getProperty(@NonNull String, @NonNull String); - method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static String getString(@NonNull String, @NonNull String, @Nullable String); + method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static void addOnPropertiesChangedListener(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.provider.DeviceConfig.OnPropertiesChangedListener); + method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static boolean getBoolean(@NonNull String, @NonNull String, boolean); + method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static float getFloat(@NonNull String, @NonNull String, float); + method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static int getInt(@NonNull String, @NonNull String, int); + method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static long getLong(@NonNull String, @NonNull String, long); + method @NonNull @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static android.provider.DeviceConfig.Properties getProperties(@NonNull String, @NonNull java.lang.String...); + method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static String getProperty(@NonNull String, @NonNull String); + method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static String getString(@NonNull String, @NonNull String, @Nullable String); method public static void removeOnPropertiesChangedListener(@NonNull android.provider.DeviceConfig.OnPropertiesChangedListener); method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static void resetToDefaults(int, @Nullable String); method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static boolean setProperties(@NonNull android.provider.DeviceConfig.Properties) throws android.provider.DeviceConfig.BadConfigException; @@ -3268,12 +3173,6 @@ package android.provider { method @NonNull public static android.net.Uri setManageMode(@NonNull android.net.Uri); } - public final class MediaStore { - method @NonNull @WorkerThread public static android.net.Uri scanFile(@NonNull android.content.ContentResolver, @NonNull java.io.File); - method @WorkerThread public static void scanVolume(@NonNull android.content.ContentResolver, @NonNull String); - method @WorkerThread public static void waitForIdle(@NonNull android.content.ContentResolver); - } - public final class Settings { field public static final String ACTION_ENTERPRISE_PRIVACY_SETTINGS = "android.settings.ENTERPRISE_PRIVACY_SETTINGS"; field public static final String ACTION_MANAGE_APP_OVERLAY_PERMISSION = "android.settings.MANAGE_APP_OVERLAY_PERMISSION"; @@ -3290,6 +3189,7 @@ package android.provider { field public static final String DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD = "dynamic_power_savings_disable_threshold"; field public static final String DYNAMIC_POWER_SAVINGS_ENABLED = "dynamic_power_savings_enabled"; field public static final String HIDDEN_API_BLACKLIST_EXEMPTIONS = "hidden_api_blacklist_exemptions"; + field public static final String HIDDEN_API_POLICY = "hidden_api_policy"; field public static final String HIDE_ERROR_DIALOGS = "hide_error_dialogs"; field public static final String LOCATION_GLOBAL_KILL_SWITCH = "location_global_kill_switch"; field public static final String LOCATION_IGNORE_SETTINGS_PACKAGE_WHITELIST = "location_ignore_settings_package_whitelist"; @@ -3387,7 +3287,7 @@ package android.security { package android.security.keystore { public abstract class AttestationUtils { - method @NonNull @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public static java.security.cert.X509Certificate[] attestDeviceIds(android.content.Context, @NonNull int[], @NonNull byte[]) throws android.security.keystore.DeviceIdAttestationException; + method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static java.security.cert.X509Certificate[] attestDeviceIds(android.content.Context, @NonNull int[], @NonNull byte[]) throws android.security.keystore.DeviceIdAttestationException; field public static final int ID_TYPE_IMEI = 2; // 0x2 field public static final int ID_TYPE_MEID = 3; // 0x3 field public static final int ID_TYPE_SERIAL = 1; // 0x1 @@ -3923,11 +3823,11 @@ package android.telecom { public class TelecomManager { method @NonNull public android.content.Intent createLaunchEmergencyDialerIntent(@Nullable String); - method @NonNull @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public java.util.List<android.telecom.PhoneAccountHandle> getCallCapablePhoneAccounts(boolean); - method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public int getCurrentTtyMode(); - method @Nullable @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getDefaultDialerPackage(@NonNull android.os.UserHandle); + method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.List<android.telecom.PhoneAccountHandle> getCallCapablePhoneAccounts(boolean); + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCurrentTtyMode(); + method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getDefaultDialerPackage(@NonNull android.os.UserHandle); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean isInEmergencyCall(); - method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PHONE_STATE}) public boolean isRinging(); + method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isRinging(); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setUserSelectedOutgoingPhoneAccount(@Nullable android.telecom.PhoneAccountHandle); field public static final String ACTION_CURRENT_TTY_MODE_CHANGED = "android.telecom.action.CURRENT_TTY_MODE_CHANGED"; field public static final String ACTION_TTY_PREFERRED_MODE_CHANGED = "android.telecom.action.TTY_PREFERRED_MODE_CHANGED"; @@ -4066,8 +3966,8 @@ package android.telephony { public class PhoneStateListener { method public void onOutgoingEmergencyCall(@NonNull android.telephony.emergency.EmergencyNumber); method public void onOutgoingEmergencySms(@NonNull android.telephony.emergency.EmergencyNumber); - field @RequiresPermission("android.permission.READ_ACTIVE_EMERGENCY_SESSION") public static final int LISTEN_OUTGOING_EMERGENCY_CALL = 268435456; // 0x10000000 - field @RequiresPermission("android.permission.READ_ACTIVE_EMERGENCY_SESSION") public static final int LISTEN_OUTGOING_EMERGENCY_SMS = 536870912; // 0x20000000 + field @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public static final int LISTEN_OUTGOING_EMERGENCY_CALL = 268435456; // 0x10000000 + field @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public static final int LISTEN_OUTGOING_EMERGENCY_SMS = 536870912; // 0x20000000 } public final class PreciseDataConnectionState implements android.os.Parcelable { @@ -4108,22 +4008,22 @@ package android.telephony { public class TelephonyManager { method public int addDevicePolicyOverrideApn(@NonNull android.content.Context, @NonNull android.telephony.data.ApnSetting); method public int checkCarrierPrivilegesForPackage(String); - method @Nullable @RequiresPermission("android.permission.INTERACT_ACROSS_USERS") public android.content.ComponentName getAndUpdateDefaultRespondViaMessageApplication(); + method @Nullable @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public android.content.ComponentName getAndUpdateDefaultRespondViaMessageApplication(); method public int getCarrierIdListVersion(); method public java.util.List<java.lang.String> getCarrierPackageNamesForIntent(android.content.Intent); - method @Nullable @RequiresPermission("android.permission.INTERACT_ACROSS_USERS") public android.content.ComponentName getDefaultRespondViaMessageApplication(); + method @Nullable @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public android.content.ComponentName getDefaultRespondViaMessageApplication(); method @NonNull public java.util.List<android.telephony.data.ApnSetting> getDevicePolicyOverrideApns(@NonNull android.content.Context); - method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public int getEmergencyNumberDbVersion(); + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getEmergencyNumberDbVersion(); method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getLine1AlphaTag(); method public android.util.Pair<java.lang.Integer,java.lang.Integer> getRadioHalVersion(); method public boolean modifyDevicePolicyOverrideApn(@NonNull android.content.Context, int, @NonNull android.telephony.data.ApnSetting); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void refreshUiccProfile(); - method @RequiresPermission("android.permission.READ_ACTIVE_EMERGENCY_SESSION") public void resetOtaEmergencyNumberDbFilePath(); + method @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public void resetOtaEmergencyNumberDbFilePath(); method @Deprecated public void setCarrierTestOverride(String, String, String, String, String, String, String); method public void setCarrierTestOverride(String, String, String, String, String, String, String, String, String); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setSystemSelectionChannels(@NonNull java.util.List<android.telephony.RadioAccessSpecifier>, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setSystemSelectionChannels(@NonNull java.util.List<android.telephony.RadioAccessSpecifier>); - method @RequiresPermission("android.permission.READ_ACTIVE_EMERGENCY_SESSION") public void updateOtaEmergencyNumberDbFilePath(@NonNull android.os.ParcelFileDescriptor); + method @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public void updateOtaEmergencyNumberDbFilePath(@NonNull android.os.ParcelFileDescriptor); field public static final int CARRIER_PRIVILEGE_STATUS_ERROR_LOADING_RULES = -2; // 0xfffffffe field public static final int CARRIER_PRIVILEGE_STATUS_HAS_ACCESS = 1; // 0x1 field public static final int CARRIER_PRIVILEGE_STATUS_NO_ACCESS = 0; // 0x0 @@ -4351,14 +4251,14 @@ package android.telephony.ims { } public class ImsMmTelManager implements android.telephony.ims.RegistrationManager { - method @Deprecated @NonNull @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public static android.telephony.ims.ImsMmTelManager createForSubscriptionId(int); - method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void getFeatureState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>) throws android.telephony.ims.ImsException; - method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void getRegistrationState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); - method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public int getVoWiFiRoamingModeSetting(); - method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public boolean isAvailable(int, int); - method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public boolean isCapable(int, int); - method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void isSupported(int, int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>) throws android.telephony.ims.ImsException; - method @Deprecated @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void registerImsRegistrationCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ImsMmTelManager.RegistrationCallback) throws android.telephony.ims.ImsException; + method @Deprecated @NonNull @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public static android.telephony.ims.ImsMmTelManager createForSubscriptionId(int); + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getFeatureState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>) throws android.telephony.ims.ImsException; + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getRegistrationState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getVoWiFiRoamingModeSetting(); + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isAvailable(int, int); + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isCapable(int, int); + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void isSupported(int, int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>) throws android.telephony.ims.ImsException; + method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerImsRegistrationCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ImsMmTelManager.RegistrationCallback) throws android.telephony.ims.ImsException; method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setAdvancedCallingSettingEnabled(boolean); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setRttCapabilitySetting(boolean); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVoWiFiModeSetting(int); @@ -4367,7 +4267,7 @@ package android.telephony.ims { method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVoWiFiRoamingSettingEnabled(boolean); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVoWiFiSettingEnabled(boolean); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVtSettingEnabled(boolean); - method @Deprecated @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void unregisterImsRegistrationCallback(@NonNull android.telephony.ims.ImsMmTelManager.RegistrationCallback); + method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterImsRegistrationCallback(@NonNull android.telephony.ims.ImsMmTelManager.RegistrationCallback); } @Deprecated public static class ImsMmTelManager.RegistrationCallback extends android.telephony.ims.RegistrationManager.RegistrationCallback { @@ -4600,17 +4500,17 @@ package android.telephony.ims { public class ProvisioningManager { method @NonNull public static android.telephony.ims.ProvisioningManager createForSubscriptionId(int); - method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") @WorkerThread public int getProvisioningIntValue(int); - method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") @WorkerThread public boolean getProvisioningStatusForCapability(int, int); - method @Nullable @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") @WorkerThread public String getProvisioningStringValue(int); - method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") @WorkerThread public boolean getRcsProvisioningStatusForCapability(int); + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public int getProvisioningIntValue(int); + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public boolean getProvisioningStatusForCapability(int, int); + method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public String getProvisioningStringValue(int); + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public boolean getRcsProvisioningStatusForCapability(int); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void notifyRcsAutoConfigurationReceived(@NonNull byte[], boolean); - method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void registerProvisioningChangedCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ProvisioningManager.Callback) throws android.telephony.ims.ImsException; + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerProvisioningChangedCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ProvisioningManager.Callback) throws android.telephony.ims.ImsException; method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public int setProvisioningIntValue(int, int); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public void setProvisioningStatusForCapability(int, int, boolean); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public int setProvisioningStringValue(int, @NonNull String); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public void setRcsProvisioningStatusForCapability(int, boolean); - method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void unregisterProvisioningChangedCallback(@NonNull android.telephony.ims.ProvisioningManager.Callback); + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterProvisioningChangedCallback(@NonNull android.telephony.ims.ProvisioningManager.Callback); field public static final int KEY_VOICE_OVER_WIFI_ENTITLEMENT_ID = 67; // 0x43 field public static final int KEY_VOICE_OVER_WIFI_MODE_OVERRIDE = 27; // 0x1b field public static final int KEY_VOICE_OVER_WIFI_ROAMING_ENABLED_OVERRIDE = 26; // 0x1a @@ -4706,7 +4606,6 @@ package android.telephony.ims.feature { ctor @Deprecated public MmTelFeature.MmTelCapabilities(android.telephony.ims.feature.ImsFeature.Capabilities); ctor public MmTelFeature.MmTelCapabilities(int); method public final void addCapabilities(int); - method public final boolean isCapable(int); method public final void removeCapabilities(int); } @@ -5226,11 +5125,11 @@ package android.view.accessibility { public final class AccessibilityManager { method public void addAccessibilityServicesStateChangeListener(@NonNull android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener, @Nullable android.os.Handler); - method @NonNull @RequiresPermission("android.permission.MANAGE_ACCESSIBILITY") public java.util.List<java.lang.String> getAccessibilityShortcutTargets(int); - method @RequiresPermission("android.permission.MANAGE_ACCESSIBILITY") public void performAccessibilityShortcut(); - method @RequiresPermission("android.permission.MANAGE_ACCESSIBILITY") public void registerSystemAction(@NonNull android.app.RemoteAction, int); + method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_ACCESSIBILITY) public java.util.List<java.lang.String> getAccessibilityShortcutTargets(int); + method @RequiresPermission(android.Manifest.permission.MANAGE_ACCESSIBILITY) public void performAccessibilityShortcut(); + method @RequiresPermission(android.Manifest.permission.MANAGE_ACCESSIBILITY) public void registerSystemAction(@NonNull android.app.RemoteAction, int); method public void removeAccessibilityServicesStateChangeListener(@NonNull android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener); - method @RequiresPermission("android.permission.MANAGE_ACCESSIBILITY") public void unregisterSystemAction(int); + method @RequiresPermission(android.Manifest.permission.MANAGE_ACCESSIBILITY) public void unregisterSystemAction(int); } public static interface AccessibilityManager.AccessibilityServicesStateChangeListener { diff --git a/api/test-lint-baseline.txt b/api/test-lint-baseline.txt index 0287a286e69c..f5ab40abdf37 100644 --- a/api/test-lint-baseline.txt +++ b/api/test-lint-baseline.txt @@ -2499,6 +2499,8 @@ NoSettingsProvider: android.provider.Settings.Global#DYNAMIC_POWER_SAVINGS_ENABL NoSettingsProvider: android.provider.Settings.Global#HIDDEN_API_BLACKLIST_EXEMPTIONS: +NoSettingsProvider: android.provider.Settings.Global#HIDDEN_API_POLICY: + NoSettingsProvider: android.provider.Settings.Global#HIDE_ERROR_DIALOGS: NoSettingsProvider: android.provider.Settings.Global#LOCATION_GLOBAL_KILL_SWITCH: diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp index e7b32c56551a..c10f248f4702 100644 --- a/cmds/statsd/src/StatsLogProcessor.cpp +++ b/cmds/statsd/src/StatsLogProcessor.cpp @@ -120,10 +120,9 @@ static void flushProtoToBuffer(ProtoOutputStream& proto, vector<uint8_t>* outDat } } -void StatsLogProcessor::onAnomalyAlarmFired( +void StatsLogProcessor::processFiredAnomalyAlarmsLocked( const int64_t& timestampNs, unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> alarmSet) { - std::lock_guard<std::mutex> lock(mMetricsMutex); for (const auto& itr : mMetricsManagers) { itr.second->onAnomalyAlarmFired(timestampNs, alarmSet); } @@ -431,6 +430,20 @@ void StatsLogProcessor::OnLogEvent(LogEvent* event, int64_t elapsedRealtimeNs) { return; } + bool fireAlarm = false; + { + std::lock_guard<std::mutex> anomalyLock(mAnomalyAlarmMutex); + if (mNextAnomalyAlarmTime != 0 && + MillisToNano(mNextAnomalyAlarmTime) <= elapsedRealtimeNs) { + mNextAnomalyAlarmTime = 0; + VLOG("informing anomaly alarm at time %lld", (long long)elapsedRealtimeNs); + fireAlarm = true; + } + } + if (fireAlarm) { + informAnomalyAlarmFiredLocked(NanoToMillis(elapsedRealtimeNs)); + } + int64_t curTimeSec = getElapsedRealtimeSec(); if (curTimeSec - mLastPullerCacheClearTimeSec > StatsdStats::kPullerCacheClearIntervalSec) { mPullerManager->ClearPullerCacheIfNecessary(curTimeSec * NS_PER_SEC); @@ -1092,6 +1105,28 @@ void StatsLogProcessor::noteOnDiskData(const ConfigKey& key) { mOnDiskDataConfigs.insert(key); } +void StatsLogProcessor::setAnomalyAlarm(const int64_t elapsedTimeMillis) { + std::lock_guard<std::mutex> lock(mAnomalyAlarmMutex); + mNextAnomalyAlarmTime = elapsedTimeMillis; +} + +void StatsLogProcessor::cancelAnomalyAlarm() { + std::lock_guard<std::mutex> lock(mAnomalyAlarmMutex); + mNextAnomalyAlarmTime = 0; +} + +void StatsLogProcessor::informAnomalyAlarmFiredLocked(const int64_t elapsedTimeMillis) { + VLOG("StatsService::informAlarmForSubscriberTriggeringFired was called"); + std::unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> alarmSet = + mAnomalyAlarmMonitor->popSoonerThan(static_cast<uint32_t>(elapsedTimeMillis / 1000)); + if (alarmSet.size() > 0) { + VLOG("Found periodic alarm fired."); + processFiredAnomalyAlarmsLocked(MillisToNano(elapsedTimeMillis), alarmSet); + } else { + ALOGW("Cannot find an periodic alarm that fired. Perhaps it was recently cancelled."); + } +} + } // namespace statsd } // namespace os } // namespace android diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h index 23f2584655b0..08f46688bbba 100644 --- a/cmds/statsd/src/StatsLogProcessor.h +++ b/cmds/statsd/src/StatsLogProcessor.h @@ -66,11 +66,6 @@ public: const DumpLatency dumpLatency, ProtoOutputStream* proto); - /* Tells MetricsManager that the alarms in alarmSet have fired. Modifies anomaly alarmSet. */ - void onAnomalyAlarmFired( - const int64_t& timestampNs, - unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> alarmSet); - /* Tells MetricsManager that the alarms in alarmSet have fired. Modifies periodic alarmSet. */ void onPeriodicAlarmFired( const int64_t& timestampNs, @@ -148,6 +143,10 @@ public: // Add a specific config key to the possible configs to dump ASAP. void noteOnDiskData(const ConfigKey& key); + void setAnomalyAlarm(const int64_t timeMillis); + + void cancelAnomalyAlarm(); + private: // For testing only. inline sp<AlarmMonitor> getAnomalyAlarmMonitor() const { @@ -160,6 +159,11 @@ private: mutable mutex mMetricsMutex; + // Guards mNextAnomalyAlarmTime. A separate mutex is needed because alarms are set/cancelled + // in the onLogEvent code path, which is locked by mMetricsMutex. + // DO NOT acquire mMetricsMutex while holding mAnomalyAlarmMutex. This can lead to a deadlock. + mutable mutex mAnomalyAlarmMutex; + std::unordered_map<ConfigKey, sp<MetricsManager>> mMetricsManagers; std::unordered_map<ConfigKey, int64_t> mLastBroadcastTimes; @@ -250,6 +254,15 @@ private: // Reset the specified configs. void resetConfigsLocked(const int64_t timestampNs, const std::vector<ConfigKey>& configs); + // An anomaly alarm should have fired. + // Check with anomaly alarm manager to find the alarms and process the result. + void informAnomalyAlarmFiredLocked(const int64_t elapsedTimeMillis); + + /* Tells MetricsManager that the alarms in alarmSet have fired. Modifies anomaly alarmSet. */ + void processFiredAnomalyAlarmsLocked( + const int64_t& timestampNs, + unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> alarmSet); + // Function used to send a broadcast so that receiver for the config key can call getData // to retrieve the stored data. std::function<bool(const ConfigKey& key)> mSendBroadcast; @@ -276,6 +289,9 @@ private: //Last time we wrote metadata to disk. int64_t mLastMetadataWriteNs = 0; + // The time for the next anomaly alarm for alerts. + int64_t mNextAnomalyAlarmTime = 0; + #ifdef VERY_VERBOSE_PRINTING bool mPrintAllLogs = false; #endif diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp index 322648229d0e..368a6c40c746 100644 --- a/cmds/statsd/src/StatsService.cpp +++ b/cmds/statsd/src/StatsService.cpp @@ -91,17 +91,13 @@ Status checkUid(uid_t expectedUid) { StatsService::StatsService(const sp<Looper>& handlerLooper, shared_ptr<LogEventQueue> queue) : mAnomalyAlarmMonitor(new AlarmMonitor( MIN_DIFF_TO_UPDATE_REGISTERED_ALARM_SECS, - [](const shared_ptr<IStatsCompanionService>& sc, int64_t timeMillis) { - if (sc != nullptr) { - sc->setAnomalyAlarm(timeMillis); - StatsdStats::getInstance().noteRegisteredAnomalyAlarmChanged(); - } + [this](const shared_ptr<IStatsCompanionService>& /*sc*/, int64_t timeMillis) { + mProcessor->setAnomalyAlarm(timeMillis); + StatsdStats::getInstance().noteRegisteredAnomalyAlarmChanged(); }, - [](const shared_ptr<IStatsCompanionService>& sc) { - if (sc != nullptr) { - sc->cancelAnomalyAlarm(); - StatsdStats::getInstance().noteRegisteredAnomalyAlarmChanged(); - } + [this](const shared_ptr<IStatsCompanionService>& /*sc*/) { + mProcessor->cancelAnomalyAlarm(); + StatsdStats::getInstance().noteRegisteredAnomalyAlarmChanged(); })), mPeriodicAlarmMonitor(new AlarmMonitor( MIN_DIFF_TO_UPDATE_REGISTERED_ALARM_SECS, @@ -975,22 +971,6 @@ Status StatsService::informOnePackageRemoved(const string& app, int32_t uid) { return Status::ok(); } -Status StatsService::informAnomalyAlarmFired() { - ENFORCE_UID(AID_SYSTEM); - - VLOG("StatsService::informAnomalyAlarmFired was called"); - int64_t currentTimeSec = getElapsedRealtimeSec(); - std::unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> alarmSet = - mAnomalyAlarmMonitor->popSoonerThan(static_cast<uint32_t>(currentTimeSec)); - if (alarmSet.size() > 0) { - VLOG("Found an anomaly alarm that fired."); - mProcessor->onAnomalyAlarmFired(currentTimeSec * NS_PER_SEC, alarmSet); - } else { - VLOG("Cannot find an anomaly alarm that fired. Perhaps it was recently cancelled."); - } - return Status::ok(); -} - Status StatsService::informAlarmForSubscriberTriggeringFired() { ENFORCE_UID(AID_SYSTEM); diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h index 324ffbd65e51..479f4e87ec96 100644 --- a/cmds/statsd/src/StatsService.h +++ b/cmds/statsd/src/StatsService.h @@ -66,7 +66,6 @@ public: virtual Status systemRunning(); virtual Status statsCompanionReady(); virtual Status bootCompleted(); - virtual Status informAnomalyAlarmFired(); virtual Status informPollAlarmFired(); virtual Status informAlarmForSubscriberTriggeringFired(); @@ -404,6 +403,10 @@ private: FRIEND_TEST(PartialBucketE2eTest, TestGaugeMetricOnBootWithoutMinPartialBucket); FRIEND_TEST(PartialBucketE2eTest, TestGaugeMetricWithoutMinPartialBucket); FRIEND_TEST(PartialBucketE2eTest, TestGaugeMetricWithMinPartialBucket); + + FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket); + FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_multiple_buckets); + FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_long_refractory_period); }; } // namespace statsd diff --git a/cmds/statsd/tests/e2e/Anomaly_duration_sum_e2e_test.cpp b/cmds/statsd/tests/e2e/Anomaly_duration_sum_e2e_test.cpp index 95e301002a1b..70e7365ec238 100644 --- a/cmds/statsd/tests/e2e/Anomaly_duration_sum_e2e_test.cpp +++ b/cmds/statsd/tests/e2e/Anomaly_duration_sum_e2e_test.cpp @@ -12,14 +12,19 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include <android/binder_ibinder.h> +#include <android/binder_interface_utils.h> #include <gtest/gtest.h> -#include "src/anomaly/DurationAnomalyTracker.h" +#include <vector> + #include "src/StatsLogProcessor.h" +#include "src/StatsService.h" +#include "src/anomaly/DurationAnomalyTracker.h" #include "src/stats_log_util.h" #include "tests/statsd_test_util.h" -#include <vector> +using ::ndk::SharedRefBase; namespace android { namespace os { @@ -29,6 +34,9 @@ namespace statsd { namespace { +const int kConfigKey = 789130124; +const int kCallingUid = 0; + StatsdConfig CreateStatsdConfig(int num_buckets, uint64_t threshold_ns, DurationMetric::AggregationType aggregationType, @@ -89,6 +97,13 @@ MetricDimensionKey dimensionKey2( (int32_t)0x02010101), Value((int32_t)222))}), DEFAULT_DIMENSION_KEY); +void sendConfig(shared_ptr<StatsService>& service, const StatsdConfig& config) { + string str; + config.SerializeToString(&str); + std::vector<uint8_t> configAsVec(str.begin(), str.end()); + service->addConfiguration(kConfigKey, configAsVec, kCallingUid); +} + } // namespace TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket) { @@ -98,16 +113,18 @@ TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket) { const uint64_t alert_id = config.alert(0).id(); const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs(); - int64_t bucketStartTimeNs = 10 * NS_PER_SEC; - int64_t bucketSizeNs = - TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000; + shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr); + sendConfig(service, config); - ConfigKey cfgKey; - auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey); + auto processor = service->mProcessor; ASSERT_EQ(processor->mMetricsManagers.size(), 1u); EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); ASSERT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size()); + int64_t bucketStartTimeNs = processor->mTimeBaseNs; + int64_t roundedBucketStartTimeNs = bucketStartTimeNs / NS_PER_SEC * NS_PER_SEC; + int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1e6; + sp<AnomalyTracker> anomalyTracker = processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0]; @@ -158,12 +175,13 @@ TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket) { const int64_t alarmFiredTimestampSec0 = anomalyTracker->getAlarmTimestampSec(dimensionKey1); EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + NS_PER_SEC + 109) / NS_PER_SEC + 1, (uint32_t)alarmFiredTimestampSec0); + EXPECT_EQ(alarmFiredTimestampSec0, + processor->getAnomalyAlarmMonitor()->getRegisteredAlarmTimeSec()); // Anomaly alarm fired. - auto alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan( - static_cast<uint32_t>(alarmFiredTimestampSec0)); - ASSERT_EQ(1u, alarmSet.size()); - processor->onAnomalyAlarmFired(alarmFiredTimestampSec0 * NS_PER_SEC, alarmSet); + auto alarmTriggerEvent = CreateBatterySaverOnEvent(alarmFiredTimestampSec0 * NS_PER_SEC); + processor->OnLogEvent(alarmTriggerEvent.get(), alarmFiredTimestampSec0 * NS_PER_SEC); + EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); EXPECT_EQ(refractory_period_sec + alarmFiredTimestampSec0, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); @@ -179,39 +197,39 @@ TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket) { anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); // Acquire wakelock wl1. - acquire_event = - CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - 5 * NS_PER_SEC - 11, - attributionUids2, attributionTags2, "wl1"); + acquire_event = CreateAcquireWakelockEvent( + roundedBucketStartTimeNs + bucketSizeNs - 5 * NS_PER_SEC - 11, attributionUids2, + attributionTags2, "wl1"); processor->OnLogEvent(acquire_event.get()); const int64_t alarmFiredTimestampSec1 = anomalyTracker->getAlarmTimestampSec(dimensionKey1); EXPECT_EQ((bucketStartTimeNs + bucketSizeNs - 5 * NS_PER_SEC) / NS_PER_SEC, (uint64_t)alarmFiredTimestampSec1); // Release wakelock wl1. - release_event = - CreateReleaseWakelockEvent(bucketStartTimeNs + bucketSizeNs - 4 * NS_PER_SEC - 10, - attributionUids2, attributionTags2, "wl1"); - processor->OnLogEvent(release_event.get()); + int64_t release_event_time = roundedBucketStartTimeNs + bucketSizeNs - 4 * NS_PER_SEC - 10; + release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids2, + attributionTags2, "wl1"); + processor->OnLogEvent(release_event.get(), release_event_time); EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); - EXPECT_EQ(refractory_period_sec + - (bucketStartTimeNs + bucketSizeNs - 4 * NS_PER_SEC - 10) / NS_PER_SEC + 1, + EXPECT_EQ(refractory_period_sec + (release_event_time) / NS_PER_SEC + 1, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); - alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan( + auto alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan( static_cast<uint32_t>(alarmFiredTimestampSec1)); ASSERT_EQ(0u, alarmSet.size()); // Acquire wakelock wl1 near the end of bucket #0. - acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - 2, + acquire_event = CreateAcquireWakelockEvent(roundedBucketStartTimeNs + bucketSizeNs - 2, attributionUids1, attributionTags1, "wl1"); processor->OnLogEvent(acquire_event.get()); EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); // Release the event at early bucket #1. - release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + bucketSizeNs + NS_PER_SEC - 1, - attributionUids1, attributionTags1, "wl1"); - processor->OnLogEvent(release_event.get()); + release_event_time = roundedBucketStartTimeNs + bucketSizeNs + NS_PER_SEC - 1; + release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids1, + attributionTags1, "wl1"); + processor->OnLogEvent(release_event.get(), release_event_time); EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); // Anomaly detected when stopping the alarm. The refractory period does not change. EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + NS_PER_SEC) / NS_PER_SEC, @@ -236,17 +254,17 @@ TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket) { // Condition turns true. screen_off_event = - CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * bucketSizeNs + NS_PER_SEC, + CreateScreenStateChangedEvent(roundedBucketStartTimeNs + 2 * bucketSizeNs + NS_PER_SEC, android::view::DisplayStateEnum::DISPLAY_STATE_OFF); processor->OnLogEvent(screen_off_event.get()); EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs + NS_PER_SEC + threshold_ns) / NS_PER_SEC, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); // Condition turns to false. - screen_on_event = - CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC + 1, - android::view::DisplayStateEnum::DISPLAY_STATE_ON); - processor->OnLogEvent(screen_on_event.get()); + int64_t condition_false_time = bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC + 1; + screen_on_event = CreateScreenStateChangedEvent( + condition_false_time, android::view::DisplayStateEnum::DISPLAY_STATE_ON); + processor->OnLogEvent(screen_on_event.get(), condition_false_time); // Condition turns to false. Cancelled the alarm. EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); // Detected one anomaly. @@ -262,12 +280,11 @@ TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket) { EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 2 + 2 + 1, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); - release_event = - CreateReleaseWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 5 * NS_PER_SEC, - attributionUids2, attributionTags2, "wl1"); + release_event_time = roundedBucketStartTimeNs + 2 * bucketSizeNs + 5 * NS_PER_SEC; + release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids2, + attributionTags2, "wl1"); processor->OnLogEvent(release_event.get()); - EXPECT_EQ(refractory_period_sec + - (bucketStartTimeNs + 2 * bucketSizeNs + 5 * NS_PER_SEC) / NS_PER_SEC, + EXPECT_EQ(refractory_period_sec + (release_event_time) / NS_PER_SEC, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); } @@ -279,16 +296,18 @@ TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_multiple_buckets) { const uint64_t alert_id = config.alert(0).id(); const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs(); - int64_t bucketStartTimeNs = 10 * NS_PER_SEC; - int64_t bucketSizeNs = - TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000; + shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr); + sendConfig(service, config); - ConfigKey cfgKey; - auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey); + auto processor = service->mProcessor; ASSERT_EQ(processor->mMetricsManagers.size(), 1u); EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); ASSERT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size()); + int64_t bucketStartTimeNs = processor->mTimeBaseNs; + int64_t roundedBucketStartTimeNs = bucketStartTimeNs / NS_PER_SEC * NS_PER_SEC; + int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1e6; + sp<AnomalyTracker> anomalyTracker = processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0]; @@ -298,96 +317,97 @@ TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_multiple_buckets) { // Acquire wakelock "wc1" in bucket #0. auto acquire_event = - CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - NS_PER_SEC / 2 - 1, + CreateAcquireWakelockEvent(roundedBucketStartTimeNs + bucketSizeNs - NS_PER_SEC / 2 - 1, attributionUids1, attributionTags1, "wl1"); processor->OnLogEvent(acquire_event.get()); - EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 1, + EXPECT_EQ((roundedBucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 1, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); // Release wakelock "wc1" in bucket #0. - auto release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + bucketSizeNs - 1, - attributionUids1, attributionTags1, "wl1"); - processor->OnLogEvent(release_event.get()); + int64_t release_event_time = roundedBucketStartTimeNs + bucketSizeNs - 1; + auto release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids1, + attributionTags1, "wl1"); + processor->OnLogEvent(release_event.get(), release_event_time); EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); // Acquire wakelock "wc1" in bucket #1. - acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 1, - attributionUids2, attributionTags2, "wl1"); + acquire_event = + CreateAcquireWakelockEvent(roundedBucketStartTimeNs + bucketSizeNs + NS_PER_SEC + 1, + attributionUids2, attributionTags2, "wl1"); processor->OnLogEvent(acquire_event.get()); - EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 1, + EXPECT_EQ((bucketStartTimeNs + bucketSizeNs + NS_PER_SEC) / NS_PER_SEC + 1, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); - release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + bucketSizeNs + 100, - attributionUids2, attributionTags2, "wl1"); - processor->OnLogEvent(release_event.get()); + release_event_time = roundedBucketStartTimeNs + bucketSizeNs + NS_PER_SEC + 100; + release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids2, + attributionTags2, "wl1"); + processor->OnLogEvent(release_event.get(), release_event_time); EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); // Acquire wakelock "wc2" in bucket #2. - acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 1, - attributionUids3, attributionTags3, "wl2"); + acquire_event = + CreateAcquireWakelockEvent(roundedBucketStartTimeNs + 2 * bucketSizeNs + NS_PER_SEC + 1, + attributionUids3, attributionTags3, "wl2"); processor->OnLogEvent(acquire_event.get()); - EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 2, + EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 3, anomalyTracker->getAlarmTimestampSec(dimensionKey2)); EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2)); // Release wakelock "wc2" in bucket #2. - release_event = - CreateReleaseWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC, - attributionUids3, attributionTags3, "wl2"); - processor->OnLogEvent(release_event.get()); + release_event_time = roundedBucketStartTimeNs + 2 * bucketSizeNs + 3 * NS_PER_SEC; + release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids3, + attributionTags3, "wl2"); + processor->OnLogEvent(release_event.get(), release_event_time); EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey2)); - EXPECT_EQ(refractory_period_sec + - (bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC) / NS_PER_SEC, + EXPECT_EQ(refractory_period_sec + (release_event_time) / NS_PER_SEC, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2)); // Acquire wakelock "wc1" in bucket #2. acquire_event = - CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC, + CreateAcquireWakelockEvent(roundedBucketStartTimeNs + 2 * bucketSizeNs + 3 * NS_PER_SEC, attributionUids2, attributionTags2, "wl1"); processor->OnLogEvent(acquire_event.get()); - EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 2 + 1, + EXPECT_EQ((roundedBucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 3 + 1, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); // Release wakelock "wc1" in bucket #2. - release_event = - CreateReleaseWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 2.5 * NS_PER_SEC, - attributionUids2, attributionTags2, "wl1"); - processor->OnLogEvent(release_event.get()); + release_event_time = roundedBucketStartTimeNs + 2 * bucketSizeNs + 3.5 * NS_PER_SEC; + release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids2, + attributionTags2, "wl1"); + processor->OnLogEvent(release_event.get(), release_event_time); EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); - EXPECT_EQ(refractory_period_sec + - (int64_t)(bucketStartTimeNs + 2 * bucketSizeNs + 2.5 * NS_PER_SEC) / - NS_PER_SEC + - 1, + EXPECT_EQ(refractory_period_sec + (release_event_time) / NS_PER_SEC + 1, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); - acquire_event = - CreateAcquireWakelockEvent(bucketStartTimeNs + 6 * bucketSizeNs - NS_PER_SEC + 4, - attributionUids3, attributionTags3, "wl2"); + acquire_event = CreateAcquireWakelockEvent(roundedBucketStartTimeNs + 6 * bucketSizeNs + 4, + attributionUids3, attributionTags3, "wl2"); processor->OnLogEvent(acquire_event.get()); - acquire_event = - CreateAcquireWakelockEvent(bucketStartTimeNs + 6 * bucketSizeNs - NS_PER_SEC + 5, - attributionUids1, attributionTags1, "wl1"); + acquire_event = CreateAcquireWakelockEvent(roundedBucketStartTimeNs + 6 * bucketSizeNs + 5, + attributionUids1, attributionTags1, "wl1"); processor->OnLogEvent(acquire_event.get()); - EXPECT_EQ((bucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC + 1, + EXPECT_EQ((roundedBucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC + 2, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); - EXPECT_EQ((bucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC + 1, + EXPECT_EQ((roundedBucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC + 2, anomalyTracker->getAlarmTimestampSec(dimensionKey2)); - release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + 6 * bucketSizeNs + 2, - attributionUids3, attributionTags3, "wl2"); - processor->OnLogEvent(release_event.get()); - release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + 6 * bucketSizeNs + 6, - attributionUids1, attributionTags1, "wl1"); - processor->OnLogEvent(release_event.get()); + release_event_time = roundedBucketStartTimeNs + 6 * bucketSizeNs + NS_PER_SEC + 2; + release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids3, + attributionTags3, "wl2"); + processor->OnLogEvent(release_event.get(), release_event_time); + release_event = CreateReleaseWakelockEvent(release_event_time + 4, attributionUids1, + attributionTags1, "wl1"); + processor->OnLogEvent(release_event.get(), release_event_time + 4); EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey2)); // The buckets are not messed up across dimensions. Only one dimension has anomaly triggered. - EXPECT_EQ(refractory_period_sec + (int64_t)(bucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC + + EXPECT_EQ(refractory_period_sec + + (int64_t)(roundedBucketStartTimeNs + 6 * bucketSizeNs + NS_PER_SEC) / + NS_PER_SEC + 1, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); } @@ -396,20 +416,22 @@ TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_long_refractory_period) { const int num_buckets = 2; const uint64_t threshold_ns = 3 * NS_PER_SEC; auto config = CreateStatsdConfig(num_buckets, threshold_ns, DurationMetric::SUM, false); - int64_t bucketStartTimeNs = 10 * NS_PER_SEC; - int64_t bucketSizeNs = - TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000; - const uint64_t alert_id = config.alert(0).id(); + int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1e6; const uint32_t refractory_period_sec = 3 * bucketSizeNs / NS_PER_SEC; config.mutable_alert(0)->set_refractory_period_secs(refractory_period_sec); - ConfigKey cfgKey; - auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey); + shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr); + sendConfig(service, config); + + auto processor = service->mProcessor; ASSERT_EQ(processor->mMetricsManagers.size(), 1u); EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); ASSERT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size()); + int64_t bucketStartTimeNs = processor->mTimeBaseNs; + int64_t roundedBucketStartTimeNs = bucketStartTimeNs / NS_PER_SEC * NS_PER_SEC; + sp<AnomalyTracker> anomalyTracker = processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0]; @@ -418,81 +440,81 @@ TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_long_refractory_period) { processor->OnLogEvent(screen_off_event.get()); // Acquire wakelock "wc1" in bucket #0. - auto acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - 100, + auto acquire_event = CreateAcquireWakelockEvent(roundedBucketStartTimeNs + bucketSizeNs - 100, attributionUids1, attributionTags1, "wl1"); processor->OnLogEvent(acquire_event.get()); - EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 3, + EXPECT_EQ((roundedBucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 3, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); // Acquire the wakelock "wc1" again. acquire_event = - CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 2 * NS_PER_SEC + 1, + CreateAcquireWakelockEvent(roundedBucketStartTimeNs + bucketSizeNs + 2 * NS_PER_SEC + 1, attributionUids1, attributionTags1, "wl1"); processor->OnLogEvent(acquire_event.get()); // The alarm does not change. - EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 3, + EXPECT_EQ((roundedBucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 3, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); // Anomaly alarm fired late. - const int64_t firedAlarmTimestampNs = bucketStartTimeNs + 2 * bucketSizeNs - NS_PER_SEC; - auto alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan( - static_cast<uint32_t>(firedAlarmTimestampNs / NS_PER_SEC)); - ASSERT_EQ(1u, alarmSet.size()); - processor->onAnomalyAlarmFired(firedAlarmTimestampNs, alarmSet); + const int64_t firedAlarmTimestampNs = roundedBucketStartTimeNs + 2 * bucketSizeNs - NS_PER_SEC; + auto alarmTriggerEvent = CreateBatterySaverOnEvent(firedAlarmTimestampNs); + processor->OnLogEvent(alarmTriggerEvent.get(), firedAlarmTimestampNs); EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); - acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs - 100, + acquire_event = CreateAcquireWakelockEvent(roundedBucketStartTimeNs + 2 * bucketSizeNs - 100, attributionUids1, attributionTags1, "wl1"); processor->OnLogEvent(acquire_event.get()); EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); - auto release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 1, - attributionUids1, attributionTags1, "wl1"); - processor->OnLogEvent(release_event.get()); + int64_t release_event_time = bucketStartTimeNs + 2 * bucketSizeNs + 1; + auto release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids1, + attributionTags1, "wl1"); + processor->OnLogEvent(release_event.get(), release_event_time); EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); // Within the refractory period. No anomaly. EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); // A new wakelock, but still within refractory period. - acquire_event = - CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 10 * NS_PER_SEC, - attributionUids1, attributionTags1, "wl1"); + acquire_event = CreateAcquireWakelockEvent( + roundedBucketStartTimeNs + 2 * bucketSizeNs + 10 * NS_PER_SEC, attributionUids1, + attributionTags1, "wl1"); processor->OnLogEvent(acquire_event.get()); EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); - release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs - NS_PER_SEC, - attributionUids1, attributionTags1, "wl1"); + release_event = + CreateReleaseWakelockEvent(roundedBucketStartTimeNs + 3 * bucketSizeNs - NS_PER_SEC, + attributionUids1, attributionTags1, "wl1"); // Still in the refractory period. No anomaly. processor->OnLogEvent(release_event.get()); EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); - acquire_event = - CreateAcquireWakelockEvent(bucketStartTimeNs + 5 * bucketSizeNs - 3 * NS_PER_SEC - 5, - attributionUids1, attributionTags1, "wl1"); + acquire_event = CreateAcquireWakelockEvent( + roundedBucketStartTimeNs + 5 * bucketSizeNs - 2 * NS_PER_SEC - 5, attributionUids1, + attributionTags1, "wl1"); processor->OnLogEvent(acquire_event.get()); - EXPECT_EQ((bucketStartTimeNs + 5 * bucketSizeNs) / NS_PER_SEC, + EXPECT_EQ((roundedBucketStartTimeNs + 5 * bucketSizeNs) / NS_PER_SEC + 1, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); - release_event = - CreateReleaseWakelockEvent(bucketStartTimeNs + 5 * bucketSizeNs - 3 * NS_PER_SEC - 4, - attributionUids1, attributionTags1, "wl1"); - processor->OnLogEvent(release_event.get()); + release_event_time = roundedBucketStartTimeNs + 5 * bucketSizeNs - 2 * NS_PER_SEC - 4; + release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids1, + attributionTags1, "wl1"); + processor->OnLogEvent(release_event.get(), release_event_time); EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); - acquire_event = - CreateAcquireWakelockEvent(bucketStartTimeNs + 5 * bucketSizeNs - 3 * NS_PER_SEC - 3, - attributionUids1, attributionTags1, "wl1"); + acquire_event = CreateAcquireWakelockEvent( + roundedBucketStartTimeNs + 5 * bucketSizeNs - 2 * NS_PER_SEC - 3, attributionUids1, + attributionTags1, "wl1"); processor->OnLogEvent(acquire_event.get()); - EXPECT_EQ((bucketStartTimeNs + 5 * bucketSizeNs) / NS_PER_SEC, + EXPECT_EQ((roundedBucketStartTimeNs + 5 * bucketSizeNs) / NS_PER_SEC + 1, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); } diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index e9683a4fdd77..97ef62bf457d 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -1386,6 +1386,7 @@ public final class SystemServiceRegistry { case Context.CONTENT_CAPTURE_MANAGER_SERVICE: case Context.APP_PREDICTION_SERVICE: case Context.INCREMENTAL_SERVICE: + case Context.ETHERNET_SERVICE: return null; } Slog.wtf(TAG, "Manager wrapper not available: " + name); diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 1fce990e01c0..237175d42dd1 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -5718,8 +5718,8 @@ public class DevicePolicyManager { * System apps can always bypass VPN. * <p> Note that the system doesn't update the allowlist when packages are installed or * uninstalled, the admin app must call this method to keep the list up to date. - * <p> When {@code lockdownEnabled} is false {@code lockdownWhitelist} is ignored . When - * {@code lockdownEnabled} is {@code true} and {@code lockdownWhitelist} is {@code null} or + * <p> When {@code lockdownEnabled} is false {@code lockdownAllowlist} is ignored . When + * {@code lockdownEnabled} is {@code true} and {@code lockdownAllowlist} is {@code null} or * empty, only system apps can bypass VPN. * <p> Setting always-on VPN package to {@code null} or using * {@link #setAlwaysOnVpnPackage(ComponentName, String, boolean)} clears lockdown allowlist. @@ -5728,24 +5728,24 @@ public class DevicePolicyManager { * to remove an existing always-on VPN configuration * @param lockdownEnabled {@code true} to disallow networking when the VPN is not connected or * {@code false} otherwise. This has no effect when clearing. - * @param lockdownWhitelist Packages that will be able to access the network directly when VPN + * @param lockdownAllowlist Packages that will be able to access the network directly when VPN * is in lockdown mode but not connected. Has no effect when clearing. * @throws SecurityException if {@code admin} is not a device or a profile * owner. * @throws NameNotFoundException if {@code vpnPackage} or one of - * {@code lockdownWhitelist} is not installed. + * {@code lockdownAllowlist} is not installed. * @throws UnsupportedOperationException if {@code vpnPackage} exists but does * not support being set as always-on, or if always-on VPN is not * available. */ public void setAlwaysOnVpnPackage(@NonNull ComponentName admin, @Nullable String vpnPackage, - boolean lockdownEnabled, @Nullable Set<String> lockdownWhitelist) + boolean lockdownEnabled, @Nullable Set<String> lockdownAllowlist) throws NameNotFoundException { throwIfParentInstance("setAlwaysOnVpnPackage"); if (mService != null) { try { mService.setAlwaysOnVpnPackage(admin, vpnPackage, lockdownEnabled, - lockdownWhitelist == null ? null : new ArrayList<>(lockdownWhitelist)); + lockdownAllowlist == null ? null : new ArrayList<>(lockdownAllowlist)); } catch (ServiceSpecificException e) { switch (e.errorCode) { case ERROR_VPN_PACKAGE_NOT_FOUND: @@ -5820,9 +5820,9 @@ public class DevicePolicyManager { throwIfParentInstance("getAlwaysOnVpnLockdownWhitelist"); if (mService != null) { try { - final List<String> whitelist = - mService.getAlwaysOnVpnLockdownWhitelist(admin); - return whitelist == null ? null : new HashSet<>(whitelist); + final List<String> allowlist = + mService.getAlwaysOnVpnLockdownAllowlist(admin); + return allowlist == null ? null : new HashSet<>(allowlist); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/app/admin/FreezePeriod.java b/core/java/android/app/admin/FreezePeriod.java index 657f0177097e..eb6efec1c330 100644 --- a/core/java/android/app/admin/FreezePeriod.java +++ b/core/java/android/app/admin/FreezePeriod.java @@ -39,8 +39,8 @@ import java.util.List; public class FreezePeriod { private static final String TAG = "FreezePeriod"; - private static final int DUMMY_YEAR = 2001; - static final int DAYS_IN_YEAR = 365; // 365 since DUMMY_YEAR is not a leap year + private static final int SENTINEL_YEAR = 2001; + static final int DAYS_IN_YEAR = 365; // 365 since SENTINEL_YEAR is not a leap year private final MonthDay mStart; private final MonthDay mEnd; @@ -60,9 +60,9 @@ public class FreezePeriod { */ public FreezePeriod(MonthDay start, MonthDay end) { mStart = start; - mStartDay = mStart.atYear(DUMMY_YEAR).getDayOfYear(); + mStartDay = mStart.atYear(SENTINEL_YEAR).getDayOfYear(); mEnd = end; - mEndDay = mEnd.atYear(DUMMY_YEAR).getDayOfYear(); + mEndDay = mEnd.atYear(SENTINEL_YEAR).getDayOfYear(); } /** @@ -166,9 +166,9 @@ public class FreezePeriod { endYearAdjustment = 1; } } - final LocalDate startDate = LocalDate.ofYearDay(DUMMY_YEAR, mStartDay).withYear( + final LocalDate startDate = LocalDate.ofYearDay(SENTINEL_YEAR, mStartDay).withYear( now.getYear() + startYearAdjustment); - final LocalDate endDate = LocalDate.ofYearDay(DUMMY_YEAR, mEndDay).withYear( + final LocalDate endDate = LocalDate.ofYearDay(SENTINEL_YEAR, mEndDay).withYear( now.getYear() + endYearAdjustment); return new Pair<>(startDate, endDate); } @@ -176,13 +176,13 @@ public class FreezePeriod { @Override public String toString() { DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMM dd"); - return LocalDate.ofYearDay(DUMMY_YEAR, mStartDay).format(formatter) + " - " - + LocalDate.ofYearDay(DUMMY_YEAR, mEndDay).format(formatter); + return LocalDate.ofYearDay(SENTINEL_YEAR, mStartDay).format(formatter) + " - " + + LocalDate.ofYearDay(SENTINEL_YEAR, mEndDay).format(formatter); } /** @hide */ private static MonthDay dayOfYearToMonthDay(int dayOfYear) { - LocalDate date = LocalDate.ofYearDay(DUMMY_YEAR, dayOfYear); + LocalDate date = LocalDate.ofYearDay(SENTINEL_YEAR, dayOfYear); return MonthDay.of(date.getMonth(), date.getDayOfMonth()); } @@ -191,7 +191,7 @@ public class FreezePeriod { * @hide */ private static int dayOfYearDisregardLeapYear(LocalDate date) { - return date.withYear(DUMMY_YEAR).getDayOfYear(); + return date.withYear(SENTINEL_YEAR).getDayOfYear(); } /** diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index 9c6a274ccf8c..3ad8b4b5294f 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -197,12 +197,12 @@ interface IDevicePolicyManager { void setCertInstallerPackage(in ComponentName who, String installerPackage); String getCertInstallerPackage(in ComponentName who); - boolean setAlwaysOnVpnPackage(in ComponentName who, String vpnPackage, boolean lockdown, in List<String> lockdownWhitelist); + boolean setAlwaysOnVpnPackage(in ComponentName who, String vpnPackage, boolean lockdown, in List<String> lockdownAllowlist); String getAlwaysOnVpnPackage(in ComponentName who); String getAlwaysOnVpnPackageForUser(int userHandle); boolean isAlwaysOnVpnLockdownEnabled(in ComponentName who); boolean isAlwaysOnVpnLockdownEnabledForUser(int userHandle); - List<String> getAlwaysOnVpnLockdownWhitelist(in ComponentName who); + List<String> getAlwaysOnVpnLockdownAllowlist(in ComponentName who); void addPersistentPreferredActivity(in ComponentName admin, in IntentFilter filter, in ComponentName activity); void clearPackagePersistentPreferredActivities(in ComponentName admin, String packageName); diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java index 3c7d8fca20a4..872c37771128 100644 --- a/core/java/android/bluetooth/BluetoothAdapter.java +++ b/core/java/android/bluetooth/BluetoothAdapter.java @@ -2529,7 +2529,7 @@ public final class BluetoothAdapter { * Create a listening, insecure RFCOMM Bluetooth socket with Service Record. * <p>The link key is not required to be authenticated, i.e the communication may be * vulnerable to Person In the Middle attacks. For Bluetooth 2.1 devices, - * the link will be encrypted, as encryption is mandartory. + * the link will be encrypted, as encryption is mandatory. * For legacy devices (pre Bluetooth 2.1 devices) the link will not * be encrypted. Use {@link #listenUsingRfcommWithServiceRecord}, if an * encrypted and authenticated communication channel is desired. @@ -2568,7 +2568,7 @@ public final class BluetoothAdapter { * an input and output capability or just has the ability to display a numeric key, * a secure socket connection is not possible and this socket can be used. * Use {@link #listenUsingInsecureRfcommWithServiceRecord}, if encryption is not required. - * For Bluetooth 2.1 devices, the link will be encrypted, as encryption is mandartory. + * For Bluetooth 2.1 devices, the link will be encrypted, as encryption is mandatory. * For more details, refer to the Security Model section 5.2 (vol 3) of * Bluetooth Core Specification version 2.1 + EDR. * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming diff --git a/core/java/android/bluetooth/le/AdvertiseData.java b/core/java/android/bluetooth/le/AdvertiseData.java index 5fd825837647..573b93232642 100644 --- a/core/java/android/bluetooth/le/AdvertiseData.java +++ b/core/java/android/bluetooth/le/AdvertiseData.java @@ -16,6 +16,7 @@ package android.bluetooth.le; +import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Parcel; import android.os.ParcelUuid; @@ -43,17 +44,22 @@ public final class AdvertiseData implements Parcelable { @Nullable private final List<ParcelUuid> mServiceUuids; + @Nullable + private final List<ParcelUuid> mServiceSolicitationUuids; + private final SparseArray<byte[]> mManufacturerSpecificData; private final Map<ParcelUuid, byte[]> mServiceData; private final boolean mIncludeTxPowerLevel; private final boolean mIncludeDeviceName; private AdvertiseData(List<ParcelUuid> serviceUuids, + List<ParcelUuid> serviceSolicitationUuids, SparseArray<byte[]> manufacturerData, Map<ParcelUuid, byte[]> serviceData, boolean includeTxPowerLevel, boolean includeDeviceName) { mServiceUuids = serviceUuids; + mServiceSolicitationUuids = serviceSolicitationUuids; mManufacturerSpecificData = manufacturerData; mServiceData = serviceData; mIncludeTxPowerLevel = includeTxPowerLevel; @@ -69,6 +75,14 @@ public final class AdvertiseData implements Parcelable { } /** + * Returns a list of service solicitation UUIDs within the advertisement that we invite to connect. + */ + @Nullable + public List<ParcelUuid> getServiceSolicitationUuids() { + return mServiceSolicitationUuids; + } + + /** * Returns an array of manufacturer Id and the corresponding manufacturer specific data. The * manufacturer id is a non-negative number assigned by Bluetooth SIG. */ @@ -102,8 +116,8 @@ public final class AdvertiseData implements Parcelable { */ @Override public int hashCode() { - return Objects.hash(mServiceUuids, mManufacturerSpecificData, mServiceData, - mIncludeDeviceName, mIncludeTxPowerLevel); + return Objects.hash(mServiceUuids, mServiceSolicitationUuids, mManufacturerSpecificData, + mServiceData, mIncludeDeviceName, mIncludeTxPowerLevel); } /** @@ -119,6 +133,7 @@ public final class AdvertiseData implements Parcelable { } AdvertiseData other = (AdvertiseData) obj; return Objects.equals(mServiceUuids, other.mServiceUuids) + && Objects.equals(mServiceSolicitationUuids, other.mServiceSolicitationUuids) && BluetoothLeUtils.equals(mManufacturerSpecificData, other.mManufacturerSpecificData) && BluetoothLeUtils.equals(mServiceData, other.mServiceData) @@ -128,7 +143,8 @@ public final class AdvertiseData implements Parcelable { @Override public String toString() { - return "AdvertiseData [mServiceUuids=" + mServiceUuids + ", mManufacturerSpecificData=" + return "AdvertiseData [mServiceUuids=" + mServiceUuids + ", mServiceSolicitationUuids=" + + mServiceSolicitationUuids + ", mManufacturerSpecificData=" + BluetoothLeUtils.toString(mManufacturerSpecificData) + ", mServiceData=" + BluetoothLeUtils.toString(mServiceData) + ", mIncludeTxPowerLevel=" + mIncludeTxPowerLevel + ", mIncludeDeviceName=" @@ -143,6 +159,8 @@ public final class AdvertiseData implements Parcelable { @Override public void writeToParcel(Parcel dest, int flags) { dest.writeTypedArray(mServiceUuids.toArray(new ParcelUuid[mServiceUuids.size()]), flags); + dest.writeTypedArray(mServiceSolicitationUuids.toArray( + new ParcelUuid[mServiceSolicitationUuids.size()]), flags); // mManufacturerSpecificData could not be null. dest.writeInt(mManufacturerSpecificData.size()); @@ -174,6 +192,11 @@ public final class AdvertiseData implements Parcelable { builder.addServiceUuid(uuid); } + ArrayList<ParcelUuid> solicitationUuids = in.createTypedArrayList(ParcelUuid.CREATOR); + for (ParcelUuid uuid : solicitationUuids) { + builder.addServiceSolicitationUuid(uuid); + } + int manufacturerSize = in.readInt(); for (int i = 0; i < manufacturerSize; ++i) { int manufacturerId = in.readInt(); @@ -198,6 +221,8 @@ public final class AdvertiseData implements Parcelable { public static final class Builder { @Nullable private List<ParcelUuid> mServiceUuids = new ArrayList<ParcelUuid>(); + @Nullable + private List<ParcelUuid> mServiceSolicitationUuids = new ArrayList<ParcelUuid>(); private SparseArray<byte[]> mManufacturerSpecificData = new SparseArray<byte[]>(); private Map<ParcelUuid, byte[]> mServiceData = new ArrayMap<ParcelUuid, byte[]>(); private boolean mIncludeTxPowerLevel; @@ -207,17 +232,31 @@ public final class AdvertiseData implements Parcelable { * Add a service UUID to advertise data. * * @param serviceUuid A service UUID to be advertised. - * @throws IllegalArgumentException If the {@code serviceUuids} are null. + * @throws IllegalArgumentException If the {@code serviceUuid} is null. */ public Builder addServiceUuid(ParcelUuid serviceUuid) { if (serviceUuid == null) { - throw new IllegalArgumentException("serivceUuids are null"); + throw new IllegalArgumentException("serviceUuid is null"); } mServiceUuids.add(serviceUuid); return this; } /** + * Add a service solicitation UUID to advertise data. + * + * @param serviceSolicitationUuid A service solicitation UUID to be advertised. + * @throws IllegalArgumentException If the {@code serviceSolicitationUuid} is null. + */ + @NonNull + public Builder addServiceSolicitationUuid(@NonNull ParcelUuid serviceSolicitationUuid) { + if (serviceSolicitationUuid == null) { + throw new IllegalArgumentException("serviceSolicitationUuid is null"); + } + mServiceSolicitationUuids.add(serviceSolicitationUuid); + return this; + } + /** * Add service data to advertise data. * * @param serviceDataUuid 16-bit UUID of the service the data is associated with @@ -279,8 +318,9 @@ public final class AdvertiseData implements Parcelable { * Build the {@link AdvertiseData}. */ public AdvertiseData build() { - return new AdvertiseData(mServiceUuids, mManufacturerSpecificData, mServiceData, - mIncludeTxPowerLevel, mIncludeDeviceName); + return new AdvertiseData(mServiceUuids, mServiceSolicitationUuids, + mManufacturerSpecificData, mServiceData, mIncludeTxPowerLevel, + mIncludeDeviceName); } } } diff --git a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java index 13c5ff690973..5f166f4a41da 100644 --- a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java +++ b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java @@ -507,6 +507,33 @@ public final class BluetoothLeAdvertiser { + num128BitUuids * BluetoothUuid.UUID_BYTES_128_BIT; } } + if (data.getServiceSolicitationUuids() != null) { + int num16BitUuids = 0; + int num32BitUuids = 0; + int num128BitUuids = 0; + for (ParcelUuid uuid : data.getServiceSolicitationUuids()) { + if (BluetoothUuid.is16BitUuid(uuid)) { + ++num16BitUuids; + } else if (BluetoothUuid.is32BitUuid(uuid)) { + ++num32BitUuids; + } else { + ++num128BitUuids; + } + } + // 16 bit service uuids are grouped into one field when doing advertising. + if (num16BitUuids != 0) { + size += OVERHEAD_BYTES_PER_FIELD + num16BitUuids * BluetoothUuid.UUID_BYTES_16_BIT; + } + // 32 bit service uuids are grouped into one field when doing advertising. + if (num32BitUuids != 0) { + size += OVERHEAD_BYTES_PER_FIELD + num32BitUuids * BluetoothUuid.UUID_BYTES_32_BIT; + } + // 128 bit service uuids are grouped into one field when doing advertising. + if (num128BitUuids != 0) { + size += OVERHEAD_BYTES_PER_FIELD + + num128BitUuids * BluetoothUuid.UUID_BYTES_128_BIT; + } + } for (ParcelUuid uuid : data.getServiceData().keySet()) { int uuidLen = BluetoothUuid.uuidToBytes(uuid).length; size += OVERHEAD_BYTES_PER_FIELD + uuidLen diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java index 591a714bfb93..ce4024a1d9ff 100644 --- a/core/java/android/companion/CompanionDeviceManager.java +++ b/core/java/android/companion/CompanionDeviceManager.java @@ -131,7 +131,7 @@ public final class CompanionDeviceManager { * you use the {@link android.Manifest.permission#REQUEST_COMPANION_RUN_IN_BACKGROUND} and {@link * android.Manifest.permission#REQUEST_COMPANION_USE_DATA_IN_BACKGROUND} respectively. Note that these * special capabilities have a negative effect on the device's battery and user's data - * usage, therefore you should requested them when absolutely necessary.</p> + * usage, therefore you should request them when absolutely necessary.</p> * * <p>You can call {@link #getAssociations} to get the list of currently associated * devices, and {@link #disassociate} to remove an association. Consider doing so when the diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index f257326904fd..2138f53e9f54 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -785,4 +785,6 @@ interface IPackageManager { List<String> getMimeGroup(String packageName, String group); boolean isAutoRevokeWhitelisted(String packageName); + + void grantImplicitAccess(int queryingUid, String visibleAuthority); } diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 46af6303d04d..0789cfb2af56 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -8018,6 +8018,20 @@ public abstract class PackageManager { "getMimeGroup not implemented in subclass"); } + /** + * Grants implicit visibility of the package that provides an authority to a querying UID. + * + * @throws SecurityException when called by a package other than the contacts provider + * @hide + */ + public void grantImplicitAccess(int queryingUid, String visibleAuthority) { + try { + ActivityThread.getPackageManager().grantImplicitAccess(queryingUid, visibleAuthority); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + // Some of the flags don't affect the query result, but let's be conservative and cache // each combination of flags separately. diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java index 38d9883f0003..a4f7b7454bd9 100644 --- a/core/java/android/net/IpSecAlgorithm.java +++ b/core/java/android/net/IpSecAlgorithm.java @@ -17,6 +17,7 @@ package android.net; import android.annotation.NonNull; import android.annotation.StringDef; +import android.content.res.Resources; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; @@ -27,6 +28,12 @@ import com.android.internal.util.HexDump; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; /** * This class represents a single algorithm that can be used by an {@link IpSecTransform}. @@ -52,6 +59,27 @@ public final class IpSecAlgorithm implements Parcelable { public static final String CRYPT_AES_CBC = "cbc(aes)"; /** + * AES-CTR Encryption/Ciphering Algorithm. + * + * <p>Valid lengths for keying material are {160, 224, 288}. + * + * <p>As per <a href="https://tools.ietf.org/html/rfc3686#section-5.1">RFC3686 (Section + * 5.1)</a>, keying material consists of a 128, 192, or 256 bit AES key followed by a 32-bit + * nonce. RFC compliance requires that the nonce must be unique per security association. + * + * <p>This algorithm may be available on the device. Caller MUST check if it is supported before + * using it by calling {@link #getSupportedAlgorithms()} and checking if this algorithm is + * included in the returned algorithm set. The returned algorithm set will not change unless the + * device is rebooted. {@link IllegalArgumentException} will be thrown if this algorithm is + * requested on an unsupported device. + * + * <p>@see {@link #getSupportedAlgorithms()} + */ + // This algorithm may be available on devices released before Android 12, and is guaranteed + // to be available on devices first shipped with Android 12 or later. + public static final String CRYPT_AES_CTR = "rfc3686(ctr(aes))"; + + /** * MD5 HMAC Authentication/Integrity Algorithm. <b>This algorithm is not recommended for use in * new applications and is provided for legacy compatibility with 3gpp infrastructure.</b> * @@ -99,6 +127,25 @@ public final class IpSecAlgorithm implements Parcelable { public static final String AUTH_HMAC_SHA512 = "hmac(sha512)"; /** + * AES-XCBC Authentication/Integrity Algorithm. + * + * <p>Keys for this algorithm must be 128 bits in length. + * + * <p>The only valid truncation length is 96 bits. + * + * <p>This algorithm may be available on the device. Caller MUST check if it is supported before + * using it by calling {@link #getSupportedAlgorithms()} and checking if this algorithm is + * included in the returned algorithm set. The returned algorithm set will not change unless the + * device is rebooted. {@link IllegalArgumentException} will be thrown if this algorithm is + * requested on an unsupported device. + * + * <p>@see {@link #getSupportedAlgorithms()} + */ + // This algorithm may be available on devices released before Android 12, and is guaranteed + // to be available on devices first shipped with Android 12 or later. + public static final String AUTH_AES_XCBC = "xcbc(aes)"; + + /** * AES-GCM Authentication/Integrity + Encryption/Ciphering Algorithm. * * <p>Valid lengths for keying material are {160, 224, 288}. @@ -111,19 +158,67 @@ public final class IpSecAlgorithm implements Parcelable { */ public static final String AUTH_CRYPT_AES_GCM = "rfc4106(gcm(aes))"; + /** + * ChaCha20-Poly1305 Authentication/Integrity + Encryption/Ciphering Algorithm. + * + * <p>Keys for this algorithm must be 288 bits in length. + * + * <p>As per <a href="https://tools.ietf.org/html/rfc7634#section-2">RFC7634 (Section 2)</a>, + * keying material consists of a 256 bit key followed by a 32-bit salt. The salt is fixed per + * security association. + * + * <p>The only valid ICV (truncation) length is 128 bits. + * + * <p>This algorithm may be available on the device. Caller MUST check if it is supported before + * using it by calling {@link #getSupportedAlgorithms()} and checking if this algorithm is + * included in the returned algorithm set. The returned algorithm set will not change unless the + * device is rebooted. {@link IllegalArgumentException} will be thrown if this algorithm is + * requested on an unsupported device. + * + * <p>@see {@link #getSupportedAlgorithms()} + */ + // This algorithm may be available on devices released before Android 12, and is guaranteed + // to be available on devices first shipped with Android 12 or later. + public static final String AUTH_CRYPT_CHACHA20_POLY1305 = "rfc7539esp(chacha20,poly1305)"; + /** @hide */ @StringDef({ CRYPT_AES_CBC, + CRYPT_AES_CTR, AUTH_HMAC_MD5, AUTH_HMAC_SHA1, AUTH_HMAC_SHA256, AUTH_HMAC_SHA384, AUTH_HMAC_SHA512, - AUTH_CRYPT_AES_GCM + AUTH_AES_XCBC, + AUTH_CRYPT_AES_GCM, + AUTH_CRYPT_CHACHA20_POLY1305 }) @Retention(RetentionPolicy.SOURCE) public @interface AlgorithmName {} + /** @hide */ + @VisibleForTesting + public static final Map<String, Integer> ALGO_TO_REQUIRED_FIRST_SDK = new HashMap<>(); + + static { + ALGO_TO_REQUIRED_FIRST_SDK.put(CRYPT_AES_CBC, Build.VERSION_CODES.P); + ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_HMAC_MD5, Build.VERSION_CODES.P); + ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_HMAC_SHA1, Build.VERSION_CODES.P); + ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_HMAC_SHA256, Build.VERSION_CODES.P); + ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_HMAC_SHA384, Build.VERSION_CODES.P); + ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_HMAC_SHA512, Build.VERSION_CODES.P); + ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_CRYPT_AES_GCM, Build.VERSION_CODES.P); + + // STOPSHIP: b/170424293 Use Build.VERSION_CODES.S when it is defined + ALGO_TO_REQUIRED_FIRST_SDK.put(CRYPT_AES_CTR, Build.VERSION_CODES.R + 1); + ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_AES_XCBC, Build.VERSION_CODES.R + 1); + ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_CRYPT_CHACHA20_POLY1305, Build.VERSION_CODES.R + 1); + } + + private static final Set<String> ENABLED_ALGOS = + Collections.unmodifiableSet(loadAlgos(Resources.getSystem())); + private final String mName; private final byte[] mKey; private final int mTruncLenBits; @@ -137,6 +232,7 @@ public final class IpSecAlgorithm implements Parcelable { * * @param algorithm name of the algorithm. * @param key key padded to a multiple of 8 bits. + * @throws IllegalArgumentException if algorithm or key length is invalid. */ public IpSecAlgorithm(@NonNull @AlgorithmName String algorithm, @NonNull byte[] key) { this(algorithm, key, 0); @@ -152,6 +248,7 @@ public final class IpSecAlgorithm implements Parcelable { * @param algorithm name of the algorithm. * @param key key padded to a multiple of 8 bits. * @param truncLenBits number of bits of output hash to use. + * @throws IllegalArgumentException if algorithm, key length or truncation length is invalid. */ public IpSecAlgorithm( @NonNull @AlgorithmName String algorithm, @NonNull byte[] key, int truncLenBits) { @@ -206,13 +303,59 @@ public final class IpSecAlgorithm implements Parcelable { } }; + /** + * Returns supported IPsec algorithms for the current device. + * + * <p>Some algorithms may not be supported on old devices. Callers MUST check if an algorithm is + * supported before using it. + */ + @NonNull + public static Set<String> getSupportedAlgorithms() { + return ENABLED_ALGOS; + } + + /** @hide */ + @VisibleForTesting + public static Set<String> loadAlgos(Resources systemResources) { + final Set<String> enabledAlgos = new HashSet<>(); + + // Load and validate the optional algorithm resource. Undefined or duplicate algorithms in + // the resource are not allowed. + final String[] resourceAlgos = systemResources.getStringArray( + com.android.internal.R.array.config_optionalIpSecAlgorithms); + for (String str : resourceAlgos) { + if (!ALGO_TO_REQUIRED_FIRST_SDK.containsKey(str) || !enabledAlgos.add(str)) { + // This error should be caught by CTS and never be thrown to API callers + throw new IllegalArgumentException("Invalid or repeated algorithm " + str); + } + } + + for (Entry<String, Integer> entry : ALGO_TO_REQUIRED_FIRST_SDK.entrySet()) { + if (Build.VERSION.FIRST_SDK_INT >= entry.getValue()) { + enabledAlgos.add(entry.getKey()); + } + } + + return enabledAlgos; + } + private static void checkValidOrThrow(String name, int keyLen, int truncLen) { - boolean isValidLen = true; - boolean isValidTruncLen = true; + final boolean isValidLen; + final boolean isValidTruncLen; + + if (!getSupportedAlgorithms().contains(name)) { + throw new IllegalArgumentException("Unsupported algorithm: " + name); + } - switch(name) { + switch (name) { case CRYPT_AES_CBC: isValidLen = keyLen == 128 || keyLen == 192 || keyLen == 256; + isValidTruncLen = true; + break; + case CRYPT_AES_CTR: + // The keying material for AES-CTR is a key plus a 32-bit salt + isValidLen = keyLen == 128 + 32 || keyLen == 192 + 32 || keyLen == 256 + 32; + isValidTruncLen = true; break; case AUTH_HMAC_MD5: isValidLen = keyLen == 128; @@ -234,12 +377,22 @@ public final class IpSecAlgorithm implements Parcelable { isValidLen = keyLen == 512; isValidTruncLen = truncLen >= 256 && truncLen <= 512; break; + case AUTH_AES_XCBC: + isValidLen = keyLen == 128; + isValidTruncLen = truncLen == 96; + break; case AUTH_CRYPT_AES_GCM: // The keying material for GCM is a key plus a 32-bit salt isValidLen = keyLen == 128 + 32 || keyLen == 192 + 32 || keyLen == 256 + 32; isValidTruncLen = truncLen == 64 || truncLen == 96 || truncLen == 128; break; + case AUTH_CRYPT_CHACHA20_POLY1305: + // The keying material for ChaCha20Poly1305 is a key plus a 32-bit salt + isValidLen = keyLen == 256 + 32; + isValidTruncLen = truncLen == 128; + break; default: + // Should never hit here. throw new IllegalArgumentException("Couldn't find an algorithm: " + name); } @@ -260,6 +413,7 @@ public final class IpSecAlgorithm implements Parcelable { case AUTH_HMAC_SHA256: case AUTH_HMAC_SHA384: case AUTH_HMAC_SHA512: + case AUTH_AES_XCBC: return true; default: return false; @@ -268,12 +422,24 @@ public final class IpSecAlgorithm implements Parcelable { /** @hide */ public boolean isEncryption() { - return getName().equals(CRYPT_AES_CBC); + switch (getName()) { + case CRYPT_AES_CBC: // fallthrough + case CRYPT_AES_CTR: + return true; + default: + return false; + } } /** @hide */ public boolean isAead() { - return getName().equals(AUTH_CRYPT_AES_GCM); + switch (getName()) { + case AUTH_CRYPT_AES_GCM: // fallthrough + case AUTH_CRYPT_CHACHA20_POLY1305: + return true; + default: + return false; + } } // Because encryption keys are sensitive and userdebug builds are used by large user pools diff --git a/core/java/android/net/KeepalivePacketData.java b/core/java/android/net/KeepalivePacketData.java index e21cb44f72d8..5877f1f4e269 100644 --- a/core/java/android/net/KeepalivePacketData.java +++ b/core/java/android/net/KeepalivePacketData.java @@ -22,9 +22,10 @@ import static android.net.InvalidPacketException.ERROR_INVALID_PORT; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.SystemApi; -import android.net.util.IpUtils; import android.util.Log; +import com.android.net.module.util.IpUtils; + import java.net.InetAddress; /** diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java index 651494d1c99c..493f0d387f0e 100644 --- a/core/java/android/net/LinkProperties.java +++ b/core/java/android/net/LinkProperties.java @@ -22,7 +22,6 @@ import android.annotation.SystemApi; import android.annotation.TestApi; import android.compat.annotation.UnsupportedAppUsage; import android.net.util.LinkPropertiesUtils; -import android.net.util.LinkPropertiesUtils.CompareResult; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; @@ -1669,78 +1668,6 @@ public final class LinkProperties implements Parcelable { } /** - * Compares the DNS addresses in this LinkProperties with another - * LinkProperties, examining only DNS addresses on the base link. - * - * @param target a LinkProperties with the new list of dns addresses - * @return the differences between the DNS addresses. - * @hide - */ - public @NonNull CompareResult<InetAddress> compareDnses(@Nullable LinkProperties target) { - /* - * Duplicate the InetAddresses into removed, we will be removing - * dns address which are common between mDnses and target - * leaving the addresses that are different. And dns address which - * are in target but not in mDnses are placed in the - * addedAddresses. - */ - return new CompareResult<>(mDnses, target != null ? target.getDnsServers() : null); - } - - /** - * Compares the validated private DNS addresses in this LinkProperties with another - * LinkProperties. - * - * @param target a LinkProperties with the new list of validated private dns addresses - * @return the differences between the DNS addresses. - * @hide - */ - public @NonNull CompareResult<InetAddress> compareValidatedPrivateDnses( - @Nullable LinkProperties target) { - return new CompareResult<>(mValidatedPrivateDnses, - target != null ? target.getValidatedPrivateDnsServers() : null); - } - - /** - * Compares all routes in this LinkProperties with another LinkProperties, - * examining both the the base link and all stacked links. - * - * @param target a LinkProperties with the new list of routes - * @return the differences between the routes. - * @hide - */ - public @NonNull CompareResult<RouteInfo> compareAllRoutes(@Nullable LinkProperties target) { - /* - * Duplicate the RouteInfos into removed, we will be removing - * routes which are common between mRoutes and target - * leaving the routes that are different. And route address which - * are in target but not in mRoutes are placed in added. - */ - return new CompareResult<>(getAllRoutes(), target != null ? target.getAllRoutes() : null); - } - - /** - * Compares all interface names in this LinkProperties with another - * LinkProperties, examining both the the base link and all stacked links. - * - * @param target a LinkProperties with the new list of interface names - * @return the differences between the interface names. - * @hide - */ - public @NonNull CompareResult<String> compareAllInterfaceNames( - @Nullable LinkProperties target) { - /* - * Duplicate the interface names into removed, we will be removing - * interface names which are common between this and target - * leaving the interface names that are different. And interface names which - * are in target but not in this are placed in added. - */ - return new CompareResult<>(getAllInterfaceNames(), - target != null ? target.getAllInterfaceNames() : null); - } - - - /** * Generate hashcode based on significant fields * * Equal objects must produce the same hash code, while unequal objects diff --git a/core/java/android/net/NattKeepalivePacketData.java b/core/java/android/net/NattKeepalivePacketData.java index 22288b6205d7..c4f8fc281f25 100644 --- a/core/java/android/net/NattKeepalivePacketData.java +++ b/core/java/android/net/NattKeepalivePacketData.java @@ -22,11 +22,12 @@ import static android.net.InvalidPacketException.ERROR_INVALID_PORT; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; -import android.net.util.IpUtils; import android.os.Parcel; import android.os.Parcelable; import android.system.OsConstants; +import com.android.net.module.util.IpUtils; + import java.net.Inet4Address; import java.net.InetAddress; import java.nio.ByteBuffer; diff --git a/core/java/android/net/NetworkProvider.java b/core/java/android/net/NetworkProvider.java index 75086cf82b57..d31218d9b67b 100644 --- a/core/java/android/net/NetworkProvider.java +++ b/core/java/android/net/NetworkProvider.java @@ -30,7 +30,7 @@ import android.util.Log; /** * Base class for network providers such as telephony or Wi-Fi. NetworkProviders connect the device - * to networks and makes them available to to the core network stack by creating + * to networks and makes them available to the core network stack by creating * {@link NetworkAgent}s. The networks can then provide connectivity to apps and can be interacted * with via networking APIs such as {@link ConnectivityManager}. * diff --git a/core/java/android/net/NetworkSpecifier.java b/core/java/android/net/NetworkSpecifier.java index 160259e39813..6ef496b1f6fe 100644 --- a/core/java/android/net/NetworkSpecifier.java +++ b/core/java/android/net/NetworkSpecifier.java @@ -22,10 +22,14 @@ import android.annotation.SystemApi; /** * Describes specific properties of a requested network for use in a {@link NetworkRequest}. * - * Applications cannot instantiate this class by themselves, but can obtain instances of - * subclasses of this class via other APIs. + * This as an abstract class. Applications shouldn't instantiate this class by themselves, but can + * obtain instances of subclasses of this class via other APIs. */ public abstract class NetworkSpecifier { + /** + * Create a placeholder object. Please use subclasses of this class in a {@link NetworkRequest} + * to request a network. + */ public NetworkSpecifier() {} /** diff --git a/core/java/android/net/TEST_MAPPING b/core/java/android/net/TEST_MAPPING new file mode 100644 index 000000000000..abac81117deb --- /dev/null +++ b/core/java/android/net/TEST_MAPPING @@ -0,0 +1,20 @@ +{ + "imports": [ + { + // Also includes cts/tests/tests/net + "path": "frameworks/base/tests/net" + }, + { + "path": "packages/modules/NetworkStack" + }, + { + "path": "packages/modules/CaptivePortalLogin" + }, + { + "path": "frameworks/base/packages/Tethering" + }, + { + "path": "frameworks/opt/net/wifi" + } + ] +}
\ No newline at end of file diff --git a/core/java/android/net/util/IpUtils.java b/core/java/android/net/util/IpUtils.java deleted file mode 100644 index e037c4035aca..000000000000 --- a/core/java/android/net/util/IpUtils.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net.util; - -import java.net.Inet6Address; -import java.net.InetAddress; -import java.nio.BufferOverflowException; -import java.nio.BufferUnderflowException; -import java.nio.ByteBuffer; -import java.nio.ShortBuffer; - -import static android.system.OsConstants.IPPROTO_TCP; -import static android.system.OsConstants.IPPROTO_UDP; - -/** - * @hide - */ -public class IpUtils { - /** - * Converts a signed short value to an unsigned int value. Needed - * because Java does not have unsigned types. - */ - private static int intAbs(short v) { - return v & 0xFFFF; - } - - /** - * Performs an IP checksum (used in IP header and across UDP - * payload) on the specified portion of a ByteBuffer. The seed - * allows the checksum to commence with a specified value. - */ - private static int checksum(ByteBuffer buf, int seed, int start, int end) { - int sum = seed; - final int bufPosition = buf.position(); - - // set position of original ByteBuffer, so that the ShortBuffer - // will be correctly initialized - buf.position(start); - ShortBuffer shortBuf = buf.asShortBuffer(); - - // re-set ByteBuffer position - buf.position(bufPosition); - - final int numShorts = (end - start) / 2; - for (int i = 0; i < numShorts; i++) { - sum += intAbs(shortBuf.get(i)); - } - start += numShorts * 2; - - // see if a singleton byte remains - if (end != start) { - short b = buf.get(start); - - // make it unsigned - if (b < 0) { - b += 256; - } - - sum += b * 256; - } - - sum = ((sum >> 16) & 0xFFFF) + (sum & 0xFFFF); - sum = ((sum + ((sum >> 16) & 0xFFFF)) & 0xFFFF); - int negated = ~sum; - return intAbs((short) negated); - } - - private static int pseudoChecksumIPv4( - ByteBuffer buf, int headerOffset, int protocol, int transportLen) { - int partial = protocol + transportLen; - partial += intAbs(buf.getShort(headerOffset + 12)); - partial += intAbs(buf.getShort(headerOffset + 14)); - partial += intAbs(buf.getShort(headerOffset + 16)); - partial += intAbs(buf.getShort(headerOffset + 18)); - return partial; - } - - private static int pseudoChecksumIPv6( - ByteBuffer buf, int headerOffset, int protocol, int transportLen) { - int partial = protocol + transportLen; - for (int offset = 8; offset < 40; offset += 2) { - partial += intAbs(buf.getShort(headerOffset + offset)); - } - return partial; - } - - private static byte ipversion(ByteBuffer buf, int headerOffset) { - return (byte) ((buf.get(headerOffset) & (byte) 0xf0) >> 4); - } - - public static short ipChecksum(ByteBuffer buf, int headerOffset) { - byte ihl = (byte) (buf.get(headerOffset) & 0x0f); - return (short) checksum(buf, 0, headerOffset, headerOffset + ihl * 4); - } - - private static short transportChecksum(ByteBuffer buf, int protocol, - int ipOffset, int transportOffset, int transportLen) { - if (transportLen < 0) { - throw new IllegalArgumentException("Transport length < 0: " + transportLen); - } - int sum; - byte ver = ipversion(buf, ipOffset); - if (ver == 4) { - sum = pseudoChecksumIPv4(buf, ipOffset, protocol, transportLen); - } else if (ver == 6) { - sum = pseudoChecksumIPv6(buf, ipOffset, protocol, transportLen); - } else { - throw new UnsupportedOperationException("Checksum must be IPv4 or IPv6"); - } - - sum = checksum(buf, sum, transportOffset, transportOffset + transportLen); - if (protocol == IPPROTO_UDP && sum == 0) { - sum = (short) 0xffff; - } - return (short) sum; - } - - public static short udpChecksum(ByteBuffer buf, int ipOffset, int transportOffset) { - int transportLen = intAbs(buf.getShort(transportOffset + 4)); - return transportChecksum(buf, IPPROTO_UDP, ipOffset, transportOffset, transportLen); - } - - public static short tcpChecksum(ByteBuffer buf, int ipOffset, int transportOffset, - int transportLen) { - return transportChecksum(buf, IPPROTO_TCP, ipOffset, transportOffset, transportLen); - } - - public static String addressAndPortToString(InetAddress address, int port) { - return String.format( - (address instanceof Inet6Address) ? "[%s]:%d" : "%s:%d", - address.getHostAddress(), port); - } - - public static boolean isValidUdpOrTcpPort(int port) { - return port > 0 && port < 65536; - } -} diff --git a/core/java/android/os/FileBridge.java b/core/java/android/os/FileBridge.java index 21fd819f3d94..ab5637cbb878 100644 --- a/core/java/android/os/FileBridge.java +++ b/core/java/android/os/FileBridge.java @@ -16,7 +16,6 @@ package android.os; -import static android.system.OsConstants.AF_UNIX; import static android.system.OsConstants.SOCK_STREAM; import android.system.ErrnoException; @@ -58,17 +57,19 @@ public class FileBridge extends Thread { /** CMD_CLOSE */ private static final int CMD_CLOSE = 3; - private FileDescriptor mTarget; + private ParcelFileDescriptor mTarget; - private final FileDescriptor mServer = new FileDescriptor(); - private final FileDescriptor mClient = new FileDescriptor(); + private ParcelFileDescriptor mServer; + private ParcelFileDescriptor mClient; private volatile boolean mClosed; public FileBridge() { try { - Os.socketpair(AF_UNIX, SOCK_STREAM, 0, mServer, mClient); - } catch (ErrnoException e) { + ParcelFileDescriptor[] fds = ParcelFileDescriptor.createSocketPair(SOCK_STREAM); + mServer = fds[0]; + mClient = fds[1]; + } catch (IOException e) { throw new RuntimeException("Failed to create bridge"); } } @@ -80,15 +81,14 @@ public class FileBridge extends Thread { public void forceClose() { IoUtils.closeQuietly(mTarget); IoUtils.closeQuietly(mServer); - IoUtils.closeQuietly(mClient); mClosed = true; } - public void setTargetFile(FileDescriptor target) { + public void setTargetFile(ParcelFileDescriptor target) { mTarget = target; } - public FileDescriptor getClientSocket() { + public ParcelFileDescriptor getClientSocket() { return mClient; } @@ -96,32 +96,33 @@ public class FileBridge extends Thread { public void run() { final byte[] temp = new byte[8192]; try { - while (IoBridge.read(mServer, temp, 0, MSG_LENGTH) == MSG_LENGTH) { + while (IoBridge.read(mServer.getFileDescriptor(), temp, 0, MSG_LENGTH) == MSG_LENGTH) { final int cmd = Memory.peekInt(temp, 0, ByteOrder.BIG_ENDIAN); if (cmd == CMD_WRITE) { // Shuttle data into local file int len = Memory.peekInt(temp, 4, ByteOrder.BIG_ENDIAN); while (len > 0) { - int n = IoBridge.read(mServer, temp, 0, Math.min(temp.length, len)); + int n = IoBridge.read(mServer.getFileDescriptor(), temp, 0, + Math.min(temp.length, len)); if (n == -1) { throw new IOException( "Unexpected EOF; still expected " + len + " bytes"); } - IoBridge.write(mTarget, temp, 0, n); + IoBridge.write(mTarget.getFileDescriptor(), temp, 0, n); len -= n; } } else if (cmd == CMD_FSYNC) { // Sync and echo back to confirm - Os.fsync(mTarget); - IoBridge.write(mServer, temp, 0, MSG_LENGTH); + Os.fsync(mTarget.getFileDescriptor()); + IoBridge.write(mServer.getFileDescriptor(), temp, 0, MSG_LENGTH); } else if (cmd == CMD_CLOSE) { // Close and echo back to confirm - Os.fsync(mTarget); - Os.close(mTarget); + Os.fsync(mTarget.getFileDescriptor()); + mTarget.close(); mClosed = true; - IoBridge.write(mServer, temp, 0, MSG_LENGTH); + IoBridge.write(mServer.getFileDescriptor(), temp, 0, MSG_LENGTH); break; } } @@ -143,17 +144,11 @@ public class FileBridge extends Thread { mClient = clientPfd.getFileDescriptor(); } - public FileBridgeOutputStream(FileDescriptor client) { - mClientPfd = null; - mClient = client; - } - @Override public void close() throws IOException { try { writeCommandAndBlock(CMD_CLOSE, "close()"); } finally { - IoBridge.closeAndSignalBlockedThreads(mClient); IoUtils.closeQuietly(mClientPfd); } } diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java index 7b82b1a2e0d4..fe70a8803eb4 100644 --- a/core/java/android/os/Parcel.java +++ b/core/java/android/os/Parcel.java @@ -642,11 +642,11 @@ public final class Parcel { * {@link #dataPosition}. This is used to validate that the marshalled * transaction is intended for the target interface. */ - public final void writeInterfaceToken(String interfaceName) { + public final void writeInterfaceToken(@NonNull String interfaceName) { nativeWriteInterfaceToken(mNativePtr, interfaceName); } - public final void enforceInterface(String interfaceName) { + public final void enforceInterface(@NonNull String interfaceName) { nativeEnforceInterface(mNativePtr, interfaceName); } diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java index 52dd86554e91..2aa5c13e6e9f 100644 --- a/core/java/android/os/Process.java +++ b/core/java/android/os/Process.java @@ -851,12 +851,11 @@ public class Process { /** * Set the priority of a thread, based on Linux priorities. - * - * @param tid The identifier of the thread/process to change. It should be - * the native thread id but not the managed id of {@link java.lang.Thread}. + * + * @param tid The identifier of the thread/process to change. * @param priority A Linux priority level, from -20 for highest scheduling * priority to 19 for lowest scheduling priority. - * + * * @throws IllegalArgumentException Throws IllegalArgumentException if * <var>tid</var> does not exist. * @throws SecurityException Throws SecurityException if your process does diff --git a/core/java/android/permission/Permissions.md b/core/java/android/permission/Permissions.md index 1ef3ad211cee..2da1193c02ed 100644 --- a/core/java/android/permission/Permissions.md +++ b/core/java/android/permission/Permissions.md @@ -847,7 +847,7 @@ private val whitelistedPkgs = listOf("my.whitelisted.package") @Test fun onlySomeAppsAreAllowedToHavePermissionGranted() { - assertThat(whitelistedPkgs).containsAllIn( + assertThat(whitelistedPkgs).containsAtLeastElementsIn( context.packageManager.getInstalledPackages(MATCH_ALL) .filter { pkg -> context.checkPermission(android.Manifest.permission.MY_PRIVILEGED_PERMISSION, -1, diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 9ee88982f598..d9aae25065f6 100755 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -13278,6 +13278,7 @@ public final class Settings { * * @hide */ + @TestApi public static final String HIDDEN_API_POLICY = "hidden_api_policy"; /** diff --git a/core/java/android/text/format/DateFormat.java b/core/java/android/text/format/DateFormat.java index 38e3b39f8cfc..4a0bec1300b7 100755 --- a/core/java/android/text/format/DateFormat.java +++ b/core/java/android/text/format/DateFormat.java @@ -17,10 +17,14 @@ package android.text.format; import android.annotation.NonNull; +import android.app.compat.CompatChanges; +import android.compat.annotation.ChangeId; +import android.compat.annotation.EnabledAfter; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.icu.text.DateFormatSymbols; import android.icu.text.DateTimePatternGenerator; +import android.os.Build; import android.provider.Settings; import android.text.SpannableStringBuilder; import android.text.Spanned; @@ -159,6 +163,16 @@ public class DateFormat { private static boolean sIs24Hour; /** + * {@link #getBestDateTimePattern(Locale, String)} does not allow non-consecutive repeated + * symbol in the skeleton. For example, please use a skeleton of {@code "jmm"} or + * {@code "hmma"} instead of {@code "ahmma"} or {@code "jmma"}, because the field 'j' could + * mean using 12-hour in some locales and, in this case, is duplicated as the 'a' field. + */ + @ChangeId + @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R) + static final long DISALLOW_DUPLICATE_FIELD_IN_SKELETON = 170233598L; + + /** * Returns true if times should be formatted as 24 hour times, false if times should be * formatted as 12 hour (AM/PM) times. Based on the user's chosen locale and other preferences. * @param context the context to use for the content resolver @@ -251,7 +265,9 @@ public class DateFormat { */ public static String getBestDateTimePattern(Locale locale, String skeleton) { DateTimePatternGenerator dtpg = DateTimePatternGenerator.getInstance(locale); - return dtpg.getBestPattern(skeleton); + boolean allowDuplicateFields = !CompatChanges.isChangeEnabled( + DISALLOW_DUPLICATE_FIELD_IN_SKELETON); + return dtpg.getBestPattern(skeleton, allowDuplicateFields); } /** diff --git a/core/java/android/uwb/UwbAddress.java b/core/java/android/uwb/UwbAddress.java new file mode 100644 index 000000000000..48fcb10e1a1a --- /dev/null +++ b/core/java/android/uwb/UwbAddress.java @@ -0,0 +1,82 @@ +/* + * Copyright 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.uwb; + +import android.annotation.NonNull; +import android.annotation.Nullable; + +/** + * A class representing a UWB address + * + * @hide + */ +public final class UwbAddress { + public static final int SHORT_ADDRESS_BYTE_LENGTH = 2; + public static final int EXTENDED_ADDRESS_BYTE_LENGTH = 8; + + /** + * Create a {@link UwbAddress} from a byte array. + * + * <p>If the provided array is {@link #SHORT_ADDRESS_BYTE_LENGTH} bytes, a short address is + * created. If the provided array is {@link #EXTENDED_ADDRESS_BYTE_LENGTH} bytes, then an + * extended address is created. + * + * @param address a byte array to convert to a {@link UwbAddress} + * @return a {@link UwbAddress} created from the input byte array + * @throw IllegableArumentException when the length is not one of + * {@link #SHORT_ADDRESS_BYTE_LENGTH} or {@link #EXTENDED_ADDRESS_BYTE_LENGTH} bytes + */ + @NonNull + public static UwbAddress fromBytes(byte[] address) throws IllegalArgumentException { + throw new UnsupportedOperationException(); + } + + /** + * Get the address as a byte array + * + * @return the byte representation of this {@link UwbAddress} + */ + @NonNull + public byte[] toBytes() { + throw new UnsupportedOperationException(); + } + + /** + * The length of the address in bytes + * <p>Possible values are {@link #SHORT_ADDRESS_BYTE_LENGTH} and + * {@link #EXTENDED_ADDRESS_BYTE_LENGTH}. + */ + public int size() { + throw new UnsupportedOperationException(); + } + + @NonNull + @Override + public String toString() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean equals(@Nullable Object obj) { + throw new UnsupportedOperationException(); + } + + @Override + public int hashCode() { + throw new UnsupportedOperationException(); + } +} diff --git a/core/java/android/uwb/UwbManager.java b/core/java/android/uwb/UwbManager.java new file mode 100644 index 000000000000..8097dc6dca11 --- /dev/null +++ b/core/java/android/uwb/UwbManager.java @@ -0,0 +1,269 @@ +/* + * Copyright 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.uwb; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.SuppressLint; +import android.os.PersistableBundle; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.List; +import java.util.Set; +import java.util.concurrent.Executor; + +/** + * This class provides a way to perform Ultra Wideband (UWB) operations such as querying the + * device's capabilities and determining the distance and angle between the local device and a + * remote device. + * + * <p>To get a {@link UwbManager}, call the <code>Context.getSystemService(UwbManager.class)</code>. + * + * @hide + */ +public final class UwbManager { + /** + * Interface for receiving UWB adapter state changes + */ + public interface AdapterStateCallback { + @Retention(RetentionPolicy.SOURCE) + @IntDef(value = { + STATE_CHANGED_REASON_SESSION_STARTED, + STATE_CHANGED_REASON_ALL_SESSIONS_CLOSED, + STATE_CHANGED_REASON_SYSTEM_POLICY, + STATE_CHANGED_REASON_SYSTEM_BOOT, + STATE_CHANGED_REASON_ERROR_UNKNOWN}) + @interface StateChangedReason {} + + /** + * Indicates that the state change was due to opening of first UWB session + */ + int STATE_CHANGED_REASON_SESSION_STARTED = 0; + + /** + * Indicates that the state change was due to closure of all UWB sessions + */ + int STATE_CHANGED_REASON_ALL_SESSIONS_CLOSED = 1; + + /** + * Indicates that the state change was due to changes in system policy + */ + int STATE_CHANGED_REASON_SYSTEM_POLICY = 2; + + /** + * Indicates that the current state is due to a system boot + */ + int STATE_CHANGED_REASON_SYSTEM_BOOT = 3; + + /** + * Indicates that the state change was due to some unknown error + */ + int STATE_CHANGED_REASON_ERROR_UNKNOWN = 4; + + /** + * Invoked when underlying UWB adapter's state is changed + * <p>Invoked with the adapter's current state after registering an + * {@link AdapterStateCallback} using + * {@link UwbManager#registerAdapterStateCallback(Executor, AdapterStateCallback)}. + * + * <p>Possible values for the state to change are + * {@link #STATE_CHANGED_REASON_SESSION_STARTED}, + * {@link #STATE_CHANGED_REASON_ALL_SESSIONS_CLOSED}, + * {@link #STATE_CHANGED_REASON_SYSTEM_POLICY}, + * {@link #STATE_CHANGED_REASON_SYSTEM_BOOT}, + * {@link #STATE_CHANGED_REASON_ERROR_UNKNOWN}. + * + * @param isEnabled true when UWB adapter is enabled, false when it is disabled + * @param reason the reason for the state change + */ + void onStateChanged(boolean isEnabled, @StateChangedReason int reason); + } + + /** + * Use <code>Context.getSystemService(UwbManager.class)</code> to get an instance. + */ + private UwbManager() { + throw new UnsupportedOperationException(); + } + /** + * Register an {@link AdapterStateCallback} to listen for UWB adapter state changes + * <p>The provided callback will be invoked by the given {@link Executor}. + * + * <p>When first registering a callback, the callbacks's + * {@link AdapterStateCallback#onStateChanged(boolean, int)} is immediately invoked to indicate + * the current state of the underlying UWB adapter with the most recent + * {@link AdapterStateCallback.StateChangedReason} that caused the change. + * + * @param executor an {@link Executor} to execute given callback + * @param callback user implementation of the {@link AdapterStateCallback} + */ + public void registerAdapterStateCallback(Executor executor, AdapterStateCallback callback) { + throw new UnsupportedOperationException(); + } + + /** + * Unregister the specified {@link AdapterStateCallback} + * <p>The same {@link AdapterStateCallback} object used when calling + * {@link #registerAdapterStateCallback(Executor, AdapterStateCallback)} must be used. + * + * <p>Callbacks are automatically unregistered when application process goes away + * + * @param callback user implementation of the {@link AdapterStateCallback} + */ + public void unregisterAdapterStateCallback(AdapterStateCallback callback) { + throw new UnsupportedOperationException(); + } + + /** + * Get a {@link PersistableBundle} with the supported UWB protocols and parameters. + * <p>The {@link PersistableBundle} should be parsed using a support library + * + * <p>Android reserves the '^android.*' namespace</p> + * + * @return {@link PersistableBundle} of the device's supported UWB protocols and parameters + */ + @NonNull + public PersistableBundle getSpecificationInfo() { + throw new UnsupportedOperationException(); + } + + /** + * Check if ranging is supported, regardless of ranging method + * + * @return true if ranging is supported + */ + public boolean isRangingSupported() { + throw new UnsupportedOperationException(); + } + + @Retention(RetentionPolicy.SOURCE) + @IntDef(value = { + ANGLE_OF_ARRIVAL_SUPPORT_TYPE_NONE, + ANGLE_OF_ARRIVAL_SUPPORT_TYPE_2D, + ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_HEMISPHERICAL, + ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_SPHERICAL}) + public @interface AngleOfArrivalSupportType {} + + /** + * Indicate absence of support for angle of arrival measurement + */ + public static final int ANGLE_OF_ARRIVAL_SUPPORT_TYPE_NONE = 1; + + /** + * Indicate support for planar angle of arrival measurement, due to antenna + * limitation. Typically requires at least two antennas. + */ + public static final int ANGLE_OF_ARRIVAL_SUPPORT_TYPE_2D = 2; + + /** + * Indicate support for three dimensional angle of arrival measurement. + * Typically requires at least three antennas. However, due to antenna + * arrangement, a platform may only support hemi-spherical azimuth angles + * ranging from -pi/2 to pi/2 + */ + public static final int ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_HEMISPHERICAL = 2; + + /** + * Indicate support for three dimensional angle of arrival measurement. + * Typically requires at least three antennas. This mode supports full + * azimuth angles ranging from -pi to pi. + */ + public static final int ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_SPHERICAL = 3; + + + /** + * Gets the {@link AngleOfArrivalSupportType} supported on this platform + * <p>Possible return values are + * {@link #ANGLE_OF_ARRIVAL_SUPPORT_TYPE_NONE}, + * {@link #ANGLE_OF_ARRIVAL_SUPPORT_TYPE_2D}, + * {@link #ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_HEMISPHERICAL}, + * {@link #ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_SPHERICAL}. + * + * @return angle of arrival type supported + */ + @AngleOfArrivalSupportType + public int getAngleOfArrivalSupport() { + throw new UnsupportedOperationException(); + } + + /** + * Get a {@link List} of supported channel numbers based on the device's current location + * <p>The returned values are ordered by the system's desired ordered of use, with the first + * entry being the most preferred. + * + * <p>Channel numbers are defined based on the IEEE 802.15.4z standard for UWB. + * + * @return {@link List} of supported channel numbers ordered by preference + */ + @NonNull + public List<Integer> getSupportedChannelNumbers() { + throw new UnsupportedOperationException(); + } + + /** + * Get a {@link List} of supported preamble code indices + * <p> Preamble code indices are defined based on the IEEE 802.15.4z standard for UWB. + * + * @return {@link List} of supported preamble code indices + */ + @NonNull + public Set<Integer> getSupportedPreambleCodeIndices() { + throw new UnsupportedOperationException(); + } + + /** + * Get the timestamp resolution for events in nanoseconds + * <p>This value defines the maximum error of all timestamps for events reported to + * {@link RangingSession.Callback}. + * + * @return the timestamp resolution in nanoseconds + */ + @SuppressLint("MethodNameUnits") + public long elapsedRealtimeResolutionNanos() { + throw new UnsupportedOperationException(); + } + + /** + * Get the number of simultaneous sessions allowed in the system + * + * @return the maximum allowed number of simultaneously open {@link RangingSession} instances. + */ + public int getMaxSimultaneousSessions() { + throw new UnsupportedOperationException(); + } + + /** + * Get the maximum number of remote devices in a {@link RangingSession} when the local device + * is the initiator. + * + * @return the maximum number of remote devices per {@link RangingSession} + */ + public int getMaxRemoteDevicesPerInitiatorSession() { + throw new UnsupportedOperationException(); + } + + /** + * Get the maximum number of remote devices in a {@link RangingSession} when the local device + * is a responder. + * + * @return the maximum number of remote devices per {@link RangingSession} + */ + public int getMaxRemoteDevicesPerResponderSession() { + throw new UnsupportedOperationException(); + } +} diff --git a/core/java/com/android/ims/internal/uce/presence/PresCmdId.aidl b/core/java/com/android/ims/internal/uce/presence/PresCmdID.aidl index 6ece045ffcf7..6ece045ffcf7 100644 --- a/core/java/com/android/ims/internal/uce/presence/PresCmdId.aidl +++ b/core/java/com/android/ims/internal/uce/presence/PresCmdID.aidl diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index 4b661ca3ab80..236e67a1ea70 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -951,7 +951,7 @@ public class ChooserActivity extends ResolverActivity implements updateStickyContentPreview(); if (shouldShowStickyContentPreview() || mChooserMultiProfilePagerAdapter - .getCurrentRootAdapter().getContentPreviewRowCount() != 0) { + .getCurrentRootAdapter().getSystemRowCount() != 0) { logActionShareWithPreview(); } return postRebuildListInternal(rebuildCompleted); @@ -1316,13 +1316,14 @@ public class ChooserActivity extends ResolverActivity implements ViewGroup parent) { ViewGroup contentPreviewLayout = (ViewGroup) layoutInflater.inflate( R.layout.chooser_grid_preview_image, parent, false); + ViewGroup imagePreview = contentPreviewLayout.findViewById(R.id.content_preview_image_area); final ViewGroup actionRow = (ViewGroup) contentPreviewLayout.findViewById(R.id.chooser_action_row); //TODO: addActionButton(actionRow, createCopyButton()); addActionButton(actionRow, createNearbyButton(targetIntent)); - mPreviewCoord = new ContentPreviewCoordinator(contentPreviewLayout, true); + mPreviewCoord = new ContentPreviewCoordinator(contentPreviewLayout, false); String action = targetIntent.getAction(); if (Intent.ACTION_SEND.equals(action)) { @@ -1342,7 +1343,7 @@ public class ChooserActivity extends ResolverActivity implements if (imageUris.size() == 0) { Log.i(TAG, "Attempted to display image preview area with zero" + " available images detected in EXTRA_STREAM list"); - contentPreviewLayout.setVisibility(View.GONE); + imagePreview.setVisibility(View.GONE); return contentPreviewLayout; } @@ -2680,7 +2681,7 @@ public class ChooserActivity extends ResolverActivity implements final int bottomInset = mSystemWindowInsets != null ? mSystemWindowInsets.bottom : 0; int offset = bottomInset; - int rowsToShow = gridAdapter.getContentPreviewRowCount() + int rowsToShow = gridAdapter.getSystemRowCount() + gridAdapter.getProfileRowCount() + gridAdapter.getServiceTargetRowCount() + gridAdapter.getCallerAndRankedTargetRowCount(); @@ -3273,7 +3274,7 @@ public class ChooserActivity extends ResolverActivity implements public int getRowCount() { return (int) ( - getContentPreviewRowCount() + getSystemRowCount() + getProfileRowCount() + getServiceTargetRowCount() + getCallerAndRankedTargetRowCount() @@ -3289,7 +3290,7 @@ public class ChooserActivity extends ResolverActivity implements * content preview. Not to be confused with the sticky content preview which is above the * personal and work tabs. */ - public int getContentPreviewRowCount() { + public int getSystemRowCount() { // For the tabbed case we show the sticky content preview above the tabs, // please refer to shouldShowStickyContentPreview if (shouldShowTabs()) { @@ -3299,8 +3300,7 @@ public class ChooserActivity extends ResolverActivity implements return 0; } - if (mHideContentPreview || mChooserListAdapter == null - || mChooserListAdapter.getCount() == 0) { + if (mChooserListAdapter == null || mChooserListAdapter.getCount() == 0) { return 0; } @@ -3342,7 +3342,7 @@ public class ChooserActivity extends ResolverActivity implements @Override public int getItemCount() { return (int) ( - getContentPreviewRowCount() + getSystemRowCount() + getProfileRowCount() + getServiceTargetRowCount() + getCallerAndRankedTargetRowCount() @@ -3397,7 +3397,7 @@ public class ChooserActivity extends ResolverActivity implements public int getItemViewType(int position) { int count; - int countSum = (count = getContentPreviewRowCount()); + int countSum = (count = getSystemRowCount()); if (count > 0 && position < countSum) return VIEW_TYPE_CONTENT_PREVIEW; countSum += (count = getProfileRowCount()); @@ -3621,7 +3621,7 @@ public class ChooserActivity extends ResolverActivity implements } int getListPosition(int position) { - position -= getContentPreviewRowCount() + getProfileRowCount(); + position -= getSystemRowCount() + getProfileRowCount(); final int serviceCount = mChooserListAdapter.getServiceTargetCount(); final int serviceRows = (int) Math.ceil((float) serviceCount diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java index 233231cfcfdf..16991b472037 100644 --- a/core/java/com/android/internal/app/ResolverActivity.java +++ b/core/java/com/android/internal/app/ResolverActivity.java @@ -1281,7 +1281,7 @@ public class ResolverActivity extends Activity implements private void safelyStartActivityInternal(TargetInfo cti) { // If the target is suspended, the activity will not be successfully launched. // Do not unregister from package manager updates in this case - if (!cti.isSuspended()) { + if (!cti.isSuspended() && mRegistered) { if (mPersonalPackageMonitor != null) { mPersonalPackageMonitor.unregister(); } diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java index 095882ebe669..60f1b4438f54 100644 --- a/core/java/com/android/internal/os/RuntimeInit.java +++ b/core/java/com/android/internal/os/RuntimeInit.java @@ -36,7 +36,6 @@ import com.android.internal.logging.AndroidConfig; import com.android.server.NetworkManagementSocketTagger; import dalvik.system.RuntimeHooks; -import dalvik.system.ThreadPrioritySetter; import dalvik.system.VMRuntime; import libcore.content.type.MimeMap; @@ -208,7 +207,6 @@ public class RuntimeInit { */ public static void preForkInit() { if (DEBUG) Slog.d(TAG, "Entered preForkInit."); - RuntimeHooks.setThreadPrioritySetter(new RuntimeThreadPrioritySetter()); RuntimeInit.enableDdms(); // TODO(b/142019040#comment13): Decide whether to load the default instance eagerly, i.e. // MimeMap.setDefault(DefaultMimeMapFactory.create()); @@ -221,35 +219,6 @@ public class RuntimeInit { MimeMap.setDefaultSupplier(DefaultMimeMapFactory::create); } - private static class RuntimeThreadPrioritySetter implements ThreadPrioritySetter { - // Should remain consistent with kNiceValues[] in system/libartpalette/palette_android.cc - private static final int[] NICE_VALUES = { - Process.THREAD_PRIORITY_LOWEST, // 1 (MIN_PRIORITY) - Process.THREAD_PRIORITY_BACKGROUND + 6, - Process.THREAD_PRIORITY_BACKGROUND + 3, - Process.THREAD_PRIORITY_BACKGROUND, - Process.THREAD_PRIORITY_DEFAULT, // 5 (NORM_PRIORITY) - Process.THREAD_PRIORITY_DEFAULT - 2, - Process.THREAD_PRIORITY_DEFAULT - 4, - Process.THREAD_PRIORITY_URGENT_DISPLAY + 3, - Process.THREAD_PRIORITY_URGENT_DISPLAY + 2, - Process.THREAD_PRIORITY_URGENT_DISPLAY // 10 (MAX_PRIORITY) - }; - - @Override - public void setPriority(int nativeTid, int priority) { - // Check NICE_VALUES[] length first. - if (NICE_VALUES.length != (1 + Thread.MAX_PRIORITY - Thread.MIN_PRIORITY)) { - throw new AssertionError("Unexpected NICE_VALUES.length=" + NICE_VALUES.length); - } - // Priority should be in the range of MIN_PRIORITY (1) to MAX_PRIORITY (10). - if (priority < Thread.MIN_PRIORITY || priority > Thread.MAX_PRIORITY) { - throw new IllegalArgumentException("Priority out of range: " + priority); - } - Process.setThreadPriority(nativeTid, NICE_VALUES[priority - Thread.MIN_PRIORITY]); - } - } - @UnsupportedAppUsage protected static final void commonInit() { if (DEBUG) Slog.d(TAG, "Entered RuntimeInit!"); diff --git a/core/jni/Android.bp b/core/jni/Android.bp index f0f1b74c37b3..1968146099ae 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -315,4 +315,9 @@ cc_library_shared { cflags: ["-DANDROID_EXPERIMENTAL_MTE"], }, }, + + // Workaround Clang LTO crash. + lto: { + never: true, + }, } diff --git a/core/jni/android_os_HwParcel.cpp b/core/jni/android_os_HwParcel.cpp index ff336ee64b54..4c4443fc29c3 100644 --- a/core/jni/android_os_HwParcel.cpp +++ b/core/jni/android_os_HwParcel.cpp @@ -990,6 +990,8 @@ static jobject JHwParcel_native_readStrongBinder(JNIEnv *env, jobject thiz) { } if (!validateCanUseHwBinder(binder)) { + jniThrowException(env, "java/lang/IllegalArgumentException", + "Local binder is not supported in Java"); return nullptr; } diff --git a/core/jni/android_os_Parcel.cpp b/core/jni/android_os_Parcel.cpp index 9ae3d160be98..9c7ee0c641a6 100644 --- a/core/jni/android_os_Parcel.cpp +++ b/core/jni/android_os_Parcel.cpp @@ -638,50 +638,77 @@ static jboolean android_os_Parcel_hasFileDescriptors(jlong nativePtr) return ret; } +// String tries to allocate itself on the stack, within a known size, but will +// make a heap allocation if not. +template <size_t StackReserve> +class StackString { +public: + StackString(JNIEnv* env, jstring str) : mEnv(env), mJStr(str) { + LOG_ALWAYS_FATAL_IF(str == nullptr); + mSize = env->GetStringLength(str); + if (mSize > StackReserve) { + mStr = new jchar[mSize]; + } else { + mStr = &mBuffer[0]; + } + mEnv->GetStringRegion(str, 0, mSize, mStr); + } + ~StackString() { + if (mStr != &mBuffer[0]) { + delete[] mStr; + } + } + const jchar* str() { return mStr; } + jsize size() { return mSize; } + +private: + JNIEnv* mEnv; + jstring mJStr; + + jchar mBuffer[StackReserve]; + // pointer to &mBuffer[0] if string fits in mBuffer, otherwise owned + jchar* mStr; + jsize mSize; +}; + +// This size is chosen to be longer than most interface descriptors. +// Ones longer than this will be allocated on the heap. +typedef StackString<64> InterfaceDescriptorString; + static void android_os_Parcel_writeInterfaceToken(JNIEnv* env, jclass clazz, jlong nativePtr, jstring name) { Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr); - if (parcel != NULL) { - // In the current implementation, the token is just the serialized interface name that - // the caller expects to be invoking - const jchar* str = env->GetStringCritical(name, 0); - if (str != NULL) { - parcel->writeInterfaceToken(String16( - reinterpret_cast<const char16_t*>(str), - env->GetStringLength(name))); - env->ReleaseStringCritical(name, str); - } + if (parcel != nullptr) { + InterfaceDescriptorString descriptor(env, name); + parcel->writeInterfaceToken(reinterpret_cast<const char16_t*>(descriptor.str()), + descriptor.size()); } } static void android_os_Parcel_enforceInterface(JNIEnv* env, jclass clazz, jlong nativePtr, jstring name) { Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr); - if (parcel != NULL) { - const jchar* str = env->GetStringCritical(name, 0); - if (str) { - IPCThreadState* threadState = IPCThreadState::self(); - const int32_t oldPolicy = threadState->getStrictModePolicy(); - const bool isValid = parcel->enforceInterface( - reinterpret_cast<const char16_t*>(str), - env->GetStringLength(name), - threadState); - env->ReleaseStringCritical(name, str); - if (isValid) { - const int32_t newPolicy = threadState->getStrictModePolicy(); - if (oldPolicy != newPolicy) { - // Need to keep the Java-level thread-local strict - // mode policy in sync for the libcore - // enforcements, which involves an upcall back - // into Java. (We can't modify the - // Parcel.enforceInterface signature, as it's - // pseudo-public, and used via AIDL - // auto-generation...) - set_dalvik_blockguard_policy(env, newPolicy); - } - return; // everything was correct -> return silently + if (parcel != nullptr) { + InterfaceDescriptorString descriptor(env, name); + IPCThreadState* threadState = IPCThreadState::self(); + const int32_t oldPolicy = threadState->getStrictModePolicy(); + const bool isValid = + parcel->enforceInterface(reinterpret_cast<const char16_t*>(descriptor.str()), + descriptor.size(), threadState); + if (isValid) { + const int32_t newPolicy = threadState->getStrictModePolicy(); + if (oldPolicy != newPolicy) { + // Need to keep the Java-level thread-local strict + // mode policy in sync for the libcore + // enforcements, which involves an upcall back + // into Java. (We can't modify the + // Parcel.enforceInterface signature, as it's + // pseudo-public, and used via AIDL + // auto-generation...) + set_dalvik_blockguard_policy(env, newPolicy); } + return; // everything was correct -> return silently } } diff --git a/core/jni/android_view_InputEventReceiver.cpp b/core/jni/android_view_InputEventReceiver.cpp index cc94d6ff5d67..4220c1d87087 100644 --- a/core/jni/android_view_InputEventReceiver.cpp +++ b/core/jni/android_view_InputEventReceiver.cpp @@ -321,7 +321,7 @@ status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env, jboolean(focusEvent->getHasFocus()), jboolean(focusEvent->getInTouchMode())); finishInputEvent(seq, true /* handled */); - return OK; + continue; } default: diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index dadf08f2cc90..95c295a4784c 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -80,6 +80,7 @@ #include <bionic/mte.h> #include <bionic/mte_kernel.h> #include <cutils/fs.h> +#include <cutils/memory.h> #include <cutils/multiuser.h> #include <cutils/sockets.h> #include <private/android_filesystem_config.h> @@ -647,6 +648,13 @@ static void PreApplicationInit() { // Set the jemalloc decay time to 1. mallopt(M_DECAY_TIME, 1); + + // Avoid potentially expensive memory mitigations, mostly meant for system + // processes, in apps. These may cause app compat problems, use more memory, + // or reduce performance. While it would be nice to have them for apps, + // we will have to wait until they are proven out, have more efficient + // hardware, and/or apply them only to new applications. + process_disable_memory_mitigations(); } static void SetUpSeccompFilter(uid_t uid, bool is_child_zygote) { diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 8656820c4ea2..48275f656b2f 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -511,6 +511,7 @@ <protected-broadcast android:name="android.telecom.action.NUISANCE_CALL_STATUS_CHANGED" /> <protected-broadcast android:name="android.telecom.action.PHONE_ACCOUNT_REGISTERED" /> <protected-broadcast android:name="android.telecom.action.PHONE_ACCOUNT_UNREGISTERED" /> + <protected-broadcast android:name="android.telecom.action.POST_CALL" /> <protected-broadcast android:name="android.telecom.action.SHOW_MISSED_CALLS_NOTIFICATION" /> <protected-broadcast android:name="android.telephony.action.CARRIER_CONFIG_CHANGED" /> <protected-broadcast android:name="android.telephony.action.DEFAULT_SUBSCRIPTION_CHANGED" /> @@ -2150,7 +2151,7 @@ <permission android:name="android.permission.READ_PRECISE_PHONE_STATE" android:protectionLevel="signature|privileged" /> - <!-- @SystemApi Allows read access to privileged phone state. + <!-- @SystemApi @TestApi Allows read access to privileged phone state. @hide Used internally. --> <permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" android:protectionLevel="signature|privileged" /> @@ -2682,6 +2683,14 @@ <permission android:name="android.permission.SUGGEST_MANUAL_TIME_AND_ZONE" android:protectionLevel="signature" /> + <!-- Allows applications like settings to manage configuration associated with automatic time + and time zone detection. + <p>Not for use by third-party applications. + @hide + --> + <permission android:name="android.permission.MANAGE_TIME_AND_ZONE_DETECTION" + android:protectionLevel="signature|privileged" /> + <!-- ==================================================== --> <!-- Permissions related to changing status bar --> <!-- ==================================================== --> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index e0b58dd83981..2284dc8db0ef 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -1663,6 +1663,21 @@ --> </string-array> + <!-- Optional IPsec algorithms enabled by this device, defaulting to empty. OEMs can override + it by providing a list of algorithm names in an overlay config.xml file. + + As Android releases new versions, more algorithms are becoming mandatory. Mandatory + algorithms will be automatically enabled on the device. Optional algorithms need + to be explicitly declared in this resource to be enabled. + * SDK level 28 makes the following algorithms mandatory : "cbc(aes)", "hmac(md5)", + "hmac(sha1)", "hmac(sha256)", "hmac(sha384)", "hmac(sha512)", "rfc4106(gcm(aes))" + * SDK level 30 makes the following algorithms mandatory : "rfc3686(ctr(aes))", + "xcbc(aes)", "rfc7539esp(chacha20,poly1305)" + --> + <string-array name="config_optionalIpSecAlgorithms" translatable="false"> + <!-- Add algorithm here --> + </string-array> + <!-- Boolean indicating if current platform supports bluetooth SCO for off call use cases --> <bool name="config_bluetooth_sco_off_call">true</bool> @@ -1780,6 +1795,9 @@ Note: This config is deprecated, please use config_defaultSms instead. --> <string name="default_sms_application" translatable="false">com.android.messaging</string> + <!-- Flag indicating whether the current device supports "Ask every time" for sms--> + <bool name="config_sms_ask_every_time_support">true</bool> + <!-- Flag indicating whether the current device allows data. If true, this means that the device supports data connectivity through the telephony network. diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index b130b91b2cd2..90667791ac8a 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -312,6 +312,7 @@ <java-symbol type="bool" name="config_networkSamplingWakesDevice" /> <java-symbol type="bool" name="config_showMenuShortcutsWhenKeyboardPresent" /> <java-symbol type="bool" name="config_sip_wifi_only" /> + <java-symbol type="bool" name="config_sms_ask_every_time_support" /> <java-symbol type="bool" name="config_sms_capable" /> <java-symbol type="bool" name="config_sms_utf8_support" /> <java-symbol type="bool" name="config_mobile_data_capable" /> @@ -3185,6 +3186,9 @@ <!-- Network Recommendation --> <java-symbol type="string" name="config_defaultNetworkRecommendationProviderPackage" /> + <!-- Optional IPsec algorithms --> + <java-symbol type="array" name="config_optionalIpSecAlgorithms" /> + <!-- Whether allow 3rd party apps on internal storage. --> <java-symbol type="bool" name="config_allow3rdPartyAppOnInternal" /> diff --git a/core/sysprop/Android.bp b/core/sysprop/Android.bp index 7f20a0ba6642..237ede2006ea 100644 --- a/core/sysprop/Android.bp +++ b/core/sysprop/Android.bp @@ -19,3 +19,11 @@ sysprop_library { api_packages: ["android.sysprop"], vendor_available: false, } + +sysprop_library { + name: "com.android.sysprop.watchdog", + srcs: ["WatchdogProperties.sysprop"], + property_owner: "Platform", + api_packages: ["android.sysprop"], + vendor_available: false, +} diff --git a/core/sysprop/WatchdogProperties.sysprop b/core/sysprop/WatchdogProperties.sysprop new file mode 100644 index 000000000000..1bcc773a9a5d --- /dev/null +++ b/core/sysprop/WatchdogProperties.sysprop @@ -0,0 +1,45 @@ +# 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. + +module: "android.sysprop.WatchdogProperties" +owner: Platform + +# To escape the watchdog timeout loop, fatal reboot the system when +# watchdog timed out 'fatal_count' times in 'fatal_window_second' +# seconds, if both values are not 0. Default value of both is 0. +prop { + api_name: "fatal_count" + type: Integer + prop_name: "framework_watchdog.fatal_count" + scope: Internal + access: Readonly +} + +prop { + api_name: "fatal_window_second" + type: Integer + prop_name: "framework_watchdog.fatal_window.second" + scope: Internal + access: Readonly +} + +# The fatal counting can be disabled by setting property +# 'is_fatal_ignore' to true. +prop { + api_name: "is_fatal_ignore" + type: Boolean + prop_name: "persist.debug.framework_watchdog.fatal_ignore" + scope: Internal + access: Readonly +} diff --git a/core/sysprop/api/com.android.sysprop.localization-current.txt b/core/sysprop/api/com.android.sysprop.localization-current.txt index fe4f4578683c..e69de29bb2d1 100644 --- a/core/sysprop/api/com.android.sysprop.localization-current.txt +++ b/core/sysprop/api/com.android.sysprop.localization-current.txt @@ -1,9 +0,0 @@ -props { - module: "android.sysprop.LocalizationProperties" - prop { - api_name: "locale_filter" - type: String - scope: Internal - prop_name: "ro.localization.locale_filter" - } -} diff --git a/core/sysprop/api/com.android.sysprop.watchdog-current.txt b/core/sysprop/api/com.android.sysprop.watchdog-current.txt new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/core/sysprop/api/com.android.sysprop.watchdog-current.txt diff --git a/core/sysprop/api/com.android.sysprop.watchdog-latest.txt b/core/sysprop/api/com.android.sysprop.watchdog-latest.txt new file mode 100644 index 000000000000..d901aef945c9 --- /dev/null +++ b/core/sysprop/api/com.android.sysprop.watchdog-latest.txt @@ -0,0 +1,20 @@ +props { + module: "android.sysprop.WatchdogProperties" + prop { + api_name: "fatal_count" + type: Integer + scope: Internal + prop_name: "framework_watchdog.fatal_count" + } + prop { + api_name: "fatal_window_second" + type: Integer + scope: Internal + prop_name: "framework_watchdog.fatal_window.second" + } + prop { + api_name: "is_fatal_ignore" + scope: Internal + prop_name: "persist.debug.framework_watchdog.fatal_ignore" + } +} diff --git a/core/tests/coretests/src/android/app/NotificationHistoryTest.java b/core/tests/coretests/src/android/app/NotificationHistoryTest.java index c9510918e555..20ac83173ff2 100644 --- a/core/tests/coretests/src/android/app/NotificationHistoryTest.java +++ b/core/tests/coretests/src/android/app/NotificationHistoryTest.java @@ -117,8 +117,8 @@ public class NotificationHistoryTest { history.addNotificationToWrite(n); assertThat(history.getNotificationsToWrite().size()).isEqualTo(2); - assertThat(history.getNotificationsToWrite().get(0)).isSameAs(n2); - assertThat(history.getNotificationsToWrite().get(1)).isSameAs(n); + assertThat(history.getNotificationsToWrite().get(0)).isSameInstanceAs(n2); + assertThat(history.getNotificationsToWrite().get(1)).isSameInstanceAs(n); assertThat(history.getHistoryCount()).isEqualTo(2); } @@ -141,11 +141,11 @@ public class NotificationHistoryTest { history.addNotificationsToWrite(secondHistory); assertThat(history.getNotificationsToWrite().size()).isEqualTo(5); - assertThat(history.getNotificationsToWrite().get(0)).isSameAs(n3); - assertThat(history.getNotificationsToWrite().get(1)).isSameAs(n); - assertThat(history.getNotificationsToWrite().get(2)).isSameAs(n4); - assertThat(history.getNotificationsToWrite().get(3)).isSameAs(n2); - assertThat(history.getNotificationsToWrite().get(4)).isSameAs(n5); + assertThat(history.getNotificationsToWrite().get(0)).isSameInstanceAs(n3); + assertThat(history.getNotificationsToWrite().get(1)).isSameInstanceAs(n); + assertThat(history.getNotificationsToWrite().get(2)).isSameInstanceAs(n4); + assertThat(history.getNotificationsToWrite().get(3)).isSameInstanceAs(n2); + assertThat(history.getNotificationsToWrite().get(4)).isSameInstanceAs(n5); assertThat(history.getHistoryCount()).isEqualTo(5); assertThat(history.getPooledStringsToWrite()).asList().contains(n2.getChannelName()); diff --git a/core/tests/coretests/src/android/content/integrity/CompoundFormulaTest.java b/core/tests/coretests/src/android/content/integrity/CompoundFormulaTest.java index ba060fa630c5..593e70e6b257 100644 --- a/core/tests/coretests/src/android/content/integrity/CompoundFormulaTest.java +++ b/core/tests/coretests/src/android/content/integrity/CompoundFormulaTest.java @@ -45,7 +45,8 @@ public class CompoundFormulaTest { CompoundFormula.AND, Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2)); assertThat(compoundFormula.getConnector()).isEqualTo(CompoundFormula.AND); - assertThat(compoundFormula.getFormulas()).containsAllOf(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2); + assertThat(compoundFormula.getFormulas()) + .containsAtLeast(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2); } @Test diff --git a/core/tests/coretests/src/android/content/pm/parsing/result/ParseInputAndResultTest.kt b/core/tests/coretests/src/android/content/pm/parsing/result/ParseInputAndResultTest.kt index d45fee97950f..9ad63adda6b7 100644 --- a/core/tests/coretests/src/android/content/pm/parsing/result/ParseInputAndResultTest.kt +++ b/core/tests/coretests/src/android/content/pm/parsing/result/ParseInputAndResultTest.kt @@ -113,7 +113,7 @@ class ParseInputAndResultTest { assertError(result) assertThat(result.errorCode).isEqualTo(errorCode) assertThat(result.errorMessage).isEqualTo(errorMessage) - assertThat(result.exception).isSameAs(exception) + assertThat(result.exception).isSameInstanceAs(exception) } @Test @@ -125,13 +125,13 @@ class ParseInputAndResultTest { assertError(result) assertThat(result.errorCode).isEqualTo(errorCode) assertThat(result.errorMessage).isEqualTo(errorMessage) - assertThat(result.exception).isSameAs(exception) + assertThat(result.exception).isSameInstanceAs(exception) val carriedResult = input.error<Int>(result) assertError(carriedResult) assertThat(carriedResult.errorCode).isEqualTo(errorCode) assertThat(carriedResult.errorMessage).isEqualTo(errorMessage) - assertThat(carriedResult.exception).isSameAs(exception) + assertThat(carriedResult.exception).isSameInstanceAs(exception) } @Test @@ -259,7 +259,7 @@ class ParseInputAndResultTest { private fun assertSuccess(expected: Any? = null, result: ParseResult<*>) { assertThat(result.isError).isFalse() assertThat(result.isSuccess).isTrue() - assertThat(result.result).isSameAs(expected) + assertThat(result.result).isSameInstanceAs(expected) assertThat(result.errorCode).isEqualTo(PackageManager.INSTALL_SUCCEEDED) assertThat(result.errorMessage).isNull() assertThat(result.exception).isNull() diff --git a/core/tests/coretests/src/android/os/FileBridgeTest.java b/core/tests/coretests/src/android/os/FileBridgeTest.java index d4f6b1fcec4e..708bfa6ece2e 100644 --- a/core/tests/coretests/src/android/os/FileBridgeTest.java +++ b/core/tests/coretests/src/android/os/FileBridgeTest.java @@ -16,6 +16,9 @@ package android.os; +import static android.os.ParcelFileDescriptor.MODE_CREATE; +import static android.os.ParcelFileDescriptor.MODE_READ_WRITE; + import android.os.FileBridge.FileBridgeOutputStream; import android.test.AndroidTestCase; import android.test.MoreAsserts; @@ -25,7 +28,6 @@ import libcore.io.Streams; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; -import java.io.FileOutputStream; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.Random; @@ -33,7 +35,7 @@ import java.util.Random; public class FileBridgeTest extends AndroidTestCase { private File file; - private FileOutputStream fileOs; + private ParcelFileDescriptor outputFile; private FileBridge bridge; private FileBridgeOutputStream client; @@ -44,17 +46,17 @@ public class FileBridgeTest extends AndroidTestCase { file = getContext().getFileStreamPath("meow.dat"); file.delete(); - fileOs = new FileOutputStream(file); + outputFile = ParcelFileDescriptor.open(file, MODE_CREATE | MODE_READ_WRITE); bridge = new FileBridge(); - bridge.setTargetFile(fileOs.getFD()); + bridge.setTargetFile(outputFile); bridge.start(); client = new FileBridgeOutputStream(bridge.getClientSocket()); } @Override protected void tearDown() throws Exception { - fileOs.close(); + outputFile.close(); file.delete(); } diff --git a/core/tests/coretests/src/android/text/format/DateFormatTest.java b/core/tests/coretests/src/android/text/format/DateFormatTest.java index a3434e885012..212cc44eefab 100644 --- a/core/tests/coretests/src/android/text/format/DateFormatTest.java +++ b/core/tests/coretests/src/android/text/format/DateFormatTest.java @@ -21,13 +21,19 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import android.compat.testing.PlatformCompatChangeRule; import android.icu.text.DateFormatSymbols; import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges; +import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges; + +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.TestRule; import org.junit.runner.RunWith; import java.util.Arrays; @@ -38,6 +44,9 @@ import java.util.Locale; @RunWith(AndroidJUnit4.class) public class DateFormatTest { + @Rule + public TestRule compatChangeRule = new PlatformCompatChangeRule(); + @Test public void testHasDesignator() { assertTrue(DateFormat.hasDesignator("hh:mm:ss", DateFormat.MINUTE)); @@ -135,4 +144,29 @@ public class DateFormatTest { private static String best(Locale l, String skeleton) { return DateFormat.getBestDateTimePattern(l, skeleton); } + + @Test + @EnableCompatChanges({DateFormat.DISALLOW_DUPLICATE_FIELD_IN_SKELETON}) + public void testGetBestDateTimePattern_disableDuplicateField() { + assertIllegalArgumentException(Locale.US, "jmma"); + assertIllegalArgumentException(Locale.US, "ahmma"); + } + + @Test + @DisableCompatChanges({DateFormat.DISALLOW_DUPLICATE_FIELD_IN_SKELETON}) + public void testGetBestDateTimePattern_enableDuplicateField() { + // en-US uses 12-hour format by default. + assertEquals("h:mm a", DateFormat.getBestDateTimePattern(Locale.US, "jmma")); + assertEquals("h:mm a", DateFormat.getBestDateTimePattern(Locale.US, "ahmma")); + } + + private static void assertIllegalArgumentException(Locale l, String skeleton) { + try { + DateFormat.getBestDateTimePattern(l, skeleton); + fail("getBestDateTimePattern() does not fail with Locale: " + l + + " skeleton: " + skeleton); + } catch (IllegalArgumentException expected) { + // ignored + } + } } diff --git a/core/tests/coretests/src/android/text/format/OWNERS b/core/tests/coretests/src/android/text/format/OWNERS new file mode 100644 index 000000000000..32adc12bb901 --- /dev/null +++ b/core/tests/coretests/src/android/text/format/OWNERS @@ -0,0 +1,3 @@ +# Inherits OWNERS from parent directory, plus the following + +vichang@google.com diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java index 628252d8ca6c..402b92a3f2a2 100644 --- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java +++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java @@ -52,7 +52,8 @@ public class TextClassificationManagerTest { @Test public void testGetLocalTextClassifier() { - assertThat(mTcm.getTextClassifier(TextClassifier.LOCAL)).isSameAs(TextClassifier.NO_OP); + assertThat(mTcm.getTextClassifier(TextClassifier.LOCAL)) + .isSameInstanceAs(TextClassifier.NO_OP); } @Test diff --git a/core/tests/coretests/src/com/android/internal/infra/AndroidFutureTest.java b/core/tests/coretests/src/com/android/internal/infra/AndroidFutureTest.java index f108eb8aeb0b..a2bc77a71c90 100644 --- a/core/tests/coretests/src/com/android/internal/infra/AndroidFutureTest.java +++ b/core/tests/coretests/src/com/android/internal/infra/AndroidFutureTest.java @@ -81,7 +81,7 @@ public class AndroidFutureTest { future.completeExceptionally(origException); ExecutionException executionException = expectThrows(ExecutionException.class, future::get); - assertThat(executionException.getCause()).isSameAs(origException); + assertThat(executionException.getCause()).isSameInstanceAs(origException); } @Test @@ -92,7 +92,7 @@ public class AndroidFutureTest { CountDownLatch latch = new CountDownLatch(1); future.whenComplete((obj, err) -> { assertThat(obj).isNull(); - assertThat(err).isSameAs(origException); + assertThat(err).isSameInstanceAs(origException); latch.countDown(); }); latch.await(); diff --git a/core/tests/coretests/src/com/android/internal/os/BinderDeathDispatcherTest.java b/core/tests/coretests/src/com/android/internal/os/BinderDeathDispatcherTest.java index 59148870fa3c..942045c8bf35 100644 --- a/core/tests/coretests/src/com/android/internal/os/BinderDeathDispatcherTest.java +++ b/core/tests/coretests/src/com/android/internal/os/BinderDeathDispatcherTest.java @@ -107,7 +107,7 @@ public class BinderDeathDispatcherTest { if (!isAlive) { return false; } - assertThat(mRecipient).isSameAs(recipient); + assertThat(mRecipient).isSameInstanceAs(recipient); mRecipient = null; return true; } diff --git a/core/tests/coretests/src/com/android/internal/statusbar/RegisterStatusBarResultTest.java b/core/tests/coretests/src/com/android/internal/statusbar/RegisterStatusBarResultTest.java index 9f68ef31c166..7eca320d4aeb 100644 --- a/core/tests/coretests/src/com/android/internal/statusbar/RegisterStatusBarResultTest.java +++ b/core/tests/coretests/src/com/android/internal/statusbar/RegisterStatusBarResultTest.java @@ -74,7 +74,7 @@ public class RegisterStatusBarResultTest { assertThat(copy.mImeBackDisposition).isEqualTo(original.mImeBackDisposition); assertThat(copy.mShowImeSwitcher).isEqualTo(original.mShowImeSwitcher); assertThat(copy.mDisabledFlags2).isEqualTo(original.mDisabledFlags2); - assertThat(copy.mImeToken).isSameAs(original.mImeToken); + assertThat(copy.mImeToken).isSameInstanceAs(original.mImeToken); assertThat(copy.mNavbarColorManagedByIme).isEqualTo(original.mNavbarColorManagedByIme); assertThat(copy.mAppFullscreen).isEqualTo(original.mAppFullscreen); assertThat(copy.mAppImmersive).isEqualTo(original.mAppImmersive); diff --git a/core/xsd/vts/Android.bp b/core/xsd/vts/Android.bp index 4b43b4136076..ca655f18149c 100644 --- a/core/xsd/vts/Android.bp +++ b/core/xsd/vts/Android.bp @@ -40,7 +40,3 @@ cc_test { ], test_config: "vts_permission_validate_test.xml", } - -vts_config { - name: "VtsValidatePermission", -} diff --git a/core/xsd/vts/AndroidTest.xml b/core/xsd/vts/AndroidTest.xml deleted file mode 100644 index e5cc9a0f74ee..000000000000 --- a/core/xsd/vts/AndroidTest.xml +++ /dev/null @@ -1,30 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2019 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> -<configuration description="Config for VTS VtsValidatePermission."> - <option name="config-descriptor:metadata" key="plan" value="vts-treble" /> - <target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher"> - <option name="abort-on-push-failure" value="false"/> - <option name="push-group" value="HostDrivenTest.push"/> - <option name="push" value="DATA/etc/permission.xsd->/data/local/tmp/permission.xsd"/> - </target_preparer> - <test class="com.android.tradefed.testtype.VtsMultiDeviceTest"> - <option name="test-module-name" value="VtsValidatePermission"/> - <option name="binary-test-source" value="_32bit::DATA/nativetest/vts_permission_validate_test/vts_permission_validate_test" /> - <option name="binary-test-source" value="_64bit::DATA/nativetest64/vts_permission_validate_test/vts_permission_validate_test" /> - <option name="binary-test-type" value="gtest"/> - <option name="test-timeout" value="30s"/> - </test> -</configuration> diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml index 672b428d1623..0a9e50eb92dd 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -427,6 +427,8 @@ applications that come with the platform <permission name="android.permission.CAPTURE_AUDIO_OUTPUT" /> <!-- Permissions required for CTS test - AdbManagerTest --> <permission name="android.permission.MANAGE_DEBUGGING" /> + <!-- Permissions required for CTS test - TimeManagerTest --> + <permission name="android.permission.MANAGE_TIME_AND_ZONE_DETECTION" /> </privapp-permissions> <privapp-permissions package="com.android.statementservice"> diff --git a/data/keyboards/Vendor_2378_Product_1008.kl b/data/keyboards/Vendor_2378_Product_1008.kl index 478da03b9a78..7b19469ab6b4 100644 --- a/data/keyboards/Vendor_2378_Product_1008.kl +++ b/data/keyboards/Vendor_2378_Product_1008.kl @@ -14,6 +14,10 @@ # OnLive, Inc. OnLive Wireless Controller, USB adapter +key 164 MEDIA_PLAY_PAUSE +key 167 MEDIA_RECORD +key 168 MEDIA_REWIND +key 208 MEDIA_FAST_FORWARD key 304 BUTTON_A key 305 BUTTON_B key 307 BUTTON_X @@ -22,6 +26,7 @@ key 310 BUTTON_L1 key 311 BUTTON_R1 key 315 BUTTON_START key 314 BUTTON_SELECT +key 316 BUTTON_MODE key 317 BUTTON_THUMBL key 318 BUTTON_THUMBR diff --git a/data/keyboards/Vendor_2378_Product_100a.kl b/data/keyboards/Vendor_2378_Product_100a.kl index d9cd17120464..cb2b73afee3d 100644 --- a/data/keyboards/Vendor_2378_Product_100a.kl +++ b/data/keyboards/Vendor_2378_Product_100a.kl @@ -14,6 +14,10 @@ # OnLive, Inc. OnLive Wireless Controller +key 164 MEDIA_PLAY_PAUSE +key 167 MEDIA_RECORD +key 168 MEDIA_REWIND +key 208 MEDIA_FAST_FORWARD key 304 BUTTON_A key 305 BUTTON_B key 307 BUTTON_X @@ -22,6 +26,7 @@ key 310 BUTTON_L1 key 311 BUTTON_R1 key 315 BUTTON_START key 314 BUTTON_SELECT +key 316 BUTTON_MODE key 317 BUTTON_THUMBL key 318 BUTTON_THUMBR diff --git a/libs/hwui/service/GraphicsStatsService.cpp b/libs/hwui/service/GraphicsStatsService.cpp index 644d5fbd5bf9..e4198017aee0 100644 --- a/libs/hwui/service/GraphicsStatsService.cpp +++ b/libs/hwui/service/GraphicsStatsService.cpp @@ -559,6 +559,7 @@ void GraphicsStatsService::finishDumpInMemory(Dump* dump, AStatsEventList* data, AStatsEvent_writeBool(event, !lastFullDay); AStatsEvent_build(event); } + delete dump; } diff --git a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java index 67a040dba3e7..139474c1c01d 100644 --- a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java +++ b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java @@ -28,7 +28,6 @@ import android.location.LocationManager; import android.os.RemoteException; import android.os.SystemClock; import android.os.UserHandle; -import android.telephony.PhoneNumberUtils; import android.telephony.PhoneStateListener; import android.telephony.TelephonyManager; import android.util.Log; @@ -161,7 +160,7 @@ public class GpsNetInitiatedHandler { be set to true when the phone is having emergency call, and then will be set to false by mPhoneStateListener when the emergency call ends. */ - mIsInEmergencyCall = PhoneNumberUtils.isEmergencyNumber(phoneNumber); + mIsInEmergencyCall = mTelephonyManager.isEmergencyNumber(phoneNumber); if (DEBUG) Log.v(TAG, "ACTION_NEW_OUTGOING_CALL - " + getInEmergency()); } else if (action.equals(LocationManager.MODE_CHANGED_ACTION)) { updateLocationMode(); diff --git a/media/OWNERS b/media/OWNERS index 36df3a05e0ee..e74149019b11 100644 --- a/media/OWNERS +++ b/media/OWNERS @@ -1,4 +1,3 @@ -andrewlewis@google.com chz@google.com elaurent@google.com essick@google.com @@ -15,6 +14,15 @@ jsharkey@android.com klhyun@google.com lajos@google.com marcone@google.com +nchalko@google.com philburk@google.com -sungsoo@google.com +quxiangfang@google.com wonsik@google.com + +# LON +andrewlewis@google.com +aquilescanta@google.com +olly@google.com + +# SEO +sungsoo@google.com diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java index 1c0a526f536c..eff56f3d8c19 100644 --- a/media/java/android/media/AudioTrack.java +++ b/media/java/android/media/AudioTrack.java @@ -1261,14 +1261,20 @@ public class AudioTrack extends PlayerBase // TODO: Check mEncapsulationMode compatibility with MODE_STATIC, etc? - try { - // If the buffer size is not specified in streaming mode, - // use a single frame for the buffer size and let the - // native code figure out the minimum buffer size. - if (mMode == MODE_STREAM && mBufferSizeInBytes == 0) { - mBufferSizeInBytes = mFormat.getChannelCount() - * mFormat.getBytesPerSample(mFormat.getEncoding()); + // If the buffer size is not specified in streaming mode, + // use a single frame for the buffer size and let the + // native code figure out the minimum buffer size. + if (mMode == MODE_STREAM && mBufferSizeInBytes == 0) { + int bytesPerSample = 1; + try { + bytesPerSample = mFormat.getBytesPerSample(mFormat.getEncoding()); + } catch (IllegalArgumentException e) { + // do nothing } + mBufferSizeInBytes = mFormat.getChannelCount() * bytesPerSample; + } + + try { final AudioTrack track = new AudioTrack( mAttributes, mFormat, mBufferSizeInBytes, mMode, mSessionId, mOffload, mEncapsulationMode, mTunerConfiguration); diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java index c75296c73a90..9deeb8fbab16 100644 --- a/media/java/android/media/RingtoneManager.java +++ b/media/java/android/media/RingtoneManager.java @@ -34,6 +34,7 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.UserInfo; import android.content.res.AssetFileDescriptor; import android.database.Cursor; +import android.database.StaleDataException; import android.net.Uri; import android.os.Environment; import android.os.FileUtils; @@ -492,7 +493,12 @@ public class RingtoneManager { public Uri getRingtoneUri(int position) { // use cursor directly instead of requerying it, which could easily // cause position to shuffle. - if (mCursor == null || !mCursor.moveToPosition(position)) { + try { + if (mCursor == null || !mCursor.moveToPosition(position)) { + return null; + } + } catch (StaleDataException | IllegalStateException e) { + Log.e(TAG, "Unexpected Exception has been catched.", e); return null; } diff --git a/media/jni/Android.bp b/media/jni/Android.bp index d2294b38d992..d3466702ebf2 100644 --- a/media/jni/Android.bp +++ b/media/jni/Android.bp @@ -96,6 +96,11 @@ cc_library_shared { "-Wunused", "-Wunreachable-code", ], + + // Workaround Clang LTO crash. + lto: { + never: true, + }, } cc_library_shared { diff --git a/media/jni/audioeffect/Android.bp b/media/jni/audioeffect/Android.bp index 5ba5c0159275..40e4c54c2921 100644 --- a/media/jni/audioeffect/Android.bp +++ b/media/jni/audioeffect/Android.bp @@ -28,4 +28,9 @@ cc_library_shared { "-Wunused", "-Wunreachable-code", ], + + // Workaround Clang LTO crash. + lto: { + never: true, + }, } diff --git a/non-updatable-api/Android.bp b/non-updatable-api/Android.bp index 4037781c1844..00b901992b90 100644 --- a/non-updatable-api/Android.bp +++ b/non-updatable-api/Android.bp @@ -23,13 +23,31 @@ filegroup { } filegroup { + name: "non-updatable-removed.txt", + srcs: ["removed.txt"], + visibility: ["//frameworks/base/api"], +} + +filegroup { name: "non-updatable-system-current.txt", srcs: ["system-current.txt"], visibility: ["//frameworks/base/api"], } filegroup { + name: "non-updatable-system-removed.txt", + srcs: ["system-removed.txt"], + visibility: ["//frameworks/base/api"], +} + +filegroup { name: "non-updatable-module-lib-current.txt", srcs: ["module-lib-current.txt"], visibility: ["//frameworks/base/api"], } + +filegroup { + name: "non-updatable-module-lib-removed.txt", + srcs: ["module-lib-removed.txt"], + visibility: ["//frameworks/base/api"], +} diff --git a/non-updatable-api/current.txt b/non-updatable-api/current.txt index caed80abbdaa..da3d0f7ff059 100644 --- a/non-updatable-api/current.txt +++ b/non-updatable-api/current.txt @@ -9126,6 +9126,7 @@ package android.bluetooth.le { method public boolean getIncludeTxPowerLevel(); method public android.util.SparseArray<byte[]> getManufacturerSpecificData(); method public java.util.Map<android.os.ParcelUuid,byte[]> getServiceData(); + method @Nullable public java.util.List<android.os.ParcelUuid> getServiceSolicitationUuids(); method public java.util.List<android.os.ParcelUuid> getServiceUuids(); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.le.AdvertiseData> CREATOR; @@ -9135,6 +9136,7 @@ package android.bluetooth.le { ctor public AdvertiseData.Builder(); method public android.bluetooth.le.AdvertiseData.Builder addManufacturerData(int, byte[]); method public android.bluetooth.le.AdvertiseData.Builder addServiceData(android.os.ParcelUuid, byte[]); + method @NonNull public android.bluetooth.le.AdvertiseData.Builder addServiceSolicitationUuid(@NonNull android.os.ParcelUuid); method public android.bluetooth.le.AdvertiseData.Builder addServiceUuid(android.os.ParcelUuid); method public android.bluetooth.le.AdvertiseData build(); method public android.bluetooth.le.AdvertiseData.Builder setIncludeDeviceName(boolean); @@ -29828,9 +29830,12 @@ package android.net { method public int describeContents(); method @NonNull public byte[] getKey(); method @NonNull public String getName(); + method @NonNull public static java.util.Set<java.lang.String> getSupportedAlgorithms(); method public int getTruncationLengthBits(); method public void writeToParcel(android.os.Parcel, int); + field public static final String AUTH_AES_XCBC = "xcbc(aes)"; field public static final String AUTH_CRYPT_AES_GCM = "rfc4106(gcm(aes))"; + field public static final String AUTH_CRYPT_CHACHA20_POLY1305 = "rfc7539esp(chacha20,poly1305)"; field public static final String AUTH_HMAC_MD5 = "hmac(md5)"; field public static final String AUTH_HMAC_SHA1 = "hmac(sha1)"; field public static final String AUTH_HMAC_SHA256 = "hmac(sha256)"; @@ -29838,6 +29843,7 @@ package android.net { field public static final String AUTH_HMAC_SHA512 = "hmac(sha512)"; field @NonNull public static final android.os.Parcelable.Creator<android.net.IpSecAlgorithm> CREATOR; field public static final String CRYPT_AES_CBC = "cbc(aes)"; + field public static final String CRYPT_AES_CTR = "rfc3686(ctr(aes))"; } public final class IpSecManager { @@ -35031,7 +35037,7 @@ package android.os { method public int dataCapacity(); method public int dataPosition(); method public int dataSize(); - method public void enforceInterface(String); + method public void enforceInterface(@NonNull String); method public boolean hasFileDescriptors(); method public byte[] marshall(); method @NonNull public static android.os.Parcel obtain(); @@ -35102,7 +35108,7 @@ package android.os { method public void writeFloatArray(@Nullable float[]); method public void writeInt(int); method public void writeIntArray(@Nullable int[]); - method public void writeInterfaceToken(String); + method public void writeInterfaceToken(@NonNull String); method public void writeList(@Nullable java.util.List); method public void writeLong(long); method public void writeLongArray(@Nullable long[]); @@ -45207,9 +45213,9 @@ package android.telephony { field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CellInfoWcdma> CREATOR; } - public abstract class CellLocation { - ctor public CellLocation(); - method public static android.telephony.CellLocation getEmpty(); + @Deprecated public abstract class CellLocation { + ctor @Deprecated public CellLocation(); + method @Deprecated public static android.telephony.CellLocation getEmpty(); method @Deprecated public static void requestLocationUpdate(); } @@ -46078,6 +46084,7 @@ package android.telephony { method @NonNull public android.os.Bundle getCarrierConfigValues(); method public static android.telephony.SmsManager getDefault(); method public static int getDefaultSmsSubscriptionId(); + method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int getSmsCapacityOnIcc(); method public static android.telephony.SmsManager getSmsManagerForSubscriptionId(int); method @RequiresPermission(android.Manifest.permission.SMS_FINANCIAL_TRANSACTIONS) public void getSmsMessagesForFinancialApp(android.os.Bundle, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.SmsManager.FinancialSmsCallback); method @Nullable @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getSmscAddress(); @@ -46420,6 +46427,7 @@ package android.telephony { method @Nullable @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getDeviceSoftwareVersion(); method @NonNull @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public java.util.Map<java.lang.Integer,java.util.List<android.telephony.emergency.EmergencyNumber>> getEmergencyNumberList(); method @NonNull @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public java.util.Map<java.lang.Integer,java.util.List<android.telephony.emergency.EmergencyNumber>> getEmergencyNumberList(int); + method @NonNull @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public java.util.List<java.lang.String> getEquivalentHomePlmns(); method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String[] getForbiddenPlmns(); method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getGroupIdLevel1(); method public String getIccAuthentication(int, int, String); @@ -46444,7 +46452,7 @@ package android.telephony { method @Deprecated public int getPhoneCount(); method public int getPhoneType(); method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PHONE_STATE}) public int getPreferredOpportunisticDataSubscription(); - method @RequiresPermission(allOf={android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.ACCESS_COARSE_LOCATION}) public android.telephony.ServiceState getServiceState(); + method @Nullable @RequiresPermission(allOf={android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.ACCESS_COARSE_LOCATION}) public android.telephony.ServiceState getServiceState(); method @Nullable public android.telephony.SignalStrength getSignalStrength(); method public int getSimCarrierId(); method @Nullable public CharSequence getSimCarrierIdName(); @@ -46467,7 +46475,7 @@ package android.telephony { method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getVoiceMailAlphaTag(); method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getVoiceMailNumber(); method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int getVoiceNetworkType(); - method public android.net.Uri getVoicemailRingtoneUri(android.telecom.PhoneAccountHandle); + method @Nullable public android.net.Uri getVoicemailRingtoneUri(android.telecom.PhoneAccountHandle); method public boolean hasCarrierPrivileges(); method public boolean hasIccCard(); method @Deprecated public boolean iccCloseLogicalChannel(int); @@ -46717,19 +46725,19 @@ package android.telephony { package android.telephony.cdma { - public class CdmaCellLocation extends android.telephony.CellLocation { - ctor public CdmaCellLocation(); - ctor public CdmaCellLocation(android.os.Bundle); - method public static double convertQuartSecToDecDegrees(int); - method public void fillInNotifierBundle(android.os.Bundle); - method public int getBaseStationId(); - method public int getBaseStationLatitude(); - method public int getBaseStationLongitude(); - method public int getNetworkId(); - method public int getSystemId(); - method public void setCellLocationData(int, int, int); - method public void setCellLocationData(int, int, int, int, int); - method public void setStateInvalid(); + @Deprecated public class CdmaCellLocation extends android.telephony.CellLocation { + ctor @Deprecated public CdmaCellLocation(); + ctor @Deprecated public CdmaCellLocation(android.os.Bundle); + method @Deprecated public static double convertQuartSecToDecDegrees(int); + method @Deprecated public void fillInNotifierBundle(android.os.Bundle); + method @Deprecated public int getBaseStationId(); + method @Deprecated public int getBaseStationLatitude(); + method @Deprecated public int getBaseStationLongitude(); + method @Deprecated public int getNetworkId(); + method @Deprecated public int getSystemId(); + method @Deprecated public void setCellLocationData(int, int, int); + method @Deprecated public void setCellLocationData(int, int, int, int, int); + method @Deprecated public void setStateInvalid(); } } @@ -46929,15 +46937,15 @@ package android.telephony.euicc { package android.telephony.gsm { - public class GsmCellLocation extends android.telephony.CellLocation { - ctor public GsmCellLocation(); - ctor public GsmCellLocation(android.os.Bundle); - method public void fillInNotifierBundle(android.os.Bundle); - method public int getCid(); - method public int getLac(); - method public int getPsc(); - method public void setLacAndCid(int, int); - method public void setStateInvalid(); + @Deprecated public class GsmCellLocation extends android.telephony.CellLocation { + ctor @Deprecated public GsmCellLocation(); + ctor @Deprecated public GsmCellLocation(android.os.Bundle); + method @Deprecated public void fillInNotifierBundle(android.os.Bundle); + method @Deprecated public int getCid(); + method @Deprecated public int getLac(); + method @Deprecated public int getPsc(); + method @Deprecated public void setLacAndCid(int, int); + method @Deprecated public void setStateInvalid(); } @Deprecated public final class SmsManager { @@ -47273,6 +47281,7 @@ package android.telephony.ims.feature { } public static class MmTelFeature.MmTelCapabilities { + method public final boolean isCapable(int); field public static final int CAPABILITY_TYPE_SMS = 8; // 0x8 field public static final int CAPABILITY_TYPE_UT = 4; // 0x4 field public static final int CAPABILITY_TYPE_VIDEO = 2; // 0x2 diff --git a/non-updatable-api/system-current.txt b/non-updatable-api/system-current.txt index 419d40185655..6a217b2ce847 100644 --- a/non-updatable-api/system-current.txt +++ b/non-updatable-api/system-current.txt @@ -9957,7 +9957,6 @@ package android.telephony { method public boolean disableCellBroadcastRange(int, int, int); method public boolean enableCellBroadcastRange(int, int, int); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getPremiumSmsConsent(@NonNull String); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getSmsCapacityOnIcc(); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void sendMultipartTextMessageWithoutPersisting(String, String, java.util.List<java.lang.String>, java.util.List<android.app.PendingIntent>, java.util.List<android.app.PendingIntent>); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setPremiumSmsConsent(@NonNull String, int); field public static final int PREMIUM_SMS_CONSENT_ALWAYS_ALLOW = 3; // 0x3 @@ -11131,7 +11130,6 @@ package android.telephony.ims.feature { ctor @Deprecated public MmTelFeature.MmTelCapabilities(android.telephony.ims.feature.ImsFeature.Capabilities); ctor public MmTelFeature.MmTelCapabilities(int); method public final void addCapabilities(int); - method public final boolean isCapable(int); method public final void removeCapabilities(int); } diff --git a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserGridRecyclerView.java b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserGridRecyclerView.java index 2ff667093e58..a526e6943004 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserGridRecyclerView.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserGridRecyclerView.java @@ -478,6 +478,9 @@ public class UserGridRecyclerView extends RecyclerView { if (user != null) { mCarUserManagerHelper.switchToUser(user); } + if (mAddUserView != null) { + mAddUserView.setEnabled(true); + } } } diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java index 9ff868467531..f7f3cbb7d332 100644 --- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java +++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java @@ -321,6 +321,9 @@ public class DynamicSystemInstallationService extends Service if (!isDynamicSystemInstalled() && (getStatus() != STATUS_READY)) { Log.e(TAG, "Trying to discard AOT while there is no complete installation"); + // Stop foreground state and dismiss stale notification. + stopForeground(STOP_FOREGROUND_REMOVE); + resetTaskAndStop(); return; } diff --git a/packages/InputDevices/res/raw/keyboard_layout_turkish_f.kcm b/packages/InputDevices/res/raw/keyboard_layout_turkish_f.kcm new file mode 100644 index 000000000000..5b96da027be7 --- /dev/null +++ b/packages/InputDevices/res/raw/keyboard_layout_turkish_f.kcm @@ -0,0 +1,366 @@ +# 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. + +# +# Turkish F keyboard layout. +# + +type OVERLAY + +map key 12 SLASH +map key 13 MINUS +map key 43 COMMA +map key 51 EQUALS +map key 52 BACKSLASH +map key 53 PERIOD +map key 86 PLUS + +### ROW 1 + +key GRAVE { + label: '+' + base: '+' + shift: '*' + ralt: '\u00ac' +} + +key 1 { + label: '1' + base: '1' + shift: '!' + ralt: '\u00b9' +} + +key 2 { + label: '2' + base: '2' + shift: '"' + ralt: '\u00b2' +} + +key 3 { + label: '3' + base: '3' + shift: '^' + ralt: '#' +} + +key 4 { + label: '4' + base: '4' + shift: '$' + ralt: '\u00bc' +} + +key 5 { + label: '5' + base: '5' + shift: '%' + ralt: '\u00bd' +} + +key 6 { + label: '6' + base: '6' + shift: '&' + ralt: '\u00be' +} + +key 7 { + label: '7' + base: '7' + shift: '\'' + ralt: '{' +} + +key 8 { + label: '8' + base: '8' + shift: '(' + ralt: '[' +} + +key 9 { + label: '9' + base: '9' + shift: ')' + ralt: ']' +} + +key 0 { + label: '0' + base: '0' + shift: '=' + ralt: '}' +} + +key SLASH { + label: '/' + base: '/' + shift: '?' + ralt: '\\' +} + +key MINUS { + label: '-' + base: '-' + shift: '_' + ralt: '|' +} + +### ROW 2 + +key Q { + label: 'F' + base: 'f' + shift, capslock: 'F' + ralt: '@' +} + +key W { + label: 'G' + base: 'g' + shift, capslock: 'G' +} + +key E { + label: '\u011f' + base: '\u011f' + shift, capslock: '\u011e' +} + +key R { + label: '\u0131' + base: '\u0131' + shift, capslock: 'I' + ralt: '\u00b6' + ralt+shift, ralt+capslock: '\u00ae' +} + +key T { + label: 'O' + base: 'o' + shift, capslock: 'O' +} + +key Y { + label: 'D' + base: 'd' + shift, capslock: 'D' + ralt: '\u00a5' +} + +key U { + label: 'R' + base: 'r' + shift, capslock: 'R' +} + +key I { + label: 'N' + base: 'n' + shift, capslock: 'N' +} + +key O { + label: 'H' + base: 'h' + shift, capslock: 'H' + ralt: '\u00f8' + ralt+shift, ralt+capslock: '\u00d8' +} + +key P { + label: 'P' + base: 'p' + shift, capslock: 'P' + ralt: '\u00a3' +} + +key LEFT_BRACKET { + label: 'Q' + base: 'q' + shift, capslock: 'Q' + ralt: '"' +} + +key RIGHT_BRACKET { + label: 'W' + base: 'w' + shift, capslock: 'W' + ralt: '~' +} + +### ROW 3 + +key A { + label: '\u0075' + base: '\u0075' + shift, capslock: '\u0055' + ralt: '\u00e6' + ralt+shift, ralt+capslock: '\u00c6' +} + +key S { + label: 'i' + base: 'i' + shift, capslock: '\u0130' + ralt: '\u00df' + ralt+shift, ralt+capslock: '\u00a7' +} + +key D { + label: 'E' + base: 'e' + shift, capslock: 'E' + ralt: '\u20ac' +} + +key F { + label: 'A' + base: 'a' + shift, capslock: 'A' + ralt: '\u00aa' +} + +key G { + label: '\u00fc' + base: '\u00fc' + shift, capslock: '\u00dc' +} + +key H { + label: 'T' + base: 't' + shift, capslock: 'T' + ralt: '\u20ba' +} + +key J { + label: 'K' + base: 'k' + shift, capslock: 'K' +} + +key K { + label: 'M' + base: 'm' + shift, capslock: 'M' +} + +key L { + label: 'L' + base: 'l' + shift, capslock: 'L' +} + +key SEMICOLON { + label: 'Y' + base: 'y' + shift, capslock: 'Y' + ralt: '\u00b4' +} + +key APOSTROPHE { + label: '\u015f' + base: '\u015f' + shift, capslock: '\u015e' +} + +key COMMA { + label: 'X' + base: 'x' + shift: 'X' + ralt: '\u0060' +} + +### ROW 4 + +key PLUS { + label: '<' + base: '<' + shift: '>' + ralt: '|' + ralt+shift, ralt+capslock: '\u00a6' +} + +key Z { + label: 'J' + base: 'j' + shift, capslock: 'J' + ralt: '\u00ab' + ralt+shift, ralt+capslock: '<' +} + +key X { + label: '\u00f6' + base: '\u00f6' + shift, capslock: '\u00d6' + ralt: '\u00bb' + ralt+shift, ralt+capslock: '>' +} + +key C { + label: 'V' + base: 'v' + shift, capslock: 'V' + ralt: '\u00a2' + ralt+shift, ralt+capslock: '\u00a9' +} + +key V { + label: 'C' + base: 'c' + shift, capslock: 'C' +} + +key B { + label: '\u00e7' + base: '\u00e7' + shift, capslock: '\u00c7' +} + +key N { + label: 'Z' + base: 'z' + shift, capslock: 'Z' +} + +key M { + label: 'S' + base: 's' + shift, capslock: 'S' + ralt: '\u00b5' + ralt+shift, ralt+capslock: '\u00ba' +} + +key EQUALS { + label: 'B' + base: 'b' + shift, capslock: 'B' + ralt: '\u00d7' +} + +key BACKSLASH { + label: '.' + base: '.' + shift, capslock: ':' + ralt: '\u00f7' +} + +key PERIOD { + label: ',' + base: ',' + shift: ';' +} diff --git a/packages/InputDevices/res/values/strings.xml b/packages/InputDevices/res/values/strings.xml index e95a15912397..c2585ff49a11 100644 --- a/packages/InputDevices/res/values/strings.xml +++ b/packages/InputDevices/res/values/strings.xml @@ -102,6 +102,9 @@ <!-- Turkish keyboard layout label. [CHAR LIMIT=35] --> <string name="keyboard_layout_turkish">Turkish</string> + <!-- Turkish keyboard layout label. [CHAR LIMIT=35] --> + <string name="keyboard_layout_turkish_f">Turkish F</string> + <!-- Ukrainian keyboard layout label. [CHAR LIMIT=35] --> <string name="keyboard_layout_ukrainian">Ukrainian</string> diff --git a/packages/InputDevices/res/xml/keyboard_layouts.xml b/packages/InputDevices/res/xml/keyboard_layouts.xml index aa599ae7f2d0..d3c421da9055 100644 --- a/packages/InputDevices/res/xml/keyboard_layouts.xml +++ b/packages/InputDevices/res/xml/keyboard_layouts.xml @@ -128,6 +128,10 @@ android:label="@string/keyboard_layout_turkish" android:keyboardLayout="@raw/keyboard_layout_turkish" /> + <keyboard-layout android:name="keyboard_layout_turkish_f" + android:label="@string/keyboard_layout_turkish_f" + android:keyboardLayout="@raw/keyboard_layout_turkish_f" /> + <keyboard-layout android:name="keyboard_layout_ukrainian" android:label="@string/keyboard_layout_ukrainian" android:keyboardLayout="@raw/keyboard_layout_ukrainian" /> diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java index 81cf118031bf..b0a913617ba0 100644 --- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java +++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java @@ -1090,7 +1090,7 @@ public class WifiTrackerTest { // Verify second update AP is the same object as the first update AP assertThat(passpointAccessPointsFirstUpdate.get(0)) - .isSameAs(passpointAccessPointsSecondUpdate.get(0)); + .isSameInstanceAs(passpointAccessPointsSecondUpdate.get(0)); // Verify second update AP has the average of the first and second update RSSIs assertThat(passpointAccessPointsSecondUpdate.get(0).getRssi()) .isEqualTo((prevRssi + newRssi) / 2); @@ -1210,7 +1210,8 @@ public class WifiTrackerTest { providersAndScans, cachedAccessPoints); // Verify second update AP is the same object as the first update AP - assertThat(osuAccessPointsFirstUpdate.get(0)).isSameAs(osuAccessPointsSecondUpdate.get(0)); + assertThat(osuAccessPointsFirstUpdate.get(0)) + .isSameInstanceAs(osuAccessPointsSecondUpdate.get(0)); // Verify second update AP has the average of the first and second update RSSIs assertThat(osuAccessPointsSecondUpdate.get(0).getRssi()) .isEqualTo((prevRssi + newRssi) / 2); diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/IpAddressPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/IpAddressPreferenceControllerTest.java index a83d7e099e51..b392c5e5d772 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/IpAddressPreferenceControllerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/IpAddressPreferenceControllerTest.java @@ -69,7 +69,7 @@ public class IpAddressPreferenceControllerTest { assertWithMessage("Intent filter should contain expected intents") .that(ipAddressPreferenceController.getConnectivityIntents()) - .asList().containsAllIn(expectedIntents); + .asList().containsAtLeastElementsIn(expectedIntents); } private static class ConcreteIpAddressPreferenceController extends diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/WifiMacAddressPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/WifiMacAddressPreferenceControllerTest.java index 40b9b13ef55f..37052673eb4d 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/WifiMacAddressPreferenceControllerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/WifiMacAddressPreferenceControllerTest.java @@ -90,7 +90,7 @@ public class WifiMacAddressPreferenceControllerTest { assertWithMessage("Intent filter should contain expected intents") .that(mController.getConnectivityIntents()) - .asList().containsAllIn(expectedIntents); + .asList().containsAtLeastElementsIn(expectedIntents); } @Test diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java index 9b4b97e7f55d..f334cd332ad9 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java @@ -281,7 +281,7 @@ public class TileUtilsTest { assertThat(outTiles).hasSize(1); final Bundle newMetaData = outTiles.get(0).getMetaData(); - assertThat(newMetaData).isNotSameAs(oldMetadata); + assertThat(newMetaData).isNotSameInstanceAs(oldMetadata); } @Test diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index f5f58efb72e6..a9279971ce1e 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -326,6 +326,9 @@ <!-- Permission needed for CTS test - DisplayTest --> <uses-permission android:name="android.permission.OVERRIDE_DISPLAY_MODE_REQUESTS" /> + <!-- Permission needed for CTS test - TimeManagerTest --> + <uses-permission android:name="android.permission.MANAGE_TIME_AND_ZONE_DETECTION" /> + <application android:label="@string/app_label" android:theme="@android:style/Theme.DeviceDefault.DayNight" android:defaultToDeviceProtectedStorage="true" diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java index 1a9abb9cf27d..e6f43c1ff1d2 100644 --- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java +++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java @@ -132,7 +132,7 @@ public class ScreenMediaRecorder { mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264); mMediaRecorder.setVideoEncodingProfileLevel( MediaCodecInfo.CodecProfileLevel.AVCProfileHigh, - MediaCodecInfo.CodecProfileLevel.AVCLevel42); + MediaCodecInfo.CodecProfileLevel.AVCLevel3); mMediaRecorder.setVideoSize(screenWidth, screenHeight); mMediaRecorder.setVideoFrameRate(refereshRate); mMediaRecorder.setVideoEncodingBitRate(vidBitRate); diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationsController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationsController.java index fbcd6ba0ff47..42dde4064a97 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationsController.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationsController.java @@ -205,7 +205,8 @@ public class ScreenshotNotificationsController { mPublicNotificationBuilder .setContentTitle(mResources.getString(R.string.screenshot_saved_title)) .setContentText(mResources.getString(R.string.screenshot_saved_text)) - .setContentIntent(PendingIntent.getActivity(mContext, 0, launchIntent, 0)) + .setContentIntent(PendingIntent + .getActivity(mContext, 0, launchIntent, PendingIntent.FLAG_IMMUTABLE)) .setWhen(now) .setAutoCancel(true) .setColor(mContext.getColor( @@ -213,7 +214,8 @@ public class ScreenshotNotificationsController { mNotificationBuilder .setContentTitle(mResources.getString(R.string.screenshot_saved_title)) .setContentText(mResources.getString(R.string.screenshot_saved_text)) - .setContentIntent(PendingIntent.getActivity(mContext, 0, launchIntent, 0)) + .setContentIntent(PendingIntent + .getActivity(mContext, 0, launchIntent, PendingIntent.FLAG_IMMUTABLE)) .setWhen(now) .setAutoCancel(true) .setColor(mContext.getColor( diff --git a/packages/SystemUI/src/com/android/systemui/util/leak/LeakReporter.java b/packages/SystemUI/src/com/android/systemui/util/leak/LeakReporter.java index b25df5f9c07f..5e7280840bb9 100644 --- a/packages/SystemUI/src/com/android/systemui/util/leak/LeakReporter.java +++ b/packages/SystemUI/src/com/android/systemui/util/leak/LeakReporter.java @@ -104,9 +104,13 @@ public class LeakReporter { .setContentText(String.format( "SystemUI has detected %d leaked objects. Tap to send", garbageCount)) .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb) - .setContentIntent(PendingIntent.getActivityAsUser(mContext, 0, + .setContentIntent(PendingIntent.getActivityAsUser( + mContext, + 0, getIntent(hprofFile, dumpFile), - PendingIntent.FLAG_UPDATE_CURRENT, null, UserHandle.CURRENT)); + PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE, + null, + UserHandle.CURRENT)); notiMan.notify(TAG, 0, builder.build()); } catch (IOException e) { Log.e(TAG, "Couldn't dump heap for leak", e); diff --git a/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java index 353fe625b8ea..35fe1ba8f805 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java @@ -168,7 +168,7 @@ public final class ClockManagerTest extends SysuiTestCase { verify(mMockListener2).onClockChanged(captor2.capture()); assertThat(captor1.getValue()).isInstanceOf(BUBBLE_CLOCK_CLASS); assertThat(captor2.getValue()).isInstanceOf(BUBBLE_CLOCK_CLASS); - assertThat(captor1.getValue()).isNotSameAs(captor2.getValue()); + assertThat(captor1.getValue()).isNotSameInstanceAs(captor2.getValue()); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java index 315caeebe0e9..12221bcc3310 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java @@ -19,6 +19,7 @@ package com.android.systemui.bubbles; import static com.android.systemui.statusbar.NotificationEntryHelper.modifyRanking; import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth.assertWithMessage; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.reset; @@ -793,47 +794,48 @@ public class BubbleDataTest extends SysuiTestCase { private void assertBubbleAdded(Bubble expected) { BubbleData.Update update = mUpdateCaptor.getValue(); - assertThat(update.addedBubble).named("addedBubble").isEqualTo(expected); + assertWithMessage("addedBubble").that(update.addedBubble).isEqualTo(expected); } private void assertBubbleRemoved(Bubble expected, @BubbleController.DismissReason int reason) { BubbleData.Update update = mUpdateCaptor.getValue(); - assertThat(update.removedBubbles).named("removedBubbles") + assertWithMessage("removedBubbles").that(update.removedBubbles) .isEqualTo(ImmutableList.of(Pair.create(expected, reason))); } private void assertOrderNotChanged() { BubbleData.Update update = mUpdateCaptor.getValue(); - assertThat(update.orderChanged).named("orderChanged").isFalse(); + assertWithMessage("orderChanged").that(update.orderChanged).isFalse(); } private void assertOrderChangedTo(Bubble... order) { BubbleData.Update update = mUpdateCaptor.getValue(); - assertThat(update.orderChanged).named("orderChanged").isTrue(); - assertThat(update.bubbles).named("bubble order").isEqualTo(ImmutableList.copyOf(order)); + assertWithMessage("orderChanged").that(update.orderChanged).isTrue(); + assertWithMessage("bubble order").that(update.bubbles) + .isEqualTo(ImmutableList.copyOf(order)); } private void assertSelectionNotChanged() { BubbleData.Update update = mUpdateCaptor.getValue(); - assertThat(update.selectionChanged).named("selectionChanged").isFalse(); + assertWithMessage("selectionChanged").that(update.selectionChanged).isFalse(); } private void assertSelectionChangedTo(Bubble bubble) { BubbleData.Update update = mUpdateCaptor.getValue(); - assertThat(update.selectionChanged).named("selectionChanged").isTrue(); - assertThat(update.selectedBubble).named("selectedBubble").isEqualTo(bubble); + assertWithMessage("selectionChanged").that(update.selectionChanged).isTrue(); + assertWithMessage("selectedBubble").that(update.selectedBubble).isEqualTo(bubble); } private void assertSelectionCleared() { BubbleData.Update update = mUpdateCaptor.getValue(); - assertThat(update.selectionChanged).named("selectionChanged").isTrue(); - assertThat(update.selectedBubble).named("selectedBubble").isNull(); + assertWithMessage("selectionChanged").that(update.selectionChanged).isTrue(); + assertWithMessage("selectedBubble").that(update.selectedBubble).isNull(); } private void assertExpandedChangedTo(boolean expected) { BubbleData.Update update = mUpdateCaptor.getValue(); - assertThat(update.expandedChanged).named("expandedChanged").isTrue(); - assertThat(update.expanded).named("expanded").isEqualTo(expected); + assertWithMessage("expandedChanged").that(update.expandedChanged).isTrue(); + assertWithMessage("expanded").that(update.expanded).isEqualTo(expected); } private void assertOverflowChangedTo(ImmutableList<Bubble> bubbles) { @@ -895,4 +897,4 @@ public class BubbleDataTest extends SysuiTestCase { setCurrentTime(time); mBubbleData.setExpanded(shouldBeExpanded); } -}
\ No newline at end of file +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/MediaArtworkProcessorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/MediaArtworkProcessorTest.kt index 72e6df27a254..724ea023f2bd 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/MediaArtworkProcessorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/MediaArtworkProcessorTest.kt @@ -80,7 +80,7 @@ class MediaArtworkProcessorTest : SysuiTestCase() { val background2 = processor.processArtwork(context, artwork)!! // THEN the two bitmaps are the same // Note: This is currently broken and trying to use caching causes issues - assertThat(background1).isNotSameAs(background2) + assertThat(background1).isNotSameInstanceAs(background2) } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt index 79fa43604c38..5898664dea8e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt @@ -118,7 +118,7 @@ class PeopleHubViewControllerTest : SysuiTestCase() { val people = viewModel.people.toList() assertThat(people.size).isEqualTo(1) assertThat(people[0].name).isEqualTo("name") - assertThat(people[0].icon).isSameAs(fakePerson.avatar) + assertThat(people[0].icon).isSameInstanceAs(fakePerson.avatar) people[0].onClick() diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java index b0b66b87d421..00332cc9cd92 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java @@ -326,7 +326,7 @@ public class NotificationPanelViewTest extends SysuiTestCase { mAccessibiltyDelegate.onInitializeAccessibilityNodeInfo(mView, nodeInfo); List<AccessibilityNodeInfo.AccessibilityAction> actionList = nodeInfo.getActionList(); - assertThat(actionList).containsAllIn( + assertThat(actionList).containsAtLeastElementsIn( new AccessibilityNodeInfo.AccessibilityAction[] { AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD, AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_UP} diff --git a/packages/Tethering/Android.bp b/packages/Tethering/Android.bp index 257538d6216d..5526c657b874 100644 --- a/packages/Tethering/Android.bp +++ b/packages/Tethering/Android.bp @@ -101,6 +101,7 @@ java_defaults { ], libs: [ "framework-tethering", + "framework-wifi", ], jarjar_rules: "jarjar-rules.txt", optimize: { diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheredClient.java b/packages/Tethering/common/TetheringLib/src/android/net/TetheredClient.java index 645b00001330..0b223f42b954 100644 --- a/packages/Tethering/common/TetheringLib/src/android/net/TetheredClient.java +++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheredClient.java @@ -19,7 +19,6 @@ package android.net; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; -import android.annotation.TestApi; import android.os.Parcel; import android.os.Parcelable; @@ -34,7 +33,6 @@ import java.util.Objects; * @hide */ @SystemApi -@TestApi public final class TetheredClient implements Parcelable { @NonNull private final MacAddress mMacAddress; diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java index 88e0b4253446..97fb4974d0f6 100644 --- a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java +++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java @@ -23,7 +23,6 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; -import android.annotation.TestApi; import android.content.Context; import android.os.Bundle; import android.os.ConditionVariable; @@ -55,7 +54,6 @@ import java.util.function.Supplier; * @hide */ @SystemApi -@TestApi public class TetheringManager { private static final String TAG = TetheringManager.class.getSimpleName(); private static final int DEFAULT_TIMEOUT_MS = 60_000; diff --git a/packages/Tethering/src/android/net/ip/IpServer.java b/packages/Tethering/src/android/net/ip/IpServer.java index 336124dc1b90..52d59fcdc19b 100644 --- a/packages/Tethering/src/android/net/ip/IpServer.java +++ b/packages/Tethering/src/android/net/ip/IpServer.java @@ -616,7 +616,7 @@ public class IpServer extends StateMachine { if (VDBG) Log.d(TAG, "configureIPv4(" + enabled + ")"); if (enabled) { - mIpv4Address = requestIpv4Address(); + mIpv4Address = requestIpv4Address(true /* useLastAddress */); } if (mIpv4Address == null) { @@ -661,14 +661,14 @@ public class IpServer extends StateMachine { return configureDhcp(enabled, mIpv4Address, mStaticIpv4ClientAddr); } - private LinkAddress requestIpv4Address() { + private LinkAddress requestIpv4Address(final boolean useLastAddress) { if (mStaticIpv4ServerAddr != null) return mStaticIpv4ServerAddr; if (mInterfaceType == TetheringManager.TETHERING_BLUETOOTH) { return new LinkAddress(BLUETOOTH_IFACE_ADDR); } - return mPrivateAddressCoordinator.requestDownstreamAddress(this); + return mPrivateAddressCoordinator.requestDownstreamAddress(this, useLastAddress); } private boolean startIPv6() { @@ -957,7 +957,7 @@ public class IpServer extends StateMachine { } final LinkAddress deprecatedLinkAddress = mIpv4Address; - mIpv4Address = requestIpv4Address(); + mIpv4Address = requestIpv4Address(false); if (mIpv4Address == null) { mLog.e("Fail to request a new downstream prefix"); return; diff --git a/packages/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java b/packages/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java index 33b9d00e70dc..da5f25b2a596 100644 --- a/packages/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java +++ b/packages/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java @@ -28,6 +28,7 @@ import android.hardware.tetheroffload.control.V1_0.NatTimeoutUpdate; import android.hardware.tetheroffload.control.V1_0.NetworkProtocol; import android.hardware.tetheroffload.control.V1_0.OffloadCallbackEvent; import android.net.netlink.NetlinkSocket; +import android.net.netlink.StructNfGenMsg; import android.net.netlink.StructNlMsgHdr; import android.net.util.SharedLog; import android.net.util.SocketUtils; @@ -41,11 +42,12 @@ import android.system.OsConstants; import com.android.internal.annotations.VisibleForTesting; import java.io.FileDescriptor; -import java.io.InterruptedIOException; import java.io.IOException; +import java.io.InterruptedIOException; import java.net.SocketAddress; import java.net.SocketException; import java.nio.ByteBuffer; +import java.nio.ByteOrder; import java.util.ArrayList; import java.util.NoSuchElementException; @@ -66,11 +68,12 @@ public class OffloadHardwareInterface { private static final String NO_IPV4_ADDRESS = ""; private static final String NO_IPV4_GATEWAY = ""; // Reference kernel/uapi/linux/netfilter/nfnetlink_compat.h - private static final int NF_NETLINK_CONNTRACK_NEW = 1; - private static final int NF_NETLINK_CONNTRACK_UPDATE = 2; - private static final int NF_NETLINK_CONNTRACK_DESTROY = 4; + public static final int NF_NETLINK_CONNTRACK_NEW = 1; + public static final int NF_NETLINK_CONNTRACK_UPDATE = 2; + public static final int NF_NETLINK_CONNTRACK_DESTROY = 4; // Reference libnetfilter_conntrack/linux_nfnetlink_conntrack.h public static final short NFNL_SUBSYS_CTNETLINK = 1; + public static final short IPCTNL_MSG_CT_NEW = 0; public static final short IPCTNL_MSG_CT_GET = 1; private final long NETLINK_MESSAGE_TIMEOUT_MS = 500; @@ -237,7 +240,7 @@ public class OffloadHardwareInterface { NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY); if (h1 == null) return false; - sendNetlinkMessage(h1, (short) ((NFNL_SUBSYS_CTNETLINK << 8) | IPCTNL_MSG_CT_GET), + sendIpv4NfGenMsg(h1, (short) ((NFNL_SUBSYS_CTNETLINK << 8) | IPCTNL_MSG_CT_GET), (short) (NLM_F_REQUEST | NLM_F_DUMP)); final NativeHandle h2 = mDeps.createConntrackSocket( @@ -267,16 +270,23 @@ public class OffloadHardwareInterface { } @VisibleForTesting - public void sendNetlinkMessage(@NonNull NativeHandle handle, short type, short flags) { - final int length = StructNlMsgHdr.STRUCT_SIZE; + public void sendIpv4NfGenMsg(@NonNull NativeHandle handle, short type, short flags) { + final int length = StructNlMsgHdr.STRUCT_SIZE + StructNfGenMsg.STRUCT_SIZE; final byte[] msg = new byte[length]; - final StructNlMsgHdr nlh = new StructNlMsgHdr(); final ByteBuffer byteBuffer = ByteBuffer.wrap(msg); + byteBuffer.order(ByteOrder.nativeOrder()); + + final StructNlMsgHdr nlh = new StructNlMsgHdr(); nlh.nlmsg_len = length; nlh.nlmsg_type = type; nlh.nlmsg_flags = flags; - nlh.nlmsg_seq = 1; + nlh.nlmsg_seq = 0; nlh.pack(byteBuffer); + + // Header needs to be added to buffer since a generic netlink request is being sent. + final StructNfGenMsg nfh = new StructNfGenMsg((byte) OsConstants.AF_INET); + nfh.pack(byteBuffer); + try { NetlinkSocket.sendMessage(handle.getFileDescriptor(), msg, 0 /* offset */, length, NETLINK_MESSAGE_TIMEOUT_MS); diff --git a/packages/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java b/packages/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java index fd9e36080c80..4f616cdff086 100644 --- a/packages/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java +++ b/packages/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java @@ -15,7 +15,14 @@ */ package com.android.networkstack.tethering; +import static android.net.NetworkCapabilities.TRANSPORT_VPN; +import static android.net.TetheringManager.TETHERING_BLUETOOTH; import static android.net.TetheringManager.TETHERING_WIFI_P2P; +import static android.net.util.PrefixUtils.asIpPrefix; + +import static com.android.net.module.util.Inet4AddressUtils.inet4AddressToIntHTH; +import static com.android.net.module.util.Inet4AddressUtils.intToInet4AddressHTH; +import static com.android.net.module.util.Inet4AddressUtils.prefixLengthToV4NetmaskIntHTH; import static java.util.Arrays.asList; @@ -23,21 +30,22 @@ import android.content.Context; import android.net.ConnectivityManager; import android.net.IpPrefix; import android.net.LinkAddress; -import android.net.LinkProperties; import android.net.Network; import android.net.ip.IpServer; -import android.net.util.PrefixUtils; import android.util.ArrayMap; import android.util.ArraySet; +import android.util.SparseArray; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.IndentingPrintWriter; +import java.net.Inet4Address; import java.net.InetAddress; -import java.net.UnknownHostException; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Random; @@ -56,13 +64,6 @@ import java.util.Set; public class PrivateAddressCoordinator { public static final int PREFIX_LENGTH = 24; - private static final int MAX_UBYTE = 256; - private static final int BYTE_MASK = 0xff; - // reserved for bluetooth tethering. - private static final int BLUETOOTH_RESERVED = 44; - private static final int WIFI_P2P_RESERVED = 49; - private static final byte DEFAULT_ID = (byte) 42; - // Upstream monitor would be stopped when tethering is down. When tethering restart, downstream // address may be requested before coordinator get current upstream notification. To ensure // coordinator do not select conflict downstream prefix, mUpstreamPrefixMap would not be cleared @@ -70,36 +71,53 @@ public class PrivateAddressCoordinator { // mUpstreamPrefixMap when tethering is starting. See #maybeRemoveDeprecatedUpstreams(). private final ArrayMap<Network, List<IpPrefix>> mUpstreamPrefixMap; private final ArraySet<IpServer> mDownstreams; - // IANA has reserved the following three blocks of the IP address space for private intranets: - // 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 - // Tethering use 192.168.0.0/16 that has 256 contiguous class C network numbers. - private static final String DEFAULT_TETHERING_PREFIX = "192.168.0.0/16"; private static final String LEGACY_WIFI_P2P_IFACE_ADDRESS = "192.168.49.1/24"; - private final IpPrefix mTetheringPrefix; + private static final String LEGACY_BLUETOOTH_IFACE_ADDRESS = "192.168.44.1/24"; + private final List<IpPrefix> mTetheringPrefixes; private final ConnectivityManager mConnectivityMgr; private final TetheringConfiguration mConfig; + // keyed by downstream type(TetheringManager.TETHERING_*). + private final SparseArray<LinkAddress> mCachedAddresses; public PrivateAddressCoordinator(Context context, TetheringConfiguration config) { mDownstreams = new ArraySet<>(); mUpstreamPrefixMap = new ArrayMap<>(); - mTetheringPrefix = new IpPrefix(DEFAULT_TETHERING_PREFIX); mConnectivityMgr = (ConnectivityManager) context.getSystemService( Context.CONNECTIVITY_SERVICE); mConfig = config; + mCachedAddresses = new SparseArray<>(); + // Reserved static addresses for bluetooth and wifi p2p. + mCachedAddresses.put(TETHERING_BLUETOOTH, new LinkAddress(LEGACY_BLUETOOTH_IFACE_ADDRESS)); + mCachedAddresses.put(TETHERING_WIFI_P2P, new LinkAddress(LEGACY_WIFI_P2P_IFACE_ADDRESS)); + + mTetheringPrefixes = new ArrayList<>(Arrays.asList(new IpPrefix("192.168.0.0/16"))); + if (config.isSelectAllPrefixRangeEnabled()) { + mTetheringPrefixes.add(new IpPrefix("172.16.0.0/12")); + mTetheringPrefixes.add(new IpPrefix("10.0.0.0/8")); + } } /** * Record a new upstream IpPrefix which may conflict with tethering downstreams. - * The downstreams will be notified if a conflict is found. + * The downstreams will be notified if a conflict is found. When updateUpstreamPrefix is called, + * UpstreamNetworkState must have an already populated LinkProperties. */ - public void updateUpstreamPrefix(final Network network, final LinkProperties lp) { - final ArrayList<IpPrefix> ipv4Prefixes = getIpv4Prefixes(lp.getAllLinkAddresses()); + public void updateUpstreamPrefix(final UpstreamNetworkState ns) { + // Do not support VPN as upstream. Normally, networkCapabilities is not expected to be null, + // but just checking to be sure. + if (ns.networkCapabilities != null && ns.networkCapabilities.hasTransport(TRANSPORT_VPN)) { + removeUpstreamPrefix(ns.network); + return; + } + + final ArrayList<IpPrefix> ipv4Prefixes = getIpv4Prefixes( + ns.linkProperties.getAllLinkAddresses()); if (ipv4Prefixes.isEmpty()) { - removeUpstreamPrefix(network); + removeUpstreamPrefix(ns.network); return; } - mUpstreamPrefixMap.put(network, ipv4Prefixes); + mUpstreamPrefixMap.put(ns.network, ipv4Prefixes); handleMaybePrefixConflict(ipv4Prefixes); } @@ -108,7 +126,7 @@ public class PrivateAddressCoordinator { for (LinkAddress address : linkAddresses) { if (!address.isIpv4()) continue; - list.add(PrefixUtils.asIpPrefix(address)); + list.add(asIpPrefix(address)); } return list; @@ -117,7 +135,6 @@ public class PrivateAddressCoordinator { private void handleMaybePrefixConflict(final List<IpPrefix> prefixes) { for (IpServer downstream : mDownstreams) { final IpPrefix target = getDownstreamPrefix(downstream); - if (target == null) continue; for (IpPrefix source : prefixes) { if (isConflictPrefix(source, target)) { @@ -147,65 +164,166 @@ public class PrivateAddressCoordinator { mUpstreamPrefixMap.removeAll(toBeRemoved); } - private boolean isReservedSubnet(final int subnet) { - return subnet == BLUETOOTH_RESERVED || subnet == WIFI_P2P_RESERVED; - } - /** * Pick a random available address and mark its prefix as in use for the provided IpServer, * returns null if there is no available address. */ @Nullable - public LinkAddress requestDownstreamAddress(final IpServer ipServer) { + public LinkAddress requestDownstreamAddress(final IpServer ipServer, boolean useLastAddress) { if (mConfig.shouldEnableWifiP2pDedicatedIp() && ipServer.interfaceType() == TETHERING_WIFI_P2P) { return new LinkAddress(LEGACY_WIFI_P2P_IFACE_ADDRESS); } - // Address would be 192.168.[subAddress]/24. - final byte[] bytes = mTetheringPrefix.getRawAddress(); - final int subAddress = getRandomSubAddr(); - final int subNet = (subAddress >> 8) & BYTE_MASK; - bytes[3] = getSanitizedAddressSuffix(subAddress, (byte) 0, (byte) 1, (byte) 0xff); - for (int i = 0; i < MAX_UBYTE; i++) { - final int newSubNet = (subNet + i) & BYTE_MASK; - if (isReservedSubnet(newSubNet)) continue; - - bytes[2] = (byte) newSubNet; - final InetAddress addr; - try { - addr = InetAddress.getByAddress(bytes); - } catch (UnknownHostException e) { - throw new IllegalStateException("Invalid address, shouldn't happen.", e); + final LinkAddress cachedAddress = mCachedAddresses.get(ipServer.interfaceType()); + if (useLastAddress && cachedAddress != null + && !isConflictWithUpstream(asIpPrefix(cachedAddress))) { + mDownstreams.add(ipServer); + return cachedAddress; + } + + for (IpPrefix prefixRange : mTetheringPrefixes) { + final LinkAddress newAddress = chooseDownstreamAddress(prefixRange); + if (newAddress != null) { + mDownstreams.add(ipServer); + mCachedAddresses.put(ipServer.interfaceType(), newAddress); + return newAddress; } + } + + // No available address. + return null; + } - final IpPrefix prefix = new IpPrefix(addr, PREFIX_LENGTH); - // Check whether this prefix is in use. - if (isDownstreamPrefixInUse(prefix)) continue; - // Check whether this prefix is conflict with any current upstream network. - if (isConflictWithUpstream(prefix)) continue; + private int getPrefixBaseAddress(final IpPrefix prefix) { + return inet4AddressToIntHTH((Inet4Address) prefix.getAddress()); + } - mDownstreams.add(ipServer); - return new LinkAddress(addr, PREFIX_LENGTH); + /** + * Check whether input prefix conflict with upstream prefixes or in-use downstream prefixes. + * If yes, return one of them. + */ + private IpPrefix getConflictPrefix(final IpPrefix prefix) { + final IpPrefix upstream = getConflictWithUpstream(prefix); + if (upstream != null) return upstream; + + return getInUseDownstreamPrefix(prefix); + } + + // Get the next non-conflict sub prefix. E.g: To get next sub prefix from 10.0.0.0/8, if the + // previously selected prefix is 10.20.42.0/24(subPrefix: 0.20.42.0) and the conflicting prefix + // is 10.16.0.0/20 (10.16.0.0 ~ 10.16.15.255), then the max address under subPrefix is + // 0.16.15.255 and the next subPrefix is 0.16.16.255/24 (0.16.15.255 + 0.0.1.0). + // Note: the sub address 0.0.0.255 here is fine to be any value that it will be replaced as + // selected random sub address later. + private int getNextSubPrefix(final IpPrefix conflictPrefix, final int prefixRangeMask) { + final int suffixMask = ~prefixLengthToV4NetmaskIntHTH(conflictPrefix.getPrefixLength()); + // The largest offset within the prefix assignment block that still conflicts with + // conflictPrefix. + final int maxConflict = + (getPrefixBaseAddress(conflictPrefix) | suffixMask) & ~prefixRangeMask; + + final int prefixMask = prefixLengthToV4NetmaskIntHTH(PREFIX_LENGTH); + // Pick a sub prefix a full prefix (1 << (32 - PREFIX_LENGTH) addresses) greater than + // maxConflict. This ensures that the selected prefix never overlaps with conflictPrefix. + // There is no need to mask the result with PREFIX_LENGTH bits because this is done by + // findAvailablePrefixFromRange when it constructs the prefix. + return maxConflict + (1 << (32 - PREFIX_LENGTH)); + } + + private LinkAddress chooseDownstreamAddress(final IpPrefix prefixRange) { + // The netmask of the prefix assignment block (e.g., 0xfff00000 for 172.16.0.0/12). + final int prefixRangeMask = prefixLengthToV4NetmaskIntHTH(prefixRange.getPrefixLength()); + + // The zero address in the block (e.g., 0xac100000 for 172.16.0.0/12). + final int baseAddress = getPrefixBaseAddress(prefixRange); + + // The subnet mask corresponding to PREFIX_LENGTH. + final int prefixMask = prefixLengthToV4NetmaskIntHTH(PREFIX_LENGTH); + + // The offset within prefixRange of a randomly-selected prefix of length PREFIX_LENGTH. + // This may not be the prefix of the address returned by this method: + // - If it is already in use, the method will return an address in another prefix. + // - If all prefixes within prefixRange are in use, the method will return null. For + // example, for a /24 prefix within 172.26.0.0/12, this will be a multiple of 256 in + // [0, 1048576). In other words, a random 32-bit number with mask 0x000fff00. + // + // prefixRangeMask is required to ensure no wrapping. For example, consider: + // - prefixRange 127.0.0.0/8 + // - randomPrefixStart 127.255.255.0 + // - A conflicting prefix of 127.255.254.0/23 + // In this case without prefixRangeMask, getNextSubPrefix would return 128.0.0.0, which + // means the "start < end" check in findAvailablePrefixFromRange would not reject the prefix + // because Java doesn't have unsigned integers, so 128.0.0.0 = 0x80000000 = -2147483648 + // is less than 127.0.0.0 = 0x7f000000 = 2130706432. + // + // Additionally, it makes debug output easier to read by making the numbers smaller. + final int randomPrefixStart = getRandomInt() & ~prefixRangeMask & prefixMask; + + // A random offset within the prefix. Used to determine the local address once the prefix + // is selected. It does not result in an IPv4 address ending in .0, .1, or .255 + // For a PREFIX_LENGTH of 255, this is a number between 2 and 254. + final int subAddress = getSanitizedSubAddr(~prefixMask); + + // Find a prefix length PREFIX_LENGTH between randomPrefixStart and the end of the block, + // such that the prefix does not conflict with any upstream. + IpPrefix downstreamPrefix = findAvailablePrefixFromRange( + randomPrefixStart, (~prefixRangeMask) + 1, baseAddress, prefixRangeMask); + if (downstreamPrefix != null) return getLinkAddress(downstreamPrefix, subAddress); + + // If that failed, do the same, but between 0 and randomPrefixStart. + downstreamPrefix = findAvailablePrefixFromRange( + 0, randomPrefixStart, baseAddress, prefixRangeMask); + + return getLinkAddress(downstreamPrefix, subAddress); + } + + private LinkAddress getLinkAddress(final IpPrefix prefix, final int subAddress) { + if (prefix == null) return null; + + final InetAddress address = intToInet4AddressHTH(getPrefixBaseAddress(prefix) | subAddress); + return new LinkAddress(address, PREFIX_LENGTH); + } + + private IpPrefix findAvailablePrefixFromRange(final int start, final int end, + final int baseAddress, final int prefixRangeMask) { + int newSubPrefix = start; + while (newSubPrefix < end) { + final InetAddress address = intToInet4AddressHTH(baseAddress | newSubPrefix); + final IpPrefix prefix = new IpPrefix(address, PREFIX_LENGTH); + + final IpPrefix conflictPrefix = getConflictPrefix(prefix); + + if (conflictPrefix == null) return prefix; + + newSubPrefix = getNextSubPrefix(conflictPrefix, prefixRangeMask); } - // No available address. return null; } - /** Get random sub address value. Return value is in 0 ~ 0xffff. */ + /** Get random int which could be used to generate random address. */ @VisibleForTesting - public int getRandomSubAddr() { - return ((new Random()).nextInt()) & 0xffff; // subNet is in 0 ~ 0xffff. + public int getRandomInt() { + return (new Random()).nextInt(); } - private byte getSanitizedAddressSuffix(final int source, byte... excluded) { - final byte subId = (byte) (source & BYTE_MASK); - for (byte value : excluded) { - if (subId == value) return DEFAULT_ID; + /** Get random subAddress and avoid selecting x.x.x.0, x.x.x.1 and x.x.x.255 address. */ + private int getSanitizedSubAddr(final int subAddrMask) { + final int randomSubAddr = getRandomInt() & subAddrMask; + // If prefix length > 30, the selecting speace would be less than 4 which may be hard to + // avoid 3 consecutive address. + if (PREFIX_LENGTH > 30) return randomSubAddr; + + // TODO: maybe it is not necessary to avoid .0, .1 and .255 address because tethering + // address would not be conflicted. This code only works because PREFIX_LENGTH is not longer + // than 24 + final int candidate = randomSubAddr & 0xff; + if (candidate == 0 || candidate == 1 || candidate == 255) { + return (randomSubAddr & 0xfffffffc) + 2; } - return subId; + return randomSubAddr; } /** Release downstream record for IpServer. */ @@ -218,14 +336,18 @@ public class PrivateAddressCoordinator { mUpstreamPrefixMap.clear(); } - private boolean isConflictWithUpstream(final IpPrefix source) { + private IpPrefix getConflictWithUpstream(final IpPrefix prefix) { for (int i = 0; i < mUpstreamPrefixMap.size(); i++) { final List<IpPrefix> list = mUpstreamPrefixMap.valueAt(i); - for (IpPrefix target : list) { - if (isConflictPrefix(source, target)) return true; + for (IpPrefix upstream : list) { + if (isConflictPrefix(prefix, upstream)) return upstream; } } - return false; + return null; + } + + private boolean isConflictWithUpstream(final IpPrefix prefix) { + return getConflictWithUpstream(prefix) != null; } private boolean isConflictPrefix(final IpPrefix prefix1, final IpPrefix prefix2) { @@ -236,35 +358,59 @@ public class PrivateAddressCoordinator { return prefix1.contains(prefix2.getAddress()); } - private boolean isDownstreamPrefixInUse(final IpPrefix source) { - // This class always generates downstream prefixes with the same prefix length, so - // prefixes cannot be contained in each other. They can only be equal to each other. + // InUse Prefixes are prefixes of mCachedAddresses which are active downstream addresses, last + // downstream addresses(reserved for next time) and static addresses(e.g. bluetooth, wifi p2p). + private IpPrefix getInUseDownstreamPrefix(final IpPrefix prefix) { + for (int i = 0; i < mCachedAddresses.size(); i++) { + final IpPrefix downstream = asIpPrefix(mCachedAddresses.valueAt(i)); + if (isConflictPrefix(prefix, downstream)) return downstream; + } + + // IpServer may use manually-defined address (mStaticIpv4ServerAddr) which does not include + // in mCachedAddresses. for (IpServer downstream : mDownstreams) { - final IpPrefix prefix = getDownstreamPrefix(downstream); - if (source.equals(prefix)) return true; + final IpPrefix target = getDownstreamPrefix(downstream); + + if (isConflictPrefix(prefix, target)) return target; } - return false; + + return null; } + @NonNull private IpPrefix getDownstreamPrefix(final IpServer downstream) { final LinkAddress address = downstream.getAddress(); - if (address == null) return null; - return PrefixUtils.asIpPrefix(address); + return asIpPrefix(address); } void dump(final IndentingPrintWriter pw) { + pw.println("mTetheringPrefixes:"); + pw.increaseIndent(); + for (IpPrefix prefix : mTetheringPrefixes) { + pw.println(prefix); + } + pw.decreaseIndent(); + pw.println("mUpstreamPrefixMap:"); pw.increaseIndent(); for (int i = 0; i < mUpstreamPrefixMap.size(); i++) { pw.println(mUpstreamPrefixMap.keyAt(i) + " - " + mUpstreamPrefixMap.valueAt(i)); } pw.decreaseIndent(); + pw.println("mDownstreams:"); pw.increaseIndent(); for (IpServer ipServer : mDownstreams) { pw.println(ipServer.interfaceType() + " - " + ipServer.getAddress()); } pw.decreaseIndent(); + + pw.println("mCachedAddresses:"); + pw.increaseIndent(); + for (int i = 0; i < mCachedAddresses.size(); i++) { + pw.println(mCachedAddresses.keyAt(i) + " - " + mCachedAddresses.valueAt(i)); + } + pw.decreaseIndent(); } } diff --git a/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java b/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java index 64d5025807e7..5a0c5b0cff5f 100644 --- a/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java +++ b/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java @@ -326,7 +326,7 @@ public class Tethering { // It is OK for the configuration to be passed to the PrivateAddressCoordinator at // construction time because the only part of the configuration it uses is // shouldEnableWifiP2pDedicatedIp(), and currently do not support changing that. - mPrivateAddressCoordinator = new PrivateAddressCoordinator(mContext, mConfig); + mPrivateAddressCoordinator = mDeps.getPrivateAddressCoordinator(mContext, mConfig); // Must be initialized after tethering configuration is loaded because BpfCoordinator // constructor needs to use the configuration. @@ -1678,14 +1678,6 @@ public class Tethering { } } - private void addUpstreamPrefixes(final UpstreamNetworkState ns) { - mPrivateAddressCoordinator.updateUpstreamPrefix(ns.network, ns.linkProperties); - } - - private void removeUpstreamPrefixes(final UpstreamNetworkState ns) { - mPrivateAddressCoordinator.removeUpstreamPrefix(ns.network); - } - @VisibleForTesting void handleUpstreamNetworkMonitorCallback(int arg1, Object o) { if (arg1 == UpstreamNetworkMonitor.NOTIFY_LOCAL_PREFIXES) { @@ -1696,10 +1688,10 @@ public class Tethering { final UpstreamNetworkState ns = (UpstreamNetworkState) o; switch (arg1) { case UpstreamNetworkMonitor.EVENT_ON_LINKPROPERTIES: - addUpstreamPrefixes(ns); + mPrivateAddressCoordinator.updateUpstreamPrefix(ns); break; case UpstreamNetworkMonitor.EVENT_ON_LOST: - removeUpstreamPrefixes(ns); + mPrivateAddressCoordinator.removeUpstreamPrefix(ns.network); break; } diff --git a/packages/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java b/packages/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java index 5783805861a3..799637c9b1c5 100644 --- a/packages/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java +++ b/packages/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java @@ -40,7 +40,6 @@ import java.util.Arrays; import java.util.Collection; import java.util.StringJoiner; - /** * A utility class to encapsulate the various tethering configuration elements. * @@ -88,6 +87,13 @@ public class TetheringConfiguration { "use_legacy_wifi_p2p_dedicated_ip"; /** + * Flag use to enable select all prefix ranges feature. + * TODO: Remove this flag if there are no problems after M-2020-12 rolls out. + */ + public static final String TETHER_ENABLE_SELECT_ALL_PREFIX_RANGES = + "tether_enable_select_all_prefix_ranges"; + + /** * Default value that used to periodic polls tether offload stats from tethering offload HAL * to make the data warnings work. */ @@ -118,6 +124,8 @@ public class TetheringConfiguration { private final boolean mEnableBpfOffload; private final boolean mEnableWifiP2pDedicatedIp; + private final boolean mEnableSelectAllPrefixRange; + public TetheringConfiguration(Context ctx, SharedLog log, int id) { final SharedLog configLog = log.forSubComponent("config"); @@ -164,6 +172,11 @@ public class TetheringConfiguration { R.bool.config_tether_enable_legacy_wifi_p2p_dedicated_ip, false /* defaultValue */); + // Flags should normally not be booleans, but this is a kill-switch flag that is only used + // to turn off the feature, so binary rollback problems do not apply. + mEnableSelectAllPrefixRange = getDeviceConfigBoolean( + TETHER_ENABLE_SELECT_ALL_PREFIX_RANGES, true /* defaultValue */); + configLog.log(toString()); } @@ -249,6 +262,9 @@ public class TetheringConfiguration { pw.print("enableWifiP2pDedicatedIp: "); pw.println(mEnableWifiP2pDedicatedIp); + + pw.print("mEnableSelectAllPrefixRange: "); + pw.println(mEnableSelectAllPrefixRange); } /** Returns the string representation of this object.*/ @@ -310,6 +326,10 @@ public class TetheringConfiguration { return mEnableBpfOffload; } + public boolean isSelectAllPrefixRangeEnabled() { + return mEnableSelectAllPrefixRange; + } + private static Collection<Integer> getUpstreamIfaceTypes(Resources res, boolean dunRequired) { final int[] ifaceTypes = res.getIntArray(R.array.config_tether_upstream_types); final ArrayList<Integer> upstreamIfaceTypes = new ArrayList<>(ifaceTypes.length); diff --git a/packages/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java b/packages/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java index 131a5fbf2abe..45b914178e97 100644 --- a/packages/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java +++ b/packages/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java @@ -156,4 +156,12 @@ public abstract class TetheringDependencies { public boolean isTetheringDenied() { return TextUtils.equals(SystemProperties.get("ro.tether.denied"), "true"); } + + /** + * Get a reference to PrivateAddressCoordinator to be used by Tethering. + */ + public PrivateAddressCoordinator getPrivateAddressCoordinator(Context ctx, + TetheringConfiguration cfg) { + return new PrivateAddressCoordinator(ctx, cfg); + } } diff --git a/packages/Tethering/tests/mts/Android.bp b/packages/Tethering/tests/mts/Android.bp new file mode 100644 index 000000000000..f925b0a53f32 --- /dev/null +++ b/packages/Tethering/tests/mts/Android.bp @@ -0,0 +1,56 @@ +// 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. + +android_test { + // This tests for functionality that is not required for devices that + // don't use Tethering mainline module. + name: "MtsTetheringTest", + + libs: [ + "android.test.base", + ], + + srcs: [ + "src/**/*.java", + ], + + static_libs: [ + "androidx.test.rules", + // mockito-target-extended-minus-junit4 used in this lib have dependency with + // jni_libs libdexmakerjvmtiagent and libstaticjvmtiagent. + "cts-net-utils", + // This is needed for androidx.test.runner.AndroidJUnitRunner. + "ctstestrunner-axt", + "junit", + "junit-params", + ], + + jni_libs: [ + // For mockito extended which is pulled in from -net-utils -> net-tests-utils + // (mockito-target-extended-minus-junit4). + "libdexmakerjvmtiagent", + "libstaticjvmtiagent", + ], + + platform_apis: true, + + // Tag this module as a mts test artifact + test_suites: [ + "general-tests", + "mts", + ], + + // Include both the 32 and 64 bit versions + compile_multilib: "both", +} diff --git a/packages/Tethering/tests/mts/AndroidManifest.xml b/packages/Tethering/tests/mts/AndroidManifest.xml new file mode 100644 index 000000000000..6d2abcad42a3 --- /dev/null +++ b/packages/Tethering/tests/mts/AndroidManifest.xml @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + * 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. + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="android.tethering.mts"> + + <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> + <uses-permission android:name="android.permission.INTERNET"/> + + <application android:debuggable="true"> + <uses-library android:name="android.test.runner" /> + </application> + <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="android.tethering.mts" + android:label="MTS tests of android.tethering"> + <meta-data android:name="listener" + android:value="com.android.cts.runner.CtsTestRunListener" /> + </instrumentation> + +</manifest> diff --git a/packages/Tethering/tests/mts/AndroidTest.xml b/packages/Tethering/tests/mts/AndroidTest.xml new file mode 100644 index 000000000000..80788dfa6f40 --- /dev/null +++ b/packages/Tethering/tests/mts/AndroidTest.xml @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2019 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<configuration description="Config for MTS Tethering test cases"> + <option name="test-suite-tag" value="mts" /> + <option name="config-descriptor:metadata" key="component" value="networking" /> + <!-- Instant app do not have INTERNET permission. --> + <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" /> + <!-- Feature is not backed by native code. --> + <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" /> + <!-- Allow running this against a secondary user. --> + <option name="config-descriptor:metadata" key="parameter" value="secondary_user" /> + <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> + <option name="cleanup-apks" value="true" /> + <option name="test-file-name" value="MtsTetheringTest.apk" /> + </target_preparer> + <test class="com.android.tradefed.testtype.AndroidJUnitTest" > + <option name="package" value="android.tethering.mts" /> + </test> + + <object type="module_controller" class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController"> + <option name="mainline-module-package-name" value="com.google.android.tethering" /> + </object> +</configuration> diff --git a/packages/Tethering/tests/mts/src/android/tethering/mts/TetheringModuleTest.java b/packages/Tethering/tests/mts/src/android/tethering/mts/TetheringModuleTest.java new file mode 100644 index 000000000000..7ffe37ad648d --- /dev/null +++ b/packages/Tethering/tests/mts/src/android/tethering/mts/TetheringModuleTest.java @@ -0,0 +1,183 @@ +/* + * 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.tethering.mts; + +import static android.Manifest.permission.MANAGE_TEST_NETWORKS; +import static android.Manifest.permission.NETWORK_SETTINGS; +import static android.Manifest.permission.READ_DEVICE_CONFIG; +import static android.Manifest.permission.TETHER_PRIVILEGED; +import static android.Manifest.permission.WRITE_SETTINGS; +import static android.net.cts.util.CtsTetheringUtils.isWifiTetheringSupported; +import static android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY; + +import static com.android.testutils.TestNetworkTrackerKt.initTestNetwork; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; +import static org.junit.Assume.assumeTrue; + +import android.app.UiAutomation; +import android.content.Context; +import android.net.IpPrefix; +import android.net.LinkAddress; +import android.net.TetheringManager; +import android.net.cts.util.CtsTetheringUtils; +import android.net.cts.util.CtsTetheringUtils.TestTetheringEventCallback; +import android.provider.DeviceConfig; + +import androidx.annotation.NonNull; +import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import com.android.testutils.TestNetworkTracker; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.net.InterfaceAddress; +import java.net.NetworkInterface; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +@RunWith(AndroidJUnit4.class) +public class TetheringModuleTest { + private Context mContext; + private TetheringManager mTm; + private CtsTetheringUtils mCtsTetheringUtils; + + private UiAutomation mUiAutomation = + InstrumentationRegistry.getInstrumentation().getUiAutomation(); + + @Before + public void setUp() throws Exception { + mUiAutomation.adoptShellPermissionIdentity(MANAGE_TEST_NETWORKS, NETWORK_SETTINGS, + WRITE_SETTINGS, READ_DEVICE_CONFIG, TETHER_PRIVILEGED); + mContext = InstrumentationRegistry.getContext(); + mTm = mContext.getSystemService(TetheringManager.class); + mCtsTetheringUtils = new CtsTetheringUtils(mContext); + } + + @After + public void tearDown() throws Exception { + mUiAutomation.dropShellPermissionIdentity(); + } + + private static final String TETHER_ENABLE_SELECT_ALL_PREFIX_RANGES = + "tether_enable_select_all_prefix_ranges"; + @Test + public void testSwitchBasePrefixRangeWhenConflict() throws Exception { + assumeTrue(isFeatureEnabled(TETHER_ENABLE_SELECT_ALL_PREFIX_RANGES, true)); + + addressConflictTest(true); + } + + @Test + public void testSwitchPrefixRangeWhenConflict() throws Exception { + addressConflictTest(false); + } + + private void addressConflictTest(final boolean wholeRangeConflict) throws Exception { + final TestTetheringEventCallback tetherEventCallback = + mCtsTetheringUtils.registerTetheringEventCallback(); + + TestNetworkTracker tnt = null; + try { + tetherEventCallback.assumeTetheringSupported(); + assumeTrue(isWifiTetheringSupported(tetherEventCallback)); + + mCtsTetheringUtils.startWifiTethering(tetherEventCallback); + + final List<String> tetheredIfaces = tetherEventCallback.getTetheredInterfaces(); + assertEquals(1, tetheredIfaces.size()); + final String wifiTetheringIface = tetheredIfaces.get(0); + + NetworkInterface nif = NetworkInterface.getByName(wifiTetheringIface); + // Tethering downstream only have one ipv4 address. + final LinkAddress hotspotAddr = getFirstIpv4Address(nif); + assertNotNull(hotspotAddr); + + final IpPrefix testPrefix = getConflictingPrefix(hotspotAddr, wholeRangeConflict); + assertNotNull(testPrefix); + + tnt = setUpTestNetwork( + new LinkAddress(testPrefix.getAddress(), testPrefix.getPrefixLength())); + + tetherEventCallback.expectTetheredInterfacesChanged(null); + final List<String> wifiRegexs = + tetherEventCallback.getTetheringInterfaceRegexps().getTetherableWifiRegexs(); + + tetherEventCallback.expectTetheredInterfacesChanged(wifiRegexs); + nif = NetworkInterface.getByName(wifiTetheringIface); + final LinkAddress newHotspotAddr = getFirstIpv4Address(nif); + assertNotNull(newHotspotAddr); + + assertFalse(testPrefix.containsPrefix( + new IpPrefix(newHotspotAddr.getAddress(), newHotspotAddr.getPrefixLength()))); + + mCtsTetheringUtils.stopWifiTethering(tetherEventCallback); + } finally { + if (tnt != null) { + tnt.teardown(); + } + mTm.stopAllTethering(); + mCtsTetheringUtils.unregisterTetheringEventCallback(tetherEventCallback); + } + } + + private LinkAddress getFirstIpv4Address(final NetworkInterface nif) { + for (InterfaceAddress ia : nif.getInterfaceAddresses()) { + final LinkAddress addr = new LinkAddress(ia.getAddress(), ia.getNetworkPrefixLength()); + if (addr.isIpv4()) return addr; + } + return null; + } + + @NonNull + private IpPrefix getConflictingPrefix(final LinkAddress address, + final boolean wholeRangeConflict) { + if (!wholeRangeConflict) { + return new IpPrefix(address.getAddress(), address.getPrefixLength()); + } + + final ArrayList<IpPrefix> prefixPool = new ArrayList<>(Arrays.asList( + new IpPrefix("192.168.0.0/16"), + new IpPrefix("172.16.0.0/12"), + new IpPrefix("10.0.0.0/8"))); + + for (IpPrefix prefix : prefixPool) { + if (prefix.contains(address.getAddress())) return prefix; + } + + fail("Could not find sutiable conflict prefix"); + + // Never go here. + return null; + } + + private TestNetworkTracker setUpTestNetwork(final LinkAddress address) throws Exception { + return initTestNetwork(mContext, address, 10_000L /* test timeout ms*/); + + } + + public static boolean isFeatureEnabled(final String name, final boolean defaultValue) { + return DeviceConfig.getBoolean(NAMESPACE_CONNECTIVITY, name, defaultValue); + } +} diff --git a/packages/Tethering/tests/privileged/src/android/net/ip/DadProxyTest.java b/packages/Tethering/tests/privileged/src/android/net/ip/DadProxyTest.java index 747d3e803026..42a91aa9acd5 100644 --- a/packages/Tethering/tests/privileged/src/android/net/ip/DadProxyTest.java +++ b/packages/Tethering/tests/privileged/src/android/net/ip/DadProxyTest.java @@ -17,9 +17,9 @@ package android.net.ip; import static android.system.OsConstants.IPPROTO_ICMPV6; -import static android.system.OsConstants.IPPROTO_TCP; -import static com.android.internal.util.BitUtils.uint16; +import static com.android.net.module.util.IpUtils.icmpv6Checksum; +import static com.android.net.module.util.NetworkStackConstants.ETHER_SRC_ADDR_OFFSET; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -30,34 +30,29 @@ import android.content.Context; import android.net.INetd; import android.net.InetAddresses; import android.net.MacAddress; -import android.net.TestNetworkInterface; -import android.net.TestNetworkManager; import android.net.util.InterfaceParams; -import android.net.util.IpUtils; import android.net.util.TetheringUtils; import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; import android.os.Looper; -import android.system.ErrnoException; -import android.system.Os; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.testutils.TapPacketReader; +import com.android.testutils.TapPacketReaderRule; import org.junit.After; import org.junit.Before; import org.junit.BeforeClass; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.MockitoAnnotations; -import java.io.FileDescriptor; import java.nio.ByteBuffer; -import java.util.concurrent.atomic.AtomicReference; @RunWith(AndroidJUnit4.class) @SmallTest @@ -65,16 +60,18 @@ public class DadProxyTest { private static final int DATA_BUFFER_LEN = 4096; private static final int PACKET_TIMEOUT_MS = 5_000; - // TODO: make NetworkStackConstants accessible to this test and use the constant from there. - private static final int ETHER_SRC_ADDR_OFFSET = 6; + // Start the readers manually on a common handler shared with DadProxy, for simplicity + @Rule + public final TapPacketReaderRule mUpstreamReader = new TapPacketReaderRule( + DATA_BUFFER_LEN, false /* autoStart */); + @Rule + public final TapPacketReaderRule mTetheredReader = new TapPacketReaderRule( + DATA_BUFFER_LEN, false /* autoStart */); - private DadProxy mProxy; - TestNetworkInterface mUpstreamTestIface, mTetheredTestIface; private InterfaceParams mUpstreamParams, mTetheredParams; private HandlerThread mHandlerThread; private Handler mHandler; private TapPacketReader mUpstreamPacketReader, mTetheredPacketReader; - private FileDescriptor mUpstreamTapFd, mTetheredTapFd; private static INetd sNetd; @@ -106,12 +103,12 @@ public class DadProxyTest { @After public void tearDown() throws Exception { + mUpstreamReader.stop(); + mTetheredReader.stop(); + if (mHandlerThread != null) { - mHandler.post(mUpstreamPacketReader::stop); // Also closes the socket - mHandler.post(mTetheredPacketReader::stop); // Also closes the socket - mUpstreamTapFd = null; - mTetheredTapFd = null; mHandlerThread.quitSafely(); + mHandlerThread.join(PACKET_TIMEOUT_MS); } if (mTetheredParams != null) { @@ -120,54 +117,20 @@ public class DadProxyTest { if (mUpstreamParams != null) { sNetd.networkRemoveInterface(INetd.LOCAL_NET_ID, mUpstreamParams.name); } - - if (mUpstreamTestIface != null) { - try { - Os.close(mUpstreamTestIface.getFileDescriptor().getFileDescriptor()); - } catch (ErrnoException e) { } - } - - if (mTetheredTestIface != null) { - try { - Os.close(mTetheredTestIface.getFileDescriptor().getFileDescriptor()); - } catch (ErrnoException e) { } - } - } - - private TestNetworkInterface setupTapInterface() { - final Instrumentation inst = InstrumentationRegistry.getInstrumentation(); - AtomicReference<TestNetworkInterface> iface = new AtomicReference<>(); - - inst.getUiAutomation().adoptShellPermissionIdentity(); - try { - final TestNetworkManager tnm = (TestNetworkManager) inst.getContext().getSystemService( - Context.TEST_NETWORK_SERVICE); - iface.set(tnm.createTapInterface()); - } finally { - inst.getUiAutomation().dropShellPermissionIdentity(); - } - - return iface.get(); } private void setupTapInterfaces() { // Create upstream test iface. - mUpstreamTestIface = setupTapInterface(); - mUpstreamParams = InterfaceParams.getByName(mUpstreamTestIface.getInterfaceName()); + mUpstreamReader.start(mHandler); + mUpstreamParams = InterfaceParams.getByName(mUpstreamReader.iface.getInterfaceName()); assertNotNull(mUpstreamParams); - mUpstreamTapFd = mUpstreamTestIface.getFileDescriptor().getFileDescriptor(); - mUpstreamPacketReader = new TapPacketReader(mHandler, mUpstreamTapFd, - DATA_BUFFER_LEN); - mHandler.post(mUpstreamPacketReader::start); + mUpstreamPacketReader = mUpstreamReader.getReader(); // Create tethered test iface. - mTetheredTestIface = setupTapInterface(); - mTetheredParams = InterfaceParams.getByName(mTetheredTestIface.getInterfaceName()); + mTetheredReader.start(mHandler); + mTetheredParams = InterfaceParams.getByName(mTetheredReader.getIface().getInterfaceName()); assertNotNull(mTetheredParams); - mTetheredTapFd = mTetheredTestIface.getFileDescriptor().getFileDescriptor(); - mTetheredPacketReader = new TapPacketReader(mHandler, mTetheredTapFd, - DATA_BUFFER_LEN); - mHandler.post(mTetheredPacketReader::start); + mTetheredPacketReader = mTetheredReader.getReader(); } private static final int IPV6_HEADER_LEN = 40; @@ -177,31 +140,6 @@ public class DadProxyTest { private static final int ICMPV6_CHECKSUM_OFFSET = 2; private static final int ETHER_TYPE_IPV6 = 0x86dd; - // TODO: move the IpUtils code to frameworks/lib/net and link it statically. - private static int checksumFold(int sum) { - while (sum > 0xffff) { - sum = (sum >> 16) + (sum & 0xffff); - } - return sum; - } - - // TODO: move the IpUtils code to frameworks/lib/net and link it statically. - private static short checksumAdjust(short checksum, short oldWord, short newWord) { - checksum = (short) ~checksum; - int tempSum = checksumFold(uint16(checksum) + uint16(newWord) + 0xffff - uint16(oldWord)); - return (short) ~tempSum; - } - - // TODO: move the IpUtils code to frameworks/lib/net and link it statically. - private static short icmpv6Checksum(ByteBuffer buf, int ipOffset, int transportOffset, - int transportLen) { - // The ICMPv6 checksum is the same as the TCP checksum, except the pseudo-header uses - // 58 (ICMPv6) instead of 6 (TCP). Calculate the TCP checksum, and then do an incremental - // checksum adjustment for the change in the next header byte. - short checksum = IpUtils.tcpChecksum(buf, ipOffset, transportOffset, transportLen); - return checksumAdjust(checksum, (short) IPPROTO_TCP, (short) IPPROTO_ICMPV6); - } - private static ByteBuffer createDadPacket(int type) { // Refer to buildArpPacket() int icmpLen = ICMPV6_NA_NS_LEN diff --git a/packages/Tethering/tests/privileged/src/com/android/networkstack/tethering/ConntrackSocketTest.java b/packages/Tethering/tests/privileged/src/com/android/networkstack/tethering/ConntrackSocketTest.java new file mode 100644 index 000000000000..57c28fc67cc3 --- /dev/null +++ b/packages/Tethering/tests/privileged/src/com/android/networkstack/tethering/ConntrackSocketTest.java @@ -0,0 +1,130 @@ +/* + * 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 com.android.networkstack.tethering; + +import static android.net.netlink.NetlinkSocket.DEFAULT_RECV_BUFSIZE; +import static android.net.netlink.StructNlMsgHdr.NLM_F_DUMP; +import static android.net.netlink.StructNlMsgHdr.NLM_F_REQUEST; + +import static com.android.networkstack.tethering.OffloadHardwareInterface.IPCTNL_MSG_CT_GET; +import static com.android.networkstack.tethering.OffloadHardwareInterface.IPCTNL_MSG_CT_NEW; +import static com.android.networkstack.tethering.OffloadHardwareInterface.NFNL_SUBSYS_CTNETLINK; +import static com.android.networkstack.tethering.OffloadHardwareInterface.NF_NETLINK_CONNTRACK_DESTROY; +import static com.android.networkstack.tethering.OffloadHardwareInterface.NF_NETLINK_CONNTRACK_NEW; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import android.net.netlink.StructNlMsgHdr; +import android.net.util.SharedLog; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Looper; +import android.os.NativeHandle; +import android.system.Os; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.MockitoAnnotations; + +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketAddress; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class ConntrackSocketTest { + private static final long TIMEOUT = 500; + + private HandlerThread mHandlerThread; + private Handler mHandler; + private final SharedLog mLog = new SharedLog("privileged-test"); + + private OffloadHardwareInterface mOffloadHw; + private OffloadHardwareInterface.Dependencies mDeps; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + + mHandlerThread = new HandlerThread(getClass().getSimpleName()); + mHandlerThread.start(); + mHandler = new Handler(mHandlerThread.getLooper()); + + // Looper must be prepared here since AndroidJUnitRunner runs tests on separate threads. + if (Looper.myLooper() == null) Looper.prepare(); + + mDeps = new OffloadHardwareInterface.Dependencies(mLog); + mOffloadHw = new OffloadHardwareInterface(mHandler, mLog, mDeps); + } + + @Test + public void testIpv4ConntrackSocket() throws Exception { + // Set up server and connect. + final InetSocketAddress anyAddress = new InetSocketAddress( + InetAddress.getByName("127.0.0.1"), 0); + final ServerSocket serverSocket = new ServerSocket(); + serverSocket.bind(anyAddress); + final SocketAddress theAddress = serverSocket.getLocalSocketAddress(); + + // Make a connection to the server. + final Socket socket = new Socket(); + socket.connect(theAddress); + final Socket acceptedSocket = serverSocket.accept(); + + final NativeHandle handle = mDeps.createConntrackSocket( + NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY); + mOffloadHw.sendIpv4NfGenMsg(handle, + (short) ((NFNL_SUBSYS_CTNETLINK << 8) | IPCTNL_MSG_CT_GET), + (short) (NLM_F_REQUEST | NLM_F_DUMP)); + + boolean foundConntrackEntry = false; + ByteBuffer buffer = ByteBuffer.allocate(DEFAULT_RECV_BUFSIZE); + buffer.order(ByteOrder.nativeOrder()); + + try { + while (Os.read(handle.getFileDescriptor(), buffer) > 0) { + buffer.flip(); + + // TODO: ConntrackMessage should get a parse API like StructNlMsgHdr + // so we can confirm that the conntrack added is for the TCP connection above. + final StructNlMsgHdr nlmsghdr = StructNlMsgHdr.parse(buffer); + assertNotNull(nlmsghdr); + + // As long as 1 conntrack entry is found test case will pass, even if it's not + // the from the TCP connection above. + if (nlmsghdr.nlmsg_type == ((NFNL_SUBSYS_CTNETLINK << 8) | IPCTNL_MSG_CT_NEW)) { + foundConntrackEntry = true; + break; + } + } + } finally { + socket.close(); + serverSocket.close(); + } + assertTrue("Did not receive any NFNL_SUBSYS_CTNETLINK/IPCTNL_MSG_CT_NEW message", + foundConntrackEntry); + } +} diff --git a/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java index 1a976adc60e0..2eb75895ac3e 100644 --- a/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java +++ b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java @@ -47,6 +47,7 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyBoolean; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doAnswer; @@ -230,7 +231,8 @@ public class IpServerTest { dispatchTetherConnectionChanged(upstreamIface, lp, 0); } reset(mNetd, mCallback, mAddressCoordinator); - when(mAddressCoordinator.requestDownstreamAddress(any())).thenReturn(mTestAddress); + when(mAddressCoordinator.requestDownstreamAddress(any(), anyBoolean())).thenReturn( + mTestAddress); } private void setUpDhcpServer() throws Exception { @@ -250,7 +252,8 @@ public class IpServerTest { @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); when(mSharedLog.forSubComponent(anyString())).thenReturn(mSharedLog); - when(mAddressCoordinator.requestDownstreamAddress(any())).thenReturn(mTestAddress); + when(mAddressCoordinator.requestDownstreamAddress(any(), anyBoolean())).thenReturn( + mTestAddress); when(mTetherConfig.isBpfOffloadEnabled()).thenReturn(true /* default value */); mBpfCoordinator = spy(new BpfCoordinator( @@ -372,7 +375,7 @@ public class IpServerTest { dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED); InOrder inOrder = inOrder(mCallback, mNetd, mAddressCoordinator); - inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any()); + inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any(), eq(true)); inOrder.verify(mNetd).interfaceSetCfg(argThat(cfg -> IFACE_NAME.equals(cfg.ifName) && assertContainsFlag(cfg.flags, IF_STATE_UP))); inOrder.verify(mNetd).tetherInterfaceAdd(IFACE_NAME); @@ -393,7 +396,7 @@ public class IpServerTest { dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_LOCAL_ONLY); InOrder inOrder = inOrder(mCallback, mNetd, mAddressCoordinator); - inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any()); + inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any(), eq(true)); inOrder.verify(mNetd).interfaceSetCfg(argThat(cfg -> IFACE_NAME.equals(cfg.ifName) && assertNotContainsFlag(cfg.flags, IF_STATE_UP))); inOrder.verify(mNetd).tetherInterfaceAdd(IFACE_NAME); @@ -607,7 +610,7 @@ public class IpServerTest { final ArgumentCaptor<LinkProperties> lpCaptor = ArgumentCaptor.forClass(LinkProperties.class); InOrder inOrder = inOrder(mNetd, mCallback, mAddressCoordinator); - inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any()); + inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any(), eq(true)); inOrder.verify(mNetd).networkAddInterface(INetd.LOCAL_NET_ID, IFACE_NAME); // One for ipv4 route, one for ipv6 link local route. inOrder.verify(mNetd, times(2)).networkAddRoute(eq(INetd.LOCAL_NET_ID), eq(IFACE_NAME), @@ -620,11 +623,12 @@ public class IpServerTest { // Simulate the DHCP server receives DHCPDECLINE on MirrorLink and then signals // onNewPrefixRequest callback. final LinkAddress newAddress = new LinkAddress("192.168.100.125/24"); - when(mAddressCoordinator.requestDownstreamAddress(any())).thenReturn(newAddress); + when(mAddressCoordinator.requestDownstreamAddress(any(), anyBoolean())).thenReturn( + newAddress); eventCallbacks.onNewPrefixRequest(new IpPrefix("192.168.42.0/24")); mLooper.dispatchAll(); - inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any()); + inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any(), eq(false)); inOrder.verify(mNetd).tetherApplyDnsInterfaces(); inOrder.verify(mCallback).updateLinkProperties(eq(mIpServer), lpCaptor.capture()); verifyNoMoreInteractions(mCallback); diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHardwareInterfaceTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHardwareInterfaceTest.java index c543fad62dba..38b19dd3da5c 100644 --- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHardwareInterfaceTest.java +++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHardwareInterfaceTest.java @@ -17,8 +17,9 @@ package com.android.networkstack.tethering; import static android.net.util.TetheringUtils.uint16; -import static android.system.OsConstants.SOCK_STREAM; +import static android.system.OsConstants.AF_INET; import static android.system.OsConstants.AF_UNIX; +import static android.system.OsConstants.SOCK_STREAM; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -35,14 +36,15 @@ import android.hardware.tetheroffload.control.V1_0.ITetheringOffloadCallback; import android.hardware.tetheroffload.control.V1_0.NatTimeoutUpdate; import android.hardware.tetheroffload.control.V1_0.NetworkProtocol; import android.hardware.tetheroffload.control.V1_0.OffloadCallbackEvent; +import android.net.netlink.StructNfGenMsg; import android.net.netlink.StructNlMsgHdr; import android.net.util.SharedLog; import android.os.Handler; import android.os.NativeHandle; import android.os.test.TestLooper; import android.system.ErrnoException; -import android.system.OsConstants; import android.system.Os; +import android.system.OsConstants; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -55,8 +57,8 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.io.FileDescriptor; -import java.io.OutputStream; import java.nio.ByteBuffer; +import java.nio.ByteOrder; import java.util.ArrayList; @RunWith(AndroidJUnit4.class) @@ -218,7 +220,7 @@ public final class OffloadHardwareInterfaceTest { } @Test - public void testNetlinkMessage() throws Exception { + public void testSendIpv4NfGenMsg() throws Exception { FileDescriptor writeSocket = new FileDescriptor(); FileDescriptor readSocket = new FileDescriptor(); try { @@ -229,17 +231,25 @@ public final class OffloadHardwareInterfaceTest { } when(mNativeHandle.getFileDescriptor()).thenReturn(writeSocket); - mOffloadHw.sendNetlinkMessage(mNativeHandle, TEST_TYPE, TEST_FLAGS); + mOffloadHw.sendIpv4NfGenMsg(mNativeHandle, TEST_TYPE, TEST_FLAGS); + + ByteBuffer buffer = ByteBuffer.allocate(9823); // Arbitrary value > expectedLen. + buffer.order(ByteOrder.nativeOrder()); - ByteBuffer buffer = ByteBuffer.allocate(StructNlMsgHdr.STRUCT_SIZE); int read = Os.read(readSocket, buffer); + final int expectedLen = StructNlMsgHdr.STRUCT_SIZE + StructNfGenMsg.STRUCT_SIZE; + assertEquals(expectedLen, read); buffer.flip(); - assertEquals(StructNlMsgHdr.STRUCT_SIZE, buffer.getInt()); + assertEquals(expectedLen, buffer.getInt()); assertEquals(TEST_TYPE, buffer.getShort()); assertEquals(TEST_FLAGS, buffer.getShort()); - assertEquals(1 /* seq */, buffer.getInt()); + assertEquals(0 /* seq */, buffer.getInt()); assertEquals(0 /* pid */, buffer.getInt()); + assertEquals(AF_INET, buffer.get()); // nfgen_family + assertEquals(0 /* error */, buffer.get()); // version + assertEquals(0 /* error */, buffer.getShort()); // res_id + assertEquals(expectedLen, buffer.position()); } private NatTimeoutUpdate buildNatTimeoutUpdate(final int proto) { diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java index 8e93c2e447b3..41d46e522ca4 100644 --- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java +++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java @@ -15,10 +15,15 @@ */ package com.android.networkstack.tethering; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; +import static android.net.NetworkCapabilities.TRANSPORT_VPN; +import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.net.TetheringManager.TETHERING_ETHERNET; import static android.net.TetheringManager.TETHERING_USB; import static android.net.TetheringManager.TETHERING_WIFI; import static android.net.TetheringManager.TETHERING_WIFI_P2P; +import static android.net.util.PrefixUtils.asIpPrefix; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; @@ -30,14 +35,12 @@ import static org.mockito.Mockito.when; import android.content.Context; import android.net.ConnectivityManager; -import android.net.InetAddresses; import android.net.IpPrefix; import android.net.LinkAddress; import android.net.LinkProperties; import android.net.Network; +import android.net.NetworkCapabilities; import android.net.ip.IpServer; -import android.net.util.NetworkConstants; -import android.net.util.PrefixUtils; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -48,13 +51,13 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import java.util.List; +import java.util.ArrayList; +import java.util.Arrays; @RunWith(AndroidJUnit4.class) @SmallTest public final class PrivateAddressCoordinatorTest { - private static final String TEST_MOBILE_IFNAME = "test_rmnet_data0"; - private static final String TEST_WIFI_IFNAME = "test_wlan0"; + private static final String TEST_IFNAME = "test0"; @Mock private IpServer mHotspotIpServer; @Mock private IpServer mUsbIpServer; @@ -65,11 +68,22 @@ public final class PrivateAddressCoordinatorTest { @Mock private TetheringConfiguration mConfig; private PrivateAddressCoordinator mPrivateAddressCoordinator; - private final IpPrefix mBluetoothPrefix = new IpPrefix("192.168.44.0/24"); + private final LinkAddress mBluetoothAddress = new LinkAddress("192.168.44.1/24"); private final LinkAddress mLegacyWifiP2pAddress = new LinkAddress("192.168.49.1/24"); private final Network mWifiNetwork = new Network(1); private final Network mMobileNetwork = new Network(2); - private final Network[] mAllNetworks = {mMobileNetwork, mWifiNetwork}; + private final Network mVpnNetwork = new Network(3); + private final Network mMobileNetwork2 = new Network(4); + private final Network mMobileNetwork3 = new Network(5); + private final Network mMobileNetwork4 = new Network(6); + private final Network mMobileNetwork5 = new Network(7); + private final Network mMobileNetwork6 = new Network(8); + private final Network[] mAllNetworks = {mMobileNetwork, mWifiNetwork, mVpnNetwork, + mMobileNetwork2, mMobileNetwork3, mMobileNetwork4, mMobileNetwork5, mMobileNetwork6}; + private final ArrayList<IpPrefix> mTetheringPrefixes = new ArrayList<>(Arrays.asList( + new IpPrefix("192.168.0.0/16"), + new IpPrefix("172.16.0.0/12"), + new IpPrefix("10.0.0.0/8"))); private void setUpIpServers() throws Exception { when(mUsbIpServer.interfaceType()).thenReturn(TETHERING_USB); @@ -85,195 +99,422 @@ public final class PrivateAddressCoordinatorTest { when(mContext.getSystemService(Context.CONNECTIVITY_SERVICE)).thenReturn(mConnectivityMgr); when(mConnectivityMgr.getAllNetworks()).thenReturn(mAllNetworks); when(mConfig.shouldEnableWifiP2pDedicatedIp()).thenReturn(false); + when(mConfig.isSelectAllPrefixRangeEnabled()).thenReturn(true); setUpIpServers(); mPrivateAddressCoordinator = spy(new PrivateAddressCoordinator(mContext, mConfig)); } + private LinkAddress requestDownstreamAddress(final IpServer ipServer, boolean useLastAddress) { + final LinkAddress address = mPrivateAddressCoordinator.requestDownstreamAddress( + ipServer, useLastAddress); + when(ipServer.getAddress()).thenReturn(address); + return address; + } + @Test - public void testDownstreamPrefixRequest() throws Exception { - LinkAddress address = mPrivateAddressCoordinator.requestDownstreamAddress( - mHotspotIpServer); - final IpPrefix hotspotPrefix = PrefixUtils.asIpPrefix(address); - assertNotEquals(hotspotPrefix, mBluetoothPrefix); - - address = mPrivateAddressCoordinator.requestDownstreamAddress( - mHotspotIpServer); - final IpPrefix testDupRequest = PrefixUtils.asIpPrefix(address); + public void testRequestDownstreamAddressWithoutUsingLastAddress() throws Exception { + final IpPrefix bluetoothPrefix = asIpPrefix(mBluetoothAddress); + final LinkAddress address = requestDownstreamAddress(mHotspotIpServer, + false /* useLastAddress */); + final IpPrefix hotspotPrefix = asIpPrefix(address); + assertNotEquals(hotspotPrefix, bluetoothPrefix); + + final LinkAddress newAddress = requestDownstreamAddress(mHotspotIpServer, + false /* useLastAddress */); + final IpPrefix testDupRequest = asIpPrefix(newAddress); assertNotEquals(hotspotPrefix, testDupRequest); - assertNotEquals(mBluetoothPrefix, testDupRequest); + assertNotEquals(bluetoothPrefix, testDupRequest); mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); - address = mPrivateAddressCoordinator.requestDownstreamAddress( - mUsbIpServer); - final IpPrefix usbPrefix = PrefixUtils.asIpPrefix(address); - assertNotEquals(usbPrefix, mBluetoothPrefix); + final LinkAddress usbAddress = requestDownstreamAddress(mUsbIpServer, + false /* useLastAddress */); + final IpPrefix usbPrefix = asIpPrefix(usbAddress); + assertNotEquals(usbPrefix, bluetoothPrefix); assertNotEquals(usbPrefix, hotspotPrefix); mPrivateAddressCoordinator.releaseDownstream(mUsbIpServer); } @Test - public void testRequestDownstreamAddress() throws Exception { - LinkAddress expectedAddress = new LinkAddress("192.168.43.42/24"); - int fakeSubAddr = 0x2b00; - when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeSubAddr); - LinkAddress actualAddress = mPrivateAddressCoordinator.requestDownstreamAddress( - mHotspotIpServer); - assertEquals(actualAddress, expectedAddress); + public void testSanitizedAddress() throws Exception { + int fakeSubAddr = 0x2b00; // 43.0. + when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(fakeSubAddr); + LinkAddress actualAddress = requestDownstreamAddress(mHotspotIpServer, + false /* useLastAddress */); + assertEquals(new LinkAddress("192.168.43.2/24"), actualAddress); mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); - fakeSubAddr = 0x2b01; - when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeSubAddr); - actualAddress = mPrivateAddressCoordinator.requestDownstreamAddress( - mHotspotIpServer); - assertEquals(actualAddress, expectedAddress); + fakeSubAddr = 0x2d01; // 45.1. + when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(fakeSubAddr); + actualAddress = requestDownstreamAddress(mHotspotIpServer, false /* useLastAddress */); + assertEquals(new LinkAddress("192.168.45.2/24"), actualAddress); mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); - fakeSubAddr = 0x2bff; - when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeSubAddr); - actualAddress = mPrivateAddressCoordinator.requestDownstreamAddress( - mHotspotIpServer); - assertEquals(actualAddress, expectedAddress); + fakeSubAddr = 0x2eff; // 46.255. + when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(fakeSubAddr); + actualAddress = requestDownstreamAddress(mHotspotIpServer, false /* useLastAddress */); + assertEquals(new LinkAddress("192.168.46.254/24"), actualAddress); mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); - expectedAddress = new LinkAddress("192.168.43.5/24"); - fakeSubAddr = 0x2b05; - when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeSubAddr); - actualAddress = mPrivateAddressCoordinator.requestDownstreamAddress( - mHotspotIpServer); - assertEquals(actualAddress, expectedAddress); + fakeSubAddr = 0x2f05; // 47.5. + when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(fakeSubAddr); + actualAddress = requestDownstreamAddress(mHotspotIpServer, false /* useLastAddress */); + assertEquals(new LinkAddress("192.168.47.5/24"), actualAddress); mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); } - private int getBluetoothSubAddress() { - final byte[] rawAddress = mBluetoothPrefix.getRawAddress(); - int bluetoothSubNet = rawAddress[2] & 0xff; - return (bluetoothSubNet << 8) + 0x5; - } - @Test - public void testReserveBluetoothPrefix() throws Exception { - when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(getBluetoothSubAddress()); - LinkAddress address = mPrivateAddressCoordinator.requestDownstreamAddress( - mHotspotIpServer); - final IpPrefix hotspotPrefix = PrefixUtils.asIpPrefix(address); - assertNotEquals("Should not get reserved prefix: ", mBluetoothPrefix, hotspotPrefix); + public void testReservedPrefix() throws Exception { + // - Test bluetooth prefix is reserved. + when(mPrivateAddressCoordinator.getRandomInt()).thenReturn( + getSubAddress(mBluetoothAddress.getAddress().getAddress())); + final LinkAddress hotspotAddress = requestDownstreamAddress(mHotspotIpServer, + false /* useLastAddress */); + final IpPrefix hotspotPrefix = asIpPrefix(hotspotAddress); + assertNotEquals(asIpPrefix(mBluetoothAddress), hotspotPrefix); mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); + + // - Test previous enabled hotspot prefix(cached prefix) is reserved. + when(mPrivateAddressCoordinator.getRandomInt()).thenReturn( + getSubAddress(hotspotAddress.getAddress().getAddress())); + final LinkAddress usbAddress = requestDownstreamAddress(mUsbIpServer, + false /* useLastAddress */); + final IpPrefix usbPrefix = asIpPrefix(usbAddress); + assertNotEquals(asIpPrefix(mBluetoothAddress), usbPrefix); + assertNotEquals(hotspotPrefix, usbPrefix); + mPrivateAddressCoordinator.releaseDownstream(mUsbIpServer); + + // - Test wifi p2p prefix is reserved. + when(mPrivateAddressCoordinator.getRandomInt()).thenReturn( + getSubAddress(mLegacyWifiP2pAddress.getAddress().getAddress())); + final LinkAddress etherAddress = requestDownstreamAddress(mEthernetIpServer, + false /* useLastAddress */); + final IpPrefix etherPrefix = asIpPrefix(etherAddress); + assertNotEquals(asIpPrefix(mLegacyWifiP2pAddress), etherPrefix); + assertNotEquals(asIpPrefix(mBluetoothAddress), etherPrefix); + assertNotEquals(hotspotPrefix, etherPrefix); + mPrivateAddressCoordinator.releaseDownstream(mEthernetIpServer); } @Test - public void testNoConflictDownstreamPrefix() throws Exception { - final int fakeHotspotSubAddr = 0x2b05; - final IpPrefix predefinedPrefix = new IpPrefix("192.168.43.0/24"); - when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeHotspotSubAddr); - LinkAddress address = mPrivateAddressCoordinator.requestDownstreamAddress( - mHotspotIpServer); - final IpPrefix hotspotPrefix = PrefixUtils.asIpPrefix(address); - assertEquals("Wrong wifi prefix: ", predefinedPrefix, hotspotPrefix); - when(mHotspotIpServer.getAddress()).thenReturn(address); + public void testRequestLastDownstreamAddress() throws Exception { + final int fakeHotspotSubAddr = 0x2b05; // 43.5 + when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(fakeHotspotSubAddr); + final LinkAddress hotspotAddress = requestDownstreamAddress(mHotspotIpServer, + true /* useLastAddress */); + assertEquals("Wrong wifi prefix: ", new LinkAddress("192.168.43.5/24"), hotspotAddress); - address = mPrivateAddressCoordinator.requestDownstreamAddress( - mUsbIpServer); - final IpPrefix usbPrefix = PrefixUtils.asIpPrefix(address); - assertNotEquals(predefinedPrefix, usbPrefix); + final LinkAddress usbAddress = requestDownstreamAddress(mUsbIpServer, + true /* useLastAddress */); + assertEquals("Wrong wifi prefix: ", new LinkAddress("192.168.45.5/24"), usbAddress); mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); mPrivateAddressCoordinator.releaseDownstream(mUsbIpServer); - address = mPrivateAddressCoordinator.requestDownstreamAddress( - mUsbIpServer); - final IpPrefix allowUseFreePrefix = PrefixUtils.asIpPrefix(address); - assertEquals("Fail to reselect available prefix: ", predefinedPrefix, allowUseFreePrefix); - } - private LinkProperties buildUpstreamLinkProperties(boolean withIPv4, boolean withIPv6, - boolean isMobile) { - final String testIface; - final String testIpv4Address; - if (isMobile) { - testIface = TEST_MOBILE_IFNAME; - testIpv4Address = "10.0.0.1"; - } else { - testIface = TEST_WIFI_IFNAME; - testIpv4Address = "192.168.43.5"; - } + final int newFakeSubAddr = 0x3c05; + when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(fakeHotspotSubAddr); + + final LinkAddress newHotspotAddress = requestDownstreamAddress(mHotspotIpServer, + true /* useLastAddress */); + assertEquals(hotspotAddress, newHotspotAddress); + final LinkAddress newUsbAddress = requestDownstreamAddress(mUsbIpServer, + true /* useLastAddress */); + assertEquals(usbAddress, newUsbAddress); + + final UpstreamNetworkState wifiUpstream = buildUpstreamNetworkState(mWifiNetwork, + new LinkAddress("192.168.88.23/16"), null, + makeNetworkCapabilities(TRANSPORT_WIFI)); + mPrivateAddressCoordinator.updateUpstreamPrefix(wifiUpstream); + verify(mHotspotIpServer).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT); + verify(mUsbIpServer).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT); + } + private UpstreamNetworkState buildUpstreamNetworkState(final Network network, + final LinkAddress v4Addr, final LinkAddress v6Addr, final NetworkCapabilities cap) { final LinkProperties prop = new LinkProperties(); - prop.setInterfaceName(testIface); + prop.setInterfaceName(TEST_IFNAME); + if (v4Addr != null) prop.addLinkAddress(v4Addr); - if (withIPv4) { - prop.addLinkAddress( - new LinkAddress(InetAddresses.parseNumericAddress(testIpv4Address), - NetworkConstants.IPV4_ADDR_BITS)); - } + if (v6Addr != null) prop.addLinkAddress(v6Addr); + + return new UpstreamNetworkState(prop, cap, network); + } - if (withIPv6) { - prop.addLinkAddress( - new LinkAddress(InetAddresses.parseNumericAddress("2001:db8::"), - NetworkConstants.RFC7421_PREFIX_LENGTH)); + private NetworkCapabilities makeNetworkCapabilities(final int transportType) { + final NetworkCapabilities cap = new NetworkCapabilities(); + cap.addTransportType(transportType); + if (transportType == TRANSPORT_VPN) { + cap.removeCapability(NET_CAPABILITY_NOT_VPN); } - return prop; + + return cap; } @Test public void testNoConflictUpstreamPrefix() throws Exception { - final int fakeHotspotSubId = 43; - final int fakeHotspotSubAddr = 0x2b05; + final int fakeHotspotSubAddr = 0x2b05; // 43.5 final IpPrefix predefinedPrefix = new IpPrefix("192.168.43.0/24"); // Force always get subAddress "43.5" for conflict testing. - when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeHotspotSubAddr); - // 1. Enable hotspot with prefix 192.168.43.0/24 - final LinkAddress hotspotAddr = mPrivateAddressCoordinator.requestDownstreamAddress( - mHotspotIpServer); - final IpPrefix hotspotPrefix = PrefixUtils.asIpPrefix(hotspotAddr); + when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(fakeHotspotSubAddr); + // - Enable hotspot with prefix 192.168.43.0/24 + final LinkAddress hotspotAddr = requestDownstreamAddress(mHotspotIpServer, + true /* useLastAddress */); + final IpPrefix hotspotPrefix = asIpPrefix(hotspotAddr); assertEquals("Wrong wifi prefix: ", predefinedPrefix, hotspotPrefix); - when(mHotspotIpServer.getAddress()).thenReturn(hotspotAddr); - // 2. Update v6 only mobile network, hotspot prefix should not be removed. - List<String> testConflicts; - final LinkProperties v6OnlyMobileProp = buildUpstreamLinkProperties(false, true, true); - mPrivateAddressCoordinator.updateUpstreamPrefix(mMobileNetwork, v6OnlyMobileProp); + // - test mobile network with null NetworkCapabilities. Ideally this should not happen + // because NetworkCapabilities update should always happen before LinkProperties update + // and the UpstreamNetworkState update, just make sure no crash in this case. + final UpstreamNetworkState noCapUpstream = buildUpstreamNetworkState(mMobileNetwork, + new LinkAddress("10.0.0.8/24"), null, null); + mPrivateAddressCoordinator.updateUpstreamPrefix(noCapUpstream); + verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT); + // - test mobile upstream with no address. + final UpstreamNetworkState noAddress = buildUpstreamNetworkState(mMobileNetwork, + null, null, makeNetworkCapabilities(TRANSPORT_CELLULAR)); + mPrivateAddressCoordinator.updateUpstreamPrefix(noCapUpstream); + verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT); + // - Update v6 only mobile network, hotspot prefix should not be removed. + final UpstreamNetworkState v6OnlyMobile = buildUpstreamNetworkState(mMobileNetwork, + null, new LinkAddress("2001:db8::/64"), + makeNetworkCapabilities(TRANSPORT_CELLULAR)); + mPrivateAddressCoordinator.updateUpstreamPrefix(v6OnlyMobile); verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT); mPrivateAddressCoordinator.removeUpstreamPrefix(mMobileNetwork); - // 3. Update v4 only mobile network, hotspot prefix should not be removed. - final LinkProperties v4OnlyMobileProp = buildUpstreamLinkProperties(true, false, true); - mPrivateAddressCoordinator.updateUpstreamPrefix(mMobileNetwork, v4OnlyMobileProp); + // - Update v4 only mobile network, hotspot prefix should not be removed. + final UpstreamNetworkState v4OnlyMobile = buildUpstreamNetworkState(mMobileNetwork, + new LinkAddress("10.0.0.8/24"), null, + makeNetworkCapabilities(TRANSPORT_CELLULAR)); + mPrivateAddressCoordinator.updateUpstreamPrefix(v4OnlyMobile); verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT); - // 4. Update v4v6 mobile network, hotspot prefix should not be removed. - final LinkProperties v4v6MobileProp = buildUpstreamLinkProperties(true, true, true); - mPrivateAddressCoordinator.updateUpstreamPrefix(mMobileNetwork, v4v6MobileProp); + // - Update v4v6 mobile network, hotspot prefix should not be removed. + final UpstreamNetworkState v4v6Mobile = buildUpstreamNetworkState(mMobileNetwork, + new LinkAddress("10.0.0.8/24"), new LinkAddress("2001:db8::/64"), + makeNetworkCapabilities(TRANSPORT_CELLULAR)); + mPrivateAddressCoordinator.updateUpstreamPrefix(v4v6Mobile); verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT); - // 5. Update v6 only wifi network, hotspot prefix should not be removed. - final LinkProperties v6OnlyWifiProp = buildUpstreamLinkProperties(false, true, false); - mPrivateAddressCoordinator.updateUpstreamPrefix(mWifiNetwork, v6OnlyWifiProp); + // - Update v6 only wifi network, hotspot prefix should not be removed. + final UpstreamNetworkState v6OnlyWifi = buildUpstreamNetworkState(mWifiNetwork, + null, new LinkAddress("2001:db8::/64"), makeNetworkCapabilities(TRANSPORT_WIFI)); + mPrivateAddressCoordinator.updateUpstreamPrefix(v6OnlyWifi); verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT); mPrivateAddressCoordinator.removeUpstreamPrefix(mWifiNetwork); - // 6. Update v4 only wifi network, it conflict with hotspot prefix. - final LinkProperties v4OnlyWifiProp = buildUpstreamLinkProperties(true, false, false); - mPrivateAddressCoordinator.updateUpstreamPrefix(mWifiNetwork, v4OnlyWifiProp); + // - Update vpn network, it conflict with hotspot prefix but VPN networks are ignored. + final UpstreamNetworkState v4OnlyVpn = buildUpstreamNetworkState(mVpnNetwork, + new LinkAddress("192.168.43.5/24"), null, makeNetworkCapabilities(TRANSPORT_VPN)); + mPrivateAddressCoordinator.updateUpstreamPrefix(v4OnlyVpn); + verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT); + // - Update v4 only wifi network, it conflict with hotspot prefix. + final UpstreamNetworkState v4OnlyWifi = buildUpstreamNetworkState(mWifiNetwork, + new LinkAddress("192.168.43.5/24"), null, makeNetworkCapabilities(TRANSPORT_WIFI)); + mPrivateAddressCoordinator.updateUpstreamPrefix(v4OnlyWifi); verify(mHotspotIpServer).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT); reset(mHotspotIpServer); - // 7. Restart hotspot again and its prefix is different previous. + // - Restart hotspot again and its prefix is different previous. mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); - final LinkAddress hotspotAddr2 = mPrivateAddressCoordinator.requestDownstreamAddress( - mHotspotIpServer); - final IpPrefix hotspotPrefix2 = PrefixUtils.asIpPrefix(hotspotAddr2); + final LinkAddress hotspotAddr2 = requestDownstreamAddress(mHotspotIpServer, + true /* useLastAddress */); + final IpPrefix hotspotPrefix2 = asIpPrefix(hotspotAddr2); assertNotEquals(hotspotPrefix, hotspotPrefix2); - when(mHotspotIpServer.getAddress()).thenReturn(hotspotAddr2); - mPrivateAddressCoordinator.updateUpstreamPrefix(mWifiNetwork, v4OnlyWifiProp); + mPrivateAddressCoordinator.updateUpstreamPrefix(v4OnlyWifi); verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT); - // 7. Usb tethering can be enabled and its prefix is different with conflict one. - final LinkAddress usbAddr = mPrivateAddressCoordinator.requestDownstreamAddress( - mUsbIpServer); - final IpPrefix usbPrefix = PrefixUtils.asIpPrefix(usbAddr); + // - Usb tethering can be enabled and its prefix is different with conflict one. + final LinkAddress usbAddr = requestDownstreamAddress(mUsbIpServer, + true /* useLastAddress */); + final IpPrefix usbPrefix = asIpPrefix(usbAddr); assertNotEquals(predefinedPrefix, usbPrefix); assertNotEquals(hotspotPrefix2, usbPrefix); - when(mUsbIpServer.getAddress()).thenReturn(usbAddr); - // 8. Disable wifi upstream, then wifi's prefix can be selected again. + // - Disable wifi upstream, then wifi's prefix can be selected again. mPrivateAddressCoordinator.removeUpstreamPrefix(mWifiNetwork); - final LinkAddress ethAddr = mPrivateAddressCoordinator.requestDownstreamAddress( - mEthernetIpServer); - final IpPrefix ethPrefix = PrefixUtils.asIpPrefix(ethAddr); + final LinkAddress ethAddr = requestDownstreamAddress(mEthernetIpServer, + true /* useLastAddress */); + final IpPrefix ethPrefix = asIpPrefix(ethAddr); assertEquals(predefinedPrefix, ethPrefix); } + @Test + public void testChooseAvailablePrefix() throws Exception { + final int randomAddress = 0x8605; // 134.5 + when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(randomAddress); + final LinkAddress addr0 = requestDownstreamAddress(mHotspotIpServer, + true /* useLastAddress */); + // Check whether return address is prefix 192.168.0.0/16 + subAddress 0.0.134.5. + assertEquals("Wrong prefix: ", new LinkAddress("192.168.134.5/24"), addr0); + final UpstreamNetworkState wifiUpstream = buildUpstreamNetworkState(mWifiNetwork, + new LinkAddress("192.168.134.13/26"), null, + makeNetworkCapabilities(TRANSPORT_WIFI)); + mPrivateAddressCoordinator.updateUpstreamPrefix(wifiUpstream); + + // Check whether return address is next prefix of 192.168.134.0/24. + final LinkAddress addr1 = requestDownstreamAddress(mHotspotIpServer, + true /* useLastAddress */); + assertEquals("Wrong prefix: ", new LinkAddress("192.168.135.5/24"), addr1); + final UpstreamNetworkState wifiUpstream2 = buildUpstreamNetworkState(mWifiNetwork, + new LinkAddress("192.168.149.16/19"), null, + makeNetworkCapabilities(TRANSPORT_WIFI)); + mPrivateAddressCoordinator.updateUpstreamPrefix(wifiUpstream2); + + + // The conflict range is 128 ~ 159, so the address is 192.168.160.5/24. + final LinkAddress addr2 = requestDownstreamAddress(mHotspotIpServer, + true /* useLastAddress */); + assertEquals("Wrong prefix: ", new LinkAddress("192.168.160.5/24"), addr2); + final UpstreamNetworkState mobileUpstream = buildUpstreamNetworkState(mMobileNetwork, + new LinkAddress("192.168.129.53/18"), null, + makeNetworkCapabilities(TRANSPORT_CELLULAR)); + // Update another conflict upstream which is covered by the previous one (but not the first + // one) and verify whether this would affect the result. + final UpstreamNetworkState mobileUpstream2 = buildUpstreamNetworkState(mMobileNetwork2, + new LinkAddress("192.168.170.7/19"), null, + makeNetworkCapabilities(TRANSPORT_CELLULAR)); + mPrivateAddressCoordinator.updateUpstreamPrefix(mobileUpstream); + mPrivateAddressCoordinator.updateUpstreamPrefix(mobileUpstream2); + + // The conflict range are 128 ~ 159 and 159 ~ 191, so the address is 192.168.192.5/24. + final LinkAddress addr3 = requestDownstreamAddress(mHotspotIpServer, + true /* useLastAddress */); + assertEquals("Wrong prefix: ", new LinkAddress("192.168.192.5/24"), addr3); + final UpstreamNetworkState mobileUpstream3 = buildUpstreamNetworkState(mMobileNetwork3, + new LinkAddress("192.168.188.133/17"), null, + makeNetworkCapabilities(TRANSPORT_CELLULAR)); + mPrivateAddressCoordinator.updateUpstreamPrefix(mobileUpstream3); + + // Conflict range: 128 ~ 255. The next available address is 192.168.0.5 because + // 192.168.134/24 ~ 192.168.255.255/24 is not available. + final LinkAddress addr4 = requestDownstreamAddress(mHotspotIpServer, + true /* useLastAddress */); + assertEquals("Wrong prefix: ", new LinkAddress("192.168.0.5/24"), addr4); + final UpstreamNetworkState mobileUpstream4 = buildUpstreamNetworkState(mMobileNetwork4, + new LinkAddress("192.168.3.59/21"), null, + makeNetworkCapabilities(TRANSPORT_CELLULAR)); + mPrivateAddressCoordinator.updateUpstreamPrefix(mobileUpstream4); + + // Conflict ranges: 128 ~ 255 and 0 ~ 7, so the address is 192.168.8.5/24. + final LinkAddress addr5 = requestDownstreamAddress(mHotspotIpServer, + true /* useLastAddress */); + assertEquals("Wrong prefix: ", new LinkAddress("192.168.8.5/24"), addr5); + final UpstreamNetworkState mobileUpstream5 = buildUpstreamNetworkState(mMobileNetwork5, + new LinkAddress("192.168.68.43/21"), null, + makeNetworkCapabilities(TRANSPORT_CELLULAR)); + mPrivateAddressCoordinator.updateUpstreamPrefix(mobileUpstream5); + + // Update an upstream that does *not* conflict, check whether return the same address + // 192.168.5/24. + final LinkAddress addr6 = requestDownstreamAddress(mHotspotIpServer, + true /* useLastAddress */); + assertEquals("Wrong prefix: ", new LinkAddress("192.168.8.5/24"), addr6); + final UpstreamNetworkState mobileUpstream6 = buildUpstreamNetworkState(mMobileNetwork6, + new LinkAddress("192.168.10.97/21"), null, + makeNetworkCapabilities(TRANSPORT_CELLULAR)); + mPrivateAddressCoordinator.updateUpstreamPrefix(mobileUpstream6); + + // Conflict ranges: 0 ~ 15 and 128 ~ 255, so the address is 192.168.16.5/24. + final LinkAddress addr7 = requestDownstreamAddress(mHotspotIpServer, + true /* useLastAddress */); + assertEquals("Wrong prefix: ", new LinkAddress("192.168.16.5/24"), addr7); + final UpstreamNetworkState mobileUpstream7 = buildUpstreamNetworkState(mMobileNetwork6, + new LinkAddress("192.168.0.0/17"), null, + makeNetworkCapabilities(TRANSPORT_CELLULAR)); + mPrivateAddressCoordinator.updateUpstreamPrefix(mobileUpstream7); + + // Choose prefix from next range(172.16.0.0/12) when no available prefix in 192.168.0.0/16. + final LinkAddress addr8 = requestDownstreamAddress(mHotspotIpServer, + true /* useLastAddress */); + assertEquals("Wrong prefix: ", new LinkAddress("172.16.134.5/24"), addr8); + } + + @Test + public void testChoosePrefixFromDifferentRanges() throws Exception { + final int randomAddress = 0x1f2b2a; // 31.43.42 + when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(randomAddress); + final LinkAddress classC1 = requestDownstreamAddress(mHotspotIpServer, + true /* useLastAddress */); + // Check whether return address is prefix 192.168.0.0/16 + subAddress 0.0.43.42. + assertEquals("Wrong prefix: ", new LinkAddress("192.168.43.42/24"), classC1); + final UpstreamNetworkState wifiUpstream = buildUpstreamNetworkState(mWifiNetwork, + new LinkAddress("192.168.88.23/17"), null, + makeNetworkCapabilities(TRANSPORT_WIFI)); + mPrivateAddressCoordinator.updateUpstreamPrefix(wifiUpstream); + verifyNotifyConflictAndRelease(mHotspotIpServer); + + // Check whether return address is next address of prefix 192.168.128.0/17. + final LinkAddress classC2 = requestDownstreamAddress(mHotspotIpServer, + true /* useLastAddress */); + assertEquals("Wrong prefix: ", new LinkAddress("192.168.128.42/24"), classC2); + final UpstreamNetworkState mobileUpstream = buildUpstreamNetworkState(mMobileNetwork, + new LinkAddress("192.1.2.3/8"), null, + makeNetworkCapabilities(TRANSPORT_CELLULAR)); + mPrivateAddressCoordinator.updateUpstreamPrefix(mobileUpstream); + verifyNotifyConflictAndRelease(mHotspotIpServer); + + // Check whether return address is under prefix 172.16.0.0/12. + final LinkAddress classB1 = requestDownstreamAddress(mHotspotIpServer, + true /* useLastAddress */); + assertEquals("Wrong prefix: ", new LinkAddress("172.31.43.42/24"), classB1); + final UpstreamNetworkState mobileUpstream2 = buildUpstreamNetworkState(mMobileNetwork2, + new LinkAddress("172.28.123.100/14"), null, + makeNetworkCapabilities(TRANSPORT_CELLULAR)); + mPrivateAddressCoordinator.updateUpstreamPrefix(mobileUpstream2); + verifyNotifyConflictAndRelease(mHotspotIpServer); + + // 172.28.0.0 ~ 172.31.255.255 is not available. + // Check whether return address is next address of prefix 172.16.0.0/14. + final LinkAddress classB2 = requestDownstreamAddress(mHotspotIpServer, + true /* useLastAddress */); + assertEquals("Wrong prefix: ", new LinkAddress("172.16.0.42/24"), classB2); + + // Check whether new downstream is next address of address 172.16.0.42/24. + final LinkAddress classB3 = requestDownstreamAddress(mUsbIpServer, + true /* useLastAddress */); + assertEquals("Wrong prefix: ", new LinkAddress("172.16.1.42/24"), classB3); + final UpstreamNetworkState mobileUpstream3 = buildUpstreamNetworkState(mMobileNetwork3, + new LinkAddress("172.16.0.1/24"), null, + makeNetworkCapabilities(TRANSPORT_CELLULAR)); + mPrivateAddressCoordinator.updateUpstreamPrefix(mobileUpstream3); + verifyNotifyConflictAndRelease(mHotspotIpServer); + verify(mUsbIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT); + + // Check whether return address is next address of prefix 172.16.1.42/24. + final LinkAddress classB4 = requestDownstreamAddress(mHotspotIpServer, + true /* useLastAddress */); + assertEquals("Wrong prefix: ", new LinkAddress("172.16.2.42/24"), classB4); + final UpstreamNetworkState mobileUpstream4 = buildUpstreamNetworkState(mMobileNetwork4, + new LinkAddress("172.16.0.1/13"), null, + makeNetworkCapabilities(TRANSPORT_CELLULAR)); + mPrivateAddressCoordinator.updateUpstreamPrefix(mobileUpstream4); + verifyNotifyConflictAndRelease(mHotspotIpServer); + verifyNotifyConflictAndRelease(mUsbIpServer); + + // Check whether return address is next address of prefix 172.16.0.1/13. + final LinkAddress classB5 = requestDownstreamAddress(mHotspotIpServer, + true /* useLastAddress */); + assertEquals("Wrong prefix: ", new LinkAddress("172.24.0.42/24"), classB5); + // Check whether return address is next address of prefix 172.24.0.42/24. + final LinkAddress classB6 = requestDownstreamAddress(mUsbIpServer, + true /* useLastAddress */); + assertEquals("Wrong prefix: ", new LinkAddress("172.24.1.42/24"), classB6); + final UpstreamNetworkState mobileUpstream5 = buildUpstreamNetworkState(mMobileNetwork5, + new LinkAddress("172.24.0.1/12"), null, + makeNetworkCapabilities(TRANSPORT_CELLULAR)); + mPrivateAddressCoordinator.updateUpstreamPrefix(mobileUpstream5); + verifyNotifyConflictAndRelease(mHotspotIpServer); + verifyNotifyConflictAndRelease(mUsbIpServer); + + // Check whether return address is prefix 10.0.0.0/8 + subAddress 0.31.43.42. + final LinkAddress classA1 = requestDownstreamAddress(mHotspotIpServer, + true /* useLastAddress */); + assertEquals("Wrong prefix: ", new LinkAddress("10.31.43.42/24"), classA1); + // Check whether new downstream is next address of address 10.31.43.42/24. + final LinkAddress classA2 = requestDownstreamAddress(mUsbIpServer, + true /* useLastAddress */); + assertEquals("Wrong prefix: ", new LinkAddress("10.31.44.42/24"), classA2); + } + + private void verifyNotifyConflictAndRelease(final IpServer ipServer) throws Exception { + verify(ipServer).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT); + mPrivateAddressCoordinator.releaseDownstream(ipServer); + reset(ipServer); + setUpIpServers(); + } + private int getSubAddress(final byte... ipv4Address) { assertEquals(4, ipv4Address.length); @@ -282,17 +523,17 @@ public final class PrivateAddressCoordinatorTest { } private void assertReseveredWifiP2pPrefix() throws Exception { - LinkAddress address = mPrivateAddressCoordinator.requestDownstreamAddress( - mHotspotIpServer); - final IpPrefix hotspotPrefix = PrefixUtils.asIpPrefix(address); - final IpPrefix legacyWifiP2pPrefix = PrefixUtils.asIpPrefix(mLegacyWifiP2pAddress); + LinkAddress address = requestDownstreamAddress(mHotspotIpServer, + true /* useLastAddress */); + final IpPrefix hotspotPrefix = asIpPrefix(address); + final IpPrefix legacyWifiP2pPrefix = asIpPrefix(mLegacyWifiP2pAddress); assertNotEquals(legacyWifiP2pPrefix, hotspotPrefix); mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); } @Test public void testEnableLegacyWifiP2PAddress() throws Exception { - when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn( + when(mPrivateAddressCoordinator.getRandomInt()).thenReturn( getSubAddress(mLegacyWifiP2pAddress.getAddress().getAddress())); // No matter #shouldEnableWifiP2pDedicatedIp() is enabled or not, legacy wifi p2p prefix // is resevered. @@ -302,8 +543,8 @@ public final class PrivateAddressCoordinatorTest { assertReseveredWifiP2pPrefix(); // If #shouldEnableWifiP2pDedicatedIp() is enabled, wifi P2P gets the configured address. - LinkAddress address = mPrivateAddressCoordinator.requestDownstreamAddress( - mWifiP2pIpServer); + LinkAddress address = requestDownstreamAddress(mWifiP2pIpServer, + true /* useLastAddress */); assertEquals(mLegacyWifiP2pAddress, address); mPrivateAddressCoordinator.releaseDownstream(mWifiP2pIpServer); } diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java index dc0940cc0222..237e2c27bfa1 100644 --- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java +++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java @@ -131,6 +131,7 @@ public class TetheringConfigurationTest { when(mResources.getBoolean(R.bool.config_tether_enable_legacy_wifi_p2p_dedicated_ip)) .thenReturn(false); initializeBpfOffloadConfiguration(true, null /* unset */); + initEnableSelectAllPrefixRangeFlag(null /* unset */); mHasTelephonyManager = true; mMockContext = new MockContext(mContext); @@ -428,4 +429,30 @@ public class TetheringConfigurationTest { mMockContext, mLog, INVALID_SUBSCRIPTION_ID); assertTrue(testCfg.shouldEnableWifiP2pDedicatedIp()); } + + private void initEnableSelectAllPrefixRangeFlag(final String value) { + doReturn(value).when( + () -> DeviceConfig.getProperty(eq(NAMESPACE_CONNECTIVITY), + eq(TetheringConfiguration.TETHER_ENABLE_SELECT_ALL_PREFIX_RANGES))); + } + + @Test + public void testSelectAllPrefixRangeFlag() throws Exception { + // Test default value. + final TetheringConfiguration defaultCfg = new TetheringConfiguration( + mMockContext, mLog, INVALID_SUBSCRIPTION_ID); + assertTrue(defaultCfg.isSelectAllPrefixRangeEnabled()); + + // Test disable flag. + initEnableSelectAllPrefixRangeFlag("false"); + final TetheringConfiguration testDisable = new TetheringConfiguration( + mMockContext, mLog, INVALID_SUBSCRIPTION_ID); + assertFalse(testDisable.isSelectAllPrefixRangeEnabled()); + + // Test enable flag. + initEnableSelectAllPrefixRangeFlag("true"); + final TetheringConfiguration testEnable = new TetheringConfiguration( + mMockContext, mLog, INVALID_SUBSCRIPTION_ID); + assertTrue(testEnable.isSelectAllPrefixRangeEnabled()); + } } diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java index df570206e389..114cb7ca6ec7 100644 --- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java +++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java @@ -24,6 +24,9 @@ import static android.hardware.usb.UsbManager.USB_FUNCTION_RNDIS; import static android.net.ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED; import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED; import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED; +import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; +import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.net.RouteInfo.RTN_UNICAST; import static android.net.TetheringManager.ACTION_TETHER_STATE_CHANGED; import static android.net.TetheringManager.EXTRA_ACTIVE_LOCAL_ONLY; @@ -179,6 +182,7 @@ public class TetheringTest { private static final String TEST_P2P_IFNAME = "test_p2p-p2p0-0"; private static final String TEST_NCM_IFNAME = "test_ncm0"; private static final String TEST_ETH_IFNAME = "test_eth0"; + private static final String TEST_BT_IFNAME = "test_pan0"; private static final String TETHERING_NAME = "Tethering"; private static final String[] PROVISIONING_APP_NAME = {"some", "app"}; private static final String PROVISIONING_NO_UI_APP_NAME = "no_ui_app"; @@ -230,6 +234,7 @@ public class TetheringTest { private TetheringConfiguration mConfig; private EntitlementManager mEntitleMgr; private OffloadController mOffloadCtrl; + private PrivateAddressCoordinator mPrivateAddressCoordinator; private class TestContext extends BroadcastInterceptingContext { TestContext(Context base) { @@ -446,6 +451,14 @@ public class TetheringTest { public boolean isTetheringDenied() { return false; } + + + @Override + public PrivateAddressCoordinator getPrivateAddressCoordinator(Context ctx, + TetheringConfiguration cfg) { + mPrivateAddressCoordinator = super.getPrivateAddressCoordinator(ctx, cfg); + return mPrivateAddressCoordinator; + } } private static UpstreamNetworkState buildMobileUpstreamState(boolean withIPv4, @@ -1875,27 +1888,36 @@ public class TetheringTest { sendConfigurationChanged(); } - private static UpstreamNetworkState buildV4WifiUpstreamState(final String ipv4Address, - final int prefixLength, final Network network) { + private static UpstreamNetworkState buildV4UpstreamState(final LinkAddress address, + final Network network, final String iface, final int transportType) { final LinkProperties prop = new LinkProperties(); - prop.setInterfaceName(TEST_WIFI_IFNAME); + prop.setInterfaceName(iface); - prop.addLinkAddress( - new LinkAddress(InetAddresses.parseNumericAddress(ipv4Address), - prefixLength)); + prop.addLinkAddress(address); final NetworkCapabilities capabilities = new NetworkCapabilities() - .addTransportType(NetworkCapabilities.TRANSPORT_WIFI); + .addTransportType(transportType); return new UpstreamNetworkState(prop, capabilities, network); } + private void updateV4Upstream(final LinkAddress ipv4Address, final Network network, + final String iface, final int transportType) { + final UpstreamNetworkState upstream = buildV4UpstreamState(ipv4Address, network, iface, + transportType); + mTetheringDependencies.mUpstreamNetworkMonitorSM.sendMessage( + Tethering.TetherMainSM.EVENT_UPSTREAM_CALLBACK, + UpstreamNetworkMonitor.EVENT_ON_LINKPROPERTIES, + 0, + upstream); + mLooper.dispatchAll(); + } + @Test public void testHandleIpConflict() throws Exception { final Network wifiNetwork = new Network(200); final Network[] allNetworks = { wifiNetwork }; when(mCm.getAllNetworks()).thenReturn(allNetworks); - UpstreamNetworkState upstreamNetwork = null; - runUsbTethering(upstreamNetwork); + runUsbTethering(null); final ArgumentCaptor<InterfaceConfigurationParcel> ifaceConfigCaptor = ArgumentCaptor.forClass(InterfaceConfigurationParcel.class); verify(mNetd).interfaceSetCfg(ifaceConfigCaptor.capture()); @@ -1903,13 +1925,10 @@ public class TetheringTest { verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).startWithCallbacks( any(), any()); reset(mNetd, mUsbManager); - upstreamNetwork = buildV4WifiUpstreamState(ipv4Address, 30, wifiNetwork); - mTetheringDependencies.mUpstreamNetworkMonitorSM.sendMessage( - Tethering.TetherMainSM.EVENT_UPSTREAM_CALLBACK, - UpstreamNetworkMonitor.EVENT_ON_LINKPROPERTIES, - 0, - upstreamNetwork); - mLooper.dispatchAll(); + + // Cause a prefix conflict by assigning a /30 out of the downstream's /24 to the upstream. + updateV4Upstream(new LinkAddress(InetAddresses.parseNumericAddress(ipv4Address), 30), + wifiNetwork, TEST_WIFI_IFNAME, TRANSPORT_WIFI); // verify turn off usb tethering verify(mUsbManager).setCurrentFunctions(UsbManager.FUNCTION_NONE); mTethering.interfaceRemoved(TEST_USB_IFNAME); @@ -1921,9 +1940,10 @@ public class TetheringTest { @Test public void testNoAddressAvailable() throws Exception { final Network wifiNetwork = new Network(200); - final Network[] allNetworks = { wifiNetwork }; + final Network btNetwork = new Network(201); + final Network mobileNetwork = new Network(202); + final Network[] allNetworks = { wifiNetwork, btNetwork, mobileNetwork }; when(mCm.getAllNetworks()).thenReturn(allNetworks); - final String upstreamAddress = "192.168.0.100"; runUsbTethering(null); verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).startWithCallbacks( any(), any()); @@ -1940,13 +1960,13 @@ public class TetheringTest { mLooper.dispatchAll(); reset(mUsbManager, mEm); - final UpstreamNetworkState upstreamNetwork = buildV4WifiUpstreamState( - upstreamAddress, 16, wifiNetwork); - mTetheringDependencies.mUpstreamNetworkMonitorSM.sendMessage( - Tethering.TetherMainSM.EVENT_UPSTREAM_CALLBACK, - UpstreamNetworkMonitor.EVENT_ON_LINKPROPERTIES, - 0, - upstreamNetwork); + updateV4Upstream(new LinkAddress("192.168.0.100/16"), wifiNetwork, TEST_WIFI_IFNAME, + TRANSPORT_WIFI); + updateV4Upstream(new LinkAddress("172.16.0.0/12"), btNetwork, TEST_BT_IFNAME, + TRANSPORT_BLUETOOTH); + updateV4Upstream(new LinkAddress("10.0.0.0/8"), mobileNetwork, TEST_MOBILE_IFNAME, + TRANSPORT_CELLULAR); + mLooper.dispatchAll(); // verify turn off usb tethering verify(mUsbManager).setCurrentFunctions(UsbManager.FUNCTION_NONE); diff --git a/services/core/Android.bp b/services/core/Android.bp index 776c8f5912ff..431555bb57d5 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -132,6 +132,7 @@ java_library_static { "netd_aidl_interfaces-platform-java", "overlayable_policy_aidl-java", "SurfaceFlingerProperties", + "com.android.sysprop.watchdog", ], } diff --git a/services/core/java/com/android/server/BluetoothAirplaneModeListener.java b/services/core/java/com/android/server/BluetoothAirplaneModeListener.java index 31cd5d519d87..4d9680c785bc 100644 --- a/services/core/java/com/android/server/BluetoothAirplaneModeListener.java +++ b/services/core/java/com/android/server/BluetoothAirplaneModeListener.java @@ -16,22 +16,14 @@ package com.android.server; -import android.bluetooth.BluetoothA2dp; -import android.bluetooth.BluetoothAdapter; -import android.bluetooth.BluetoothHearingAid; -import android.bluetooth.BluetoothProfile; -import android.bluetooth.BluetoothProfile.ServiceListener; import android.content.Context; -import android.content.res.Resources; import android.database.ContentObserver; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.provider.Settings; import android.util.Log; -import android.widget.Toast; -import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; /** @@ -53,7 +45,7 @@ class BluetoothAirplaneModeListener { private final BluetoothManagerService mBluetoothManager; private final BluetoothAirplaneModeHandler mHandler; - private AirplaneModeHelper mAirplaneHelper; + private BluetoothModeChangeHelper mAirplaneHelper; @VisibleForTesting int mToastCount = 0; @@ -97,7 +89,7 @@ class BluetoothAirplaneModeListener { * Call after boot complete */ @VisibleForTesting - void start(AirplaneModeHelper helper) { + void start(BluetoothModeChangeHelper helper) { Log.i(TAG, "start"); mAirplaneHelper = helper; mToastCount = mAirplaneHelper.getSettingsInt(TOAST_COUNT); @@ -141,118 +133,4 @@ class BluetoothAirplaneModeListener { } return true; } - - /** - * Helper class that handles callout and callback methods without - * complex logic. - */ - @VisibleForTesting - public static class AirplaneModeHelper { - private volatile BluetoothA2dp mA2dp; - private volatile BluetoothHearingAid mHearingAid; - private final BluetoothAdapter mAdapter; - private final Context mContext; - - AirplaneModeHelper(Context context) { - mAdapter = BluetoothAdapter.getDefaultAdapter(); - mContext = context; - - mAdapter.getProfileProxy(mContext, mProfileServiceListener, BluetoothProfile.A2DP); - mAdapter.getProfileProxy(mContext, mProfileServiceListener, - BluetoothProfile.HEARING_AID); - } - - private final ServiceListener mProfileServiceListener = new ServiceListener() { - @Override - public void onServiceConnected(int profile, BluetoothProfile proxy) { - // Setup Bluetooth profile proxies - switch (profile) { - case BluetoothProfile.A2DP: - mA2dp = (BluetoothA2dp) proxy; - break; - case BluetoothProfile.HEARING_AID: - mHearingAid = (BluetoothHearingAid) proxy; - break; - default: - break; - } - } - - @Override - public void onServiceDisconnected(int profile) { - // Clear Bluetooth profile proxies - switch (profile) { - case BluetoothProfile.A2DP: - mA2dp = null; - break; - case BluetoothProfile.HEARING_AID: - mHearingAid = null; - break; - default: - break; - } - } - }; - - @VisibleForTesting - public boolean isA2dpOrHearingAidConnected() { - return isA2dpConnected() || isHearingAidConnected(); - } - - @VisibleForTesting - public boolean isBluetoothOn() { - final BluetoothAdapter adapter = mAdapter; - if (adapter == null) { - return false; - } - return adapter.getLeState() == BluetoothAdapter.STATE_ON; - } - - @VisibleForTesting - public boolean isAirplaneModeOn() { - return Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.AIRPLANE_MODE_ON, 0) == 1; - } - - @VisibleForTesting - public void onAirplaneModeChanged(BluetoothManagerService managerService) { - managerService.onAirplaneModeChanged(); - } - - @VisibleForTesting - public int getSettingsInt(String name) { - return Settings.Global.getInt(mContext.getContentResolver(), - name, 0); - } - - @VisibleForTesting - public void setSettingsInt(String name, int value) { - Settings.Global.putInt(mContext.getContentResolver(), - name, value); - } - - @VisibleForTesting - public void showToastMessage() { - Resources r = mContext.getResources(); - final CharSequence text = r.getString( - R.string.bluetooth_airplane_mode_toast, 0); - Toast.makeText(mContext, text, Toast.LENGTH_LONG).show(); - } - - private boolean isA2dpConnected() { - final BluetoothA2dp a2dp = mA2dp; - if (a2dp == null) { - return false; - } - return a2dp.getConnectedDevices().size() > 0; - } - - private boolean isHearingAidConnected() { - final BluetoothHearingAid hearingAid = mHearingAid; - if (hearingAid == null) { - return false; - } - return hearingAid.getConnectedDevices().size() > 0; - } - }; } diff --git a/services/core/java/com/android/server/BluetoothDeviceConfigListener.java b/services/core/java/com/android/server/BluetoothDeviceConfigListener.java new file mode 100644 index 000000000000..2dcf82ff9410 --- /dev/null +++ b/services/core/java/com/android/server/BluetoothDeviceConfigListener.java @@ -0,0 +1,64 @@ +/* + * Copyright 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 com.android.server; + +import android.provider.DeviceConfig; + +/** + * The BluetoothDeviceConfigListener handles system device config change callback and checks + * whether we need to inform BluetoothManagerService on this change. + * + * The information of device config change would not be passed to the BluetoothManagerService + * when Bluetooth is on and Bluetooth is in one of the following situations: + * 1. Bluetooth A2DP is connected. + * 2. Bluetooth Hearing Aid profile is connected. + */ +class BluetoothDeviceConfigListener { + private static final String TAG = "BluetoothDeviceConfigListener"; + + BluetoothManagerService mService; + + BluetoothDeviceConfigListener(BluetoothManagerService service) { + mService = service; + DeviceConfig.addOnPropertiesChangedListener( + DeviceConfig.NAMESPACE_BLUETOOTH, + (Runnable r) -> r.run(), + mDeviceConfigChangedListener); + } + + private final DeviceConfig.OnPropertiesChangedListener mDeviceConfigChangedListener = + new DeviceConfig.OnPropertiesChangedListener() { + @Override + public void onPropertiesChanged(DeviceConfig.Properties properties) { + if (!properties.getNamespace().equals(DeviceConfig.NAMESPACE_BLUETOOTH)) { + return; + } + boolean foundInit = false; + for (String name : properties.getKeyset()) { + if (name.startsWith("INIT_")) { + foundInit = true; + break; + } + } + if (!foundInit) { + return; + } + mService.onInitFlagsChanged(); + } + }; + +} diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java index bb567b4e2c78..e919f39c2155 100644 --- a/services/core/java/com/android/server/BluetoothManagerService.java +++ b/services/core/java/com/android/server/BluetoothManagerService.java @@ -23,7 +23,9 @@ import android.Manifest; import android.app.ActivityManager; import android.app.AppGlobals; import android.app.AppOpsManager; +import android.bluetooth.BluetoothA2dp; import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothHearingAid; import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothProtoEnums; import android.bluetooth.IBluetooth; @@ -63,7 +65,6 @@ import android.os.UserHandle; import android.os.UserManager; import android.os.UserManagerInternal; import android.os.UserManagerInternal.UserRestrictionsListener; -import android.provider.DeviceConfig; import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; import android.text.TextUtils; @@ -116,6 +117,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { // Delay for retrying enable and disable in msec private static final int ENABLE_DISABLE_DELAY_MS = 300; private static final int DELAY_BEFORE_RESTART_DUE_TO_INIT_FLAGS_CHANGED_MS = 300; + private static final int DELAY_FOR_RETRY_INIT_FLAG_CHECK_MS = 86400; private static final int MESSAGE_ENABLE = 1; private static final int MESSAGE_DISABLE = 2; @@ -175,8 +177,12 @@ class BluetoothManagerService extends IBluetoothManager.Stub { private int mWaitForEnableRetry; private int mWaitForDisableRetry; + private BluetoothModeChangeHelper mBluetoothModeChangeHelper; + private BluetoothAirplaneModeListener mBluetoothAirplaneModeListener; + private BluetoothDeviceConfigListener mBluetoothDeviceConfigListener; + // used inside handler thread private boolean mQuietEnable = false; private boolean mEnable; @@ -281,29 +287,13 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } }; - private final DeviceConfig.OnPropertiesChangedListener mDeviceConfigChangedListener = - new DeviceConfig.OnPropertiesChangedListener() { - @Override - public void onPropertiesChanged(DeviceConfig.Properties properties) { - if (!properties.getNamespace().equals(DeviceConfig.NAMESPACE_BLUETOOTH)) { - return; - } - boolean foundInit = false; - for (String name : properties.getKeyset()) { - if (name.startsWith("INIT_")) { - foundInit = true; - break; - } - } - if (!foundInit) { - return; - } - mHandler.removeMessages(MESSAGE_INIT_FLAGS_CHANGED); - mHandler.sendEmptyMessageDelayed( - MESSAGE_INIT_FLAGS_CHANGED, - DELAY_BEFORE_RESTART_DUE_TO_INIT_FLAGS_CHANGED_MS); - } - }; + @VisibleForTesting + public void onInitFlagsChanged() { + mHandler.removeMessages(MESSAGE_INIT_FLAGS_CHANGED); + mHandler.sendEmptyMessageDelayed( + MESSAGE_INIT_FLAGS_CHANGED, + DELAY_BEFORE_RESTART_DUE_TO_INIT_FLAGS_CHANGED_MS); + } public boolean onFactoryReset() { // Wait for stable state if bluetooth is temporary state. @@ -451,6 +441,15 @@ class BluetoothManagerService extends IBluetoothManager.Stub { mHandler.sendMessage(msg); } } + } else if (BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED.equals(action) + || BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED.equals(action)) { + final int state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, + BluetoothProfile.STATE_CONNECTED); + if (mHandler.hasMessages(MESSAGE_INIT_FLAGS_CHANGED) + && state == BluetoothProfile.STATE_DISCONNECTED + && !mBluetoothModeChangeHelper.isA2dpOrHearingAidConnected()) { + onInitFlagsChanged(); + } } } }; @@ -501,6 +500,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub { filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED); filter.addAction(BluetoothAdapter.ACTION_BLUETOOTH_ADDRESS_CHANGED); filter.addAction(Intent.ACTION_SETTING_RESTORED); + filter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED); + filter.addAction(BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED); filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); mContext.registerReceiver(mReceiver, filter); @@ -535,10 +536,6 @@ class BluetoothManagerService extends IBluetoothManager.Stub { Slog.w(TAG, "Unable to resolve SystemUI's UID."); } mSystemUiUid = systemUiUid; - DeviceConfig.addOnPropertiesChangedListener( - DeviceConfig.NAMESPACE_BLUETOOTH, - (Runnable r) -> r.run(), - mDeviceConfigChangedListener); } /** @@ -1368,10 +1365,12 @@ class BluetoothManagerService extends IBluetoothManager.Stub { Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS); mHandler.sendMessage(getMsg); } + + mBluetoothModeChangeHelper = new BluetoothModeChangeHelper(mContext); if (mBluetoothAirplaneModeListener != null) { - mBluetoothAirplaneModeListener.start( - new BluetoothAirplaneModeListener.AirplaneModeHelper(mContext)); + mBluetoothAirplaneModeListener.start(mBluetoothModeChangeHelper); } + mBluetoothDeviceConfigListener = new BluetoothDeviceConfigListener(this); } /** @@ -2214,6 +2213,12 @@ class BluetoothManagerService extends IBluetoothManager.Stub { Slog.d(TAG, "MESSAGE_INIT_FLAGS_CHANGED"); } mHandler.removeMessages(MESSAGE_INIT_FLAGS_CHANGED); + if (mBluetoothModeChangeHelper.isA2dpOrHearingAidConnected()) { + mHandler.sendEmptyMessageDelayed( + MESSAGE_INIT_FLAGS_CHANGED, + DELAY_FOR_RETRY_INIT_FLAG_CHECK_MS); + break; + } if (mBluetooth != null && isEnabled()) { restartForReason( BluetoothProtoEnums.ENABLE_DISABLE_REASON_INIT_FLAGS_CHANGED); diff --git a/services/core/java/com/android/server/BluetoothModeChangeHelper.java b/services/core/java/com/android/server/BluetoothModeChangeHelper.java new file mode 100644 index 000000000000..242fa848c25e --- /dev/null +++ b/services/core/java/com/android/server/BluetoothModeChangeHelper.java @@ -0,0 +1,143 @@ +/* + * Copyright 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 com.android.server; + +import android.bluetooth.BluetoothA2dp; +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothHearingAid; +import android.bluetooth.BluetoothProfile; +import android.bluetooth.BluetoothProfile.ServiceListener; +import android.content.Context; +import android.content.res.Resources; +import android.provider.Settings; +import android.widget.Toast; + +import com.android.internal.R; +import com.android.internal.annotations.VisibleForTesting; + +/** + * Helper class that handles callout and callback methods without + * complex logic. + */ +public class BluetoothModeChangeHelper { + private volatile BluetoothA2dp mA2dp; + private volatile BluetoothHearingAid mHearingAid; + private final BluetoothAdapter mAdapter; + private final Context mContext; + + BluetoothModeChangeHelper(Context context) { + mAdapter = BluetoothAdapter.getDefaultAdapter(); + mContext = context; + + mAdapter.getProfileProxy(mContext, mProfileServiceListener, BluetoothProfile.A2DP); + mAdapter.getProfileProxy(mContext, mProfileServiceListener, + BluetoothProfile.HEARING_AID); + } + + private final ServiceListener mProfileServiceListener = new ServiceListener() { + @Override + public void onServiceConnected(int profile, BluetoothProfile proxy) { + // Setup Bluetooth profile proxies + switch (profile) { + case BluetoothProfile.A2DP: + mA2dp = (BluetoothA2dp) proxy; + break; + case BluetoothProfile.HEARING_AID: + mHearingAid = (BluetoothHearingAid) proxy; + break; + default: + break; + } + } + + @Override + public void onServiceDisconnected(int profile) { + // Clear Bluetooth profile proxies + switch (profile) { + case BluetoothProfile.A2DP: + mA2dp = null; + break; + case BluetoothProfile.HEARING_AID: + mHearingAid = null; + break; + default: + break; + } + } + }; + + @VisibleForTesting + public boolean isA2dpOrHearingAidConnected() { + return isA2dpConnected() || isHearingAidConnected(); + } + + @VisibleForTesting + public boolean isBluetoothOn() { + final BluetoothAdapter adapter = mAdapter; + if (adapter == null) { + return false; + } + return adapter.getLeState() == BluetoothAdapter.STATE_ON; + } + + @VisibleForTesting + public boolean isAirplaneModeOn() { + return Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.AIRPLANE_MODE_ON, 0) == 1; + } + + @VisibleForTesting + public void onAirplaneModeChanged(BluetoothManagerService managerService) { + managerService.onAirplaneModeChanged(); + } + + @VisibleForTesting + public int getSettingsInt(String name) { + return Settings.Global.getInt(mContext.getContentResolver(), + name, 0); + } + + @VisibleForTesting + public void setSettingsInt(String name, int value) { + Settings.Global.putInt(mContext.getContentResolver(), + name, value); + } + + @VisibleForTesting + public void showToastMessage() { + Resources r = mContext.getResources(); + final CharSequence text = r.getString( + R.string.bluetooth_airplane_mode_toast, 0); + Toast.makeText(mContext, text, Toast.LENGTH_LONG).show(); + } + + private boolean isA2dpConnected() { + final BluetoothA2dp a2dp = mA2dp; + if (a2dp == null) { + return false; + } + return a2dp.getConnectedDevices().size() > 0; + } + + private boolean isHearingAidConnected() { + final BluetoothHearingAid hearingAid = mHearingAid; + if (hearingAid == null) { + return false; + } + return hearingAid.getConnectedDevices().size() > 0; + } +} diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 8a1baf25481b..d07a22ded6dd 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -140,6 +140,7 @@ import android.net.util.LinkPropertiesUtils.CompareOrUpdateResult; import android.net.util.LinkPropertiesUtils.CompareResult; import android.net.util.MultinetworkPolicyTracker; import android.net.util.NetdService; +import android.os.BasicShellCommandHandler; import android.os.Binder; import android.os.Build; import android.os.Bundle; @@ -156,11 +157,8 @@ import android.os.PersistableBundle; import android.os.PowerManager; import android.os.Process; import android.os.RemoteException; -import android.os.ResultReceiver; import android.os.ServiceManager; import android.os.ServiceSpecificException; -import android.os.ShellCallback; -import android.os.ShellCommand; import android.os.SystemClock; import android.os.SystemProperties; import android.os.UserHandle; @@ -238,7 +236,6 @@ import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import java.util.Comparator; import java.util.ConcurrentModificationException; import java.util.HashMap; @@ -1126,7 +1123,6 @@ public class ConnectivityService extends IConnectivityManager.Stub // Listen to package add and removal events for all users. intentFilter = new IntentFilter(); - intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED); intentFilter.addAction(Intent.ACTION_PACKAGE_REPLACED); intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); intentFilter.addDataScheme("package"); @@ -6195,20 +6191,12 @@ public class ConnectivityService extends IConnectivityManager.Stub return; // no updating necessary } - final NetworkAgentInfo defaultNai = getDefaultNetwork(); - final boolean isDefaultNetwork = (defaultNai != null && defaultNai.network.netId == netId); - if (DBG) { final Collection<InetAddress> dnses = newLp.getDnsServers(); log("Setting DNS servers for network " + netId + " to " + dnses); } try { mDnsManager.noteDnsServersForNetwork(netId, newLp); - // TODO: netd should listen on [::1]:53 and proxy queries to the current - // default network, and we should just set net.dns1 to ::1, not least - // because applications attempting to use net.dns resolvers will bypass - // the privacy protections of things like DNS-over-TLS. - if (isDefaultNetwork) mDnsManager.setDefaultDnsSystemProperties(newLp.getDnsServers()); mDnsManager.flushVmDnsCache(); } catch (Exception e) { loge("Exception in setDnsConfigurationForNetwork: " + e); @@ -6723,8 +6711,6 @@ public class ConnectivityService extends IConnectivityManager.Stub ? newNetwork.linkProperties.getHttpProxy() : null); updateTcpBufferSizes(null != newNetwork ? newNetwork.linkProperties.getTcpBufferSizes() : null); - mDnsManager.setDefaultDnsSystemProperties(null != newNetwork - ? newNetwork.linkProperties.getDnsServers() : Collections.EMPTY_LIST); notifyIfacesChangedForNetworkStats(); // Fix up the NetworkCapabilities of any VPNs that don't specify underlying networks. updateAllVpnsCapabilities(); @@ -7659,14 +7645,14 @@ public class ConnectivityService extends IConnectivityManager.Stub } @Override - public void onShellCommand(@NonNull FileDescriptor in, @NonNull FileDescriptor out, - FileDescriptor err, @NonNull String[] args, ShellCallback callback, - @NonNull ResultReceiver resultReceiver) { - (new ShellCmd()).exec(this, in, out, err, args, callback, resultReceiver); + public int handleShellCommand(@NonNull ParcelFileDescriptor in, + @NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err, + @NonNull String[] args) { + return new ShellCmd().exec(this, in.getFileDescriptor(), out.getFileDescriptor(), + err.getFileDescriptor(), args); } - private class ShellCmd extends ShellCommand { - + private class ShellCmd extends BasicShellCommandHandler { @Override public int onCommand(String cmd) { if (cmd == null) { diff --git a/services/core/java/com/android/server/MountServiceIdler.java b/services/core/java/com/android/server/MountServiceIdler.java index 6bc1a570b7c0..0f4c94bc8d4f 100644 --- a/services/core/java/com/android/server/MountServiceIdler.java +++ b/services/core/java/com/android/server/MountServiceIdler.java @@ -113,6 +113,7 @@ public class MountServiceIdler extends JobService { JobInfo.Builder builder = new JobInfo.Builder(MOUNT_JOB_ID, sIdleService); builder.setRequiresDeviceIdle(true); builder.setRequiresBatteryNotLow(true); + builder.setRequiresCharging(true); builder.setMinimumLatency(nextScheduleTime); tm.schedule(builder.build()); } diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java index 17c0970c5ca7..418deb801085 100644 --- a/services/core/java/com/android/server/Watchdog.java +++ b/services/core/java/com/android/server/Watchdog.java @@ -23,7 +23,9 @@ import android.content.Intent; import android.content.IntentFilter; import android.hidl.manager.V1_0.IServiceManager; import android.os.Binder; +import android.os.Build; import android.os.Debug; +import android.os.FileUtils; import android.os.Handler; import android.os.IPowerManager; import android.os.Looper; @@ -31,10 +33,12 @@ import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; +import android.os.SystemProperties; import android.util.EventLog; import android.util.Log; import android.util.Slog; import android.util.SparseArray; +import android.sysprop.WatchdogProperties; import com.android.internal.os.ProcessCpuTracker; import com.android.internal.os.ZygoteConnectionConstants; @@ -42,12 +46,16 @@ import com.android.internal.util.FrameworkStatsLog; import com.android.server.am.ActivityManagerService; import com.android.server.wm.SurfaceAnimationThread; +import java.io.BufferedReader; import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.StringWriter; import java.util.ArrayList; import java.util.Arrays; +import java.util.concurrent.TimeUnit; import java.util.HashSet; import java.util.List; @@ -75,6 +83,12 @@ public class Watchdog extends Thread { private static final int WAITED_HALF = 2; private static final int OVERDUE = 3; + // Track watchdog timeout history and break the crash loop if there is. + private static final String TIMEOUT_HISTORY_FILE = "/data/system/watchdog-timeout-history.txt"; + private static final String PROP_FATAL_LOOP_COUNT = "framework_watchdog.fatal_count"; + private static final String PROP_FATAL_LOOP_WINDOWS_SECS = + "framework_watchdog.fatal_window.second"; + // Which native processes to dump into dropbox's stack traces public static final String[] NATIVE_STACKS_OF_INTEREST = new String[] { "/system/bin/audioserver", @@ -688,6 +702,10 @@ public class Watchdog extends Thread { Slog.w(TAG, "*** WATCHDOG KILLING SYSTEM PROCESS: " + subject); WatchdogDiagnostics.diagnoseCheckers(blockedCheckers); Slog.w(TAG, "*** GOODBYE!"); + if (!Build.IS_USER && isCrashLoopFound() + && !WatchdogProperties.is_fatal_ignore().orElse(false)) { + breakCrashLoop(); + } Process.killProcess(Process.myPid()); System.exit(10); } @@ -705,4 +723,107 @@ public class Watchdog extends Thread { Slog.w(TAG, "Failed to write to /proc/sysrq-trigger", e); } } + + private void resetTimeoutHistory() { + writeTimeoutHistory(new ArrayList<String>()); + } + + private void writeTimeoutHistory(Iterable<String> crashHistory) { + String data = String.join(",", crashHistory); + + try (FileWriter writer = new FileWriter(TIMEOUT_HISTORY_FILE)) { + writer.write(SystemProperties.get("ro.boottime.zygote")); + writer.write(":"); + writer.write(data); + } catch (IOException e) { + Slog.e(TAG, "Failed to write file " + TIMEOUT_HISTORY_FILE, e); + } + } + + private String[] readTimeoutHistory() { + final String[] emptyStringArray = {}; + + try (BufferedReader reader = new BufferedReader(new FileReader(TIMEOUT_HISTORY_FILE))) { + String line = reader.readLine(); + if (line == null) { + return emptyStringArray; + } + + String[] data = line.trim().split(":"); + String boottime = data.length >= 1 ? data[0] : ""; + String history = data.length >= 2 ? data[1] : ""; + if (SystemProperties.get("ro.boottime.zygote").equals(boottime) && !history.isEmpty()) { + return history.split(","); + } else { + return emptyStringArray; + } + } catch (FileNotFoundException e) { + return emptyStringArray; + } catch (IOException e) { + Slog.e(TAG, "Failed to read file " + TIMEOUT_HISTORY_FILE, e); + return emptyStringArray; + } + } + + private boolean hasActiveUsbConnection() { + try { + final String state = FileUtils.readTextFile( + new File("/sys/class/android_usb/android0/state"), + 128 /*max*/, null /*ellipsis*/).trim(); + if ("CONFIGURED".equals(state)) { + return true; + } + } catch (IOException e) { + Slog.w(TAG, "Failed to determine if device was on USB", e); + } + return false; + } + + private boolean isCrashLoopFound() { + int fatalCount = WatchdogProperties.fatal_count().orElse(0); + long fatalWindowMs = TimeUnit.SECONDS.toMillis( + WatchdogProperties.fatal_window_second().orElse(0)); + if (fatalCount == 0 || fatalWindowMs == 0) { + if (fatalCount != fatalWindowMs) { + Slog.w(TAG, String.format("sysprops '%s' and '%s' should be set or unset together", + PROP_FATAL_LOOP_COUNT, PROP_FATAL_LOOP_WINDOWS_SECS)); + } + return false; + } + + // new-history = [last (fatalCount - 1) items in old-history] + [nowMs]. + long nowMs = SystemClock.elapsedRealtime(); // Time since boot including deep sleep. + String[] rawCrashHistory = readTimeoutHistory(); + ArrayList<String> crashHistory = new ArrayList<String>(Arrays.asList(Arrays.copyOfRange( + rawCrashHistory, + Math.max(0, rawCrashHistory.length - fatalCount - 1), + rawCrashHistory.length))); + // Something wrong here. + crashHistory.add(String.valueOf(nowMs)); + writeTimeoutHistory(crashHistory); + + // Returns false if the device has an active USB connection. + if (hasActiveUsbConnection()) { + return false; + } + + long firstCrashMs; + try { + firstCrashMs = Long.parseLong(crashHistory.get(0)); + } catch (NumberFormatException t) { + Slog.w(TAG, "Failed to parseLong " + crashHistory.get(0), t); + resetTimeoutHistory(); + return false; + } + return crashHistory.size() >= fatalCount && nowMs - firstCrashMs < fatalWindowMs; + } + + private void breakCrashLoop() { + try (FileWriter kmsg = new FileWriter("/dev/kmsg_debug", /* append= */ true)) { + kmsg.append("Fatal reset to escape the system_server crashing loop\n"); + } catch (IOException e) { + Slog.w(TAG, "Failed to append to kmsg", e); + } + doSysRq('c'); + } } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 09c0ba37028a..d990c1e9fbe1 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -3318,6 +3318,10 @@ public class ActivityManagerService extends IActivityManager.Stub @Override public boolean setProcessMemoryTrimLevel(String process, int userId, int level) throws RemoteException { + if (!isCallerShell()) { + EventLog.writeEvent(0x534e4554, 160390416, Binder.getCallingUid(), ""); + throw new SecurityException("Only shell can call it"); + } synchronized (this) { final ProcessRecord app = findProcessLocked(process, userId, "setProcessMemoryTrimLevel"); if (app == null) { diff --git a/services/core/java/com/android/server/connectivity/DnsManager.java b/services/core/java/com/android/server/connectivity/DnsManager.java index cf6a7f6e8d70..271ec4eac9e8 100644 --- a/services/core/java/com/android/server/connectivity/DnsManager.java +++ b/services/core/java/com/android/server/connectivity/DnsManager.java @@ -50,7 +50,6 @@ import android.util.Slog; import java.net.InetAddress; import java.util.Arrays; -import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -245,7 +244,6 @@ public class DnsManager { private final Map<Integer, LinkProperties> mLinkPropertiesMap; private final Map<Integer, int[]> mTransportsMap; - private int mNumDnsEntries; private int mSampleValidity; private int mSuccessThreshold; private int mMinSamples; @@ -409,18 +407,6 @@ public class DnsManager { } } - public void setDefaultDnsSystemProperties(Collection<InetAddress> dnses) { - int last = 0; - for (InetAddress dns : dnses) { - ++last; - setNetDnsProperty(last, dns.getHostAddress()); - } - for (int i = last + 1; i <= mNumDnsEntries; ++i) { - setNetDnsProperty(i, ""); - } - mNumDnsEntries = last; - } - /** * Flush DNS caches and events work before boot has completed. */ @@ -476,16 +462,6 @@ public class DnsManager { return Settings.Global.getInt(mContentResolver, which, dflt); } - private void setNetDnsProperty(int which, String value) { - final String key = "net.dns" + which; - // Log and forget errors setting unsupported properties. - try { - mSystemProperties.set(key, value); - } catch (Exception e) { - Slog.e(TAG, "Error setting unsupported net.dns property: ", e); - } - } - private static String getPrivateDnsMode(ContentResolver cr) { String mode = getStringSetting(cr, PRIVATE_DNS_MODE); if (TextUtils.isEmpty(mode)) mode = getStringSetting(cr, PRIVATE_DNS_DEFAULT_MODE); diff --git a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java index 01fa9e755bd6..8625a6f470c5 100644 --- a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java +++ b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java @@ -47,7 +47,6 @@ import android.net.NetworkAgent; import android.net.NetworkUtils; import android.net.SocketKeepalive.InvalidSocketException; import android.net.TcpKeepalivePacketData; -import android.net.util.IpUtils; import android.net.util.KeepaliveUtils; import android.os.Binder; import android.os.Handler; @@ -63,6 +62,7 @@ import android.util.Pair; import com.android.internal.R; import com.android.internal.util.HexDump; import com.android.internal.util.IndentingPrintWriter; +import com.android.net.module.util.IpUtils; import java.io.FileDescriptor; import java.net.InetAddress; diff --git a/services/core/java/com/android/server/connectivity/PacManager.java b/services/core/java/com/android/server/connectivity/PacManager.java index de302fc01f2d..198de78ecfa6 100644 --- a/services/core/java/com/android/server/connectivity/PacManager.java +++ b/services/core/java/com/android/server/connectivity/PacManager.java @@ -154,7 +154,7 @@ public class PacManager { mNetThreadHandler = new Handler(netThread.getLooper()); mPacRefreshIntent = PendingIntent.getBroadcast( - context, 0, new Intent(ACTION_PAC_REFRESH), 0); + context, 0, new Intent(ACTION_PAC_REFRESH), PendingIntent.FLAG_IMMUTABLE); context.registerReceiver(new PacRefreshIntentReceiver(), new IntentFilter(ACTION_PAC_REFRESH)); mConnectivityHandler = handler; diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index 8e1fccd07f7a..d3abe871b80e 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -380,8 +380,8 @@ public class Vpn { } } - public boolean checkInterfacePresent(final Vpn vpn, final String iface) { - return vpn.jniCheck(iface) == 0; + public boolean isInterfacePresent(final Vpn vpn, final String iface) { + return vpn.jniCheck(iface) != 0; } } @@ -1130,7 +1130,13 @@ public class Vpn { return mNetworkInfo; } - public int getNetId() { + /** + * Return netId of current running VPN network. + * + * @return a netId if there is a running VPN network or NETID_UNSET if there is no running VPN + * network or network is null. + */ + public synchronized int getNetId() { final NetworkAgent agent = mNetworkAgent; if (null == agent) return NETID_UNSET; final Network network = agent.getNetwork(); @@ -1602,7 +1608,7 @@ public class Vpn { */ public synchronized void onUserStopped() { // Switch off networking lockdown (if it was enabled) - setLockdown(false); + setVpnForcedLocked(false); mAlwaysOn = false; // Quit any active connections @@ -1708,7 +1714,7 @@ public class Vpn { /** * Return the configuration of the currently running VPN. */ - public VpnConfig getVpnConfig() { + public synchronized VpnConfig getVpnConfig() { enforceControlPermission(); return mConfig; } @@ -2146,7 +2152,11 @@ public class Vpn { break; } - // Prepare arguments for mtpd. + // Prepare arguments for mtpd. MTU/MRU calculated conservatively. Only IPv4 supported + // because LegacyVpn. + // 1500 - 60 (Carrier-internal IPv6 + UDP + GTP) - 10 (PPP) - 16 (L2TP) - 8 (UDP) + // - 77 (IPsec w/ SHA-2 512, 256b trunc-len, AES-CBC) - 8 (UDP encap) - 20 (IPv4) + // - 28 (464xlat) String[] mtpd = null; switch (profile.type) { case VpnProfile.TYPE_PPTP: @@ -2154,7 +2164,7 @@ public class Vpn { iface, "pptp", profile.server, "1723", "name", profile.username, "password", profile.password, "linkname", "vpn", "refuse-eap", "nodefaultroute", - "usepeerdns", "idle", "1800", "mtu", "1400", "mru", "1400", + "usepeerdns", "idle", "1800", "mtu", "1270", "mru", "1270", (profile.mppe ? "+mppe" : "nomppe"), }; break; @@ -2164,7 +2174,7 @@ public class Vpn { iface, "l2tp", profile.server, "1701", profile.l2tpSecret, "name", profile.username, "password", profile.password, "linkname", "vpn", "refuse-eap", "nodefaultroute", - "usepeerdns", "idle", "1800", "mtu", "1400", "mru", "1400", + "usepeerdns", "idle", "1800", "mtu", "1270", "mru", "1270", }; break; } @@ -2755,7 +2765,10 @@ public class Vpn { final LinkProperties lp = cm.getLinkProperties(network); if (lp != null && lp.getAllInterfaceNames().contains(mOuterInterface)) { final NetworkInfo networkInfo = cm.getNetworkInfo(network); - if (networkInfo != null) mOuterConnection.set(networkInfo.getType()); + if (networkInfo != null) { + mOuterConnection.set(networkInfo.getType()); + break; + } } } } @@ -2986,7 +2999,7 @@ public class Vpn { checkInterruptAndDelay(false); // Check if the interface is gone while we are waiting. - if (mDeps.checkInterfacePresent(Vpn.this, mConfig.interfaze)) { + if (!mDeps.isInterfacePresent(Vpn.this, mConfig.interfaze)) { throw new IllegalStateException(mConfig.interfaze + " is gone"); } diff --git a/services/core/java/com/android/server/hdmi/HdmiCecController.java b/services/core/java/com/android/server/hdmi/HdmiCecController.java index 66652ca26e54..535284083d11 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecController.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecController.java @@ -16,6 +16,8 @@ package com.android.server.hdmi; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.hardware.hdmi.HdmiPortInfo; import android.hardware.tv.cec.V1_0.CecMessage; import android.hardware.tv.cec.V1_0.HotplugEvent; @@ -725,6 +727,7 @@ final class HdmiCecController { private IHdmiCec mHdmiCec; private final Object mLock = new Object(); private int mPhysicalAddress = INVALID_PHYSICAL_ADDRESS; + @Nullable private HdmiCecCallback mCallback; @Override public String nativeInit() { @@ -733,7 +736,7 @@ final class HdmiCecController { boolean connectToHal() { try { - mHdmiCec = IHdmiCec.getService(); + mHdmiCec = IHdmiCec.getService(true); try { mHdmiCec.linkToDeath(this, HDMI_CEC_HAL_DEATH_COOKIE); } catch (RemoteException e) { @@ -747,7 +750,8 @@ final class HdmiCecController { } @Override - public void setCallback(HdmiCecCallback callback) { + public void setCallback(@NonNull HdmiCecCallback callback) { + mCallback = callback; try { mHdmiCec.setCallback(callback); } catch (RemoteException e) { @@ -887,6 +891,10 @@ final class HdmiCecController { if (cookie == HDMI_CEC_HAL_DEATH_COOKIE) { HdmiLogger.error(TAG, "Service died cokkie : " + cookie + "; reconnecting"); connectToHal(); + // Reconnect the callback + if (mCallback != null) { + setCallback(mCallback); + } } } diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index 2d7e79a7073c..a31aacbde46f 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -3867,7 +3867,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // quick check: if this uid doesn't have INTERNET permission, it // doesn't have network access anyway, so it is a waste to mess // with it here. - if (hasInternetPermissionUL(uid)) { + if (hasInternetPermissionUL(uid) && !isUidForegroundOnRestrictPowerUL(uid)) { uidRules.put(uid, FIREWALL_RULE_DENY); } } diff --git a/services/core/java/com/android/server/net/NetworkStatsAccess.java b/services/core/java/com/android/server/net/NetworkStatsAccess.java index 7c1c1c7ce403..72559b4825e7 100644 --- a/services/core/java/com/android/server/net/NetworkStatsAccess.java +++ b/services/core/java/com/android/server/net/NetworkStatsAccess.java @@ -28,6 +28,7 @@ import android.app.admin.DeviceAdminInfo; import android.app.admin.DevicePolicyManagerInternal; import android.content.Context; import android.content.pm.PackageManager; +import android.os.Process; import android.os.UserHandle; import android.telephony.TelephonyManager; @@ -113,10 +114,11 @@ public final class NetworkStatsAccess { TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; boolean isDeviceOwner = dpmi != null && dpmi.isActiveAdminWithPolicy(callingUid, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); + final int appId = UserHandle.getAppId(callingUid); if (hasCarrierPrivileges || isDeviceOwner - || UserHandle.getAppId(callingUid) == android.os.Process.SYSTEM_UID) { - // Carrier-privileged apps and device owners, and the system can access data usage for - // all apps on the device. + || appId == Process.SYSTEM_UID || appId == Process.NETWORK_STACK_UID) { + // Carrier-privileged apps and device owners, and the system (including the + // network stack) can access data usage for all apps on the device. return NetworkStatsAccess.Level.DEVICE; } diff --git a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java index d202a2a60738..5646c752fc90 100644 --- a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java +++ b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java @@ -30,6 +30,7 @@ import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.Log; +import android.util.Pair; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.CollectionUtils; @@ -94,39 +95,41 @@ public class NetworkStatsSubscriptionsMonitor extends // also needed to track CBRS. final List<Integer> newSubs = getActiveSubIdList(mSubscriptionManager); - for (final int subId : newSubs) { - final RatTypeListener match = CollectionUtils.find(mRatListeners, - it -> it.mSubId == subId); - if (match != null) continue; - - // Create listener for every newly added sub. Also store subscriberId into it to - // prevent binder call to telephony when querying RAT. If the subscriberId is empty - // for any reason, such as SIM PIN locked, skip registration. - // SubscriberId will be unavailable again if 1. modem crashed 2. reboot - // 3. re-insert SIM. If that happens, the listeners will be eventually synchronized - // with active sub list once all subscriberIds are ready. - final String subscriberId = mTeleManager.getSubscriberId(subId); - if (TextUtils.isEmpty(subscriberId)) { - Log.d(NetworkStatsService.TAG, "Empty subscriberId for newly added sub " - + subId + ", skip listener registration"); + // IMSI is needed for every newly added sub. Listener stores subscriberId into it to + // prevent binder call to telephony when querying RAT. Keep listener registration with empty + // IMSI is meaningless since the RAT type changed is ambiguous for multi-SIM if reported + // with empty IMSI. So filter the subs w/o a valid IMSI to prevent such registration. + final List<Pair<Integer, String>> filteredNewSubs = + CollectionUtils.mapNotNull(newSubs, subId -> { + final String subscriberId = mTeleManager.getSubscriberId(subId); + return TextUtils.isEmpty(subscriberId) ? null : new Pair(subId, subscriberId); + }); + + for (final Pair<Integer, String> sub : filteredNewSubs) { + // Fully match listener with subId and IMSI, since in some rare cases, IMSI might be + // suddenly change regardless of subId, such as switch IMSI feature in modem side. + // If that happens, register new listener with new IMSI and remove old one later. + if (CollectionUtils.find(mRatListeners, + it -> it.equalsKey(sub.first, sub.second)) != null) { continue; } + final RatTypeListener listener = - new RatTypeListener(mExecutor, this, subId, subscriberId); + new RatTypeListener(mExecutor, this, sub.first, sub.second); mRatListeners.add(listener); // Register listener to the telephony manager that associated with specific sub. - mTeleManager.createForSubscriptionId(subId) + mTeleManager.createForSubscriptionId(sub.first) .listen(listener, PhoneStateListener.LISTEN_SERVICE_STATE); - Log.d(NetworkStatsService.TAG, "RAT type listener registered for sub " + subId); + Log.d(NetworkStatsService.TAG, "RAT type listener registered for sub " + sub.first); } for (final RatTypeListener listener : new ArrayList<>(mRatListeners)) { - // If the new list contains the subId of the listener, keeps it. - final Integer match = CollectionUtils.find(newSubs, it -> it == listener.mSubId); - if (match != null) continue; - - handleRemoveRatTypeListener(listener); + // If there is no subId and IMSI matched the listener, removes it. + if (CollectionUtils.find(filteredNewSubs, + it -> listener.equalsKey(it.first, it.second)) == null) { + handleRemoveRatTypeListener(listener); + } } } @@ -232,5 +235,9 @@ public class NetworkStatsSubscriptionsMonitor extends public int getSubId() { return mSubId; } + + boolean equalsKey(int subId, @NonNull String subscriberId) { + return mSubId == subId && TextUtils.equals(mSubscriberId, subscriberId); + } } } diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java index bc78d66037fe..c3cb42f95cc6 100644 --- a/services/core/java/com/android/server/notification/PreferencesHelper.java +++ b/services/core/java/com/android/server/notification/PreferencesHelper.java @@ -75,6 +75,7 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; @@ -173,6 +174,8 @@ public class PreferencesHelper implements RankingConfig { private boolean mAllowInvalidShortcuts = false; + private Map<String, List<String>> mOemLockedApps = new HashMap(); + public PreferencesHelper(Context context, PackageManager pm, RankingHandler rankingHandler, ZenModeHelper zenHelper, NotificationChannelLogger notificationChannelLogger, AppOpsManager appOpsManager, @@ -314,6 +317,12 @@ public class PreferencesHelper implements RankingConfig { } channel.setImportanceLockedByCriticalDeviceFunction( r.defaultAppLockedImportance); + channel.setImportanceLockedByOEM(r.oemLockedImportance); + if (!channel.isImportanceLockedByOEM()) { + if (r.oemLockedChannels.contains(channel.getId())) { + channel.setImportanceLockedByOEM(true); + } + } boolean isInvalidShortcutChannel = channel.getConversationId() != null && channel.getConversationId().contains( @@ -396,6 +405,14 @@ public class PreferencesHelper implements RankingConfig { r.visibility = visibility; r.showBadge = showBadge; r.bubblePreference = bubblePreference; + if (mOemLockedApps.containsKey(r.pkg)) { + List<String> channels = mOemLockedApps.get(r.pkg); + if (channels == null || channels.isEmpty()) { + r.oemLockedImportance = true; + } else { + r.oemLockedChannels = channels; + } + } try { createDefaultChannelIfNeededLocked(r); @@ -1149,8 +1166,10 @@ public class PreferencesHelper implements RankingConfig { String channelId = appSplit.length == 2 ? appSplit[1] : null; synchronized (mPackagePreferences) { + boolean foundApp = false; for (PackagePreferences r : mPackagePreferences.values()) { if (r.pkg.equals(appName)) { + foundApp = true; if (channelId == null) { // lock all channels for the app r.oemLockedImportance = true; @@ -1168,6 +1187,14 @@ public class PreferencesHelper implements RankingConfig { } } } + if (!foundApp) { + List<String> channels = + mOemLockedApps.getOrDefault(appName, new ArrayList<>()); + if (channelId != null) { + channels.add(channelId); + } + mOemLockedApps.put(appName, channels); + } } } } diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java index c3c2e5e65103..069a00f03a1d 100644 --- a/services/core/java/com/android/server/pm/AppsFilter.java +++ b/services/core/java/com/android/server/pm/AppsFilter.java @@ -547,9 +547,9 @@ public class AppsFilter { final boolean newIsForceQueryable = mForceQueryable.contains(newPkgSetting.appId) /* shared user that is already force queryable */ - || newPkg.isForceQueryable() - || newPkgSetting.forceQueryableOverride + || newPkgSetting.forceQueryableOverride /* adb override */ || (newPkgSetting.isSystem() && (mSystemAppsQueryable + || newPkg.isForceQueryable() || ArrayUtils.contains(mForceQueryableByDevicePackageNames, newPkg.getPackageName()))); if (newIsForceQueryable diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java index 0dfa081e7695..48ec9b4b502d 100644 --- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java +++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java @@ -337,6 +337,7 @@ public class BackgroundDexOptService extends JobService { private int idleOptimizePackages(PackageManagerService pm, ArraySet<String> pkgs, long lowStorageThreshold) { ArraySet<String> updatedPackages = new ArraySet<>(); + ArraySet<String> updatedPackagesDueToSecondaryDex = new ArraySet<>(); try { final boolean supportSecondaryDex = supportSecondaryDex(); @@ -391,11 +392,14 @@ public class BackgroundDexOptService extends JobService { } int secondaryResult = optimizePackages(pm, pkgs, lowStorageThreshold, - /*isForPrimaryDex*/ false, updatedPackages); + /*isForPrimaryDex*/ false, updatedPackagesDueToSecondaryDex); return secondaryResult; } finally { // Always let the pinner service know about changes. notifyPinService(updatedPackages); + // Only notify IORap the primary dex opt, because we don't want to + // invalidate traces unnecessary due to b/161633001 and that it's + // better to have a trace than no trace at all. notifyPackagesUpdated(updatedPackages); } } diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 994cec2b1e59..90d9834d891a 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -943,6 +943,23 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } } + private ParcelFileDescriptor openTargetInternal(String path, int flags, int mode) + throws IOException, ErrnoException { + // TODO: this should delegate to DCS so the system process avoids + // holding open FDs into containers. + final FileDescriptor fd = Os.open(path, flags, mode); + return new ParcelFileDescriptor(fd); + } + + private ParcelFileDescriptor createRevocableFdInternal(RevocableFileDescriptor fd, + ParcelFileDescriptor pfd) throws IOException { + int releasedFdInt = pfd.detachFd(); + FileDescriptor releasedFd = new FileDescriptor(); + releasedFd.setInt$(releasedFdInt); + fd.init(mContext, releasedFd); + return fd.getRevocableFileDescriptor(); + } + private ParcelFileDescriptor doWriteInternal(String name, long offsetBytes, long lengthBytes, ParcelFileDescriptor incomingFd) throws IOException { // Quick sanity check of state, and allocate a pipe for ourselves. We @@ -975,21 +992,20 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { Binder.restoreCallingIdentity(identity); } - // TODO: this should delegate to DCS so the system process avoids - // holding open FDs into containers. - final FileDescriptor targetFd = Os.open(target.getAbsolutePath(), + ParcelFileDescriptor targetPfd = openTargetInternal(target.getAbsolutePath(), O_CREAT | O_WRONLY, 0644); Os.chmod(target.getAbsolutePath(), 0644); // If caller specified a total length, allocate it for them. Free up // cache space to grow, if needed. if (stageDir != null && lengthBytes > 0) { - mContext.getSystemService(StorageManager.class).allocateBytes(targetFd, lengthBytes, + mContext.getSystemService(StorageManager.class).allocateBytes( + targetPfd.getFileDescriptor(), lengthBytes, PackageHelper.translateAllocateFlags(params.installFlags)); } if (offsetBytes > 0) { - Os.lseek(targetFd, offsetBytes, OsConstants.SEEK_SET); + Os.lseek(targetPfd.getFileDescriptor(), offsetBytes, OsConstants.SEEK_SET); } if (incomingFd != null) { @@ -999,8 +1015,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { // inserted above to hold the session active. try { final Int64Ref last = new Int64Ref(0); - FileUtils.copy(incomingFd.getFileDescriptor(), targetFd, lengthBytes, null, - Runnable::run, (long progress) -> { + FileUtils.copy(incomingFd.getFileDescriptor(), targetPfd.getFileDescriptor(), + lengthBytes, null, Runnable::run, + (long progress) -> { if (params.sizeBytes > 0) { final long delta = progress - last.value; last.value = progress; @@ -1011,7 +1028,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } }); } finally { - IoUtils.closeQuietly(targetFd); + IoUtils.closeQuietly(targetPfd); IoUtils.closeQuietly(incomingFd); // We're done here, so remove the "bridge" that was holding @@ -1027,12 +1044,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } return null; } else if (PackageInstaller.ENABLE_REVOCABLE_FD) { - fd.init(mContext, targetFd); - return fd.getRevocableFileDescriptor(); + return createRevocableFdInternal(fd, targetPfd); } else { - bridge.setTargetFile(targetFd); + bridge.setTargetFile(targetPfd); bridge.start(); - return new ParcelFileDescriptor(bridge.getClientSocket()); + return bridge.getClientSocket(); } } catch (ErrnoException e) { diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 81748b23e6ee..9d0a5c4787fd 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -280,6 +280,7 @@ import android.os.storage.StorageManagerInternal; import android.os.storage.VolumeInfo; import android.os.storage.VolumeRecord; import android.permission.IPermissionManager; +import android.provider.ContactsContract; import android.provider.DeviceConfig; import android.provider.Settings.Global; import android.provider.Settings.Secure; @@ -3648,6 +3649,8 @@ public class PackageManagerService extends IPackageManager.Stub PackageParser.readConfigUseRoundIcon(mContext.getResources()); mServiceStartWithDelay = SystemClock.uptimeMillis() + (60 * 1000L); + + Slog.i(TAG, "Fix for b/169414761 is applied"); } /** @@ -11095,6 +11098,8 @@ public class PackageManagerService extends IPackageManager.Stub mSettings.addRenamedPackageLPw(parsedPackage.getRealPackage(), originalPkgSetting.name); mTransferredPackages.add(originalPkgSetting.name); + } else { + mSettings.removeRenamedPackageLPw(parsedPackage.getPackageName()); } } if (pkgSetting.sharedUser != null) { @@ -25400,6 +25405,32 @@ public class PackageManagerService extends IPackageManager.Stub } } + @Override + public void grantImplicitAccess(int recipientUid, String visibleAuthority) { + // This API is exposed temporarily to only the contacts provider. (b/158688602) + final int callingUid = Binder.getCallingUid(); + ProviderInfo contactsProvider = resolveContentProviderInternal( + ContactsContract.AUTHORITY, 0, UserHandle.getUserId(callingUid)); + if (contactsProvider == null || contactsProvider.applicationInfo == null + || !UserHandle.isSameApp(contactsProvider.applicationInfo.uid, callingUid)) { + throw new SecurityException(callingUid + " is not allow to call grantImplicitAccess"); + } + final int userId = UserHandle.getUserId(recipientUid); + final long token = Binder.clearCallingIdentity(); + final ProviderInfo providerInfo; + try { + providerInfo = resolveContentProvider(visibleAuthority, 0 /*flags*/, userId); + } finally { + Binder.restoreCallingIdentity(token); + } + if (providerInfo == null) { + return; + } + int visibleUid = providerInfo.applicationInfo.uid; + mPmInternal.grantImplicitAccess(userId, null /*Intent*/, UserHandle.getAppId(recipientUid), + visibleUid, false); + } + boolean canHaveOatDir(String packageName) { synchronized (mLock) { AndroidPackage p = mPackages.get(packageName); diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index a0feb94fd3fc..0f5d9781c612 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -476,6 +476,10 @@ public final class Settings { return mRenamedPackages.put(pkgName, origPkgName); } + void removeRenamedPackageLPw(String pkgName) { + mRenamedPackages.remove(pkgName); + } + public boolean canPropagatePermissionToInstantApp(String permName) { return mPermissions.canPropagatePermissionToInstantApp(permName); } diff --git a/services/core/java/com/android/server/pm/permission/OWNERS b/services/core/java/com/android/server/pm/permission/OWNERS index 01dc01efaca8..0e88862e01b1 100644 --- a/services/core/java/com/android/server/pm/permission/OWNERS +++ b/services/core/java/com/android/server/pm/permission/OWNERS @@ -1,4 +1,5 @@ moltmann@google.com +zhanghai@google.com per-file DefaultPermissionGrantPolicy.java = hackbod@android.com per-file DefaultPermissionGrantPolicy.java = jsharkey@android.com per-file DefaultPermissionGrantPolicy.java = svetoslavganov@google.com @@ -7,3 +8,4 @@ per-file DefaultPermissionGrantPolicy.java = yamasani@google.com per-file DefaultPermissionGrantPolicy.java = patb@google.com per-file DefaultPermissionGrantPolicy.java = eugenesusla@google.com per-file DefaultPermissionGrantPolicy.java = moltmann@google.com +per-file DefaultPermissionGrantPolicy.java = zhanghai@google.com diff --git a/services/core/java/com/android/server/vcn/OWNERS b/services/core/java/com/android/server/vcn/OWNERS new file mode 100644 index 000000000000..33b9f0f75f81 --- /dev/null +++ b/services/core/java/com/android/server/vcn/OWNERS @@ -0,0 +1,7 @@ +set noparent + +benedictwong@google.com +ckesting@google.com +evitayan@google.com +nharold@google.com +jchalard@google.com
\ No newline at end of file diff --git a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java index c4e03f5c65f5..aa76a07bc9c7 100644 --- a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java +++ b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java @@ -16,8 +16,6 @@ package com.android.server.wm; -import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; - import static com.android.server.wm.ActivityStack.TAG_VISIBILITY; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_VISIBILITY; @@ -174,12 +172,7 @@ class EnsureActivitiesVisibleHelper { } final int windowingMode = mContiner.getWindowingMode(); - if (windowingMode == WINDOWING_MODE_FREEFORM) { - // The visibility of tasks and the activities they contain in freeform stack are - // determined individually unlike other stacks where the visibility or fullscreen - // status of an activity in a previous task affects other. - mBehindFullscreenActivity = !mContainerShouldBeVisible; - } else if (!mBehindFullscreenActivity && mContiner.isActivityTypeHome() + if (!mBehindFullscreenActivity && mContiner.isActivityTypeHome() && r.isRootOfTask()) { if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Home task: at " + mContiner + " stackShouldBeVisible=" + mContainerShouldBeVisible diff --git a/services/core/xsd/vts/Android.mk b/services/core/xsd/vts/Android.mk deleted file mode 100644 index 6dc2c437a2f9..000000000000 --- a/services/core/xsd/vts/Android.mk +++ /dev/null @@ -1,22 +0,0 @@ -# -# Copyright (C) 2019 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_MODULE := VtsValidateDefaultPermissions -include test/vts/tools/build/Android.host_config.mk diff --git a/services/core/xsd/vts/AndroidTest.xml b/services/core/xsd/vts/AndroidTest.xml deleted file mode 100644 index 4f3b2ef1ace1..000000000000 --- a/services/core/xsd/vts/AndroidTest.xml +++ /dev/null @@ -1,30 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2019 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> -<configuration description="Config for VTS VtsValidateDefaultPermissions."> - <option name="config-descriptor:metadata" key="plan" value="vts-treble" /> - <target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher"> - <option name="abort-on-push-failure" value="false"/> - <option name="push-group" value="HostDrivenTest.push"/> - <option name="push" value="DATA/etc/default-permissions.xsd->/data/local/tmp/default-permissions.xsd"/> - </target_preparer> - <test class="com.android.tradefed.testtype.VtsMultiDeviceTest"> - <option name="test-module-name" value="VtsValidateDefaultPermissions"/> - <option name="binary-test-source" value="_32bit::DATA/nativetest/vts_defaultPermissions_validate_test/vts_defaultPermissions_validate_test" /> - <option name="binary-test-source" value="_64bit::DATA/nativetest64/vts_defaultPermissions_validate_test/vts_defaultPermissions_validate_test" /> - <option name="binary-test-type" value="gtest"/> - <option name="test-timeout" value="30s"/> - </test> -</configuration> diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index c6b93d6ca4f4..0da47ca90f5e 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -480,38 +480,38 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { private static final int STATUS_BAR_DISABLE2_MASK = StatusBarManager.DISABLE2_QUICK_SETTINGS; - private static final Set<String> SECURE_SETTINGS_WHITELIST; - private static final Set<String> SECURE_SETTINGS_DEVICEOWNER_WHITELIST; - private static final Set<String> GLOBAL_SETTINGS_WHITELIST; + private static final Set<String> SECURE_SETTINGS_ALLOWLIST; + private static final Set<String> SECURE_SETTINGS_DEVICEOWNER_ALLOWLIST; + private static final Set<String> GLOBAL_SETTINGS_ALLOWLIST; private static final Set<String> GLOBAL_SETTINGS_DEPRECATED; - private static final Set<String> SYSTEM_SETTINGS_WHITELIST; + private static final Set<String> SYSTEM_SETTINGS_ALLOWLIST; private static final Set<Integer> DA_DISALLOWED_POLICIES; // A collection of user restrictions that are deprecated and should simply be ignored. private static final Set<String> DEPRECATED_USER_RESTRICTIONS; private static final String AB_DEVICE_KEY = "ro.build.ab_update"; static { - SECURE_SETTINGS_WHITELIST = new ArraySet<>(); - SECURE_SETTINGS_WHITELIST.add(Settings.Secure.DEFAULT_INPUT_METHOD); - SECURE_SETTINGS_WHITELIST.add(Settings.Secure.SKIP_FIRST_USE_HINTS); - SECURE_SETTINGS_WHITELIST.add(Settings.Secure.INSTALL_NON_MARKET_APPS); - - SECURE_SETTINGS_DEVICEOWNER_WHITELIST = new ArraySet<>(); - SECURE_SETTINGS_DEVICEOWNER_WHITELIST.addAll(SECURE_SETTINGS_WHITELIST); - SECURE_SETTINGS_DEVICEOWNER_WHITELIST.add(Settings.Secure.LOCATION_MODE); - - GLOBAL_SETTINGS_WHITELIST = new ArraySet<>(); - GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.ADB_ENABLED); - GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.ADB_WIFI_ENABLED); - GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.AUTO_TIME); - GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.AUTO_TIME_ZONE); - GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.DATA_ROAMING); - GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.USB_MASS_STORAGE_ENABLED); - GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.WIFI_SLEEP_POLICY); - GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.STAY_ON_WHILE_PLUGGED_IN); - GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN); - GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.PRIVATE_DNS_MODE); - GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.PRIVATE_DNS_SPECIFIER); + SECURE_SETTINGS_ALLOWLIST = new ArraySet<>(); + SECURE_SETTINGS_ALLOWLIST.add(Settings.Secure.DEFAULT_INPUT_METHOD); + SECURE_SETTINGS_ALLOWLIST.add(Settings.Secure.SKIP_FIRST_USE_HINTS); + SECURE_SETTINGS_ALLOWLIST.add(Settings.Secure.INSTALL_NON_MARKET_APPS); + + SECURE_SETTINGS_DEVICEOWNER_ALLOWLIST = new ArraySet<>(); + SECURE_SETTINGS_DEVICEOWNER_ALLOWLIST.addAll(SECURE_SETTINGS_ALLOWLIST); + SECURE_SETTINGS_DEVICEOWNER_ALLOWLIST.add(Settings.Secure.LOCATION_MODE); + + GLOBAL_SETTINGS_ALLOWLIST = new ArraySet<>(); + GLOBAL_SETTINGS_ALLOWLIST.add(Settings.Global.ADB_ENABLED); + GLOBAL_SETTINGS_ALLOWLIST.add(Settings.Global.ADB_WIFI_ENABLED); + GLOBAL_SETTINGS_ALLOWLIST.add(Settings.Global.AUTO_TIME); + GLOBAL_SETTINGS_ALLOWLIST.add(Settings.Global.AUTO_TIME_ZONE); + GLOBAL_SETTINGS_ALLOWLIST.add(Settings.Global.DATA_ROAMING); + GLOBAL_SETTINGS_ALLOWLIST.add(Settings.Global.USB_MASS_STORAGE_ENABLED); + GLOBAL_SETTINGS_ALLOWLIST.add(Settings.Global.WIFI_SLEEP_POLICY); + GLOBAL_SETTINGS_ALLOWLIST.add(Settings.Global.STAY_ON_WHILE_PLUGGED_IN); + GLOBAL_SETTINGS_ALLOWLIST.add(Settings.Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN); + GLOBAL_SETTINGS_ALLOWLIST.add(Settings.Global.PRIVATE_DNS_MODE); + GLOBAL_SETTINGS_ALLOWLIST.add(Settings.Global.PRIVATE_DNS_SPECIFIER); GLOBAL_SETTINGS_DEPRECATED = new ArraySet<>(); GLOBAL_SETTINGS_DEPRECATED.add(Settings.Global.BLUETOOTH_ON); @@ -520,11 +520,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { GLOBAL_SETTINGS_DEPRECATED.add(Settings.Global.NETWORK_PREFERENCE); GLOBAL_SETTINGS_DEPRECATED.add(Settings.Global.WIFI_ON); - SYSTEM_SETTINGS_WHITELIST = new ArraySet<>(); - SYSTEM_SETTINGS_WHITELIST.add(Settings.System.SCREEN_BRIGHTNESS); - SYSTEM_SETTINGS_WHITELIST.add(Settings.System.SCREEN_BRIGHTNESS_FLOAT); - SYSTEM_SETTINGS_WHITELIST.add(Settings.System.SCREEN_BRIGHTNESS_MODE); - SYSTEM_SETTINGS_WHITELIST.add(Settings.System.SCREEN_OFF_TIMEOUT); + SYSTEM_SETTINGS_ALLOWLIST = new ArraySet<>(); + SYSTEM_SETTINGS_ALLOWLIST.add(Settings.System.SCREEN_BRIGHTNESS); + SYSTEM_SETTINGS_ALLOWLIST.add(Settings.System.SCREEN_BRIGHTNESS_FLOAT); + SYSTEM_SETTINGS_ALLOWLIST.add(Settings.System.SCREEN_BRIGHTNESS_MODE); + SYSTEM_SETTINGS_ALLOWLIST.add(Settings.System.SCREEN_OFF_TIMEOUT); DA_DISALLOWED_POLICIES = new ArraySet<>(); DA_DISALLOWED_POLICIES.add(DeviceAdminInfo.USES_POLICY_DISABLE_CAMERA); @@ -1231,13 +1231,13 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { String startUserSessionMessage = null; String endUserSessionMessage = null; - // The whitelist of packages that can access cross profile calendar APIs. - // This whitelist should be in default an empty list, which indicates that no package - // is whitelisted. + // The allowlist of packages that can access cross profile calendar APIs. + // This allowlist should be in default an empty list, which indicates that no package + // is allowed. List<String> mCrossProfileCalendarPackages = Collections.emptyList(); - // The whitelist of packages that the admin has enabled to be able to request consent from - // the user to communicate cross-profile. By default, no packages are whitelisted, which is + // The allowlist of packages that the admin has enabled to be able to request consent from + // the user to communicate cross-profile. By default, no packages are allowed, which is // represented as an empty list. List<String> mCrossProfilePackages = Collections.emptyList(); @@ -2818,7 +2818,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { final IIntentSender.Stub mLocalSender = new IIntentSender.Stub() { @Override - public void send(int code, Intent intent, String resolvedType, IBinder whitelistToken, + public void send(int code, Intent intent, String resolvedType, IBinder allowlistToken, IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) { final int status = intent.getIntExtra( PackageInstaller.EXTRA_STATUS, PackageInstaller.STATUS_FAILURE); @@ -7067,7 +7067,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { */ @Override public boolean setAlwaysOnVpnPackage(ComponentName who, String vpnPackage, boolean lockdown, - List<String> lockdownWhitelist) + List<String> lockdownAllowlist) throws SecurityException { enforceProfileOrDeviceOwner(who); @@ -7079,10 +7079,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { DevicePolicyManager.ERROR_VPN_PACKAGE_NOT_FOUND, vpnPackage); } - if (vpnPackage != null && lockdown && lockdownWhitelist != null) { - for (String packageName : lockdownWhitelist) { + if (vpnPackage != null && lockdown && lockdownAllowlist != null) { + for (String packageName : lockdownAllowlist) { if (!isPackageInstalledForUser(packageName, userId)) { - Slog.w(LOG_TAG, "Non-existent package in VPN whitelist: " + packageName); + Slog.w(LOG_TAG, "Non-existent package in VPN allowlist: " + packageName); throw new ServiceSpecificException( DevicePolicyManager.ERROR_VPN_PACKAGE_NOT_FOUND, packageName); } @@ -7090,7 +7090,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } // If some package is uninstalled after the check above, it will be ignored by CM. if (!mInjector.getConnectivityManager().setAlwaysOnVpnPackageForUser( - userId, vpnPackage, lockdown, lockdownWhitelist)) { + userId, vpnPackage, lockdown, lockdownAllowlist)) { throw new UnsupportedOperationException(); } DevicePolicyEventLogger @@ -7098,7 +7098,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { .setAdmin(who) .setStrings(vpnPackage) .setBoolean(lockdown) - .setInt(lockdownWhitelist != null ? lockdownWhitelist.size() : 0) + .setInt(lockdownAllowlist != null ? lockdownAllowlist.size() : 0) .write(); }); synchronized (getLockObject()) { @@ -7151,7 +7151,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } @Override - public List<String> getAlwaysOnVpnLockdownWhitelist(ComponentName admin) + public List<String> getAlwaysOnVpnLockdownAllowlist(ComponentName admin) throws SecurityException { enforceProfileOrDeviceOwner(admin); @@ -11911,7 +11911,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return; } - if (!GLOBAL_SETTINGS_WHITELIST.contains(setting) + if (!GLOBAL_SETTINGS_ALLOWLIST.contains(setting) && !UserManager.isDeviceInDemoMode(mContext)) { throw new SecurityException(String.format( "Permission denial: device owners cannot update %1$s", setting)); @@ -11939,7 +11939,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { synchronized (getLockObject()) { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); - if (!SYSTEM_SETTINGS_WHITELIST.contains(setting)) { + if (!SYSTEM_SETTINGS_ALLOWLIST.contains(setting)) { throw new SecurityException(String.format( "Permission denial: device owners cannot update %1$s", setting)); } @@ -12083,12 +12083,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); if (isDeviceOwner(who, callingUserId)) { - if (!SECURE_SETTINGS_DEVICEOWNER_WHITELIST.contains(setting) + if (!SECURE_SETTINGS_DEVICEOWNER_ALLOWLIST.contains(setting) && !isCurrentUserDemo()) { throw new SecurityException(String.format( "Permission denial: Device owners cannot update %1$s", setting)); } - } else if (!SECURE_SETTINGS_WHITELIST.contains(setting) && !isCurrentUserDemo()) { + } else if (!SECURE_SETTINGS_ALLOWLIST.contains(setting) && !isCurrentUserDemo()) { throw new SecurityException(String.format( "Permission denial: Profile owners cannot update %1$s", setting)); } @@ -13859,7 +13859,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { @Override public void markProfileOwnerOnOrganizationOwnedDevice(ComponentName who, int userId) { // As the caller is the system, it must specify the component name of the profile owner - // as a sanity / safety check. + // as a safety check. Objects.requireNonNull(who); if (!mHasFeature) { @@ -13895,7 +13895,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { @GuardedBy("getLockObject()") private void markProfileOwnerOnOrganizationOwnedDeviceUncheckedLocked( ComponentName who, int userId) { - // Sanity check: Make sure that the user has a profile owner and that the specified + // Make sure that the user has a profile owner and that the specified // component is the profile owner of that user. if (!isProfileOwner(who, userId)) { throw new IllegalArgumentException(String.format( diff --git a/services/net/TEST_MAPPING b/services/net/TEST_MAPPING new file mode 100644 index 000000000000..7025dd178e0f --- /dev/null +++ b/services/net/TEST_MAPPING @@ -0,0 +1,7 @@ +{ + "imports": [ + { + "path": "frameworks/base/core/java/android/net" + } + ] +}
\ No newline at end of file diff --git a/services/net/java/android/net/TcpKeepalivePacketData.java b/services/net/java/android/net/TcpKeepalivePacketData.java index c0c386b3046e..4875c7cc4263 100644 --- a/services/net/java/android/net/TcpKeepalivePacketData.java +++ b/services/net/java/android/net/TcpKeepalivePacketData.java @@ -19,11 +19,12 @@ import static android.net.SocketKeepalive.ERROR_INVALID_IP_ADDRESS; import android.annotation.NonNull; import android.annotation.Nullable; -import android.net.util.IpUtils; import android.os.Parcel; import android.os.Parcelable; import android.system.OsConstants; +import com.android.net.module.util.IpUtils; + import java.net.InetAddress; import java.net.UnknownHostException; import java.nio.ByteBuffer; diff --git a/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java b/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java index ec56e1ebc8e0..bd37e587aee7 100644 --- a/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java +++ b/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java @@ -41,6 +41,7 @@ import static com.android.server.backup.testing.Utils.oneTimeIterable; import static com.android.server.backup.testing.Utils.transferStreamedData; import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth.assertWithMessage; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; @@ -2814,8 +2815,8 @@ public class KeyValueBackupTaskTest { } private static IterableSubject assertDirectory(Path directory) throws IOException { - return assertThat(oneTimeIterable(Files.newDirectoryStream(directory).iterator())) - .named("directory " + directory); + return assertWithMessage("directory " + directory).that( + oneTimeIterable(Files.newDirectoryStream(directory).iterator())); } private static void assertJournalDoesNotContain( diff --git a/services/robotests/backup/src/com/android/server/backup/testing/TestUtils.java b/services/robotests/backup/src/com/android/server/backup/testing/TestUtils.java index 3fe1f3f90f2f..3114a751d556 100644 --- a/services/robotests/backup/src/com/android/server/backup/testing/TestUtils.java +++ b/services/robotests/backup/src/com/android/server/backup/testing/TestUtils.java @@ -17,6 +17,7 @@ package com.android.server.backup.testing; import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth.assertWithMessage; import static org.robolectric.Shadows.shadowOf; @@ -95,8 +96,8 @@ public class TestUtils { * logcat before that. */ public static void assertLogcatAtMost(String tag, int level) { - assertThat(ShadowLog.getLogsForTag(tag).stream().allMatch(logItem -> logItem.type <= level)) - .named("All logs <= " + level) + assertWithMessage("All logs <= " + level).that( + ShadowLog.getLogsForTag(tag).stream().allMatch(logItem -> logItem.type <= level)) .isTrue(); } @@ -105,8 +106,8 @@ public class TestUtils { * logcat before that. */ public static void assertLogcatAtLeast(String tag, int level) { - assertThat(ShadowLog.getLogsForTag(tag).stream().anyMatch(logItem -> logItem.type >= level)) - .named("Any log >= " + level) + assertWithMessage("Any log >= " + level).that( + ShadowLog.getLogsForTag(tag).stream().anyMatch(logItem -> logItem.type >= level)) .isTrue(); } @@ -121,11 +122,10 @@ public class TestUtils { * that uses logcat before that. */ public static void assertLogcat(String tag, int... logs) { - assertThat( + assertWithMessage("Log items (specified per level)").that( ShadowLog.getLogsForTag(tag).stream() .map(logItem -> logItem.type) .collect(toSet())) - .named("Log items (specified per level)") .containsExactly(IntStream.of(logs).boxed().toArray()); } @@ -135,15 +135,13 @@ public class TestUtils { /** Declare shadow {@link ShadowEventLog} to use this. */ public static void assertEventLogged(int tag, Object... values) { - assertThat(ShadowEventLog.getEntries()) - .named("Event logs") + assertWithMessage("Event logs").that(ShadowEventLog.getEntries()) .contains(new ShadowEventLog.Entry(tag, Arrays.asList(values))); } /** Declare shadow {@link ShadowEventLog} to use this. */ public static void assertEventNotLogged(int tag, Object... values) { - assertThat(ShadowEventLog.getEntries()) - .named("Event logs") + assertWithMessage("Event logs").that(ShadowEventLog.getEntries()) .doesNotContain(new ShadowEventLog.Entry(tag, Arrays.asList(values))); } diff --git a/services/tests/mockingservicestests/src/com/android/server/location/LocationFudgerTest.java b/services/tests/mockingservicestests/src/com/android/server/location/LocationFudgerTest.java index a0f48c674316..d67edddb30e6 100644 --- a/services/tests/mockingservicestests/src/com/android/server/location/LocationFudgerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/location/LocationFudgerTest.java @@ -79,7 +79,7 @@ public class LocationFudgerTest { Location coarse = mFudger.createCoarse(fine); assertThat(coarse).isNotNull(); - assertThat(coarse).isNotSameAs(fine); + assertThat(coarse).isNotSameInstanceAs(fine); assertThat(coarse.hasBearing()).isFalse(); assertThat(coarse.hasSpeed()).isFalse(); assertThat(coarse.hasAltitude()).isFalse(); diff --git a/services/tests/servicestests/src/com/android/server/BluetoothAirplaneModeListenerTest.java b/services/tests/servicestests/src/com/android/server/BluetoothAirplaneModeListenerTest.java index 968a402ff3b7..3ace3f4c79dc 100644 --- a/services/tests/servicestests/src/com/android/server/BluetoothAirplaneModeListenerTest.java +++ b/services/tests/servicestests/src/com/android/server/BluetoothAirplaneModeListenerTest.java @@ -27,8 +27,6 @@ import androidx.test.InstrumentationRegistry; import androidx.test.filters.MediumTest; import androidx.test.runner.AndroidJUnit4; -import com.android.server.BluetoothAirplaneModeListener.AirplaneModeHelper; - import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -41,7 +39,7 @@ public class BluetoothAirplaneModeListenerTest { private Context mContext; private BluetoothAirplaneModeListener mBluetoothAirplaneModeListener; private BluetoothAdapter mBluetoothAdapter; - private AirplaneModeHelper mHelper; + private BluetoothModeChangeHelper mHelper; @Mock BluetoothManagerService mBluetoothManagerService; @@ -49,7 +47,7 @@ public class BluetoothAirplaneModeListenerTest { public void setUp() throws Exception { mContext = InstrumentationRegistry.getTargetContext(); - mHelper = mock(AirplaneModeHelper.class); + mHelper = mock(BluetoothModeChangeHelper.class); when(mHelper.getSettingsInt(BluetoothAirplaneModeListener.TOAST_COUNT)) .thenReturn(BluetoothAirplaneModeListener.MAX_TOAST_COUNT); doNothing().when(mHelper).setSettingsInt(anyString(), anyInt()); diff --git a/services/tests/servicestests/src/com/android/server/integrity/IntegrityFileManagerTest.java b/services/tests/servicestests/src/com/android/server/integrity/IntegrityFileManagerTest.java index 41be54ab5b7a..f26e0941e008 100644 --- a/services/tests/servicestests/src/com/android/server/integrity/IntegrityFileManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/integrity/IntegrityFileManagerTest.java @@ -194,7 +194,7 @@ public class IntegrityFileManagerTest { assertThat(rulesFetched.size()) .isEqualTo(INDEXING_BLOCK_SIZE * 2 + unindexedRuleCount); assertThat(rulesFetched) - .containsAllOf( + .containsAtLeast( getPackageNameIndexedRule(installedPackageName), getAppCertificateIndexedRule(installedAppCertificate)); } diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelperTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelperTest.java index 6921bb27ceb2..8d5687c33419 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelperTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelperTest.java @@ -71,7 +71,7 @@ public class TestOnlyInsecureCertificateHelperTest { Map<String, Pair<SecretKey, byte[]>> filteredKeys = mHelper.keepOnlyWhitelistedInsecureKeys(rawKeys); assertThat(filteredKeys.entrySet()).containsExactlyElementsIn(expectedResult.entrySet()); - assertThat(filteredKeys.entrySet()).containsAllIn(rawKeys.entrySet()); + assertThat(filteredKeys.entrySet()).containsAtLeastElementsIn(rawKeys.entrySet()); } @Test @@ -85,7 +85,7 @@ public class TestOnlyInsecureCertificateHelperTest { Map<String, Pair<SecretKey, byte[]>> filteredKeys = mHelper.keepOnlyWhitelistedInsecureKeys(rawKeys); assertThat(filteredKeys.entrySet()).containsExactlyElementsIn(expectedResult.entrySet()); - assertThat(rawKeys.entrySet()).containsAllIn(filteredKeys.entrySet()); + assertThat(rawKeys.entrySet()).containsAtLeastElementsIn(filteredKeys.entrySet()); } @Test @@ -100,7 +100,7 @@ public class TestOnlyInsecureCertificateHelperTest { Map<String, Pair<SecretKey, byte[]>> filteredKeys = mHelper.keepOnlyWhitelistedInsecureKeys(rawKeys); assertThat(filteredKeys.entrySet()).containsExactlyElementsIn(expectedResult.entrySet()); - assertThat(rawKeys.entrySet()).containsAllIn(filteredKeys.entrySet()); + assertThat(rawKeys.entrySet()).containsAtLeastElementsIn(filteredKeys.entrySet()); } @Test @@ -122,7 +122,7 @@ public class TestOnlyInsecureCertificateHelperTest { Map<String, Pair<SecretKey, byte[]>> filteredKeys = mHelper.keepOnlyWhitelistedInsecureKeys(rawKeys); assertThat(filteredKeys.entrySet()).containsExactlyElementsIn(expectedResult.entrySet()); - assertThat(rawKeys.entrySet()).containsAllIn(filteredKeys.entrySet()); + assertThat(rawKeys.entrySet()).containsAtLeastElementsIn(filteredKeys.entrySet()); } @Test diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/certificate/CertXmlTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/certificate/CertXmlTest.java index 9836c64ea5b5..b0cb2ea85bf4 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/certificate/CertXmlTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/certificate/CertXmlTest.java @@ -70,7 +70,7 @@ public final class CertXmlTest { CertXml certXml = CertXml.parse(certXmlBytes); List<X509Certificate> endpointCerts = certXml.getAllEndpointCerts(); assertThat(endpointCerts).hasSize(3); - assertThat(endpointCerts).containsAllOf(TestData.LEAF_CERT_1, TestData.LEAF_CERT_2); + assertThat(endpointCerts).containsAtLeast(TestData.LEAF_CERT_1, TestData.LEAF_CERT_2); } @Test diff --git a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java index 26230949cda6..37aedac8f28e 100644 --- a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java @@ -365,14 +365,15 @@ public class AppsFilterTest { } @Test - public void testForceQueryable_DoesntFilter() throws Exception { + public void testForceQueryable_SystemDoesntFilter() throws Exception { final AppsFilter appsFilter = new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, - pkg("com.some.package").setForceQueryable(true), DUMMY_TARGET_APPID); + pkg("com.some.package").setForceQueryable(true), DUMMY_TARGET_APPID, + setting -> setting.setPkgFlags(ApplicationInfo.FLAG_SYSTEM)); PackageSetting calling = simulateAddPackage(appsFilter, pkg("com.some.other.package"), DUMMY_CALLING_APPID); @@ -380,6 +381,23 @@ public class AppsFilterTest { SYSTEM_USER)); } + + @Test + public void testForceQueryable_NonSystemFilters() throws Exception { + final AppsFilter appsFilter = + new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); + simulateAddBasicAndroid(appsFilter); + appsFilter.onSystemReady(); + + PackageSetting target = simulateAddPackage(appsFilter, + pkg("com.some.package").setForceQueryable(true), DUMMY_TARGET_APPID); + PackageSetting calling = simulateAddPackage(appsFilter, + pkg("com.some.other.package"), DUMMY_CALLING_APPID); + + assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target, + SYSTEM_USER)); + } + @Test public void testForceQueryableByDevice_SystemCaller_DoesntFilter() throws Exception { final AppsFilter appsFilter = diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java index 44bb58f62253..22b07157e94e 100644 --- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java @@ -639,7 +639,7 @@ public final class UserManagerTest { UserInfo user1 = createUser("User 1", 0); UserInfo user2 = createUser("User 2", 0); long[] serialNumbersOfUsers = mUserManager.getSerialNumbersOfUsers(false); - assertThat(serialNumbersOfUsers).asList().containsAllOf( + assertThat(serialNumbersOfUsers).asList().containsAtLeast( (long) user1.serialNumber, (long) user2.serialNumber); } diff --git a/services/tests/servicestests/src/com/android/server/rollback/RollbackStoreTest.java b/services/tests/servicestests/src/com/android/server/rollback/RollbackStoreTest.java index 102d5bb373c8..cc32d5c5a292 100644 --- a/services/tests/servicestests/src/com/android/server/rollback/RollbackStoreTest.java +++ b/services/tests/servicestests/src/com/android/server/rollback/RollbackStoreTest.java @@ -48,41 +48,25 @@ public class RollbackStoreTest { private static final String INSTALLER = "some.installer"; private static final Correspondence<VersionedPackage, VersionedPackage> VER_PKG_CORR = - new Correspondence<VersionedPackage, VersionedPackage>() { - @Override - public boolean compare(VersionedPackage a, VersionedPackage b) { - if (a == null || b == null) { - return a == b; - } - return a.equals(b); + Correspondence.from((VersionedPackage a, VersionedPackage b) -> { + if (a == null || b == null) { + return a == b; } - - @Override - public String toString() { - return "is the same as"; - } - }; + return a.equals(b); + }, "is the same as"); private static final Correspondence<PackageRollbackInfo.RestoreInfo, PackageRollbackInfo.RestoreInfo> RESTORE_INFO_CORR = - new Correspondence<PackageRollbackInfo.RestoreInfo, PackageRollbackInfo.RestoreInfo>() { - @Override - public boolean compare(PackageRollbackInfo.RestoreInfo a, - PackageRollbackInfo.RestoreInfo b) { - if (a == null || b == null) { - return a == b; - } - return a.userId == b.userId - && a.appId == b.appId - && Objects.equals(a.seInfo, b.seInfo); - } - - @Override - public String toString() { - return "is the same as"; + Correspondence.from((PackageRollbackInfo.RestoreInfo a, + PackageRollbackInfo.RestoreInfo b) -> { + if (a == null || b == null) { + return a == b; } - }; + return a.userId == b.userId + && a.appId == b.appId + && Objects.equals(a.seInfo, b.seInfo); + }, "is the same as"); private static final String JSON_ROLLBACK_NO_EXT = "{'info':{'rollbackId':123,'packages':" + "[{'versionRolledBackFrom':{'packageName':'blah','longVersionCode':55}," diff --git a/services/tests/servicestests/src/com/android/server/storage/DiskStatsFileLoggerTest.java b/services/tests/servicestests/src/com/android/server/storage/DiskStatsFileLoggerTest.java index 46224cb8f855..8fb2e6838412 100644 --- a/services/tests/servicestests/src/com/android/server/storage/DiskStatsFileLoggerTest.java +++ b/services/tests/servicestests/src/com/android/server/storage/DiskStatsFileLoggerTest.java @@ -132,7 +132,7 @@ public class DiskStatsFileLoggerTest extends AndroidTestCase { appSizes.getLong(i), cacheSizes.getLong(i)); apps.add(app); } - assertThat(apps).containsAllOf(new AppSizeGrouping("com.test.app", 1100, 20), + assertThat(apps).containsAtLeast(new AppSizeGrouping("com.test.app", 1100, 20), new AppSizeGrouping("com.test.app2", 11, 2)); } diff --git a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java index f9343236662b..2372dd25cb56 100644 --- a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java @@ -81,9 +81,7 @@ public class TunerResourceManagerServiceTest { // A correspondence to compare a FrontendResource and a TunerFrontendInfo. private static final Correspondence<FrontendResource, TunerFrontendInfo> FR_TFI_COMPARE = - new Correspondence<FrontendResource, TunerFrontendInfo>() { - @Override - public boolean compare(FrontendResource actual, TunerFrontendInfo expected) { + Correspondence.from((FrontendResource actual, TunerFrontendInfo expected) -> { if (actual == null || expected == null) { return (actual == null) && (expected == null); } @@ -91,13 +89,7 @@ public class TunerResourceManagerServiceTest { return actual.getId() == expected.getId() && actual.getType() == expected.getFrontendType() && actual.getExclusiveGroupId() == expected.getExclusiveGroupId(); - } - - @Override - public String toString() { - return "is correctly configured from "; - } - }; + }, "is correctly configured from "); @Before public void setUp() throws Exception { diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java index 4dc8ad9d0a98..a118e0df1338 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java @@ -2670,6 +2670,96 @@ public class PreferencesHelperTest extends UiServiceTestCase { } @Test + public void testLockChannelsForOEM_onlyGivenPkg_appDoesNotExistYet() { + mHelper.lockChannelsForOEM(new String[] {PKG_O}); + + NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH); + NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW); + mHelper.createNotificationChannel(PKG_O, 3, a, true, false); + mHelper.createNotificationChannel(PKG_N_MR1, 30, b, false, false); + + assertTrue(mHelper.getNotificationChannel(PKG_O, 3, a.getId(), false) + .isImportanceLockedByOEM()); + assertFalse(mHelper.getNotificationChannel(PKG_N_MR1, 30, b.getId(), false) + .isImportanceLockedByOEM()); + } + + @Test + public void testLockChannelsForOEM_channelSpecific_appDoesNotExistYet() { + mHelper.lockChannelsForOEM(new String[] {PKG_O + ":b", PKG_O + ":c"}); + + NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH); + NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW); + NotificationChannel c = new NotificationChannel("c", "c", IMPORTANCE_DEFAULT); + // different uids, same package + mHelper.createNotificationChannel(PKG_O, 3, a, true, false); + mHelper.createNotificationChannel(PKG_O, 3, b, false, false); + mHelper.createNotificationChannel(PKG_O, 30, c, true, true); + + assertFalse(mHelper.getNotificationChannel(PKG_O, 3, a.getId(), false) + .isImportanceLockedByOEM()); + assertTrue(mHelper.getNotificationChannel(PKG_O, 3, b.getId(), false) + .isImportanceLockedByOEM()); + assertTrue(mHelper.getNotificationChannel(PKG_O, 30, c.getId(), false) + .isImportanceLockedByOEM()); + } + + @Test + public void testLockChannelsForOEM_onlyGivenPkg_appDoesNotExistYet_restoreData() + throws Exception { + mHelper.lockChannelsForOEM(new String[] {PKG_O}); + + final String xml = "<ranking version=\"1\">\n" + + "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\" >\n" + + "<channel id=\"a\" name=\"a\" importance=\"3\"/>" + + "<channel id=\"b\" name=\"b\" importance=\"3\"/>" + + "</package>" + + "<package name=\"" + PKG_N_MR1 + "\" uid=\"" + UID_N_MR1 + "\" >\n" + + "<channel id=\"a\" name=\"a\" importance=\"3\"/>" + + "<channel id=\"b\" name=\"b\" importance=\"3\"/>" + + "</package>" + + "</ranking>"; + XmlPullParser parser = Xml.newPullParser(); + parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())), + null); + parser.nextTag(); + mHelper.readXml(parser, false, UserHandle.USER_ALL); + + assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, "a", false) + .isImportanceLockedByOEM()); + assertFalse(mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, "b", false) + .isImportanceLockedByOEM()); + } + + @Test + public void testLockChannelsForOEM_channelSpecific_appDoesNotExistYet_restoreData() + throws Exception { + mHelper.lockChannelsForOEM(new String[] {PKG_O + ":b", PKG_O + ":c"}); + + final String xml = "<ranking version=\"1\">\n" + + "<package name=\"" + PKG_O + "\" uid=\"" + 3 + "\" >\n" + + "<channel id=\"a\" name=\"a\" importance=\"3\"/>" + + "<channel id=\"b\" name=\"b\" importance=\"3\"/>" + + "</package>" + + "<package name=\"" + PKG_O + "\" uid=\"" + 30 + "\" >\n" + + "<channel id=\"c\" name=\"c\" importance=\"3\"/>" + + "</package>" + + "</ranking>"; + XmlPullParser parser = Xml.newPullParser(); + parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())), + null); + parser.nextTag(); + mHelper.readXml(parser, false, UserHandle.USER_ALL); + + assertFalse(mHelper.getNotificationChannel(PKG_O, 3, "a", false) + .isImportanceLockedByOEM()); + assertTrue(mHelper.getNotificationChannel(PKG_O, 3, "b", false) + .isImportanceLockedByOEM()); + assertTrue(mHelper.getNotificationChannel(PKG_O, 30, "c", false) + .isImportanceLockedByOEM()); + } + + @Test public void testLockChannelsForOEM_channelSpecific_clearData() { NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH); mHelper.getImportance(PKG_O, UID_O); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ShortcutHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ShortcutHelperTest.java index eca71b69ec0b..e5ae2d3f63ab 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ShortcutHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ShortcutHelperTest.java @@ -305,6 +305,7 @@ public class ShortcutHelperTest extends UiServiceTestCase { //when(mShortcutServiceInternal.isSharingShortcut(anyInt(), anyString(), anyString(), // anyString(), anyInt(), any())).thenReturn(true); - assertThat(mShortcutHelper.getValidShortcutInfo("a", "p", UserHandle.SYSTEM)).isSameAs(si); + assertThat(mShortcutHelper.getValidShortcutInfo("a", "p", UserHandle.SYSTEM)) + .isSameInstanceAs(si); } } diff --git a/services/usb/java/com/android/server/usb/MtpNotificationManager.java b/services/usb/java/com/android/server/usb/MtpNotificationManager.java index 462ee19124ff..39f2f296a305 100644 --- a/services/usb/java/com/android/server/usb/MtpNotificationManager.java +++ b/services/usb/java/com/android/server/usb/MtpNotificationManager.java @@ -64,12 +64,13 @@ class MtpNotificationManager { private final Context mContext; private final OnOpenInAppListener mListener; + private final Receiver mReceiver; MtpNotificationManager(Context context, OnOpenInAppListener listener) { mContext = context; mListener = listener; - final Receiver receiver = new Receiver(); - context.registerReceiver(receiver, new IntentFilter(ACTION_OPEN_IN_APPS)); + mReceiver = new Receiver(); + context.registerReceiver(mReceiver, new IntentFilter(ACTION_OPEN_IN_APPS)); } void showNotification(UsbDevice device) { @@ -154,4 +155,8 @@ class MtpNotificationManager { static interface OnOpenInAppListener { void onOpenInApp(UsbDevice device); } + + public void unregister() { + mContext.unregisterReceiver(mReceiver); + } } diff --git a/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java b/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java index d7b6b5d0d36a..26ee03c25013 100644 --- a/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java +++ b/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java @@ -261,6 +261,15 @@ class UsbProfileGroupSettingsManager { } /** + * Unregister all broadcast receivers. Must be called explicitly before + * object deletion. + */ + public void unregisterReceivers() { + mPackageMonitor.unregister(); + mMtpNotificationManager.unregister(); + } + + /** * Remove all defaults and denied packages for a user. * * @param userToRemove The user diff --git a/services/usb/java/com/android/server/usb/UsbSettingsManager.java b/services/usb/java/com/android/server/usb/UsbSettingsManager.java index 7b677eea6b8f..8e53ff412f0a 100644 --- a/services/usb/java/com/android/server/usb/UsbSettingsManager.java +++ b/services/usb/java/com/android/server/usb/UsbSettingsManager.java @@ -124,6 +124,7 @@ class UsbSettingsManager { if (mSettingsByProfileGroup.indexOfKey(userToRemove.getIdentifier()) >= 0) { // The user to remove is the parent user of the group. The parent is the last user // that gets removed. All state will be removed with the user + mSettingsByProfileGroup.get(userToRemove.getIdentifier()).unregisterReceivers(); mSettingsByProfileGroup.remove(userToRemove.getIdentifier()); } else { // We cannot find the parent user of the user that is removed, hence try to remove diff --git a/startop/iorap/tests/src/com/google/android/startop/iorap/ParcelablesTest.kt b/startop/iorap/tests/src/com/google/android/startop/iorap/ParcelablesTest.kt index 8fa0cde0f9cc..150577a21f5a 100644 --- a/startop/iorap/tests/src/com/google/android/startop/iorap/ParcelablesTest.kt +++ b/startop/iorap/tests/src/com/google/android/startop/iorap/ParcelablesTest.kt @@ -124,7 +124,7 @@ class ParcelablesTest<T : Parcelable>(private val inputData: InputData<T>) { data class InputData<T : Parcelable>(val valid: T, val validCopy: T, val validOther: T) { val kls = valid.javaClass init { - assertThat(valid).isNotSameAs(validCopy) + assertThat(valid).isNotSameInstanceAs(validCopy) // Don't use isInstanceOf because of phantom warnings in intellij about Class! assertThat(validCopy.javaClass).isEqualTo(valid.javaClass) assertThat(validOther.javaClass).isEqualTo(valid.javaClass) diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java index 0469fa56e648..9f16543c410e 100755 --- a/telecomm/java/android/telecom/Call.java +++ b/telecomm/java/android/telecom/Call.java @@ -966,6 +966,32 @@ public final class Call { /** * Gets the verification status for the phone number of an incoming call as identified in * ATIS-1000082. + * <p> + * For incoming calls, the number verification status indicates whether the device was + * able to verify the authenticity of the calling number using the STIR process outlined + * in ATIS-1000082. {@link Connection#VERIFICATION_STATUS_NOT_VERIFIED} indicates that + * the network was not able to use STIR to verify the caller's number (i.e. nothing is + * known regarding the authenticity of the number. + * {@link Connection#VERIFICATION_STATUS_PASSED} indicates that the network was able to + * use STIR to verify the caller's number. This indicates that the network has a high + * degree of confidence that the incoming call actually originated from the indicated + * number. {@link Connection#VERIFICATION_STATUS_FAILED} indicates that the network's + * STIR verification did not pass. This indicates that the incoming call may not + * actually be from the indicated number. This could occur if, for example, the caller + * is using an impersonated phone number. + * <p> + * A {@link CallScreeningService} can use this information to help determine if an + * incoming call is potentially an unwanted call. A verification status of + * {@link Connection#VERIFICATION_STATUS_FAILED} indicates that an incoming call may not + * actually be from the number indicated on the call (i.e. impersonated number) and that it + * should potentially be blocked. Likewise, + * {@link Connection#VERIFICATION_STATUS_PASSED} can be used as a positive signal to + * help clarify that the incoming call is originating from the indicated number and it + * is less likely to be an undesirable call. + * <p> + * An {@link InCallService} can use this information to provide a visual indicator to the + * user regarding the verification status of a call and to help identify calls from + * potentially impersonated numbers. * @return the verification status. */ public @Connection.VerificationStatus int getCallerNumberVerificationStatus() { @@ -2111,7 +2137,13 @@ public final class Call { /** * Obtains a list of canned, pre-configured message responses to present to the user as - * ways of rejecting this {@code Call} using via a text message. + * ways of rejecting an incoming {@code Call} using via a text message. + * <p> + * <em>Note:</em> Since canned responses may be loaded from the file system, they are not + * guaranteed to be present when this {@link Call} is first added to the {@link InCallService} + * via {@link InCallService#onCallAdded(Call)}. The callback + * {@link Call.Callback#onCannedTextResponsesLoaded(Call, List)} will be called when/if canned + * responses for the call become available. * * @see #reject(boolean, String) * diff --git a/telecomm/java/android/telecom/CallScreeningService.java b/telecomm/java/android/telecom/CallScreeningService.java index 4d9311c282f7..49f183151e27 100644 --- a/telecomm/java/android/telecom/CallScreeningService.java +++ b/telecomm/java/android/telecom/CallScreeningService.java @@ -64,7 +64,7 @@ import com.android.internal.telecom.ICallScreeningService; * </li> * </ol> * <p> - * <h2>Becoming the {@link CallScreeningService}</h2> + * <h2>Becoming the CallScreeningService</h2> * Telecom will bind to a single app chosen by the user which implements the * {@link CallScreeningService} API when there are new incoming and outgoing calls. * <p> @@ -90,7 +90,27 @@ import com.android.internal.telecom.ICallScreeningService; * } * } * } + * } * </pre> + * + * <h2>CallScreeningService Lifecycle</h2> + * + * The framework binds to the {@link CallScreeningService} implemented by the user-chosen app + * filling the {@link android.app.role.RoleManager#ROLE_CALL_SCREENING} role when incoming calls are + * received (prior to ringing) and when outgoing calls are placed. The platform calls the + * {@link #onScreenCall(Call.Details)} method to provide your service with details about the call. + * <p> + * For incoming calls, the {@link CallScreeningService} must call + * {@link #respondToCall(Call.Details, CallResponse)} within 5 seconds of being bound to indicate to + * the platform whether the call should be blocked or not. Your app must do this even if it is + * primarily performing caller ID operations and not screening calls. It is important to perform + * screening operations in a timely matter as the user's device will not begin ringing until the + * response is received (or the timeout is hit). A {@link CallScreeningService} may choose to + * perform local database lookups to help determine if a call should be screened or not; care should + * be taken to ensure the timeout is not repeatedly hit, causing delays in the incoming call flow. + * <p> + * If your app provides a caller ID experience, it should launch an activity to show the caller ID + * information from {@link #onScreenCall(Call.Details)}. */ public abstract class CallScreeningService extends Service { /** @@ -339,7 +359,7 @@ public abstract class CallScreeningService extends Service { } /** - * Called when a new incoming or outgoing call is added which is not in the user's contact list. + * Called when a new incoming or outgoing call is added. * <p> * A {@link CallScreeningService} must indicate whether an incoming call is allowed or not by * calling @@ -347,21 +367,32 @@ public abstract class CallScreeningService extends Service { * Your app can tell if a call is an incoming call by checking to see if * {@link Call.Details#getCallDirection()} is {@link Call.Details#DIRECTION_INCOMING}. * <p> - * Note: The {@link Call.Details} instance provided to a call screening service will only have - * the following properties set. The rest of the {@link Call.Details} properties will be set to - * their default value or {@code null}. + * <em>Note:</em> A {@link CallScreeningService} must respond to a call within 5 seconds. After + * this time, the framework will unbind from the {@link CallScreeningService} and ignore its + * response. + * <p> + * <em>Note:</em> The {@link Call.Details} instance provided to a call screening service will + * only have the following properties set. The rest of the {@link Call.Details} properties will + * be set to their default value or {@code null}. * <ul> * <li>{@link Call.Details#getCallDirection()}</li> + * <li>{@link Call.Details#getCallerNumberVerificationStatus()}</li> * <li>{@link Call.Details#getConnectTimeMillis()}</li> * <li>{@link Call.Details#getCreationTimeMillis()}</li> * <li>{@link Call.Details#getHandle()}</li> - * <li>{@link Call.Details#getHandlePresentation()}</li> * </ul> * <p> * Only calls where the {@link Call.Details#getHandle() handle} {@link Uri#getScheme() scheme} * is {@link PhoneAccount#SCHEME_TEL} are passed for call * screening. Further, only calls which are not in the user's contacts are passed for - * screening. For outgoing calls, no post-dial digits are passed. + * screening, unless the {@link CallScreeningService} has been granted + * {@link Manifest.permission#READ_CONTACTS} permission by the user. For outgoing calls, no + * post-dial digits are passed. + * <p> + * Calls with a {@link Call.Details#getHandlePresentation()} of + * {@link TelecomManager#PRESENTATION_RESTRICTED}, {@link TelecomManager#PRESENTATION_UNKNOWN} + * or {@link TelecomManager#PRESENTATION_PAYPHONE} presentation are not provided to the + * {@link CallScreeningService}. * * @param callDetails Information about a new call, see {@link Call.Details}. */ @@ -376,6 +407,13 @@ public abstract class CallScreeningService extends Service { * <p> * Calls to this method are ignored unless the {@link Call.Details#getCallDirection()} is * {@link Call.Details#DIRECTION_INCOMING}. + * <p> + * For incoming calls, a {@link CallScreeningService} MUST call this method within 5 seconds of + * {@link #onScreenCall(Call.Details)} being invoked by the platform. + * <p> + * Calls which are blocked/rejected will be logged to the system call log with a call type of + * {@link android.provider.CallLog.Calls#BLOCKED_TYPE} and + * {@link android.provider.CallLog.Calls#BLOCK_REASON_CALL_SCREENING_SERVICE} block reason. * * @param callDetails The call to allow. * <p> diff --git a/telecomm/java/android/telecom/CallerInfo.java b/telecomm/java/android/telecom/CallerInfo.java index fb6f99405759..aff2f0183a3b 100644 --- a/telecomm/java/android/telecom/CallerInfo.java +++ b/telecomm/java/android/telecom/CallerInfo.java @@ -405,7 +405,8 @@ public class CallerInfo { // Change the callerInfo number ONLY if it is an emergency number // or if it is the voicemail number. If it is either, take a // shortcut and skip the query. - if (PhoneNumberUtils.isLocalEmergencyNumber(context, number)) { + TelephonyManager tm = context.getSystemService(TelephonyManager.class); + if (tm.isEmergencyNumber(number)) { return new CallerInfo().markAsEmergency(context); } else if (PhoneNumberUtils.isVoiceMailNumber(null, subId, number)) { return new CallerInfo().markAsVoiceMail(context, subId); diff --git a/telecomm/java/android/telecom/CallerInfoAsyncQuery.java b/telecomm/java/android/telecom/CallerInfoAsyncQuery.java index 4a81a8eea5cf..a9e1a8fc1952 100644 --- a/telecomm/java/android/telecom/CallerInfoAsyncQuery.java +++ b/telecomm/java/android/telecom/CallerInfoAsyncQuery.java @@ -34,6 +34,7 @@ import android.os.UserManager; import android.provider.ContactsContract.PhoneLookup; import android.telephony.PhoneNumberUtils; import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; import android.text.TextUtils; import java.util.ArrayList; @@ -481,7 +482,8 @@ public class CallerInfoAsyncQuery { cw.subId = subId; // check to see if these are recognized numbers, and use shortcuts if we can. - if (PhoneNumberUtils.isLocalEmergencyNumber(context, number)) { + TelephonyManager tm = context.getSystemService(TelephonyManager.class); + if (tm.isEmergencyNumber(number)) { cw.event = EVENT_EMERGENCY_NUMBER; } else if (PhoneNumberUtils.isVoiceMailNumber(context, subId, number)) { cw.event = EVENT_VOICEMAIL_NUMBER; diff --git a/telephony/api/system-current.txt b/telephony/api/system-current.txt index ac88560dbbd9..5ad377273b90 100644 --- a/telephony/api/system-current.txt +++ b/telephony/api/system-current.txt @@ -1721,7 +1721,6 @@ package android.telephony.ims.feature { ctor @Deprecated public MmTelFeature.MmTelCapabilities(android.telephony.ims.feature.ImsFeature.Capabilities); ctor public MmTelFeature.MmTelCapabilities(int); method public final void addCapabilities(int); - method public final boolean isCapable(int); method public final void removeCapabilities(int); } diff --git a/telephony/java/android/telephony/BinderCacheManager.java b/telephony/java/android/telephony/BinderCacheManager.java new file mode 100644 index 000000000000..0d3e2fe7591c --- /dev/null +++ b/telephony/java/android/telephony/BinderCacheManager.java @@ -0,0 +1,197 @@ +/* + * 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.telephony; + +import android.annotation.NonNull; +import android.os.IBinder; +import android.os.IInterface; +import android.os.RemoteException; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.NoSuchElementException; +import java.util.concurrent.atomic.AtomicReference; + +/** + * Keeps track of the connection to a Binder node, refreshes the cache if the node dies, and lets + * interested parties register listeners on the node to be notified when the node has died via the + * registered {@link Runnable}. + * @param <T> The IInterface representing the Binder type that this manager will be managing the + * cache of. + * @hide + */ +public class BinderCacheManager<T extends IInterface> { + + /** + * Factory class for creating new IInterfaces in the case that {@link #getBinder()} is + * called and there is no active binder available. + * @param <T> The IInterface that should be cached and returned to the caller when + * {@link #getBinder()} is called until the Binder node dies. + */ + public interface BinderInterfaceFactory<T> { + /** + * @return A new instance of the Binder node, which will be cached until it dies. + */ + T create(); + } + + /** + * Tracks the cached Binder node as well as the listeners that were associated with that + * Binder node during its lifetime. If the Binder node dies, the listeners will be called and + * then this tracker will be unlinked and cleaned up. + */ + private class BinderDeathTracker implements IBinder.DeathRecipient { + + private final T mConnection; + private final HashMap<Object, Runnable> mListeners = new HashMap<>(); + + /** + * Create a tracker to cache the Binder node and add the ability to listen for the cached + * interface's death. + */ + BinderDeathTracker(@NonNull T connection) { + mConnection = connection; + try { + mConnection.asBinder().linkToDeath(this, 0 /*flags*/); + } catch (RemoteException e) { + // isAlive will return false. + } + } + + public boolean addListener(Object key, Runnable r) { + synchronized (mListeners) { + if (!isAlive()) return false; + mListeners.put(key, r); + return true; + } + } + + public void removeListener(Object runnableKey) { + synchronized (mListeners) { + mListeners.remove(runnableKey); + } + } + + @Override + public void binderDied() { + ArrayList<Runnable> listeners; + synchronized (mListeners) { + listeners = new ArrayList<>(mListeners.values()); + mListeners.clear(); + try { + mConnection.asBinder().unlinkToDeath(this, 0 /*flags*/); + } catch (NoSuchElementException e) { + // No need to worry about this, this means the death recipient was never linked. + } + } + listeners.forEach(Runnable::run); + } + + /** + * @return The cached Binder. + */ + public T getConnection() { + return mConnection; + } + + /** + * @return true if the cached Binder is alive at the time of calling, false otherwise. + */ + public boolean isAlive() { + return mConnection.asBinder().isBinderAlive(); + } + } + + private final BinderInterfaceFactory<T> mBinderInterfaceFactory; + private final AtomicReference<BinderDeathTracker> mCachedConnection; + + /** + * Create a new instance, which manages a cached IInterface and creates new ones using the + * provided factory when the cached IInterface dies. + * @param factory The factory used to create new Instances of the cached IInterface when it + * dies. + */ + public BinderCacheManager(BinderInterfaceFactory<T> factory) { + mBinderInterfaceFactory = factory; + mCachedConnection = new AtomicReference<>(); + } + + /** + * Get the binder node connection and add a Runnable to be run if this Binder dies. Once this + * Runnable is run, the Runnable itself is discarded and must be added again. + * <p> + * Note: There should be no assumptions here as to which Thread this Runnable is called on. If + * the Runnable should be called on a specific thread, it should be up to the caller to handle + * that in the runnable implementation. + * @param runnableKey The Key associated with this runnable so that it can be removed later + * using {@link #removeRunnable(Object)} if needed. + * @param deadRunnable The runnable that will be run if the cached Binder node dies. + * @return T if the runnable was added or {@code null} if the connection is not alive right now + * and the associated runnable was never added. + */ + public T listenOnBinder(Object runnableKey, Runnable deadRunnable) { + if (runnableKey == null || deadRunnable == null) return null; + BinderDeathTracker tracker = getTracker(); + if (tracker == null) return null; + + boolean addSucceeded = tracker.addListener(runnableKey, deadRunnable); + return addSucceeded ? tracker.getConnection() : null; + } + + /** + * @return The cached Binder node. May return null if the requested Binder node is not currently + * available. + */ + public T getBinder() { + BinderDeathTracker tracker = getTracker(); + return (tracker != null) ? tracker.getConnection() : null; + } + + /** + * Removes a previously registered runnable associated with the returned cached Binder node + * using the key it was registered with in {@link #listenOnBinder} if the runnable still exists. + * @param runnableKey The key that was used to register the Runnable earlier. + * @return The cached Binder node that the runnable used to registered to or null if the cached + * Binder node is not alive anymore. + */ + public T removeRunnable(Object runnableKey) { + if (runnableKey == null) return null; + BinderDeathTracker tracker = getTracker(); + if (tracker == null) return null; + tracker.removeListener(runnableKey); + return tracker.getConnection(); + } + + /** + * @return The BinderDeathTracker container, which contains the cached IInterface instance or + * null if it is not available right now. + */ + private BinderDeathTracker getTracker() { + return mCachedConnection.updateAndGet((oldVal) -> { + BinderDeathTracker tracker = oldVal; + // Update cache if no longer alive. BinderDied will eventually be called on the tracker, + // which will call listeners & clean up. + if (tracker == null || !tracker.isAlive()) { + T binder = mBinderInterfaceFactory.create(); + tracker = (binder != null) ? new BinderDeathTracker(binder) : null; + + } + return (tracker != null && tracker.isAlive()) ? tracker : null; + }); + } + +} diff --git a/telephony/java/android/telephony/CellLocation.java b/telephony/java/android/telephony/CellLocation.java index cdf735195d61..8f5ec365e65c 100644 --- a/telephony/java/android/telephony/CellLocation.java +++ b/telephony/java/android/telephony/CellLocation.java @@ -29,7 +29,10 @@ import com.android.internal.telephony.PhoneConstants; /** * Abstract class that represents the location of the device. {@more} + * + * @deprecated use {@link android.telephony.CellIdentity CellIdentity}. */ +@Deprecated public abstract class CellLocation { /** diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java index d6ce40c24b78..a3cc0abea4ce 100644 --- a/telephony/java/android/telephony/SmsManager.java +++ b/telephony/java/android/telephony/SmsManager.java @@ -2091,17 +2091,25 @@ public final class SmsManager { } /** - * Gets the total capacity of SMS storage on RUIM and SIM cards - * <p> - * This is the number of 176 byte EF-SMS records which can be stored on the RUIM or SIM card. + * Gets the total capacity of SMS storage on the SIM card. + * * <p> - * See 3GPP TS 31.102 - 4.2.25 - EF-SMS for more information + * This is the number of 176 byte EF-SMS records which can be stored on the SIM card. + * See 3GPP TS 31.102 - 4.2.25 - EF-SMS for more information. + * </p> * - * @return the total number of SMS records which can be stored on the RUIM or SIM cards. - * @hide + * <p class="note"><strong>Note:</strong> This method will never trigger an SMS disambiguation + * dialog. If this method is called on a device that has multiple active subscriptions, this + * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined + * default subscription is defined, the subscription ID associated with this method will be + * INVALID, which will result in the operation being completed on the subscription associated + * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the operation + * is performed on the correct subscription. + * </p> + * + * @return the total number of SMS records which can be stored on the SIM card. */ - @SystemApi - @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int getSmsCapacityOnIcc() { int ret = 0; try { @@ -2110,7 +2118,7 @@ public final class SmsManager { ret = iccISms.getSmsCapacityOnIccForSubscriber(getSubscriptionId()); } } catch (RemoteException ex) { - //ignore it + throw new RuntimeException(ex); } return ret; } @@ -2506,13 +2514,12 @@ public final class SmsManager { /** * Send an MMS message * - * <p class="note"><strong>Note:</strong> This method will never trigger an SMS disambiguation - * dialog. If this method is called on a device that has multiple active subscriptions, this - * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined - * default subscription is defined, the subscription ID associated with this message will be - * INVALID, which will result in the operation being completed on the subscription associated - * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the - * operation is performed on the correct subscription. + * <p class="note"><strong>Note:</strong> If {@link #getDefault()} is used to instantiate this + * manager on a multi-SIM device, this operation may fail sending the MMS message because no + * suitable default subscription could be found. In this case, if {@code sentIntent} is + * non-null, then the {@link PendingIntent} will be sent with an error code + * {@code RESULT_NO_DEFAULT_SMS_APP}. See {@link #getDefault()} for more information on the + * conditions where this operation may fail. * </p> * * @param context application context @@ -2531,21 +2538,30 @@ public final class SmsManager { } MmsManager m = (MmsManager) context.getSystemService(Context.MMS_SERVICE); if (m != null) { - m.sendMultimediaMessage(getSubscriptionId(), contentUri, locationUrl, configOverrides, - sentIntent, 0L /* messageId */); + resolveSubscriptionForOperation(new SubscriptionResolverResult() { + @Override + public void onSuccess(int subId) { + m.sendMultimediaMessage(subId, contentUri, locationUrl, configOverrides, + sentIntent, 0L /* messageId */); + } + + @Override + public void onFailure() { + notifySmsError(sentIntent, RESULT_NO_DEFAULT_SMS_APP); + } + }); } } /** * Download an MMS message from carrier by a given location URL * - * <p class="note"><strong>Note:</strong> This method will never trigger an SMS disambiguation - * dialog. If this method is called on a device that has multiple active subscriptions, this - * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined - * default subscription is defined, the subscription ID associated with this message will be - * INVALID, which will result in the operation being completed on the subscription associated - * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the - * operation is performed on the correct subscription. + * <p class="note"><strong>Note:</strong> If {@link #getDefault()} is used to instantiate this + * manager on a multi-SIM device, this operation may fail downloading the MMS message because no + * suitable default subscription could be found. In this case, if {@code downloadedIntent} is + * non-null, then the {@link PendingIntent} will be sent with an error code + * {@code RESULT_NO_DEFAULT_SMS_APP}. See {@link #getDefault()} for more information on the + * conditions where this operation may fail. * </p> * * @param context application context @@ -2568,8 +2584,18 @@ public final class SmsManager { } MmsManager m = (MmsManager) context.getSystemService(Context.MMS_SERVICE); if (m != null) { - m.downloadMultimediaMessage(getSubscriptionId(), locationUrl, contentUri, - configOverrides, downloadedIntent, 0L /* messageId */); + resolveSubscriptionForOperation(new SubscriptionResolverResult() { + @Override + public void onSuccess(int subId) { + m.downloadMultimediaMessage(subId, locationUrl, contentUri, configOverrides, + downloadedIntent, 0L /* messageId */); + } + + @Override + public void onFailure() { + notifySmsError(downloadedIntent, RESULT_NO_DEFAULT_SMS_APP); + } + }); } } diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 85dca2b4e9b3..a0a90b6d8fbd 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -85,8 +85,6 @@ import android.telephony.emergency.EmergencyNumber; import android.telephony.emergency.EmergencyNumber.EmergencyServiceCategories; import android.telephony.ims.ImsMmTelManager; import android.telephony.ims.aidl.IImsConfig; -import android.telephony.ims.aidl.IImsMmTelFeature; -import android.telephony.ims.aidl.IImsRcsFeature; import android.telephony.ims.aidl.IImsRegistration; import android.telephony.ims.feature.MmTelFeature; import android.telephony.ims.stub.ImsRegistrationImplBase; @@ -94,7 +92,6 @@ import android.text.TextUtils; import android.util.Log; import android.util.Pair; -import com.android.ims.internal.IImsServiceFeatureCallback; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.CellNetworkScanResult; @@ -7309,80 +7306,6 @@ public class TelephonyManager { } /** - * Returns the {@link IImsMmTelFeature} that corresponds to the given slot Id and MMTel - * feature or {@link null} if the service is not available. If an MMTelFeature is available, the - * {@link IImsServiceFeatureCallback} callback is registered as a listener for feature updates. - * @param slotIndex The SIM slot that we are requesting the {@link IImsMmTelFeature} for. - * @param callback Listener that will send updates to ImsManager when there are updates to - * ImsServiceController. - * @return {@link IImsMmTelFeature} interface for the feature specified or {@code null} if - * it is unavailable. - * @hide - */ - public @Nullable IImsMmTelFeature getImsMmTelFeatureAndListen(int slotIndex, - IImsServiceFeatureCallback callback) { - try { - ITelephony telephony = getITelephony(); - if (telephony != null) { - return telephony.getMmTelFeatureAndListen(slotIndex, callback); - } - } catch (RemoteException e) { - Rlog.e(TAG, "getImsMmTelFeatureAndListen, RemoteException: " - + e.getMessage()); - } - return null; - } - - /** - * Returns the {@link IImsRcsFeature} that corresponds to the given slot Id and RCS - * feature for emergency calling or {@link null} if the service is not available. If an - * RcsFeature is available, the {@link IImsServiceFeatureCallback} callback is registered as a - * listener for feature updates. - * @param slotIndex The SIM slot that we are requesting the {@link IImsRcsFeature} for. - * @param callback Listener that will send updates to ImsManager when there are updates to - * ImsServiceController. - * @return {@link IImsRcsFeature} interface for the feature specified or {@code null} if - * it is unavailable. - * @hide - */ - public @Nullable IImsRcsFeature getImsRcsFeatureAndListen(int slotIndex, - IImsServiceFeatureCallback callback) { - try { - ITelephony telephony = getITelephony(); - if (telephony != null) { - return telephony.getRcsFeatureAndListen(slotIndex, callback); - } - } catch (RemoteException e) { - Rlog.e(TAG, "getImsRcsFeatureAndListen, RemoteException: " - + e.getMessage()); - } - return null; - } - - /** - * Unregister a IImsServiceFeatureCallback previously associated with an ImsFeature through - * {@link #getImsMmTelFeatureAndListen(int, IImsServiceFeatureCallback)} or - * {@link #getImsRcsFeatureAndListen(int, IImsServiceFeatureCallback)}. - * @param slotIndex The SIM slot associated with the callback. - * @param featureType The {@link android.telephony.ims.feature.ImsFeature.FeatureType} - * associated with the callback. - * @param callback The callback to be unregistered. - * @hide - */ - public void unregisterImsFeatureCallback(int slotIndex, int featureType, - IImsServiceFeatureCallback callback) { - try { - ITelephony telephony = getITelephony(); - if (telephony != null) { - telephony.unregisterImsFeatureCallback(slotIndex, featureType, callback); - } - } catch (RemoteException e) { - Rlog.e(TAG, "unregisterImsFeatureCallback, RemoteException: " - + e.getMessage()); - } - } - - /** * @return the {@IImsRegistration} interface that corresponds with the slot index and feature. * @param slotIndex The SIM slot corresponding to the ImsService ImsRegistration is active for. * @param feature An integer indicating the feature that we wish to get the ImsRegistration for. @@ -10403,19 +10326,25 @@ public class TelephonyManager { * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}) * and {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}. + * + * May return {@code null} when the subscription is inactive or when there was an error + * communicating with the phone process. */ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges @RequiresPermission(allOf = { Manifest.permission.READ_PHONE_STATE, Manifest.permission.ACCESS_COARSE_LOCATION }) - public ServiceState getServiceState() { + public @Nullable ServiceState getServiceState() { return getServiceStateForSubscriber(getSubId()); } /** * Returns the service state information on specified subscription. Callers require * either READ_PRIVILEGED_PHONE_STATE or READ_PHONE_STATE to retrieve the information. + * + * May return {@code null} when the subscription is inactive or when there was an error + * communicating with the phone process. * @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) @@ -10442,9 +10371,9 @@ public class TelephonyManager { * @param accountHandle The handle for the {@link PhoneAccount} for which to retrieve the * voicemail ringtone. * @return The URI for the ringtone to play when receiving a voicemail from a specific - * PhoneAccount. + * PhoneAccount. May be {@code null} if no ringtone is set. */ - public Uri getVoicemailRingtoneUri(PhoneAccountHandle accountHandle) { + public @Nullable Uri getVoicemailRingtoneUri(PhoneAccountHandle accountHandle) { try { ITelephony service = getITelephony(); if (service != null) { @@ -13388,4 +13317,36 @@ public class TelephonyManager { return true; } } + + /** + * Returns a list of the equivalent home PLMNs (EF_EHPLMN) from the USIM app. + * + * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} + * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}). + * + * @return A list of equivalent home PLMNs. Returns an empty list if EF_EHPLMN is empty or + * does not exist on the SIM card. + * + * @throws IllegalStateException if the Telephony process is not currently available. + * @throws SecurityException if the caller doesn't have the permission. + * + */ + @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) + public @NonNull List<String> getEquivalentHomePlmns() { + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + return telephony.getEquivalentHomePlmns(getSubId(), mContext.getOpPackageName(), + getAttributionTag()); + } else { + throw new IllegalStateException("telephony service is null."); + } + } catch (RemoteException ex) { + if (!isSystemProcess()) { + ex.rethrowAsRuntimeException(); + } + } + + return Collections.emptyList(); + } } diff --git a/telephony/java/android/telephony/cdma/CdmaCellLocation.java b/telephony/java/android/telephony/cdma/CdmaCellLocation.java index 9bc39a0c6ced..d808cabaaa92 100644 --- a/telephony/java/android/telephony/cdma/CdmaCellLocation.java +++ b/telephony/java/android/telephony/cdma/CdmaCellLocation.java @@ -23,7 +23,10 @@ import android.telephony.CellLocation; /** * Represents the cell location on a CDMA phone. + * + * @deprecated use {@link android.telephony.CellIdentity CellIdentity}. */ +@Deprecated public class CdmaCellLocation extends CellLocation { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private int mBaseStationId = -1; diff --git a/telephony/java/android/telephony/gsm/GsmCellLocation.java b/telephony/java/android/telephony/gsm/GsmCellLocation.java index bc8ee1dd9359..2eee4ce371a0 100644 --- a/telephony/java/android/telephony/gsm/GsmCellLocation.java +++ b/telephony/java/android/telephony/gsm/GsmCellLocation.java @@ -23,7 +23,10 @@ import android.telephony.CellLocation; /** * Represents the cell location on a GSM phone. + * + * @deprecated use {@link android.telephony.CellIdentity CellIdentity}. */ +@Deprecated public class GsmCellLocation extends CellLocation { private int mLac; private int mCid; diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java index f6c14e67306b..ee2fce7e7dd5 100644 --- a/telephony/java/android/telephony/ims/ImsMmTelManager.java +++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java @@ -59,6 +59,7 @@ import java.util.function.Consumer; * manager. */ public class ImsMmTelManager implements RegistrationManager { + private static final String TAG = "ImsMmTelManager"; /** * @hide @@ -809,7 +810,7 @@ public class ImsMmTelManager implements RegistrationManager { } try { - getITelephony().isMmTelCapabilitySupported(mSubId, new IIntegerConsumer.Stub() { + iTelephony.isMmTelCapabilitySupported(mSubId, new IIntegerConsumer.Stub() { @Override public void accept(int result) { executor.execute(() -> callback.accept(result == 1)); diff --git a/telephony/java/android/telephony/ims/ImsService.java b/telephony/java/android/telephony/ims/ImsService.java index da7311c08307..8a05bdfc8401 100644 --- a/telephony/java/android/telephony/ims/ImsService.java +++ b/telephony/java/android/telephony/ims/ImsService.java @@ -16,6 +16,7 @@ package android.telephony.ims; +import android.annotation.LongDef; import android.annotation.SystemApi; import android.annotation.TestApi; import android.app.Service; @@ -41,6 +42,11 @@ import android.util.SparseArray; import com.android.ims.internal.IImsFeatureStatusCallback; import com.android.internal.annotations.VisibleForTesting; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.HashMap; +import java.util.Map; + /** * Main ImsService implementation, which binds via the Telephony ImsResolver. Services that extend * ImsService must register the service in their AndroidManifest to be detected by the framework. @@ -98,6 +104,32 @@ public class ImsService extends Service { private static final String LOG_TAG = "ImsService"; /** + * This ImsService supports the capability to place emergency calls over MMTEL. + * @hide This is encoded into the {@link ImsFeature#FEATURE_EMERGENCY_MMTEL}, but we will be + * adding other capabilities in a central location, so track this capability here as well. + */ + public static final long CAPABILITY_EMERGENCY_OVER_MMTEL = 1 << 0; + + /** + * @hide + */ + @LongDef(flag = true, + prefix = "CAPABILITY_", + value = { + CAPABILITY_EMERGENCY_OVER_MMTEL + }) + @Retention(RetentionPolicy.SOURCE) + public @interface ImsServiceCapability {} + + /** + * Used for logging purposes, see {@link #getCapabilitiesString(long)} + * @hide + */ + private static final Map<Long, String> CAPABILITIES_LOG_MAP = new HashMap<Long, String>() {{ + put(CAPABILITY_EMERGENCY_OVER_MMTEL, "EMERGENCY_OVER_MMTEL"); + }}; + + /** * The intent that must be defined as an intent-filter in the AndroidManifest of the ImsService. * @hide */ @@ -409,4 +441,30 @@ public class ImsService extends Service { public ImsRegistrationImplBase getRegistration(int slotId) { return new ImsRegistrationImplBase(); } + + /** + * @return A string representation of the ImsService capabilties for logging. + * @hide + */ + public static String getCapabilitiesString(@ImsServiceCapability long caps) { + StringBuffer result = new StringBuffer(); + result.append("capabilities={ "); + // filter incrementally fills 0s from left to right. This is used to keep filtering out + // more bits in the long until the remaining leftmost bits are all zero. + long filter = 0xFFFFFFFFFFFFFFFFL; + // position of iterator to potentially print capability. + long i = 0; + while ((caps & filter) != 0 && i <= 63) { + long bitToCheck = (1L << i); + if ((caps & bitToCheck) != 0) { + result.append(CAPABILITIES_LOG_MAP.getOrDefault(bitToCheck, bitToCheck + "?")); + result.append(" "); + } + // shift left by one and fill in another 1 on the leftmost bit. + filter <<= 1; + i++; + } + result.append("}"); + return result.toString(); + } }
\ No newline at end of file diff --git a/telephony/java/android/telephony/ims/RcsContactPresenceTuple.aidl b/telephony/java/android/telephony/ims/RcsContactPresenceTuple.aidl new file mode 100644 index 000000000000..a70470294794 --- /dev/null +++ b/telephony/java/android/telephony/ims/RcsContactPresenceTuple.aidl @@ -0,0 +1,20 @@ +/* + * 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.telephony.ims; + +parcelable RcsContactPresenceTuple; diff --git a/telephony/java/android/telephony/ims/RcsContactPresenceTuple.java b/telephony/java/android/telephony/ims/RcsContactPresenceTuple.java new file mode 100644 index 000000000000..b0aaa92dd0ac --- /dev/null +++ b/telephony/java/android/telephony/ims/RcsContactPresenceTuple.java @@ -0,0 +1,360 @@ +/* + * 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.telephony.ims; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.StringDef; +import android.net.Uri; +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.Collections; +import java.util.List; + +/** + * Represents a PIDF tuple element that is part of the presence element returned from the carrier + * network during a SUBSCRIBE request. See RFC3863 for more information. + * @hide + */ +public class RcsContactPresenceTuple implements Parcelable { + + /** The service id of the MMTEL */ + public static final String SERVICE_ID_MMTEL = "org.3gpp.urn:urn-7:3gpp-service.ims.icsi.mmtel"; + + /** The service capabilities is available. */ + public static final String TUPLE_BASIC_STATUS_OPEN = "open"; + + /** The service capabilities is unavailable. */ + public static final String TUPLE_BASIC_STATUS_CLOSED = "closed"; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @StringDef(prefix = "TUPLE_BASIC_STATUS_", value = { + TUPLE_BASIC_STATUS_OPEN, + TUPLE_BASIC_STATUS_CLOSED + }) + public @interface BasicStatus {} + + /** + * An optional addition to the PIDF Presence Tuple containing service capabilities, which is + * defined in the servcaps element. See RFC5196, section 3.2.1. + */ + public static class ServiceCapabilities implements Parcelable { + + /** The service can simultaneously send and receive data. */ + public static final String DUPLEX_MODE_FULL = "full"; + + /** The service can alternate between sending and receiving data.*/ + public static final String DUPLEX_MODE_HALF = "half"; + + /** The service can only receive data. */ + public static final String DUPLEX_MODE_RECEIVE_ONLY = "receive-only"; + + /** The service can only send data. */ + public static final String DUPLEX_MODE_SEND_ONLY = "send-only"; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @StringDef(prefix = "DUPLEX_MODE_", value = { + DUPLEX_MODE_FULL, + DUPLEX_MODE_HALF, + DUPLEX_MODE_RECEIVE_ONLY, + DUPLEX_MODE_SEND_ONLY + }) + public @interface DuplexMode {} + + /** + * Builder to help construct {@link ServiceCapabilities} instances. + */ + public static class Builder { + + private ServiceCapabilities mCapabilities; + + /** + * Create the ServiceCapabilities builder, which can be used to set service capabilities + * as well as custom capability extensions. + * @param isAudioCapable Whether the audio is capable or not. + * @param isVideoCapable Whether the video is capable or not. + */ + public Builder(boolean isAudioCapable, boolean isVideoCapable) { + mCapabilities = new ServiceCapabilities(isAudioCapable, isVideoCapable); + } + + /** + * Add the supported duplex mode. + * @param mode The supported duplex mode + */ + public Builder addSupportedDuplexMode(@NonNull @DuplexMode String mode) { + mCapabilities.mSupportedDuplexModeList.add(mode); + return this; + } + + /** + * Add the unsupported duplex mode. + * @param mode The unsupported duplex mode + */ + public Builder addUnsupportedDuplexMode(@NonNull @DuplexMode String mode) { + mCapabilities.mUnsupportedDuplexModeList.add(mode); + return this; + } + + /** + * @return the ServiceCapabilities instance. + */ + public ServiceCapabilities build() { + return mCapabilities; + } + } + + private final boolean mIsAudioCapable; + private final boolean mIsVideoCapable; + private final @DuplexMode List<String> mSupportedDuplexModeList = new ArrayList<>(); + private final @DuplexMode List<String> mUnsupportedDuplexModeList = new ArrayList<>(); + + /** + * Use {@link Builder} to build an instance of this interface. + * @param isAudioCapable Whether the audio is capable. + * @param isVideoCapable Whether the video is capable. + */ + ServiceCapabilities(boolean isAudioCapable, boolean isVideoCapable) { + mIsAudioCapable = isAudioCapable; + mIsVideoCapable = isVideoCapable; + } + + private ServiceCapabilities(Parcel in) { + mIsAudioCapable = in.readBoolean(); + mIsVideoCapable = in.readBoolean(); + in.readStringList(mSupportedDuplexModeList); + in.readStringList(mUnsupportedDuplexModeList); + } + @Override + public void writeToParcel(@NonNull Parcel out, int flags) { + out.writeBoolean(mIsAudioCapable); + out.writeBoolean(mIsVideoCapable); + out.writeStringList(mSupportedDuplexModeList); + out.writeStringList(mUnsupportedDuplexModeList); + } + + @Override + public int describeContents() { + return 0; + } + + public static final @NonNull Creator<ServiceCapabilities> CREATOR = + new Creator<ServiceCapabilities>() { + @Override + public ServiceCapabilities createFromParcel(Parcel in) { + return new ServiceCapabilities(in); + } + + @Override + public ServiceCapabilities[] newArray(int size) { + return new ServiceCapabilities[size]; + } + }; + + /** + * Query the audio capable. + * @return true if the audio is capable, false otherwise. + */ + public boolean isAudioCapable() { + return mIsAudioCapable; + } + + /** + * Query the video capable. + * @return true if the video is capable, false otherwise. + */ + public boolean isVideoCapable() { + return mIsVideoCapable; + } + + /** + * Get the supported duplex mode list. + * @return The list of supported duplex mode + */ + public @NonNull @DuplexMode List<String> getSupportedDuplexModes() { + return Collections.unmodifiableList(mSupportedDuplexModeList); + } + + /** + * Get the unsupported duplex mode list. + * @return The list of unsupported duplex mode + */ + public @NonNull @DuplexMode List<String> getUnsupportedDuplexModes() { + return Collections.unmodifiableList(mUnsupportedDuplexModeList); + } + } + + /** + * Builder to help construct {@link RcsContactPresenceTuple} instances. + */ + public static class Builder { + + private RcsContactPresenceTuple mPresenceTuple; + + /** + * Builds a RcsContactPresenceTuple instance. + * @param serviceId The OMA Presence service-id associated with this capability. See the + * OMA Presence SIMPLE specification v1.1, section 10.5.1. + * @param serviceVersion The OMA Presence version associated with the service capability. + * See the OMA Presence SIMPLE specification v1.1, section 10.5.1. + */ + public Builder(@NonNull @BasicStatus String status, @NonNull String serviceId, + @NonNull String serviceVersion) { + mPresenceTuple = new RcsContactPresenceTuple(status, serviceId, serviceVersion); + } + + /** + * The optional SIP Contact URI associated with the PIDF tuple element. + */ + public Builder addContactUri(@NonNull Uri contactUri) { + mPresenceTuple.mContactUri = contactUri; + return this; + } + + /** + * The optional timestamp indicating the data and time of the status change of this tuple. + * See RFC3863, section 4.1.7 for more information on the expected format. + */ + public Builder addTimeStamp(@NonNull String timestamp) { + mPresenceTuple.mTimestamp = timestamp; + return this; + } + + /** + * An optional parameter containing the description element of the service-description. See + * OMA Presence SIMPLE specification v1.1 + */ + public Builder addDescription(@NonNull String description) { + mPresenceTuple.mServiceDescription = description; + return this; + } + + /** + * An optional parameter containing the service capabilities of the presence tuple if they + * are present in the servcaps element. + */ + public Builder addServiceCapabilities(@NonNull ServiceCapabilities caps) { + mPresenceTuple.mServiceCapabilities = caps; + return this; + } + + /** + * @return the constructed instance. + */ + public RcsContactPresenceTuple build() { + return mPresenceTuple; + } + } + + private Uri mContactUri; + private String mTimestamp; + private @BasicStatus String mStatus; + + // The service information in the service-description element. + private String mServiceId; + private String mServiceVersion; + private String mServiceDescription; + + private ServiceCapabilities mServiceCapabilities; + + private RcsContactPresenceTuple(@NonNull @BasicStatus String status, @NonNull String serviceId, + @NonNull String serviceVersion) { + mStatus = status; + mServiceId = serviceId; + mServiceVersion = serviceVersion; + } + + private RcsContactPresenceTuple(Parcel in) { + mContactUri = in.readParcelable(Uri.class.getClassLoader()); + mTimestamp = in.readString(); + mStatus = in.readString(); + mServiceId = in.readString(); + mServiceVersion = in.readString(); + mServiceDescription = in.readString(); + mServiceCapabilities = in.readParcelable(ServiceCapabilities.class.getClassLoader()); + } + + @Override + public void writeToParcel(@NonNull Parcel out, int flags) { + out.writeParcelable(mContactUri, flags); + out.writeString(mTimestamp); + out.writeString(mStatus); + out.writeString(mServiceId); + out.writeString(mServiceVersion); + out.writeString(mServiceDescription); + out.writeParcelable(mServiceCapabilities, flags); + } + + @Override + public int describeContents() { + return 0; + } + + public static final @NonNull Creator<RcsContactPresenceTuple> CREATOR = + new Creator<RcsContactPresenceTuple>() { + @Override + public RcsContactPresenceTuple createFromParcel(Parcel in) { + return new RcsContactPresenceTuple(in); + } + + @Override + public RcsContactPresenceTuple[] newArray(int size) { + return new RcsContactPresenceTuple[size]; + } + }; + + /** @return the status of the tuple element. */ + public @NonNull @BasicStatus String getStatus() { + return mStatus; + } + + /** @return the service-id element of the service-description */ + public @NonNull String getServiceId() { + return mServiceId; + } + + /** @return the version element of the service-description */ + public @NonNull String getServiceVersion() { + return mServiceVersion; + } + + /** @return the SIP URI contained in the contact element of the tuple if it exists. */ + public @Nullable Uri getContactUri() { + return mContactUri; + } + + /** @return the timestamp element contained in the tuple if it exists */ + public @Nullable String getTimestamp() { + return mTimestamp; + } + + /** @return the description element contained in the service-description if it exists */ + public @Nullable String getServiceDescription() { + return mServiceDescription; + } + + /** @return the {@link ServiceCapabilities} of the tuple if it exists. */ + public @Nullable ServiceCapabilities getServiceCapabilities() { + return mServiceCapabilities; + } +} diff --git a/telephony/java/android/telephony/ims/RcsContactUceCapability.java b/telephony/java/android/telephony/ims/RcsContactUceCapability.java index dc36edf5aad9..d12a6aef5186 100644 --- a/telephony/java/android/telephony/ims/RcsContactUceCapability.java +++ b/telephony/java/android/telephony/ims/RcsContactUceCapability.java @@ -16,7 +16,7 @@ package android.telephony.ims; -import android.annotation.LongDef; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.net.Uri; @@ -27,9 +27,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; import java.util.List; -import java.util.Map; /** * Contains the User Capability Exchange capabilities corresponding to a contact's URI. @@ -37,114 +35,80 @@ import java.util.Map; */ public final class RcsContactUceCapability implements Parcelable { - /** Supports 1-to-1 chat */ - public static final int CAPABILITY_CHAT_STANDALONE = (1 << 0); - /** Supports group chat */ - public static final int CAPABILITY_CHAT_SESSION = (1 << 1); - /** Supports full store and forward group chat information. */ - public static final int CAPABILITY_CHAT_SESSION_STORE_FORWARD = (1 << 2); + /** Contains presence information associated with the contact */ + public static final int CAPABILITY_MECHANISM_PRESENCE = 1; + + /** Contains OPTIONS information associated with the contact */ + public static final int CAPABILITY_MECHANISM_OPTIONS = 2; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = "CAPABILITY_MECHANISM_", value = { + CAPABILITY_MECHANISM_PRESENCE, + CAPABILITY_MECHANISM_OPTIONS + }) + public @interface CapabilityMechanism {} + /** - * Supports file transfer via Message Session Relay Protocol (MSRP) without Store and Forward. + * The capabilities of this contact were requested recently enough to still be considered in + * the availability window. */ - public static final int CAPABILITY_FILE_TRANSFER = (1 << 3); - /** Supports File Transfer Thumbnail */ - public static final int CAPABILITY_FILE_TRANSFER_THUMBNAIL = (1 << 4); - /** Supports File Transfer with Store and Forward */ - public static final int CAPABILITY_FILE_TRANSFER_STORE_FORWARD = (1 << 5); - /** Supports File Transfer via HTTP */ - public static final int CAPABILITY_FILE_TRANSFER_HTTP = (1 << 6); - /** Supports file transfer via SMS */ - public static final int CAPABILITY_FILE_TRANSFER_SMS = (1 << 7); - /** Supports image sharing */ - public static final int CAPABILITY_IMAGE_SHARE = (1 << 8); - /** Supports video sharing during a circuit-switch call (IR.74)*/ - public static final int CAPABILITY_VIDEO_SHARE_DURING_CS_CALL = (1 << 9); - /** Supports video share outside of voice call (IR.84) */ - public static final int CAPABILITY_VIDEO_SHARE = (1 << 10); - /** Supports social presence information */ - public static final int CAPABILITY_SOCIAL_PRESENCE = (1 << 11); - /** Supports capability discovery via presence */ - public static final int CAPABILITY_DISCOVERY_VIA_PRESENCE = (1 << 12); - /** Supports IP Voice calling over LTE or IWLAN (IR.92/IR.51) */ - public static final int CAPABILITY_IP_VOICE_CALL = (1 << 13); - /** Supports IP video calling (IR.94) */ - public static final int CAPABILITY_IP_VIDEO_CALL = (1 << 14); - /** Supports Geolocation PUSH during 1-to-1 or multiparty chat */ - public static final int CAPABILITY_GEOLOCATION_PUSH = (1 << 15); - /** Supports Geolocation PUSH via SMS for fallback. */ - public static final int CAPABILITY_GEOLOCATION_PUSH_SMS = (1 << 16); - /** Supports Geolocation pull. */ - public static final int CAPABILITY_GEOLOCATION_PULL = (1 << 17); - /** Supports Geolocation pull using file transfer support. */ - public static final int CAPABILITY_GEOLOCATION_PULL_FILE_TRANSFER = (1 << 18); - /** Supports RCS voice calling */ - public static final int CAPABILITY_RCS_VOICE_CALL = (1 << 19); - /** Supports RCS video calling */ - public static final int CAPABILITY_RCS_VIDEO_CALL = (1 << 20); - /** Supports RCS video calling, where video media can not be dropped. */ - public static final int CAPABILITY_RCS_VIDEO_ONLY_CALL = (1 << 21); - /** Supports call composer, where outgoing calls can be enriched with pre-call content.*/ - public static final int CAPABILITY_CALL_COMPOSER = (1 << 22); - /** Supports post call information that is included in the call if the call is missed.*/ - public static final int CAPABILITY_POST_CALL = (1 << 23); - /** Supports sharing a map where the user can draw, share markers, and share their position. */ - public static final int CAPABILITY_SHARED_MAP = (1 << 24); - /** Supports sharing a canvas, where users can draw, add images, and change background colors.*/ - public static final int CAPABILITY_SHARED_SKETCH = (1 << 25); - /** Supports communication with Chatbots. */ - public static final int CAPABILITY_CHAT_BOT = (1 << 26); - /** Supports Chatbot roles. */ - public static final int CAPABILITY_CHAT_BOT_ROLE = (1 << 27); - /** Supports the unidirectional plug-ins framework. */ - public static final int CAPABILITY_PLUG_IN = (1 << 28); - /** Supports standalone Chatbot communication. */ - public static final int CAPABILITY_STANDALONE_CHAT_BOT = (1 << 29); - /** Supports MMTEL based call composer. */ - public static final int CAPABILITY_MMTEL_CALL_COMPOSER = (1 << 30); - - - - /** @hide*/ + public static final int SOURCE_TYPE_NETWORK = 0; + + /** + * The capabilities of this contact were retrieved from the cached information in the Enhanced + * Address Book. + */ + public static final int SOURCE_TYPE_CACHED = 1; + + /** @hide */ @Retention(RetentionPolicy.SOURCE) - @LongDef(prefix = "CAPABILITY_", flag = true, value = { - CAPABILITY_CHAT_STANDALONE, - CAPABILITY_CHAT_SESSION, - CAPABILITY_CHAT_SESSION_STORE_FORWARD, - CAPABILITY_FILE_TRANSFER, - CAPABILITY_FILE_TRANSFER_THUMBNAIL, - CAPABILITY_FILE_TRANSFER_STORE_FORWARD, - CAPABILITY_FILE_TRANSFER_HTTP, - CAPABILITY_FILE_TRANSFER_SMS, - CAPABILITY_IMAGE_SHARE, - CAPABILITY_VIDEO_SHARE_DURING_CS_CALL, - CAPABILITY_VIDEO_SHARE, - CAPABILITY_SOCIAL_PRESENCE, - CAPABILITY_DISCOVERY_VIA_PRESENCE, - CAPABILITY_IP_VOICE_CALL, - CAPABILITY_IP_VIDEO_CALL, - CAPABILITY_GEOLOCATION_PUSH, - CAPABILITY_GEOLOCATION_PUSH_SMS, - CAPABILITY_GEOLOCATION_PULL, - CAPABILITY_GEOLOCATION_PULL_FILE_TRANSFER, - CAPABILITY_RCS_VOICE_CALL, - CAPABILITY_RCS_VIDEO_CALL, - CAPABILITY_RCS_VIDEO_ONLY_CALL, - CAPABILITY_CALL_COMPOSER, - CAPABILITY_POST_CALL, - CAPABILITY_SHARED_MAP, - CAPABILITY_SHARED_SKETCH, - CAPABILITY_CHAT_BOT, - CAPABILITY_CHAT_BOT_ROLE, - CAPABILITY_PLUG_IN, - CAPABILITY_STANDALONE_CHAT_BOT, - CAPABILITY_MMTEL_CALL_COMPOSER + @IntDef(prefix = "SOURCE_TYPE_", value = { + SOURCE_TYPE_NETWORK, + SOURCE_TYPE_CACHED }) - public @interface CapabilityFlag {} + public @interface SourceType {} + + /** + * The requested contact was found to be offline when queried. This is only applicable to + * contact capabilities that were queried via OPTIONS requests and the network returned a + * 408/480 response. + */ + public static final int REQUEST_RESULT_NOT_ONLINE = 0; + + /** + * Capability information for the requested contact was not found. The contact should not be + * considered an RCS user. + */ + public static final int REQUEST_RESULT_NOT_FOUND = 1; /** - * Builder to help construct {@link RcsContactUceCapability} instances. + * Capability information for the requested contact was found successfully. */ - public static class Builder { + public static final int REQUEST_RESULT_FOUND = 2; + + /** + * Capability information for the requested contact has expired and can not be refreshed due to + * a temporary network error. This is a temporary error and the capabilities of the contact + * should be queried again at a later time. + */ + public static final int REQUEST_RESULT_UNKNOWN = 3; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = "REQUEST_RESULT_", value = { + REQUEST_RESULT_NOT_ONLINE, + REQUEST_RESULT_NOT_FOUND, + REQUEST_RESULT_FOUND, + REQUEST_RESULT_UNKNOWN + }) + public @interface RequestResult {} + + /** + * Builder to help construct {@link RcsContactUceCapability} instances when capabilities were + * queried through SIP OPTIONS. + */ + public static class OptionsBuilder { private final RcsContactUceCapability mCapabilities; @@ -153,51 +117,38 @@ public final class RcsContactUceCapability implements Parcelable { * capability extensions. * @param contact The contact URI that the capabilities are attached to. */ - public Builder(@NonNull Uri contact) { - mCapabilities = new RcsContactUceCapability(contact); + public OptionsBuilder(@NonNull Uri contact) { + mCapabilities = new RcsContactUceCapability(contact, CAPABILITY_MECHANISM_OPTIONS, + SOURCE_TYPE_NETWORK); } /** - * Add a UCE capability bit-field as well as the associated URI that the framework should - * use for those services. This is mainly used for capabilities that may use a URI separate - * from the contact's URI, for example the URI to use for VT calls. - * @param type The capability to map to a service URI that is different from the contact's - * URI. + * Set the result of the capabilities request. + * @param requestResult the request result + * @return this OptionBuilder */ - public @NonNull Builder add(@CapabilityFlag long type, @NonNull Uri serviceUri) { - mCapabilities.mCapabilities |= type; - // Put each of these capabilities into the map separately. - for (long shift = 0; shift < Integer.SIZE; shift++) { - long cap = type & (1 << shift); - if (cap != 0) { - mCapabilities.mServiceMap.put(cap, serviceUri); - // remove that capability from the field. - type &= ~cap; - } - if (type == 0) { - // no need to keep going, end early. - break; - } - } + public @NonNull OptionsBuilder setRequestResult(@RequestResult int requestResult) { + mCapabilities.mRequestResult = requestResult; return this; } /** - * Add a UCE capability flag that this contact supports. - * @param type the capability that the contact supports. + * Add the feature tag into the capabilities instance. + * @param tag the supported feature tag + * @return this OptionBuilder */ - public @NonNull Builder add(@CapabilityFlag long type) { - mCapabilities.mCapabilities |= type; + public @NonNull OptionsBuilder addFeatureTag(String tag) { + mCapabilities.mFeatureTags.add(tag); return this; } /** - * Add a carrier specific service tag. - * @param extension A string containing a carrier specific service tag that is an extension - * of the {@link CapabilityFlag}s that are defined here. + * Add the list of feature tag into the capabilities instance. + * @param tags the list of the supported feature tags + * @return this OptionBuilder */ - public @NonNull Builder add(@NonNull String extension) { - mCapabilities.mExtensionTags.add(extension); + public @NonNull OptionsBuilder addFeatureTags(List<String> tags) { + mCapabilities.mFeatureTags.addAll(tags); return this; } @@ -209,56 +160,88 @@ public final class RcsContactUceCapability implements Parcelable { } } - private final Uri mContactUri; - private long mCapabilities; - private List<String> mExtensionTags = new ArrayList<>(); - private Map<Long, Uri> mServiceMap = new HashMap<>(); - /** - * Use {@link Builder} to build an instance of this interface. - * @param contact The URI associated with this capability information. - * @hide + * Builder to help construct {@link RcsContactUceCapability} instances when capabilities were + * queried through a presence server. */ - RcsContactUceCapability(@NonNull Uri contact) { - mContactUri = contact; - } + public static class PresenceBuilder { - private RcsContactUceCapability(Parcel in) { - mContactUri = in.readParcelable(Uri.class.getClassLoader()); - mCapabilities = in.readLong(); - in.readStringList(mExtensionTags); - // read mServiceMap as key,value pair - int mapSize = in.readInt(); - for (int i = 0; i < mapSize; i++) { - mServiceMap.put(in.readLong(), in.readParcelable(Uri.class.getClassLoader())); + private final RcsContactUceCapability mCapabilities; + + /** + * Create the builder, which can be used to set UCE capabilities as well as custom + * capability extensions. + * @param contact The contact URI that the capabilities are attached to. + * @param sourceType The type where the capabilities of this contact were retrieved from. + * @param requestResult the request result + */ + public PresenceBuilder(@NonNull Uri contact, @SourceType int sourceType, + @RequestResult int requestResult) { + mCapabilities = new RcsContactUceCapability(contact, CAPABILITY_MECHANISM_PRESENCE, + sourceType); + mCapabilities.mRequestResult = requestResult; } - } - public static final @NonNull Creator<RcsContactUceCapability> CREATOR = - new Creator<RcsContactUceCapability>() { - @Override - public RcsContactUceCapability createFromParcel(Parcel in) { - return new RcsContactUceCapability(in); + /** + * Add the {@link RcsContactPresenceTuple} into the capabilities instance. + * @param tuple The {@link RcsContactPresenceTuple} to be added into. + * @return this PresenceBuilder + */ + public @NonNull PresenceBuilder addCapabilityTuple(RcsContactPresenceTuple tuple) { + mCapabilities.mPresenceTuples.add(tuple); + return this; } - @Override - public RcsContactUceCapability[] newArray(int size) { - return new RcsContactUceCapability[size]; + /** + * Add the list of {@link RcsContactPresenceTuple} into the capabilities instance. + * @param tuples The list of the {@link RcsContactPresenceTuple} to be added into. + * @return this PresenceBuilder + */ + public @NonNull PresenceBuilder addCapabilityTuples(List<RcsContactPresenceTuple> tuples) { + mCapabilities.mPresenceTuples.addAll(tuples); + return this; } - }; + + /** + * @return the RcsContactUceCapability instance. + */ + public @NonNull RcsContactUceCapability build() { + return mCapabilities; + } + } + + private final Uri mContactUri; + private @SourceType int mSourceType; + private @CapabilityMechanism int mCapabilityMechanism; + private @RequestResult int mRequestResult; + + private final List<String> mFeatureTags = new ArrayList<>(); + private final List<RcsContactPresenceTuple> mPresenceTuples = new ArrayList<>(); + + private RcsContactUceCapability(@NonNull Uri contactUri, @CapabilityMechanism int mechanism, + @SourceType int sourceType) { + mContactUri = contactUri; + mCapabilityMechanism = mechanism; + mSourceType = sourceType; + } + + private RcsContactUceCapability(Parcel in) { + mContactUri = in.readParcelable(Uri.class.getClassLoader()); + mCapabilityMechanism = in.readInt(); + mSourceType = in.readInt(); + mRequestResult = in.readInt(); + in.readStringList(mFeatureTags); + in.readParcelableList(mPresenceTuples, RcsContactPresenceTuple.class.getClassLoader()); + } @Override public void writeToParcel(@NonNull Parcel out, int flags) { - out.writeParcelable(mContactUri, 0); - out.writeLong(mCapabilities); - out.writeStringList(mExtensionTags); - // write mServiceMap as key,value pairs - int mapSize = mServiceMap.keySet().size(); - out.writeInt(mapSize); - for (long key : mServiceMap.keySet()) { - out.writeLong(key); - out.writeParcelable(mServiceMap.get(key), 0); - } + out.writeParcelable(mContactUri, flags); + out.writeInt(mCapabilityMechanism); + out.writeInt(mSourceType); + out.writeInt(mRequestResult); + out.writeStringList(mFeatureTags); + out.writeParcelableList(mPresenceTuples, flags); } @Override @@ -266,49 +249,87 @@ public final class RcsContactUceCapability implements Parcelable { return 0; } + public static final @NonNull Creator<RcsContactUceCapability> CREATOR = + new Creator<RcsContactUceCapability>() { + @Override + public RcsContactUceCapability createFromParcel(Parcel in) { + return new RcsContactUceCapability(in); + } + + @Override + public RcsContactUceCapability[] newArray(int size) { + return new RcsContactUceCapability[size]; + } + }; + /** - * Query for a capability - * @param type The capability flag to query. - * @return true if the capability flag specified is set, false otherwise. + * @return The mechanism used to get the capabilities. */ - public boolean isCapable(@CapabilityFlag long type) { - return (mCapabilities & type) > 0; + public @CapabilityMechanism int getCapabilityMechanism() { + return mCapabilityMechanism; } /** - * @return true if the extension service tag is set, false otherwise. + * @return The feature tags present in the OPTIONS response from the network. + * <p> + * Note: this is only populated if {@link #getCapabilityMechanism} is + * {@link CAPABILITY_MECHANISM_OPTIONS} */ - public boolean isCapable(@NonNull String extensionTag) { - return mExtensionTags.contains(extensionTag); + public @NonNull List<String> getOptionsFeatureTags() { + if (mCapabilityMechanism != CAPABILITY_MECHANISM_OPTIONS) { + return Collections.emptyList(); + } + return Collections.unmodifiableList(mFeatureTags); } /** - * @return An immutable list containing all of the extension tags that have been set as capable. - * @throws UnsupportedOperationException if this list is modified. + * @return The tuple elements associated with the presence element portion of the PIDF document + * contained in the NOTIFY response from the network. + * <p> + * Note: this is only populated if {@link #getCapabilityMechanism} is + * {@link CAPABILITY_MECHANISM_PRESENCE} */ - public @NonNull List<String> getCapableExtensionTags() { - return Collections.unmodifiableList(mExtensionTags); + public @NonNull List<RcsContactPresenceTuple> getPresenceTuples() { + if (mCapabilityMechanism != CAPABILITY_MECHANISM_PRESENCE) { + return Collections.emptyList(); + } + return Collections.unmodifiableList(mPresenceTuples); } /** - * Retrieves the {@link Uri} associated with the capability being queried. - * <p> - * This will typically be the contact {@link Uri} available via {@link #getContactUri()} unless - * a different service {@link Uri} was associated with this capability using - * {@link Builder#add(long, Uri)}. + * Get the RcsContactPresenceTuple associated with the given service id. + * @param serviceId The service id to get the presence tuple. + * @return The RcsContactPresenceTuple which has the given service id. * - * @return a String containing the {@link Uri} associated with the service tag or - * {@code null} if this capability is not set as capable. - * @see #isCapable(long) + * <p> + * Note: this is only populated if {@link #getCapabilityMechanism} is + * {@link CAPABILITY_MECHANISM_PRESENCE} */ - public @Nullable Uri getServiceUri(@CapabilityFlag long type) { - Uri result = mServiceMap.getOrDefault(type, null); - // If the capability is capable, but does not have a service URI associated, use the default - // contact URI. - if (result == null) { - return isCapable(type) ? getContactUri() : null; + public @Nullable RcsContactPresenceTuple getPresenceTuple(String serviceId) { + if (mCapabilityMechanism != CAPABILITY_MECHANISM_PRESENCE) { + return null; } - return result; + for (RcsContactPresenceTuple tuple : mPresenceTuples) { + if (tuple.getServiceId().equals(serviceId)) { + return tuple; + } + } + return null; + } + + /** + * @return the source of the data that was used to populate the capabilities of the requested + * contact. + */ + public @SourceType int getSourceType() { + return mSourceType; + } + + /** + * @return the result of querying the capabilities of the requested contact. + */ + public @RequestResult int getRequestResult() { + return mRequestResult; } /** diff --git a/telephony/java/android/telephony/ims/aidl/IImsMmTelListener.aidl b/telephony/java/android/telephony/ims/aidl/IImsMmTelListener.aidl index 7bbe30a444b9..52464703c608 100644 --- a/telephony/java/android/telephony/ims/aidl/IImsMmTelListener.aidl +++ b/telephony/java/android/telephony/ims/aidl/IImsMmTelListener.aidl @@ -27,8 +27,11 @@ import com.android.ims.internal.IImsCallSession; * See MmTelFeature#Listener for more information. * {@hide} */ -oneway interface IImsMmTelListener { + // This interface is not considered oneway because we need to ensure that these operations are + // processed by telephony before the control flow returns to the ImsService to perform + // operations on the IImsCallSession. +interface IImsMmTelListener { void onIncomingCall(IImsCallSession c, in Bundle extras); void onRejectedCall(in ImsCallProfile callProfile, in ImsReasonInfo reason); - void onVoiceMessageCountUpdate(int count); + oneway void onVoiceMessageCountUpdate(int count); } diff --git a/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl b/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl index 9e461420e126..e01ea9179452 100644 --- a/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl +++ b/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl @@ -22,6 +22,8 @@ import android.telephony.ims.aidl.IRcsUceControllerCallback; import android.telephony.ims.aidl.IRcsUcePublishStateCallback; import android.telephony.ims.aidl.IImsRegistrationCallback; +import com.android.ims.ImsFeatureContainer; +import com.android.ims.internal.IImsServiceFeatureCallback; import com.android.internal.telephony.IIntegerConsumer; /** @@ -50,4 +52,8 @@ interface IImsRcsController { void setUceSettingEnabled(int subId, boolean isEnabled); void registerUcePublishStateCallback(int subId, IRcsUcePublishStateCallback c); void unregisterUcePublishStateCallback(int subId, IRcsUcePublishStateCallback c); + + // Internal commands that should not be made public + void registerRcsFeatureCallback(int slotId, in IImsServiceFeatureCallback callback); + void unregisterImsFeatureCallback(in IImsServiceFeatureCallback callback); } diff --git a/telephony/java/android/telephony/ims/feature/MmTelFeature.java b/telephony/java/android/telephony/ims/feature/MmTelFeature.java index 01d468cb53f6..de0fb86029dd 100644 --- a/telephony/java/android/telephony/ims/feature/MmTelFeature.java +++ b/telephony/java/android/telephony/ims/feature/MmTelFeature.java @@ -285,8 +285,8 @@ public class MmTelFeature extends ImsFeature { public static final int CAPABILITY_TYPE_SMS = 1 << 3; /** - * @hide - */ + * @hide + */ @Override @SystemApi @TestApi public final void addCapabilities(@MmTelCapability int capabilities) { @@ -294,8 +294,8 @@ public class MmTelFeature extends ImsFeature { } /** - * @hide - */ + * @hide + */ @Override @SystemApi @TestApi public final void removeCapabilities(@MmTelCapability int capability) { @@ -303,17 +303,18 @@ public class MmTelFeature extends ImsFeature { } /** - * @hide - */ + * @param capabilities a bitmask of one or more {@link MmTelCapability}. + * + * @return true if all queried capabilities are true, otherwise false. + */ @Override - @SystemApi @TestApi public final boolean isCapable(@MmTelCapability int capabilities) { return super.isCapable(capabilities); } /** - * @hide - */ + * @hide + */ @NonNull @Override public String toString() { diff --git a/telephony/java/com/android/ims/ImsFeatureContainer.aidl b/telephony/java/com/android/ims/ImsFeatureContainer.aidl new file mode 100644 index 000000000000..9706f20c59ca --- /dev/null +++ b/telephony/java/com/android/ims/ImsFeatureContainer.aidl @@ -0,0 +1,19 @@ +/* + * 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 com.android.ims; + +parcelable ImsFeatureContainer;
\ No newline at end of file diff --git a/telephony/java/com/android/ims/ImsFeatureContainer.java b/telephony/java/com/android/ims/ImsFeatureContainer.java new file mode 100644 index 000000000000..b259679ea1bf --- /dev/null +++ b/telephony/java/com/android/ims/ImsFeatureContainer.java @@ -0,0 +1,172 @@ +/* + * 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 com.android.ims; + +import android.annotation.NonNull; +import android.os.IBinder; +import android.os.Parcel; +import android.os.Parcelable; +import android.telephony.ims.ImsService; +import android.telephony.ims.aidl.IImsConfig; +import android.telephony.ims.aidl.IImsRegistration; +import android.telephony.ims.feature.ImsFeature; + +import java.util.Objects; + +/** + * Contains an IBinder linking to the appropriate ImsFeature as well as the associated + * interfaces. + * @hide + */ +public final class ImsFeatureContainer implements Parcelable { + /** + * ImsFeature that is being tracked. + */ + public final IBinder imsFeature; + + /** + * IImsConfig interface that should be associated with the ImsFeature. + */ + public final android.telephony.ims.aidl.IImsConfig imsConfig; + + /** + * IImsRegistration interface that should be associated with this ImsFeature. + */ + public final IImsRegistration imsRegistration; + + /** + * State of the feature that is being tracked. + */ + private @ImsFeature.ImsState int mState = ImsFeature.STATE_UNAVAILABLE; + + /** + * Capabilities of this ImsService. + */ + private @ImsService.ImsServiceCapability long mCapabilities; + /** + * Contains the ImsFeature IBinder as well as the ImsService interfaces associated with + * that feature. + * @param iFace IBinder connection to the ImsFeature. + * @param iConfig IImsConfig interface associated with the ImsFeature. + * @param iReg IImsRegistration interface associated with the ImsFeature + * @param initialCaps The initial capabilities that the ImsService supports. + */ + public ImsFeatureContainer(@NonNull IBinder iFace, @NonNull IImsConfig iConfig, + @NonNull IImsRegistration iReg, long initialCaps) { + imsFeature = iFace; + imsConfig = iConfig; + imsRegistration = iReg; + mCapabilities = initialCaps; + } + + /** + * Create an ImsFeatureContainer from a Parcel. + */ + private ImsFeatureContainer(Parcel in) { + imsFeature = in.readStrongBinder(); + imsConfig = IImsConfig.Stub.asInterface(in.readStrongBinder()); + imsRegistration = IImsRegistration.Stub.asInterface(in.readStrongBinder()); + mState = in.readInt(); + mCapabilities = in.readLong(); + } + + /** + * @return the capabilties that are associated with the ImsService that this ImsFeature + * belongs to. + */ + public @ImsService.ImsServiceCapability long getCapabilities() { + return mCapabilities; + } + + /** + * Update the capabilities that are associated with the ImsService that this ImsFeature + * belongs to. + */ + public void setCapabilities(@ImsService.ImsServiceCapability long caps) { + mCapabilities = caps; + } + + /** + * @return The state of the ImsFeature. + */ + public @ImsFeature.ImsState int getState() { + return mState; + } + + /** + * Set the state that is associated with the ImsService that this ImsFeature + * belongs to. + */ + public void setState(@ImsFeature.ImsState int state) { + mState = state; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ImsFeatureContainer that = (ImsFeatureContainer) o; + return imsFeature.equals(that.imsFeature) && + imsConfig.equals(that.imsConfig) && + imsRegistration.equals(that.imsRegistration) && + mState == that.getState() && + mCapabilities == that.getCapabilities(); + } + + @Override + public int hashCode() { + return Objects.hash(imsFeature, imsConfig, imsRegistration, mState, mCapabilities); + } + + @Override + public String toString() { + return "FeatureContainer{" + + "imsFeature=" + imsFeature + + ", imsConfig=" + imsConfig + + ", imsRegistration=" + imsRegistration + + ", state=" + ImsFeature.STATE_LOG_MAP.get(mState) + + ", capabilities = " + ImsService.getCapabilitiesString(mCapabilities) + + '}'; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeStrongBinder(imsFeature); + dest.writeStrongInterface(imsConfig); + dest.writeStrongInterface(imsRegistration); + dest.writeInt(mState); + dest.writeLong(mCapabilities); + } + + + public static final Creator<ImsFeatureContainer> CREATOR = new Creator<ImsFeatureContainer>() { + @Override + public ImsFeatureContainer createFromParcel(Parcel source) { + return new ImsFeatureContainer(source); + } + + @Override + public ImsFeatureContainer[] newArray(int size) { + return new ImsFeatureContainer[size]; + } + }; +} diff --git a/telephony/java/com/android/ims/internal/IImsServiceFeatureCallback.aidl b/telephony/java/com/android/ims/internal/IImsServiceFeatureCallback.aidl index 9a9cf5325310..f5f67bd36ec3 100644 --- a/telephony/java/com/android/ims/internal/IImsServiceFeatureCallback.aidl +++ b/telephony/java/com/android/ims/internal/IImsServiceFeatureCallback.aidl @@ -16,13 +16,18 @@ package com.android.ims.internal; +import com.android.ims.ImsFeatureContainer; /** - * Interface from ImsResolver to ImsServiceProxy in ImsManager. - * Callback to ImsManager when a feature changes in the ImsServiceController. + * Interface from ImsResolver to FeatureConnections. + * Callback to FeatureConnections when a feature's status changes. * {@hide} */ oneway interface IImsServiceFeatureCallback { - void imsFeatureCreated(int slotId, int feature); - void imsFeatureRemoved(int slotId, int feature); - void imsStatusChanged(int slotId, int feature, int status); + void imsFeatureCreated(in ImsFeatureContainer feature); + // Reason defined in FeatureConnector.UnavailableReason + void imsFeatureRemoved(int reason); + // Status defined in ImsFeature.ImsState. + void imsStatusChanged(int status); + //Capabilities defined in ImsService.ImsServiceCapability + void updateCapabilities(long capabilities); }
\ No newline at end of file diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index ae1b5c1b50bd..934103ebe2b6 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -828,22 +828,14 @@ interface ITelephony { * as well as registering the MmTelFeature for callbacks using the IImsServiceFeatureCallback * interface. */ - IImsMmTelFeature getMmTelFeatureAndListen(int slotId, in IImsServiceFeatureCallback callback); - - /** - * Get IImsRcsFeature binder from ImsResolver that corresponds to the subId and RCS feature - * as well as registering the RcsFeature for callbacks using the IImsServiceFeatureCallback - * interface. - */ - IImsRcsFeature getRcsFeatureAndListen(int slotId, in IImsServiceFeatureCallback callback); + void registerMmTelFeatureCallback(int slotId, in IImsServiceFeatureCallback callback); /** * Unregister a callback that was previously registered through - * {@link #getMmTelFeatureAndListen} or {@link #getRcsFeatureAndListen}. This should always be - * called when the callback is no longer being used. + * {@link #registerMmTelFeatureCallback}. This should always be called when the callback is no + * longer being used. */ - void unregisterImsFeatureCallback(int slotId, int featureType, - in IImsServiceFeatureCallback callback); + void unregisterImsFeatureCallback(in IImsServiceFeatureCallback callback); /** * Returns the IImsRegistration associated with the slot and feature specified. @@ -2297,4 +2289,12 @@ interface ITelephony { * Whether device can connect to 5G network when two SIMs are active. */ boolean canConnectTo5GInDsdsMode(); + + /** + * Returns a list of the equivalent home PLMNs (EF_EHPLMN) from the USIM app. + * + * @return A list of equivalent home PLMNs. Returns an empty list if EF_EHPLMN is empty or + * does not exist on the SIM card. + */ + List<String> getEquivalentHomePlmns(int subId, String callingPackage, String callingFeatureId); } diff --git a/tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatCommandNotInstalledTest.kt b/tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatCommandNotInstalledTest.kt index 0f62c4fa66a3..e9227e94da98 100644 --- a/tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatCommandNotInstalledTest.kt +++ b/tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatCommandNotInstalledTest.kt @@ -107,7 +107,10 @@ class PlatformCompatCommandNotInstalledTest { fun ParcelFileDescriptor.text() = FileReader(fileDescriptor).readText() @After - fun resetIdentity() = uiAutomation.dropShellPermissionIdentity() + fun resetChangeIdAndIdentity() { + command("am compat reset $TEST_CHANGE_ID $TEST_PKG") + uiAutomation.dropShellPermissionIdentity() + } @Test fun execute() { diff --git a/tests/RollbackTest/Android.bp b/tests/RollbackTest/Android.bp index 2be4ae6bb214..a23df920b396 100644 --- a/tests/RollbackTest/Android.bp +++ b/tests/RollbackTest/Android.bp @@ -29,7 +29,12 @@ java_test_host { name: "StagedRollbackTest", srcs: ["StagedRollbackTest/src/**/*.java"], libs: ["tradefed"], - static_libs: ["testng", "compatibility-tradefed", "RollbackTestLib"], + static_libs: [ + "compatibility-tradefed", + "frameworks-base-hostutils", + "RollbackTestLib", + "testng", + ], test_suites: ["general-tests"], test_config: "StagedRollbackTest.xml", data: [":com.android.apex.apkrollback.test_v1"], @@ -39,7 +44,7 @@ java_test_host { name: "NetworkStagedRollbackTest", srcs: ["NetworkStagedRollbackTest/src/**/*.java"], libs: ["tradefed"], - static_libs: ["RollbackTestLib"], + static_libs: ["RollbackTestLib", "frameworks-base-hostutils"], test_suites: ["general-tests"], test_config: "NetworkStagedRollbackTest.xml", } diff --git a/tests/StagedInstallTest/Android.bp b/tests/StagedInstallTest/Android.bp index 1e286bb15c49..0e7a049f5faa 100644 --- a/tests/StagedInstallTest/Android.bp +++ b/tests/StagedInstallTest/Android.bp @@ -28,6 +28,8 @@ java_test_host { "testng", "compatibility-tradefed", "module_test_util", + "frameworks-base-hostutils", + "cts-install-lib-host", ], data: [ ":com.android.apex.cts.shim.v2_prebuilt", diff --git a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java index 86d5fd80c108..ad3460a1a3ae 100644 --- a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java +++ b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java @@ -21,7 +21,9 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeTrue; +import com.android.cts.install.lib.host.InstallUtilsHost; import com.android.ddmlib.Log; +import com.android.tests.rollback.host.AbandonSessionsRule; import com.android.tests.util.ModuleTestUtils; import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; @@ -29,6 +31,7 @@ import com.android.tradefed.util.ProcessInfo; import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -39,12 +42,15 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test { private static final String TAG = StagedInstallInternalTest.class.getSimpleName(); private static final long SYSTEM_SERVER_TIMEOUT_MS = 60 * 1000; - private boolean mWasRoot = false; + + @Rule + public AbandonSessionsRule mHostTestRule = new AbandonSessionsRule(this); private static final String SHIM_V2 = "com.android.apex.cts.shim.v2.apex"; private static final String APK_A = "TestAppAv1.apk"; private final ModuleTestUtils mTestUtils = new ModuleTestUtils(this); + private final InstallUtilsHost mHostUtils = new InstallUtilsHost(this); /** * Runs the given phase of a test by calling into the device. @@ -71,21 +77,11 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test { @Before public void setUp() throws Exception { - mWasRoot = getDevice().isAdbRoot(); - if (!mWasRoot) { - getDevice().enableAdbRoot(); - } cleanUp(); - // Abandon all staged sessions - getDevice().executeShellCommand("pm install-abandon $(pm get-stagedsessions --only-ready " - + "--only-parent --only-sessionid)"); } @After public void tearDown() throws Exception { - if (!mWasRoot) { - getDevice().disableAdbRoot(); - } cleanUp(); } @@ -99,7 +95,7 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test { @Test public void testAdbStagedInstallWaitForReadyFlagWorks() throws Exception { assumeTrue("Device does not support updating APEX", - mTestUtils.isApexUpdateSupported()); + mHostUtils.isApexUpdateSupported()); File apexFile = mTestUtils.getTestFile(SHIM_V2); String output = getDevice().executeAdbCommand("install", "--staged", @@ -113,7 +109,7 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test { @Test public void testAdbStagedInstallNoWaitFlagWorks() throws Exception { assumeTrue("Device does not support updating APEX", - mTestUtils.isApexUpdateSupported()); + mHostUtils.isApexUpdateSupported()); File apexFile = mTestUtils.getTestFile(SHIM_V2); String output = getDevice().executeAdbCommand("install", "--staged", @@ -128,7 +124,7 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test { @Test public void testAdbInstallMultiPackageCommandWorks() throws Exception { assumeTrue("Device does not support updating APEX", - mTestUtils.isApexUpdateSupported()); + mHostUtils.isApexUpdateSupported()); File apexFile = mTestUtils.getTestFile(SHIM_V2); File apkFile = mTestUtils.getTestFile(APK_A); @@ -150,8 +146,11 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test { private void restartSystemServer() throws Exception { // Restart the system server - long oldStartTime = getDevice().getProcessByName("system_server").getStartTime(); + final long oldStartTime = getDevice().getProcessByName("system_server").getStartTime(); + + getDevice().enableAdbRoot(); // Need root to restart system server assertThat(getDevice().executeShellCommand("am restart")).contains("Restart the system"); + getDevice().disableAdbRoot(); // Wait for new system server process to start long start = System.currentTimeMillis(); diff --git a/tests/net/TEST_MAPPING b/tests/net/TEST_MAPPING index 005cbe9ffdc4..89fc6ea2c47b 100644 --- a/tests/net/TEST_MAPPING +++ b/tests/net/TEST_MAPPING @@ -8,5 +8,10 @@ { "name": "FrameworksNetDeflakeTest" } + ], + "imports": [ + { + "path": "cts/tests/tests/net" + } ] }
\ No newline at end of file diff --git a/tests/net/common/Android.bp b/tests/net/common/Android.bp index 46d680fc4511..373aac604b2a 100644 --- a/tests/net/common/Android.bp +++ b/tests/net/common/Android.bp @@ -25,6 +25,7 @@ java_library { "junit", "mockito-target-minus-junit4", "net-tests-utils", + "net-utils-framework-common", "platform-test-annotations", ], libs: [ diff --git a/tests/net/common/java/android/net/LinkPropertiesTest.java b/tests/net/common/java/android/net/LinkPropertiesTest.java index 3c3076f11727..f52ab5b40fda 100644 --- a/tests/net/common/java/android/net/LinkPropertiesTest.java +++ b/tests/net/common/java/android/net/LinkPropertiesTest.java @@ -32,7 +32,6 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import android.net.LinkProperties.ProvisioningChange; -import android.net.util.LinkPropertiesUtils.CompareResult; import android.os.Build; import android.system.OsConstants; import android.util.ArraySet; @@ -41,6 +40,7 @@ import androidx.core.os.BuildCompat; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.net.module.util.LinkPropertiesUtils.CompareResult; import com.android.testutils.DevSdkIgnoreRule; import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter; import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo; @@ -447,23 +447,21 @@ public class LinkPropertiesTest { assertEquals(3, lp.getRoutes().size()); assertAllRoutesHaveInterface("wlan0", lp); - // Check comparisons work. + // Check routes are updated correctly when calling setInterfaceName. LinkProperties lp2 = new LinkProperties(lp); assertAllRoutesHaveInterface("wlan0", lp2); - // LinkProperties#compareAllRoutes exists both in R and before R, but the return type - // changed in R, so a test compiled with the R version of LinkProperties cannot run on Q. - if (isAtLeastR()) { - assertEquals(0, lp.compareAllRoutes(lp2).added.size()); - assertEquals(0, lp.compareAllRoutes(lp2).removed.size()); - } + final CompareResult<RouteInfo> cr1 = + new CompareResult<>(lp.getAllRoutes(), lp2.getAllRoutes()); + assertEquals(0, cr1.added.size()); + assertEquals(0, cr1.removed.size()); lp2.setInterfaceName("p2p0"); assertAllRoutesHaveInterface("p2p0", lp2); assertAllRoutesNotHaveInterface("wlan0", lp2); - if (isAtLeastR()) { - assertEquals(3, lp.compareAllRoutes(lp2).added.size()); - assertEquals(3, lp.compareAllRoutes(lp2).removed.size()); - } + final CompareResult<RouteInfo> cr2 = + new CompareResult<>(lp.getAllRoutes(), lp2.getAllRoutes()); + assertEquals(3, cr2.added.size()); + assertEquals(3, cr2.removed.size()); // Remove route with incorrect interface, no route removed. lp.removeRoute(new RouteInfo(prefix2, null, null)); diff --git a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java index c895420157d7..85704d033634 100644 --- a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java +++ b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java @@ -213,7 +213,7 @@ public class NetworkAgentWrapper implements TestableNetworkCallback.HasNetwork { public void connect() { assertNotEquals("MockNetworkAgents can only be connected once", - getNetworkInfo().getDetailedState(), NetworkInfo.DetailedState.CONNECTED); + mNetworkInfo.getDetailedState(), NetworkInfo.DetailedState.CONNECTED); mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null, null); mNetworkAgent.sendNetworkInfo(mNetworkInfo); } @@ -268,10 +268,6 @@ public class NetworkAgentWrapper implements TestableNetworkCallback.HasNetwork { return mNetworkAgent; } - public NetworkInfo getNetworkInfo() { - return mNetworkInfo; - } - public NetworkCapabilities getNetworkCapabilities() { return mNetworkCapabilities; } diff --git a/tests/net/java/android/net/IpSecAlgorithmTest.java b/tests/net/java/android/net/IpSecAlgorithmTest.java index 8e9d08c705f3..2e1c29a2e405 100644 --- a/tests/net/java/android/net/IpSecAlgorithmTest.java +++ b/tests/net/java/android/net/IpSecAlgorithmTest.java @@ -16,34 +16,50 @@ package android.net; +import static android.net.IpSecAlgorithm.ALGO_TO_REQUIRED_FIRST_SDK; + +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import android.content.res.Resources; +import android.os.Build; import android.os.Parcel; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.internal.util.CollectionUtils; + import org.junit.Test; import org.junit.runner.RunWith; import java.util.AbstractMap.SimpleEntry; import java.util.Arrays; +import java.util.HashSet; import java.util.Map.Entry; import java.util.Random; +import java.util.Set; /** Unit tests for {@link IpSecAlgorithm}. */ @SmallTest @RunWith(AndroidJUnit4.class) public class IpSecAlgorithmTest { - private static final byte[] KEY_MATERIAL; + private final Resources mMockResources = mock(Resources.class); + static { KEY_MATERIAL = new byte[128]; new Random().nextBytes(KEY_MATERIAL); }; + private static byte[] generateKey(int keyLenInBits) { + return Arrays.copyOf(KEY_MATERIAL, keyLenInBits / 8); + } + @Test public void testNoTruncLen() throws Exception { Entry<String, Integer>[] authAndAeadList = @@ -53,7 +69,7 @@ public class IpSecAlgorithmTest { new SimpleEntry<>(IpSecAlgorithm.AUTH_HMAC_SHA256, 256), new SimpleEntry<>(IpSecAlgorithm.AUTH_HMAC_SHA384, 384), new SimpleEntry<>(IpSecAlgorithm.AUTH_HMAC_SHA512, 512), - new SimpleEntry<>(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, 224) + new SimpleEntry<>(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, 224), }; // Expect auth and aead algorithms to throw errors if trunclen is omitted. @@ -70,6 +86,52 @@ public class IpSecAlgorithmTest { new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, Arrays.copyOf(KEY_MATERIAL, 256 / 8)); } + private void checkAuthKeyAndTruncLenValidation(String algoName, int keyLen, int truncLen) + throws Exception { + new IpSecAlgorithm(algoName, generateKey(keyLen), truncLen); + + try { + new IpSecAlgorithm(algoName, generateKey(keyLen)); + fail("Expected exception on unprovided auth trunclen"); + } catch (IllegalArgumentException pass) { + } + + try { + new IpSecAlgorithm(algoName, generateKey(keyLen + 8), truncLen); + fail("Invalid key length not validated"); + } catch (IllegalArgumentException pass) { + } + + try { + new IpSecAlgorithm(algoName, generateKey(keyLen), truncLen + 1); + fail("Invalid truncation length not validated"); + } catch (IllegalArgumentException pass) { + } + } + + private void checkCryptKeyLenValidation(String algoName, int keyLen) throws Exception { + new IpSecAlgorithm(algoName, generateKey(keyLen)); + + try { + new IpSecAlgorithm(algoName, generateKey(keyLen + 8)); + fail("Invalid key length not validated"); + } catch (IllegalArgumentException pass) { + } + } + + @Test + public void testValidationForAlgosAddedInS() throws Exception { + if (Build.VERSION.FIRST_SDK_INT <= Build.VERSION_CODES.R) { + return; + } + + for (int len : new int[] {160, 224, 288}) { + checkCryptKeyLenValidation(IpSecAlgorithm.CRYPT_AES_CTR, len); + } + checkAuthKeyAndTruncLenValidation(IpSecAlgorithm.AUTH_AES_XCBC, 128, 96); + checkAuthKeyAndTruncLenValidation(IpSecAlgorithm.AUTH_CRYPT_CHACHA20_POLY1305, 288, 128); + } + @Test public void testTruncLenValidation() throws Exception { for (int truncLen : new int[] {256, 512}) { @@ -127,4 +189,37 @@ public class IpSecAlgorithmTest { assertTrue("Parcel/Unparcel failed!", IpSecAlgorithm.equals(init, fin)); p.recycle(); } + + private static Set<String> getMandatoryAlgos() { + return CollectionUtils.filter( + ALGO_TO_REQUIRED_FIRST_SDK.keySet(), + i -> Build.VERSION.FIRST_SDK_INT >= ALGO_TO_REQUIRED_FIRST_SDK.get(i)); + } + + private static Set<String> getOptionalAlgos() { + return CollectionUtils.filter( + ALGO_TO_REQUIRED_FIRST_SDK.keySet(), + i -> Build.VERSION.FIRST_SDK_INT < ALGO_TO_REQUIRED_FIRST_SDK.get(i)); + } + + @Test + public void testGetSupportedAlgorithms() throws Exception { + assertTrue(IpSecAlgorithm.getSupportedAlgorithms().containsAll(getMandatoryAlgos())); + assertTrue(ALGO_TO_REQUIRED_FIRST_SDK.keySet().containsAll( + IpSecAlgorithm.getSupportedAlgorithms())); + } + + @Test + public void testLoadAlgos() throws Exception { + final Set<String> optionalAlgoSet = getOptionalAlgos(); + final String[] optionalAlgos = optionalAlgoSet.toArray(new String[0]); + + doReturn(optionalAlgos).when(mMockResources) + .getStringArray(com.android.internal.R.array.config_optionalIpSecAlgorithms); + + final Set<String> enabledAlgos = new HashSet<>(IpSecAlgorithm.loadAlgos(mMockResources)); + final Set<String> expectedAlgos = ALGO_TO_REQUIRED_FIRST_SDK.keySet(); + + assertEquals(expectedAlgos, enabledAlgos); + } } diff --git a/tests/net/java/android/net/util/IpUtilsTest.java b/tests/net/java/android/net/util/IpUtilsTest.java deleted file mode 100644 index 193d85d0013a..000000000000 --- a/tests/net/java/android/net/util/IpUtilsTest.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net.util; - -import static org.junit.Assert.assertEquals; - -import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.nio.ByteBuffer; - -@RunWith(AndroidJUnit4.class) -@SmallTest -public class IpUtilsTest { - - private static final int IPV4_HEADER_LENGTH = 20; - private static final int IPV6_HEADER_LENGTH = 40; - private static final int TCP_HEADER_LENGTH = 20; - private static final int UDP_HEADER_LENGTH = 8; - private static final int IP_CHECKSUM_OFFSET = 10; - private static final int TCP_CHECKSUM_OFFSET = 16; - private static final int UDP_CHECKSUM_OFFSET = 6; - - private int getUnsignedByte(ByteBuffer buf, int offset) { - return buf.get(offset) & 0xff; - } - - private int getChecksum(ByteBuffer buf, int offset) { - return getUnsignedByte(buf, offset) * 256 + getUnsignedByte(buf, offset + 1); - } - - private void assertChecksumEquals(int expected, short actual) { - assertEquals(Integer.toHexString(expected), Integer.toHexString(actual & 0xffff)); - } - - // Generate test packets using Python code like this:: - // - // from scapy import all as scapy - // - // def JavaPacketDefinition(bytes): - // out = " ByteBuffer packet = ByteBuffer.wrap(new byte[] {\n " - // for i in xrange(len(bytes)): - // out += "(byte) 0x%02x" % ord(bytes[i]) - // if i < len(bytes) - 1: - // if i % 4 == 3: - // out += ",\n " - // else: - // out += ", " - // out += "\n });" - // return out - // - // packet = (scapy.IPv6(src="2001:db8::1", dst="2001:db8::2") / - // scapy.UDP(sport=12345, dport=7) / - // "hello") - // print JavaPacketDefinition(str(packet)) - - @Test - public void testIpv6TcpChecksum() throws Exception { - // packet = (scapy.IPv6(src="2001:db8::1", dst="2001:db8::2", tc=0x80) / - // scapy.TCP(sport=12345, dport=7, - // seq=1692871236, ack=128376451, flags=16, - // window=32768) / - // "hello, world") - ByteBuffer packet = ByteBuffer.wrap(new byte[] { - (byte) 0x68, (byte) 0x00, (byte) 0x00, (byte) 0x00, - (byte) 0x00, (byte) 0x20, (byte) 0x06, (byte) 0x40, - (byte) 0x20, (byte) 0x01, (byte) 0x0d, (byte) 0xb8, - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01, - (byte) 0x20, (byte) 0x01, (byte) 0x0d, (byte) 0xb8, - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x02, - (byte) 0x30, (byte) 0x39, (byte) 0x00, (byte) 0x07, - (byte) 0x64, (byte) 0xe7, (byte) 0x2a, (byte) 0x44, - (byte) 0x07, (byte) 0xa6, (byte) 0xde, (byte) 0x83, - (byte) 0x50, (byte) 0x10, (byte) 0x80, (byte) 0x00, - (byte) 0xee, (byte) 0x71, (byte) 0x00, (byte) 0x00, - (byte) 0x68, (byte) 0x65, (byte) 0x6c, (byte) 0x6c, - (byte) 0x6f, (byte) 0x2c, (byte) 0x20, (byte) 0x77, - (byte) 0x6f, (byte) 0x72, (byte) 0x6c, (byte) 0x64 - }); - - // Check that a valid packet has checksum 0. - int transportLen = packet.limit() - IPV6_HEADER_LENGTH; - assertEquals(0, IpUtils.tcpChecksum(packet, 0, IPV6_HEADER_LENGTH, transportLen)); - - // Check that we can calculate the checksum from scratch. - int sumOffset = IPV6_HEADER_LENGTH + TCP_CHECKSUM_OFFSET; - int sum = getUnsignedByte(packet, sumOffset) * 256 + getUnsignedByte(packet, sumOffset + 1); - assertEquals(0xee71, sum); - - packet.put(sumOffset, (byte) 0); - packet.put(sumOffset + 1, (byte) 0); - assertChecksumEquals(sum, IpUtils.tcpChecksum(packet, 0, IPV6_HEADER_LENGTH, transportLen)); - - // Check that writing the checksum back into the packet results in a valid packet. - packet.putShort( - sumOffset, - IpUtils.tcpChecksum(packet, 0, IPV6_HEADER_LENGTH, transportLen)); - assertEquals(0, IpUtils.tcpChecksum(packet, 0, IPV6_HEADER_LENGTH, transportLen)); - } - - @Test - public void testIpv4UdpChecksum() { - // packet = (scapy.IP(src="192.0.2.1", dst="192.0.2.2", tos=0x40) / - // scapy.UDP(sport=32012, dport=4500) / - // "\xff") - ByteBuffer packet = ByteBuffer.wrap(new byte[] { - (byte) 0x45, (byte) 0x40, (byte) 0x00, (byte) 0x1d, - (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x00, - (byte) 0x40, (byte) 0x11, (byte) 0xf6, (byte) 0x8b, - (byte) 0xc0, (byte) 0x00, (byte) 0x02, (byte) 0x01, - (byte) 0xc0, (byte) 0x00, (byte) 0x02, (byte) 0x02, - (byte) 0x7d, (byte) 0x0c, (byte) 0x11, (byte) 0x94, - (byte) 0x00, (byte) 0x09, (byte) 0xee, (byte) 0x36, - (byte) 0xff - }); - - // Check that a valid packet has IP checksum 0 and UDP checksum 0xffff (0 is not a valid - // UDP checksum, so the udpChecksum rewrites 0 to 0xffff). - assertEquals(0, IpUtils.ipChecksum(packet, 0)); - assertEquals((short) 0xffff, IpUtils.udpChecksum(packet, 0, IPV4_HEADER_LENGTH)); - - // Check that we can calculate the checksums from scratch. - final int ipSumOffset = IP_CHECKSUM_OFFSET; - final int ipSum = getChecksum(packet, ipSumOffset); - assertEquals(0xf68b, ipSum); - - packet.put(ipSumOffset, (byte) 0); - packet.put(ipSumOffset + 1, (byte) 0); - assertChecksumEquals(ipSum, IpUtils.ipChecksum(packet, 0)); - - final int udpSumOffset = IPV4_HEADER_LENGTH + UDP_CHECKSUM_OFFSET; - final int udpSum = getChecksum(packet, udpSumOffset); - assertEquals(0xee36, udpSum); - - packet.put(udpSumOffset, (byte) 0); - packet.put(udpSumOffset + 1, (byte) 0); - assertChecksumEquals(udpSum, IpUtils.udpChecksum(packet, 0, IPV4_HEADER_LENGTH)); - - // Check that writing the checksums back into the packet results in a valid packet. - packet.putShort(ipSumOffset, IpUtils.ipChecksum(packet, 0)); - packet.putShort(udpSumOffset, IpUtils.udpChecksum(packet, 0, IPV4_HEADER_LENGTH)); - assertEquals(0, IpUtils.ipChecksum(packet, 0)); - assertEquals((short) 0xffff, IpUtils.udpChecksum(packet, 0, IPV4_HEADER_LENGTH)); - } -} diff --git a/tests/net/java/com/android/server/connectivity/DnsManagerTest.java b/tests/net/java/com/android/server/connectivity/DnsManagerTest.java index 753dbf80b449..32bfa7059b0b 100644 --- a/tests/net/java/com/android/server/connectivity/DnsManagerTest.java +++ b/tests/net/java/com/android/server/connectivity/DnsManagerTest.java @@ -159,7 +159,6 @@ public class DnsManagerTest { // Send a validation event that is tracked on the alternate netId mDnsManager.updateTransportsForNetwork(TEST_NETID, TEST_TRANSPORT_TYPES); mDnsManager.noteDnsServersForNetwork(TEST_NETID, lp); - mDnsManager.setDefaultDnsSystemProperties(lp.getDnsServers()); mDnsManager.flushVmDnsCache(); mDnsManager.updateTransportsForNetwork(TEST_NETID_ALTERNATE, TEST_TRANSPORT_TYPES); mDnsManager.noteDnsServersForNetwork(TEST_NETID_ALTERNATE, lp); @@ -196,7 +195,6 @@ public class DnsManagerTest { })); mDnsManager.updateTransportsForNetwork(TEST_NETID, TEST_TRANSPORT_TYPES); mDnsManager.noteDnsServersForNetwork(TEST_NETID, lp); - mDnsManager.setDefaultDnsSystemProperties(lp.getDnsServers()); mDnsManager.flushVmDnsCache(); fixedLp = new LinkProperties(lp); mDnsManager.updatePrivateDnsStatus(TEST_NETID, fixedLp); @@ -232,7 +230,6 @@ public class DnsManagerTest { lp.addDnsServer(InetAddress.getByName("3.3.3.3")); mDnsManager.updateTransportsForNetwork(TEST_NETID, TEST_TRANSPORT_TYPES); mDnsManager.noteDnsServersForNetwork(TEST_NETID, lp); - mDnsManager.setDefaultDnsSystemProperties(lp.getDnsServers()); mDnsManager.flushVmDnsCache(); mDnsManager.updatePrivateDnsValidation( new DnsManager.PrivateDnsValidationUpdate(TEST_NETID, @@ -246,7 +243,6 @@ public class DnsManagerTest { mDnsManager.getPrivateDnsConfig()); mDnsManager.updateTransportsForNetwork(TEST_NETID, TEST_TRANSPORT_TYPES); mDnsManager.noteDnsServersForNetwork(TEST_NETID, lp); - mDnsManager.setDefaultDnsSystemProperties(lp.getDnsServers()); mDnsManager.flushVmDnsCache(); mDnsManager.updatePrivateDnsValidation( new DnsManager.PrivateDnsValidationUpdate(TEST_NETID_UNTRACKED, @@ -295,7 +291,6 @@ public class DnsManagerTest { mDnsManager.getPrivateDnsConfig()); mDnsManager.updateTransportsForNetwork(TEST_NETID, TEST_TRANSPORT_TYPES); mDnsManager.noteDnsServersForNetwork(TEST_NETID, lp); - mDnsManager.setDefaultDnsSystemProperties(lp.getDnsServers()); mDnsManager.flushVmDnsCache(); mDnsManager.updatePrivateDnsValidation( new DnsManager.PrivateDnsValidationUpdate(TEST_NETID, @@ -341,7 +336,6 @@ public class DnsManagerTest { lp.addDnsServer(InetAddress.getByName("4.4.4.4")); mDnsManager.updateTransportsForNetwork(TEST_NETID, TEST_TRANSPORT_TYPES); mDnsManager.noteDnsServersForNetwork(TEST_NETID, lp); - mDnsManager.setDefaultDnsSystemProperties(lp.getDnsServers()); mDnsManager.flushVmDnsCache(); final ArgumentCaptor<ResolverParamsParcel> resolverParamsParcelCaptor = diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java index f2b7c1ea2ba7..daa2627d64cf 100644 --- a/tests/net/java/com/android/server/connectivity/VpnTest.java +++ b/tests/net/java/com/android/server/connectivity/VpnTest.java @@ -1155,7 +1155,7 @@ public class VpnTest { new String[] { EGRESS_IFACE, "l2tp", expectedAddr, "1701", profile.l2tpSecret, "name", profile.username, "password", profile.password, "linkname", "vpn", "refuse-eap", "nodefaultroute", "usepeerdns", - "idle", "1800", "mtu", "1400", "mru", "1400" }, + "idle", "1800", "mtu", "1270", "mru", "1270" }, deps.mtpdArgs.get(10, TimeUnit.SECONDS)); // Now wait for the runner to be ready before testing for the route. legacyRunnerReady.block(10_000); @@ -1263,7 +1263,7 @@ public class VpnTest { } @Override - public boolean checkInterfacePresent(final Vpn vpn, final String iface) { + public boolean isInterfacePresent(final Vpn vpn, final String iface) { return true; } } diff --git a/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java b/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java index 8f093779da11..6d2c7dc39ffd 100644 --- a/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java +++ b/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java @@ -21,6 +21,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.fail; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; @@ -150,7 +151,7 @@ public final class NetworkStatsSubscriptionsMonitorTest { } private void assertRatTypeChangedForSub(String subscriberId, int ratType) { - assertEquals(mMonitor.getRatTypeForSubscriberId(subscriberId), ratType); + assertEquals(ratType, mMonitor.getRatTypeForSubscriberId(subscriberId)); final ArgumentCaptor<Integer> typeCaptor = ArgumentCaptor.forClass(Integer.class); // Verify callback with the subscriberId and the RAT type should be as expected. // It will fail if get a callback with an unexpected RAT type. @@ -302,26 +303,84 @@ public final class NetworkStatsSubscriptionsMonitorTest { reset(mDelegate); // Set IMSI to null again to simulate somehow IMSI is not available, such as - // modem crash. Verify service should not unregister listener. + // modem crash. Verify service should unregister listener. updateSubscriberIdForTestSub(TEST_SUBID1, null); - verify(mTelephonyManager, never()).listen(any(), anyInt()); - assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UMTS); + verify(mTelephonyManager, times(1)).listen(eq(ratTypeListenerCaptor.getValue()), + eq(PhoneStateListener.LISTEN_NONE)); + assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN); reset(mDelegate); + clearInvocations(mTelephonyManager); - // Set RAT type of sim1 to LTE. Verify RAT type of sim1 is still changed even if the IMSI - // is not available. The monitor keeps the listener even if the IMSI disappears because - // the IMSI can never change for any given subId, therefore even if the IMSI is updated - // to null, the monitor should continue accepting updates of the RAT type. However, - // telephony is never actually supposed to do this, if the IMSI disappears there should - // not be updates, but it's still the right thing to do theoretically. - setRatTypeForSub(ratTypeListenerCaptor.getAllValues(), TEST_SUBID1, + // Simulate somehow IMSI is back. Verify service will register with + // another listener and fire callback accordingly. + final ArgumentCaptor<RatTypeListener> ratTypeListenerCaptor2 = + ArgumentCaptor.forClass(RatTypeListener.class); + updateSubscriberIdForTestSub(TEST_SUBID1, TEST_IMSI1); + verify(mTelephonyManager, times(1)).listen(ratTypeListenerCaptor2.capture(), + eq(PhoneStateListener.LISTEN_SERVICE_STATE)); + assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN); + reset(mDelegate); + clearInvocations(mTelephonyManager); + + // Set RAT type of sim1 to LTE. Verify RAT type of sim1 still works. + setRatTypeForSub(ratTypeListenerCaptor2.getAllValues(), TEST_SUBID1, TelephonyManager.NETWORK_TYPE_LTE); assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_LTE); reset(mDelegate); mMonitor.stop(); + verify(mTelephonyManager, times(1)).listen(eq(ratTypeListenerCaptor2.getValue()), + eq(PhoneStateListener.LISTEN_NONE)); + assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN); + } + + /** + * Verify that when IMSI suddenly changed for a given subId, the service will register a new + * listener and unregister the old one, and report changes on updated IMSI. This is for modem + * feature that may be enabled for certain carrier, which changes to use a different IMSI while + * roaming on certain networks for multi-IMSI SIM cards, but the subId stays the same. + */ + @Test + public void testSubscriberIdChanged() { + mMonitor.start(); + // Insert sim1, verify RAT type is NETWORK_TYPE_UNKNOWN, and never get any callback + // before changing RAT type. + addTestSub(TEST_SUBID1, TEST_IMSI1); + final ArgumentCaptor<RatTypeListener> ratTypeListenerCaptor = + ArgumentCaptor.forClass(RatTypeListener.class); + verify(mTelephonyManager, times(1)).listen(ratTypeListenerCaptor.capture(), + eq(PhoneStateListener.LISTEN_SERVICE_STATE)); + assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN); + + // Set RAT type of sim1 to UMTS. + // Verify RAT type of sim1 changes accordingly. + setRatTypeForSub(ratTypeListenerCaptor.getAllValues(), TEST_SUBID1, + TelephonyManager.NETWORK_TYPE_UMTS); + assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UMTS); + reset(mDelegate); + clearInvocations(mTelephonyManager); + + // Simulate IMSI of sim1 changed to IMSI2. Verify the service will register with + // another listener and remove the old one. The RAT type of new IMSI stays at + // NETWORK_TYPE_UNKNOWN until received initial callback from telephony. + final ArgumentCaptor<RatTypeListener> ratTypeListenerCaptor2 = + ArgumentCaptor.forClass(RatTypeListener.class); + updateSubscriberIdForTestSub(TEST_SUBID1, TEST_IMSI2); + verify(mTelephonyManager, times(1)).listen(ratTypeListenerCaptor2.capture(), + eq(PhoneStateListener.LISTEN_SERVICE_STATE)); verify(mTelephonyManager, times(1)).listen(eq(ratTypeListenerCaptor.getValue()), eq(PhoneStateListener.LISTEN_NONE)); assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN); + assertRatTypeNotChangedForSub(TEST_IMSI2, TelephonyManager.NETWORK_TYPE_UNKNOWN); + reset(mDelegate); + + // Set RAT type of sim1 to UMTS for new listener to simulate the initial callback received + // from telephony after registration. Verify RAT type of sim1 changes with IMSI2 + // accordingly. + setRatTypeForSub(ratTypeListenerCaptor2.getAllValues(), TEST_SUBID1, + TelephonyManager.NETWORK_TYPE_UMTS); + assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN); + assertRatTypeChangedForSub(TEST_IMSI2, TelephonyManager.NETWORK_TYPE_UMTS); + reset(mDelegate); } } diff --git a/tests/RollbackTest/lib/src/com/android/tests/rollback/host/AbandonSessionsRule.java b/tests/utils/hostutils/src/com/android/tests/rollback/host/AbandonSessionsRule.java index b08621314ee0..b08621314ee0 100644 --- a/tests/RollbackTest/lib/src/com/android/tests/rollback/host/AbandonSessionsRule.java +++ b/tests/utils/hostutils/src/com/android/tests/rollback/host/AbandonSessionsRule.java diff --git a/tests/vcn/OWNERS b/tests/vcn/OWNERS new file mode 100644 index 000000000000..33b9f0f75f81 --- /dev/null +++ b/tests/vcn/OWNERS @@ -0,0 +1,7 @@ +set noparent + +benedictwong@google.com +ckesting@google.com +evitayan@google.com +nharold@google.com +jchalard@google.com
\ No newline at end of file diff --git a/wifi/aidl-export/android/net/wifi/p2p/nsd/WifiP2pServiceInfo.aidl b/wifi/aidl-export/android/net/wifi/p2p/nsd/WifiP2pServiceInfo.aidl index cf2cb4ae5eb4..57055f78d03d 100644 --- a/wifi/aidl-export/android/net/wifi/p2p/nsd/WifiP2pServiceInfo.aidl +++ b/wifi/aidl-export/android/net/wifi/p2p/nsd/WifiP2pServiceInfo.aidl @@ -14,6 +14,6 @@ * limitations under the License. */ -package android.net.wifi.p2p.servicediscovery; +package android.net.wifi.p2p.nsd; parcelable WifiP2pServiceInfo; diff --git a/wifi/aidl-export/android/net/wifi/p2p/nsd/WifiP2pServiceRequest.aidl b/wifi/aidl-export/android/net/wifi/p2p/nsd/WifiP2pServiceRequest.aidl index d5a1e8f505a9..e4d28bb2d39f 100644 --- a/wifi/aidl-export/android/net/wifi/p2p/nsd/WifiP2pServiceRequest.aidl +++ b/wifi/aidl-export/android/net/wifi/p2p/nsd/WifiP2pServiceRequest.aidl @@ -14,6 +14,6 @@ * limitations under the License. */ -package android.net.wifi.p2p.servicediscovery; +package android.net.wifi.p2p.nsd; parcelable WifiP2pServiceRequest; diff --git a/wifi/jarjar-rules.txt b/wifi/jarjar-rules.txt index e253ae25659e..eef08b54f570 100644 --- a/wifi/jarjar-rules.txt +++ b/wifi/jarjar-rules.txt @@ -70,7 +70,6 @@ rule android.net.util.NetworkConstants* com.android.wifi.x.@0 rule android.net.util.InterfaceParams* com.android.wifi.x.@0 rule android.net.util.SharedLog* com.android.wifi.x.@0 rule android.net.util.NetUtils* com.android.wifi.x.@0 -rule android.net.util.IpUtils* com.android.wifi.x.@0 rule androidx.annotation.** com.android.wifi.x.@0 diff --git a/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java b/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java index 1a4427034756..31e508c5b3c2 100644 --- a/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java +++ b/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java @@ -80,12 +80,12 @@ public class SoftApConfigurationTest { assertThat(original.getMaxNumberOfClients()).isEqualTo(0); SoftApConfiguration unparceled = parcelUnparcel(original); - assertThat(unparceled).isNotSameAs(original); + assertThat(unparceled).isNotSameInstanceAs(original); assertThat(unparceled).isEqualTo(original); assertThat(unparceled.hashCode()).isEqualTo(original.hashCode()); SoftApConfiguration copy = new SoftApConfiguration.Builder(original).build(); - assertThat(copy).isNotSameAs(original); + assertThat(copy).isNotSameInstanceAs(original); assertThat(copy).isEqualTo(original); assertThat(copy.hashCode()).isEqualTo(original.hashCode()); } @@ -104,12 +104,12 @@ public class SoftApConfigurationTest { assertThat(original.getMaxNumberOfClients()).isEqualTo(0); SoftApConfiguration unparceled = parcelUnparcel(original); - assertThat(unparceled).isNotSameAs(original); + assertThat(unparceled).isNotSameInstanceAs(original); assertThat(unparceled).isEqualTo(original); assertThat(unparceled.hashCode()).isEqualTo(original.hashCode()); SoftApConfiguration copy = new SoftApConfiguration.Builder(original).build(); - assertThat(copy).isNotSameAs(original); + assertThat(copy).isNotSameInstanceAs(original); assertThat(copy).isEqualTo(original); assertThat(copy.hashCode()).isEqualTo(original.hashCode()); } @@ -145,12 +145,12 @@ public class SoftApConfigurationTest { assertThat(original.getAllowedClientList()).isEqualTo(testAllowedClientList); SoftApConfiguration unparceled = parcelUnparcel(original); - assertThat(unparceled).isNotSameAs(original); + assertThat(unparceled).isNotSameInstanceAs(original); assertThat(unparceled).isEqualTo(original); assertThat(unparceled.hashCode()).isEqualTo(original.hashCode()); SoftApConfiguration copy = new SoftApConfiguration.Builder(original).build(); - assertThat(copy).isNotSameAs(original); + assertThat(copy).isNotSameInstanceAs(original); assertThat(copy).isEqualTo(original); assertThat(copy.hashCode()).isEqualTo(original.hashCode()); } @@ -171,12 +171,12 @@ public class SoftApConfigurationTest { SoftApConfiguration unparceled = parcelUnparcel(original); - assertThat(unparceled).isNotSameAs(original); + assertThat(unparceled).isNotSameInstanceAs(original); assertThat(unparceled).isEqualTo(original); assertThat(unparceled.hashCode()).isEqualTo(original.hashCode()); SoftApConfiguration copy = new SoftApConfiguration.Builder(original).build(); - assertThat(copy).isNotSameAs(original); + assertThat(copy).isNotSameInstanceAs(original); assertThat(copy).isEqualTo(original); assertThat(copy.hashCode()).isEqualTo(original.hashCode()); } @@ -198,12 +198,12 @@ public class SoftApConfigurationTest { SoftApConfiguration unparceled = parcelUnparcel(original); - assertThat(unparceled).isNotSameAs(original); + assertThat(unparceled).isNotSameInstanceAs(original); assertThat(unparceled).isEqualTo(original); assertThat(unparceled.hashCode()).isEqualTo(original.hashCode()); SoftApConfiguration copy = new SoftApConfiguration.Builder(original).build(); - assertThat(copy).isNotSameAs(original); + assertThat(copy).isNotSameInstanceAs(original); assertThat(copy).isEqualTo(original); assertThat(copy.hashCode()).isEqualTo(original.hashCode()); } |