Merge "Updating owners of SystemUI"
diff --git a/.prebuilt_info/OWNERS b/.prebuilt_info/OWNERS
new file mode 100644
index 0000000..eb8b89b
--- /dev/null
+++ b/.prebuilt_info/OWNERS
@@ -0,0 +1 @@
+per-file prebuilt_info_packages_CtsShim_*.asciipb = file:/packages/CtsShim/OWNERS
diff --git a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShimPriv_apk.asciipb b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShimPriv_apk.asciipb
index 29bcfe0..1bd90a8 100644
--- a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShimPriv_apk.asciipb
+++ b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShimPriv_apk.asciipb
@@ -1,6 +1,6 @@
drops {
android_build_drop {
- build_id: "6508977"
+ build_id: "7197701"
target: "CtsShim"
source_file: "aosp_arm64/CtsShimPriv.apk"
}
@@ -8,5 +8,5 @@
version: ""
version_group: ""
git_project: "platform/frameworks/base"
- git_branch: "rvc-dev"
+ git_branch: "sc-dev"
}
diff --git a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShim_apk.asciipb b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShim_apk.asciipb
index be172e6..544bca02 100644
--- a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShim_apk.asciipb
+++ b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShim_apk.asciipb
@@ -1,6 +1,6 @@
drops {
android_build_drop {
- build_id: "6508977"
+ build_id: "7197701"
target: "CtsShim"
source_file: "aosp_arm64/CtsShim.apk"
}
@@ -8,5 +8,5 @@
version: ""
version_group: ""
git_project: "platform/frameworks/base"
- git_branch: "rvc-dev"
+ git_branch: "sc-dev"
}
diff --git a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShimPriv_apk.asciipb b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShimPriv_apk.asciipb
index 13eca13..72386bb 100644
--- a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShimPriv_apk.asciipb
+++ b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShimPriv_apk.asciipb
@@ -1,6 +1,6 @@
drops {
android_build_drop {
- build_id: "6508977"
+ build_id: "7197701"
target: "CtsShim"
source_file: "aosp_x86_64/CtsShimPriv.apk"
}
@@ -8,5 +8,5 @@
version: ""
version_group: ""
git_project: "platform/frameworks/base"
- git_branch: "rvc-dev"
+ git_branch: "sc-dev"
}
diff --git a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShim_apk.asciipb b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShim_apk.asciipb
index 2e863fe..893eac2 100644
--- a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShim_apk.asciipb
+++ b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShim_apk.asciipb
@@ -1,6 +1,6 @@
drops {
android_build_drop {
- build_id: "6508977"
+ build_id: "7197701"
target: "CtsShim"
source_file: "aosp_x86_64/CtsShim.apk"
}
@@ -8,5 +8,5 @@
version: ""
version_group: ""
git_project: "platform/frameworks/base"
- git_branch: "rvc-dev"
+ git_branch: "sc-dev"
}
diff --git a/Android.bp b/Android.bp
index 22246f2..4709323 100644
--- a/Android.bp
+++ b/Android.bp
@@ -306,8 +306,8 @@
genrule {
name: "statslog-telephony-common-java-gen",
tools: ["stats-log-api-gen"],
- cmd: "$(location stats-log-api-gen) --java $(out) --module telephony_common"
- + " --javaPackage com.android.internal.telephony --javaClass TelephonyCommonStatsLog",
+ cmd: "$(location stats-log-api-gen) --java $(out) --module telephony_common" +
+ " --javaPackage com.android.internal.telephony --javaClass TelephonyCommonStatsLog",
out: ["com/android/internal/telephony/TelephonyCommonStatsLog.java"],
}
@@ -363,6 +363,13 @@
":platform-compat-native-aidl",
// AIDL sources from external directories
+ ":android.hardware.security.keymint-V1-java-source",
+ ":android.hardware.security.secureclock-V1-java-source",
+ ":android.security.apc-java-source",
+ ":android.security.authorization-java-source",
+ ":android.security.maintenance-java-source",
+ ":android.security.vpnprofilestore-java-source",
+ ":android.system.keystore2-V1-java-source",
":credstore_aidl",
":dumpstate_aidl",
":framework_native_aidl",
@@ -523,11 +530,6 @@
"android.hardware.vibrator-V1.1-java",
"android.hardware.vibrator-V1.2-java",
"android.hardware.vibrator-V1.3-java",
- "android.security.apc-java",
- "android.security.authorization-java",
- "android.security.usermanager-java",
- "android.security.vpnprofilestore-java",
- "android.system.keystore2-V1-java",
"android.system.suspend.control.internal-java",
"devicepolicyprotosnano",
@@ -605,7 +607,6 @@
// TODO: remove gps_debug and protolog.conf.json when the build system propagates "required" properly.
"gps_debug.conf",
"icu4j-platform-compat-config",
- "libcore-platform-compat-config",
"protolog.conf.json.gz",
"services-platform-compat-config",
"documents-ui-compat-config",
@@ -685,7 +686,7 @@
name: "statslog-framework-java-gen",
tools: ["stats-log-api-gen"],
cmd: "$(location stats-log-api-gen) --java $(out) --module framework" +
- " --javaPackage com.android.internal.util --javaClass FrameworkStatsLog --worksource",
+ " --javaPackage com.android.internal.util --javaClass FrameworkStatsLog --worksource",
out: ["com/android/internal/util/FrameworkStatsLog.java"],
}
@@ -786,7 +787,7 @@
java_library {
name: "framework-annotations-lib",
- srcs: [ ":framework-annotations" ],
+ srcs: [":framework-annotations"],
sdk_version: "core_current",
}
@@ -834,17 +835,20 @@
],
}
-// keep these files in sync with the package/Tethering/jarjar-rules.txt for the tethering module.
+// keep these files in sync with the package/Tethering/jarjar-rules.txt and
+// package/Connectivity/jarjar-rules.txt for the tethering module and connectivity module.
filegroup {
- name: "framework-tethering-shared-srcs",
+ name: "framework-connectivity-shared-srcs",
srcs: [
"core/java/android/util/LocalLog.java",
+ // This should be android.util.IndentingPrintWriter, but it's not available in all branches.
"core/java/com/android/internal/util/IndentingPrintWriter.java",
"core/java/com/android/internal/util/IState.java",
"core/java/com/android/internal/util/MessageUtils.java",
"core/java/com/android/internal/util/State.java",
"core/java/com/android/internal/util/StateMachine.java",
"core/java/com/android/internal/util/TrafficStatsConstants.java",
+ "core/java/com/android/internal/util/WakeupMessage.java",
],
}
@@ -1010,7 +1014,6 @@
},
}
-
// This is the full proto version of libplatformprotos. It may only
// be used by test code that is not shipped on the device.
cc_library {
@@ -1171,7 +1174,7 @@
"core/java/android/os/RemoteException.java",
"core/java/android/util/AndroidException.java",
],
- libs: [ "unsupportedappusage" ],
+ libs: ["unsupportedappusage"],
dxflags: ["--core-library"],
installable: false,
diff --git a/StubLibraries.bp b/StubLibraries.bp
index d866116..6316c4a 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -422,10 +422,6 @@
name: "hwbinder-stubs-docs",
srcs: [
"core/java/android/os/HidlSupport.java",
- "core/java/android/annotation/IntDef.java",
- "core/java/android/annotation/IntRange.java",
- "core/java/android/annotation/NonNull.java",
- "core/java/android/annotation/SystemApi.java",
"core/java/android/os/HidlMemory.java",
"core/java/android/os/HwBinder.java",
"core/java/android/os/HwBlob.java",
@@ -438,6 +434,7 @@
"core/java/android/os/RemoteException.java",
"core/java/android/util/AndroidException.java",
],
+ libs: ["framework-annotations-lib"],
installable: false,
sdk_version: "core_platform",
annotations_enabled: true,
@@ -451,6 +448,7 @@
java_library_static {
name: "hwbinder.stubs",
sdk_version: "core_current",
+ libs: ["framework-annotations-lib"],
srcs: [
":hwbinder-stubs-docs",
],
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 2b12da2..4b449ef 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -57,5 +57,65 @@
{
"name": "ManagedProfileLifecycleStressTest"
}
- ]
+ ],
+ "auto-postsubmit": [
+ // Test tag for automotive targets. These are only running in postsubmit so as to harden the
+ // automotive targets to avoid introducing additional test flake and build time. The plan for
+ // presubmit testing for auto is to augment the existing tests to cover auto use cases as well.
+ // Additionally, this tag is used in targeted test suites to limit resource usage on the test
+ // infra during the hardening phase.
+ // TODO: this tag to be removed once the above is no longer an issue.
+ {
+ "name": "FrameworksUiServicesTests",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ },
+ {
+ "name": "ExtServicesUnitTests",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ },
+ {
+ "name": "TestablesTests",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ },
+ {
+ "name": "FrameworksCoreTests",
+ "options": [
+ {
+ "include-annotation": "android.platform.test.annotations.Presubmit"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation": "org.junit.Ignore"
+ }
+ ]
+ },
+ {
+ "name": "FrameworksServicesTests",
+ "options": [
+ {
+ "include-annotation": "android.platform.test.annotations.Presubmit"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation": "org.junit.Ignore"
+ }
+ ]
+ }
+ ]
}
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
index 24b8055..a3fa8ac 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
@@ -1006,6 +1006,41 @@
mJobId = jobId;
}
+ /**
+ * Creates a new Builder of JobInfo from an existing instance.
+ * @hide
+ */
+ public Builder(@NonNull JobInfo job) {
+ mJobId = job.getId();
+ mJobService = job.getService();
+ mExtras = job.getExtras();
+ mTransientExtras = job.getTransientExtras();
+ mClipData = job.getClipData();
+ mClipGrantFlags = job.getClipGrantFlags();
+ mPriority = job.getPriority();
+ mFlags = job.getFlags();
+ mConstraintFlags = job.getConstraintFlags();
+ mNetworkRequest = job.getRequiredNetwork();
+ mNetworkDownloadBytes = job.getEstimatedNetworkDownloadBytes();
+ mNetworkUploadBytes = job.getEstimatedNetworkUploadBytes();
+ mTriggerContentUris = job.getTriggerContentUris() != null
+ ? new ArrayList<>(Arrays.asList(job.getTriggerContentUris())) : null;
+ mTriggerContentUpdateDelay = job.getTriggerContentUpdateDelay();
+ mTriggerContentMaxDelay = job.getTriggerContentMaxDelay();
+ mIsPersisted = job.isPersisted();
+ mMinLatencyMillis = job.getMinLatencyMillis();
+ mMaxExecutionDelayMillis = job.getMaxExecutionDelayMillis();
+ mIsPeriodic = job.isPeriodic();
+ mHasEarlyConstraint = job.hasEarlyConstraint();
+ mHasLateConstraint = job.hasLateConstraint();
+ mIntervalMillis = job.getIntervalMillis();
+ mFlexMillis = job.getFlexMillis();
+ mInitialBackoffMillis = job.getInitialBackoffMillis();
+ // mBackoffPolicySet isn't set but it's fine since this is copying from an already valid
+ // job.
+ mBackoffPolicy = job.getBackoffPolicy();
+ }
+
/** @hide */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public Builder setPriority(int priority) {
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
index 565ed95..15e5e84 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
@@ -31,6 +31,7 @@
import android.content.ServiceConnection;
import android.net.Uri;
import android.os.Binder;
+import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -73,11 +74,12 @@
private static final String TAG = "JobServiceContext";
/** Amount of time a job is allowed to execute for before being considered timed-out. */
- public static final long EXECUTING_TIMESLICE_MILLIS = 10 * 60 * 1000; // 10mins.
+ public static final long EXECUTING_TIMESLICE_MILLIS =
+ 10 * 60 * 1000 * Build.HW_TIMEOUT_MULTIPLIER; // 10mins.
/** Amount of time the JobScheduler waits for the initial service launch+bind. */
- private static final long OP_BIND_TIMEOUT_MILLIS = 18 * 1000;
+ private static final long OP_BIND_TIMEOUT_MILLIS = 18 * 1000 * Build.HW_TIMEOUT_MULTIPLIER;
/** Amount of time the JobScheduler will wait for a response from an app for a message. */
- private static final long OP_TIMEOUT_MILLIS = 8 * 1000;
+ private static final long OP_TIMEOUT_MILLIS = 8 * 1000 * Build.HW_TIMEOUT_MULTIPLIER;
private static final String[] VERB_STRINGS = {
"VERB_BINDING", "VERB_STARTING", "VERB_EXECUTING", "VERB_STOPPING", "VERB_FINISHED"
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
index d7be259..ea8e7bc 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
@@ -28,6 +28,7 @@
import android.content.ClipData;
import android.content.ComponentName;
import android.net.Network;
+import android.net.NetworkRequest;
import android.net.Uri;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -35,6 +36,7 @@
import android.text.format.DateFormat;
import android.util.ArraySet;
import android.util.Pair;
+import android.util.Range;
import android.util.Slog;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
@@ -52,6 +54,7 @@
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.function.Predicate;
/**
@@ -486,8 +489,15 @@
// Later, when we check if a given network satisfies the required
// network, we need to know the UID that is requesting it, so push
// our source UID into place.
- job.getRequiredNetwork().networkCapabilities.setSingleUid(this.sourceUid);
+ final JobInfo.Builder builder = new JobInfo.Builder(job);
+ final NetworkRequest.Builder requestBuilder =
+ new NetworkRequest.Builder(job.getRequiredNetwork());
+ requestBuilder.setUids(
+ Collections.singleton(new Range<Integer>(this.sourceUid, this.sourceUid)));
+ builder.setRequiredNetwork(requestBuilder.build());
+ job = builder.build();
}
+
final JobSchedulerInternal jsi = LocalServices.getService(JobSchedulerInternal.class);
mHasMediaBackupExemption = !job.hasLateConstraint() && exemptedMediaUrisOnly
&& requiresNetwork && this.sourcePackageName.equals(jsi.getMediaBackupPackage());
diff --git a/cmds/app_process/Android.bp b/cmds/app_process/Android.bp
index 4e5b3ba..0eff83c 100644
--- a/cmds/app_process/Android.bp
+++ b/cmds/app_process/Android.bp
@@ -22,13 +22,9 @@
multilib: {
lib32: {
- // TODO(b/142944043): Remove version script when libsigchain is a DSO.
- version_script: "version-script32.txt",
suffix: "32",
},
lib64: {
- // TODO(b/142944043): Remove version script when libsigchain is a DSO.
- version_script: "version-script64.txt",
suffix: "64",
},
},
@@ -43,6 +39,13 @@
"libhidlbase",
"liblog",
"libnativeloader",
+
+ // Even though app_process doesn't call into libsigchain, we need to
+ // make sure it's in the DT list of app_process, as we want all code
+ // in app_process and the libraries it loads to find libsigchain
+ // symbols before libc symbols.
+ "libsigchain",
+
"libutils",
// This is a list of libraries that need to be included in order to avoid
@@ -52,8 +55,6 @@
"libwilhelm",
],
- whole_static_libs: ["libsigchain"],
-
compile_multilib: "both",
cflags: [
diff --git a/cmds/app_process/version-script32.txt b/cmds/app_process/version-script32.txt
deleted file mode 100644
index 70810e0..0000000
--- a/cmds/app_process/version-script32.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-{
-global:
- EnsureFrontOfChain;
- AddSpecialSignalHandlerFn;
- RemoveSpecialSignalHandlerFn;
- SkipAddSignalHandler;
- bsd_signal;
- sigaction;
- sigaction64;
- signal;
- sigprocmask;
- sigprocmask64;
-local:
- *;
-};
diff --git a/cmds/app_process/version-script64.txt b/cmds/app_process/version-script64.txt
deleted file mode 100644
index 7bcd76b..0000000
--- a/cmds/app_process/version-script64.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-{
-global:
- EnsureFrontOfChain;
- AddSpecialSignalHandlerFn;
- RemoveSpecialSignalHandlerFn;
- SkipAddSignalHandler;
- sigaction;
- sigaction64;
- signal;
- sigprocmask;
- sigprocmask64;
-local:
- *;
-};
diff --git a/config/preloaded-classes b/config/preloaded-classes
index 5e88d97d..56c35bc 100644
--- a/config/preloaded-classes
+++ b/config/preloaded-classes
@@ -1838,11 +1838,9 @@
android.ddm.DdmHandleAppName$Names
android.ddm.DdmHandleAppName
android.ddm.DdmHandleExit
-android.ddm.DdmHandleHeap
android.ddm.DdmHandleHello
android.ddm.DdmHandleNativeHeap
android.ddm.DdmHandleProfiling
-android.ddm.DdmHandleThread
android.ddm.DdmHandleViewDebug
android.ddm.DdmRegister
android.debug.AdbManager
diff --git a/core/api/current.txt b/core/api/current.txt
index 116ac09..ef06785 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -7999,13 +7999,13 @@
}
public class NetworkStatsManager {
- method public android.app.usage.NetworkStats queryDetails(int, String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
- method public android.app.usage.NetworkStats queryDetailsForUid(int, String, long, long, int) throws java.lang.SecurityException;
- method public android.app.usage.NetworkStats queryDetailsForUidTag(int, String, long, long, int, int) throws java.lang.SecurityException;
- method public android.app.usage.NetworkStats queryDetailsForUidTagState(int, String, long, long, int, int, int) throws java.lang.SecurityException;
- method public android.app.usage.NetworkStats querySummary(int, String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
- method public android.app.usage.NetworkStats.Bucket querySummaryForDevice(int, String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
- method public android.app.usage.NetworkStats.Bucket querySummaryForUser(int, String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
+ method @WorkerThread public android.app.usage.NetworkStats queryDetails(int, String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
+ method @WorkerThread public android.app.usage.NetworkStats queryDetailsForUid(int, String, long, long, int) throws java.lang.SecurityException;
+ method @WorkerThread public android.app.usage.NetworkStats queryDetailsForUidTag(int, String, long, long, int, int) throws java.lang.SecurityException;
+ method @WorkerThread public android.app.usage.NetworkStats queryDetailsForUidTagState(int, String, long, long, int, int, int) throws java.lang.SecurityException;
+ method @WorkerThread public android.app.usage.NetworkStats querySummary(int, String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
+ method @WorkerThread public android.app.usage.NetworkStats.Bucket querySummaryForDevice(int, String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
+ method @WorkerThread public android.app.usage.NetworkStats.Bucket querySummaryForUser(int, String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
method public void registerUsageCallback(int, String, long, android.app.usage.NetworkStatsManager.UsageCallback);
method public void registerUsageCallback(int, String, long, android.app.usage.NetworkStatsManager.UsageCallback, @Nullable android.os.Handler);
method public void unregisterUsageCallback(android.app.usage.NetworkStatsManager.UsageCallback);
@@ -8689,6 +8689,8 @@
field public static final String ACTION_NAME_CHANGED = "android.bluetooth.device.action.NAME_CHANGED";
field public static final String ACTION_PAIRING_REQUEST = "android.bluetooth.device.action.PAIRING_REQUEST";
field public static final String ACTION_UUID = "android.bluetooth.device.action.UUID";
+ field public static final int ADDRESS_TYPE_PUBLIC = 0; // 0x0
+ field public static final int ADDRESS_TYPE_RANDOM = 1; // 0x1
field public static final int BOND_BONDED = 12; // 0xc
field public static final int BOND_BONDING = 11; // 0xb
field public static final int BOND_NONE = 10; // 0xa
@@ -12137,6 +12139,7 @@
field public static final String FEATURE_FINGERPRINT = "android.hardware.fingerprint";
field public static final String FEATURE_FREEFORM_WINDOW_MANAGEMENT = "android.software.freeform_window_management";
field public static final String FEATURE_GAMEPAD = "android.hardware.gamepad";
+ field public static final String FEATURE_HARDWARE_KEYSTORE = "android.hardware.hardware_keystore";
field public static final String FEATURE_HIFI_SENSORS = "android.hardware.sensor.hifi_sensors";
field public static final String FEATURE_HOME_SCREEN = "android.software.home_screen";
field public static final String FEATURE_IDENTITY_CREDENTIAL_HARDWARE = "android.hardware.identity_credential";
@@ -19852,6 +19855,7 @@
method public android.media.AudioDeviceInfo getPreferredDevice();
method public android.media.AudioDeviceInfo getRoutedDevice();
method public int getSampleRate();
+ method @IntRange(from=1) public int getStartThresholdInFrames();
method public int getState();
method public int getStreamType();
method public boolean getTimestamp(android.media.AudioTimestamp);
@@ -19882,6 +19886,7 @@
method public int setPositionNotificationPeriod(int);
method public boolean setPreferredDevice(android.media.AudioDeviceInfo);
method public int setPresentation(@NonNull android.media.AudioPresentation);
+ method @IntRange(from=1) public int setStartThresholdInFrames(@IntRange(from=1) int);
method @Deprecated protected void setState(int);
method @Deprecated public int setStereoVolume(float, float);
method public int setVolume(float);
@@ -20441,7 +20446,9 @@
method @NonNull public android.media.MediaFormat getOutputFormat(int);
method @NonNull public android.media.MediaCodec.OutputFrame getOutputFrame(int);
method @Nullable public android.media.Image getOutputImage(int);
+ method @Nullable public android.media.MediaCodec.ParameterDescriptor getParameterDescriptor(@NonNull String);
method @NonNull public android.media.MediaCodec.QueueRequest getQueueRequest(int);
+ method @NonNull public java.util.List<java.lang.String> getSupportedVendorParameters();
method @Nullable public static android.media.Image mapHardwareBuffer(@NonNull android.hardware.HardwareBuffer);
method public void queueInputBuffer(int, int, int, long, int) throws android.media.MediaCodec.CryptoException;
method public void queueSecureInputBuffer(int, int, @NonNull android.media.MediaCodec.CryptoInfo, long, int) throws android.media.MediaCodec.CryptoException;
@@ -20460,6 +20467,8 @@
method public void signalEndOfInputStream();
method public void start();
method public void stop();
+ method public void subscribeToVendorParameters(@NonNull java.util.List<java.lang.String>);
+ method public void unsubscribeFromVendorParameters(@NonNull java.util.List<java.lang.String>);
field public static final int BUFFER_FLAG_CODEC_CONFIG = 2; // 0x2
field public static final int BUFFER_FLAG_END_OF_STREAM = 4; // 0x4
field public static final int BUFFER_FLAG_KEY_FRAME = 1; // 0x1
@@ -20581,6 +20590,11 @@
method public long getPresentationTimeUs();
}
+ public static class MediaCodec.ParameterDescriptor {
+ method @NonNull public String getName();
+ method public int getType();
+ }
+
public final class MediaCodec.QueueRequest {
method public void queue();
method @NonNull public android.media.MediaCodec.QueueRequest setByteBufferParameter(@NonNull String, @NonNull java.nio.ByteBuffer);
@@ -25018,10 +25032,6 @@
ctor public NetworkSpecifier();
}
- public class ParseException extends java.lang.RuntimeException {
- field public String response;
- }
-
public abstract class PlatformVpnProfile {
method public final int getType();
method @NonNull public final String getTypeString();
@@ -25433,236 +25443,236 @@
package android.net.rtp {
- public class AudioCodec {
- method public static android.net.rtp.AudioCodec getCodec(int, String, String);
- method public static android.net.rtp.AudioCodec[] getCodecs();
- field public static final android.net.rtp.AudioCodec AMR;
- field public static final android.net.rtp.AudioCodec GSM;
- field public static final android.net.rtp.AudioCodec GSM_EFR;
- field public static final android.net.rtp.AudioCodec PCMA;
- field public static final android.net.rtp.AudioCodec PCMU;
- field public final String fmtp;
- field public final String rtpmap;
- field public final int type;
+ @Deprecated public class AudioCodec {
+ method @Deprecated public static android.net.rtp.AudioCodec getCodec(int, String, String);
+ method @Deprecated public static android.net.rtp.AudioCodec[] getCodecs();
+ field @Deprecated public static final android.net.rtp.AudioCodec AMR;
+ field @Deprecated public static final android.net.rtp.AudioCodec GSM;
+ field @Deprecated public static final android.net.rtp.AudioCodec GSM_EFR;
+ field @Deprecated public static final android.net.rtp.AudioCodec PCMA;
+ field @Deprecated public static final android.net.rtp.AudioCodec PCMU;
+ field @Deprecated public final String fmtp;
+ field @Deprecated public final String rtpmap;
+ field @Deprecated public final int type;
}
- public class AudioGroup {
+ @Deprecated public class AudioGroup {
ctor @Deprecated public AudioGroup();
- ctor public AudioGroup(@NonNull android.content.Context);
- method public void clear();
- method public int getMode();
- method public android.net.rtp.AudioStream[] getStreams();
- method public void sendDtmf(int);
- method public void setMode(int);
- field public static final int MODE_ECHO_SUPPRESSION = 3; // 0x3
- field public static final int MODE_MUTED = 1; // 0x1
- field public static final int MODE_NORMAL = 2; // 0x2
- field public static final int MODE_ON_HOLD = 0; // 0x0
+ ctor @Deprecated public AudioGroup(@NonNull android.content.Context);
+ method @Deprecated public void clear();
+ method @Deprecated public int getMode();
+ method @Deprecated public android.net.rtp.AudioStream[] getStreams();
+ method @Deprecated public void sendDtmf(int);
+ method @Deprecated public void setMode(int);
+ field @Deprecated public static final int MODE_ECHO_SUPPRESSION = 3; // 0x3
+ field @Deprecated public static final int MODE_MUTED = 1; // 0x1
+ field @Deprecated public static final int MODE_NORMAL = 2; // 0x2
+ field @Deprecated public static final int MODE_ON_HOLD = 0; // 0x0
}
- public class AudioStream extends android.net.rtp.RtpStream {
- ctor public AudioStream(java.net.InetAddress) throws java.net.SocketException;
- method public android.net.rtp.AudioCodec getCodec();
- method public int getDtmfType();
- method public android.net.rtp.AudioGroup getGroup();
- method public final boolean isBusy();
- method public void join(android.net.rtp.AudioGroup);
- method public void setCodec(android.net.rtp.AudioCodec);
- method public void setDtmfType(int);
+ @Deprecated public class AudioStream extends android.net.rtp.RtpStream {
+ ctor @Deprecated public AudioStream(java.net.InetAddress) throws java.net.SocketException;
+ method @Deprecated public android.net.rtp.AudioCodec getCodec();
+ method @Deprecated public int getDtmfType();
+ method @Deprecated public android.net.rtp.AudioGroup getGroup();
+ method @Deprecated public final boolean isBusy();
+ method @Deprecated public void join(android.net.rtp.AudioGroup);
+ method @Deprecated public void setCodec(android.net.rtp.AudioCodec);
+ method @Deprecated public void setDtmfType(int);
}
- public class RtpStream {
- method public void associate(java.net.InetAddress, int);
- method public java.net.InetAddress getLocalAddress();
- method public int getLocalPort();
- method public int getMode();
- method public java.net.InetAddress getRemoteAddress();
- method public int getRemotePort();
- method public boolean isBusy();
- method public void release();
- method public void setMode(int);
- field public static final int MODE_NORMAL = 0; // 0x0
- field public static final int MODE_RECEIVE_ONLY = 2; // 0x2
- field public static final int MODE_SEND_ONLY = 1; // 0x1
+ @Deprecated public class RtpStream {
+ method @Deprecated public void associate(java.net.InetAddress, int);
+ method @Deprecated public java.net.InetAddress getLocalAddress();
+ method @Deprecated public int getLocalPort();
+ method @Deprecated public int getMode();
+ method @Deprecated public java.net.InetAddress getRemoteAddress();
+ method @Deprecated public int getRemotePort();
+ method @Deprecated public boolean isBusy();
+ method @Deprecated public void release();
+ method @Deprecated public void setMode(int);
+ field @Deprecated public static final int MODE_NORMAL = 0; // 0x0
+ field @Deprecated public static final int MODE_RECEIVE_ONLY = 2; // 0x2
+ field @Deprecated public static final int MODE_SEND_ONLY = 1; // 0x1
}
}
package android.net.sip {
- public class SipAudioCall {
- ctor public SipAudioCall(android.content.Context, android.net.sip.SipProfile);
- method public void answerCall(int) throws android.net.sip.SipException;
- method public void attachCall(android.net.sip.SipSession, String) throws android.net.sip.SipException;
- method public void close();
- method public void continueCall(int) throws android.net.sip.SipException;
- method public void endCall() throws android.net.sip.SipException;
- method public android.net.sip.SipProfile getLocalProfile();
- method public android.net.sip.SipProfile getPeerProfile();
- method public int getState();
- method public void holdCall(int) throws android.net.sip.SipException;
- method public boolean isInCall();
- method public boolean isMuted();
- method public boolean isOnHold();
- method public void makeCall(android.net.sip.SipProfile, android.net.sip.SipSession, int) throws android.net.sip.SipException;
- method public void sendDtmf(int);
- method public void sendDtmf(int, android.os.Message);
- method public void setListener(android.net.sip.SipAudioCall.Listener);
- method public void setListener(android.net.sip.SipAudioCall.Listener, boolean);
- method public void setSpeakerMode(boolean);
- method public void startAudio();
- method public void toggleMute();
+ @Deprecated public class SipAudioCall {
+ ctor @Deprecated public SipAudioCall(android.content.Context, android.net.sip.SipProfile);
+ method @Deprecated public void answerCall(int) throws android.net.sip.SipException;
+ method @Deprecated public void attachCall(android.net.sip.SipSession, String) throws android.net.sip.SipException;
+ method @Deprecated public void close();
+ method @Deprecated public void continueCall(int) throws android.net.sip.SipException;
+ method @Deprecated public void endCall() throws android.net.sip.SipException;
+ method @Deprecated public android.net.sip.SipProfile getLocalProfile();
+ method @Deprecated public android.net.sip.SipProfile getPeerProfile();
+ method @Deprecated public int getState();
+ method @Deprecated public void holdCall(int) throws android.net.sip.SipException;
+ method @Deprecated public boolean isInCall();
+ method @Deprecated public boolean isMuted();
+ method @Deprecated public boolean isOnHold();
+ method @Deprecated public void makeCall(android.net.sip.SipProfile, android.net.sip.SipSession, int) throws android.net.sip.SipException;
+ method @Deprecated public void sendDtmf(int);
+ method @Deprecated public void sendDtmf(int, android.os.Message);
+ method @Deprecated public void setListener(android.net.sip.SipAudioCall.Listener);
+ method @Deprecated public void setListener(android.net.sip.SipAudioCall.Listener, boolean);
+ method @Deprecated public void setSpeakerMode(boolean);
+ method @Deprecated public void startAudio();
+ method @Deprecated public void toggleMute();
}
- public static class SipAudioCall.Listener {
- ctor public SipAudioCall.Listener();
- method public void onCallBusy(android.net.sip.SipAudioCall);
- method public void onCallEnded(android.net.sip.SipAudioCall);
- method public void onCallEstablished(android.net.sip.SipAudioCall);
- method public void onCallHeld(android.net.sip.SipAudioCall);
- method public void onCalling(android.net.sip.SipAudioCall);
- method public void onChanged(android.net.sip.SipAudioCall);
- method public void onError(android.net.sip.SipAudioCall, int, String);
- method public void onReadyToCall(android.net.sip.SipAudioCall);
- method public void onRinging(android.net.sip.SipAudioCall, android.net.sip.SipProfile);
- method public void onRingingBack(android.net.sip.SipAudioCall);
+ @Deprecated public static class SipAudioCall.Listener {
+ ctor @Deprecated public SipAudioCall.Listener();
+ method @Deprecated public void onCallBusy(android.net.sip.SipAudioCall);
+ method @Deprecated public void onCallEnded(android.net.sip.SipAudioCall);
+ method @Deprecated public void onCallEstablished(android.net.sip.SipAudioCall);
+ method @Deprecated public void onCallHeld(android.net.sip.SipAudioCall);
+ method @Deprecated public void onCalling(android.net.sip.SipAudioCall);
+ method @Deprecated public void onChanged(android.net.sip.SipAudioCall);
+ method @Deprecated public void onError(android.net.sip.SipAudioCall, int, String);
+ method @Deprecated public void onReadyToCall(android.net.sip.SipAudioCall);
+ method @Deprecated public void onRinging(android.net.sip.SipAudioCall, android.net.sip.SipProfile);
+ method @Deprecated public void onRingingBack(android.net.sip.SipAudioCall);
}
- public class SipErrorCode {
- method public static String toString(int);
- field public static final int CLIENT_ERROR = -4; // 0xfffffffc
- field public static final int CROSS_DOMAIN_AUTHENTICATION = -11; // 0xfffffff5
- field public static final int DATA_CONNECTION_LOST = -10; // 0xfffffff6
- field public static final int INVALID_CREDENTIALS = -8; // 0xfffffff8
- field public static final int INVALID_REMOTE_URI = -6; // 0xfffffffa
- field public static final int IN_PROGRESS = -9; // 0xfffffff7
- field public static final int NO_ERROR = 0; // 0x0
- field public static final int PEER_NOT_REACHABLE = -7; // 0xfffffff9
- field public static final int SERVER_ERROR = -2; // 0xfffffffe
- field public static final int SERVER_UNREACHABLE = -12; // 0xfffffff4
- field public static final int SOCKET_ERROR = -1; // 0xffffffff
- field public static final int TIME_OUT = -5; // 0xfffffffb
- field public static final int TRANSACTION_TERMINTED = -3; // 0xfffffffd
+ @Deprecated public class SipErrorCode {
+ method @Deprecated public static String toString(int);
+ field @Deprecated public static final int CLIENT_ERROR = -4; // 0xfffffffc
+ field @Deprecated public static final int CROSS_DOMAIN_AUTHENTICATION = -11; // 0xfffffff5
+ field @Deprecated public static final int DATA_CONNECTION_LOST = -10; // 0xfffffff6
+ field @Deprecated public static final int INVALID_CREDENTIALS = -8; // 0xfffffff8
+ field @Deprecated public static final int INVALID_REMOTE_URI = -6; // 0xfffffffa
+ field @Deprecated public static final int IN_PROGRESS = -9; // 0xfffffff7
+ field @Deprecated public static final int NO_ERROR = 0; // 0x0
+ field @Deprecated public static final int PEER_NOT_REACHABLE = -7; // 0xfffffff9
+ field @Deprecated public static final int SERVER_ERROR = -2; // 0xfffffffe
+ field @Deprecated public static final int SERVER_UNREACHABLE = -12; // 0xfffffff4
+ field @Deprecated public static final int SOCKET_ERROR = -1; // 0xffffffff
+ field @Deprecated public static final int TIME_OUT = -5; // 0xfffffffb
+ field @Deprecated public static final int TRANSACTION_TERMINTED = -3; // 0xfffffffd
}
- public class SipException extends java.lang.Exception {
- ctor public SipException();
- ctor public SipException(String);
- ctor public SipException(String, Throwable);
+ @Deprecated public class SipException extends java.lang.Exception {
+ ctor @Deprecated public SipException();
+ ctor @Deprecated public SipException(String);
+ ctor @Deprecated public SipException(String, Throwable);
}
- public class SipManager {
- method public void close(String) throws android.net.sip.SipException;
- method public android.net.sip.SipSession createSipSession(android.net.sip.SipProfile, android.net.sip.SipSession.Listener) throws android.net.sip.SipException;
- method public static String getCallId(android.content.Intent);
- method public static String getOfferSessionDescription(android.content.Intent);
- method public android.net.sip.SipSession getSessionFor(android.content.Intent) throws android.net.sip.SipException;
- method public static boolean isApiSupported(android.content.Context);
- method public static boolean isIncomingCallIntent(android.content.Intent);
- method public boolean isOpened(String) throws android.net.sip.SipException;
- method public boolean isRegistered(String) throws android.net.sip.SipException;
- method public static boolean isSipWifiOnly(android.content.Context);
- method public static boolean isVoipSupported(android.content.Context);
- method public android.net.sip.SipAudioCall makeAudioCall(android.net.sip.SipProfile, android.net.sip.SipProfile, android.net.sip.SipAudioCall.Listener, int) throws android.net.sip.SipException;
- method public android.net.sip.SipAudioCall makeAudioCall(String, String, android.net.sip.SipAudioCall.Listener, int) throws android.net.sip.SipException;
- method public static android.net.sip.SipManager newInstance(android.content.Context);
- method public void open(android.net.sip.SipProfile) throws android.net.sip.SipException;
- method public void open(android.net.sip.SipProfile, android.app.PendingIntent, android.net.sip.SipRegistrationListener) throws android.net.sip.SipException;
- method public void register(android.net.sip.SipProfile, int, android.net.sip.SipRegistrationListener) throws android.net.sip.SipException;
- method public void setRegistrationListener(String, android.net.sip.SipRegistrationListener) throws android.net.sip.SipException;
- method public android.net.sip.SipAudioCall takeAudioCall(android.content.Intent, android.net.sip.SipAudioCall.Listener) throws android.net.sip.SipException;
- method public void unregister(android.net.sip.SipProfile, android.net.sip.SipRegistrationListener) throws android.net.sip.SipException;
- field public static final String EXTRA_CALL_ID = "android:sipCallID";
- field public static final String EXTRA_OFFER_SD = "android:sipOfferSD";
- field public static final int INCOMING_CALL_RESULT_CODE = 101; // 0x65
+ @Deprecated public class SipManager {
+ method @Deprecated public void close(String) throws android.net.sip.SipException;
+ method @Deprecated public android.net.sip.SipSession createSipSession(android.net.sip.SipProfile, android.net.sip.SipSession.Listener) throws android.net.sip.SipException;
+ method @Deprecated public static String getCallId(android.content.Intent);
+ method @Deprecated public static String getOfferSessionDescription(android.content.Intent);
+ method @Deprecated public android.net.sip.SipSession getSessionFor(android.content.Intent) throws android.net.sip.SipException;
+ method @Deprecated public static boolean isApiSupported(android.content.Context);
+ method @Deprecated public static boolean isIncomingCallIntent(android.content.Intent);
+ method @Deprecated public boolean isOpened(String) throws android.net.sip.SipException;
+ method @Deprecated public boolean isRegistered(String) throws android.net.sip.SipException;
+ method @Deprecated public static boolean isSipWifiOnly(android.content.Context);
+ method @Deprecated public static boolean isVoipSupported(android.content.Context);
+ method @Deprecated public android.net.sip.SipAudioCall makeAudioCall(android.net.sip.SipProfile, android.net.sip.SipProfile, android.net.sip.SipAudioCall.Listener, int) throws android.net.sip.SipException;
+ method @Deprecated public android.net.sip.SipAudioCall makeAudioCall(String, String, android.net.sip.SipAudioCall.Listener, int) throws android.net.sip.SipException;
+ method @Deprecated public static android.net.sip.SipManager newInstance(android.content.Context);
+ method @Deprecated public void open(android.net.sip.SipProfile) throws android.net.sip.SipException;
+ method @Deprecated public void open(android.net.sip.SipProfile, android.app.PendingIntent, android.net.sip.SipRegistrationListener) throws android.net.sip.SipException;
+ method @Deprecated public void register(android.net.sip.SipProfile, int, android.net.sip.SipRegistrationListener) throws android.net.sip.SipException;
+ method @Deprecated public void setRegistrationListener(String, android.net.sip.SipRegistrationListener) throws android.net.sip.SipException;
+ method @Deprecated public android.net.sip.SipAudioCall takeAudioCall(android.content.Intent, android.net.sip.SipAudioCall.Listener) throws android.net.sip.SipException;
+ method @Deprecated public void unregister(android.net.sip.SipProfile, android.net.sip.SipRegistrationListener) throws android.net.sip.SipException;
+ field @Deprecated public static final String EXTRA_CALL_ID = "android:sipCallID";
+ field @Deprecated public static final String EXTRA_OFFER_SD = "android:sipOfferSD";
+ field @Deprecated public static final int INCOMING_CALL_RESULT_CODE = 101; // 0x65
}
- public class SipProfile implements java.lang.Cloneable android.os.Parcelable java.io.Serializable {
- method public int describeContents();
- method public String getAuthUserName();
- method public boolean getAutoRegistration();
- method public String getDisplayName();
- method public String getPassword();
- method public int getPort();
- method public String getProfileName();
- method public String getProtocol();
- method public String getProxyAddress();
- method public boolean getSendKeepAlive();
- method public String getSipDomain();
- method public String getUriString();
- method public String getUserName();
- method public void setCallingUid(int);
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.net.sip.SipProfile> CREATOR;
+ @Deprecated public class SipProfile implements java.lang.Cloneable android.os.Parcelable java.io.Serializable {
+ method @Deprecated public int describeContents();
+ method @Deprecated public String getAuthUserName();
+ method @Deprecated public boolean getAutoRegistration();
+ method @Deprecated public String getDisplayName();
+ method @Deprecated public String getPassword();
+ method @Deprecated public int getPort();
+ method @Deprecated public String getProfileName();
+ method @Deprecated public String getProtocol();
+ method @Deprecated public String getProxyAddress();
+ method @Deprecated public boolean getSendKeepAlive();
+ method @Deprecated public String getSipDomain();
+ method @Deprecated public String getUriString();
+ method @Deprecated public String getUserName();
+ method @Deprecated public void setCallingUid(int);
+ method @Deprecated public void writeToParcel(android.os.Parcel, int);
+ field @Deprecated public static final android.os.Parcelable.Creator<android.net.sip.SipProfile> CREATOR;
}
- public static class SipProfile.Builder {
- ctor public SipProfile.Builder(android.net.sip.SipProfile);
- ctor public SipProfile.Builder(String) throws java.text.ParseException;
- ctor public SipProfile.Builder(String, String) throws java.text.ParseException;
- method public android.net.sip.SipProfile build();
- method public android.net.sip.SipProfile.Builder setAuthUserName(String);
- method public android.net.sip.SipProfile.Builder setAutoRegistration(boolean);
- method public android.net.sip.SipProfile.Builder setDisplayName(String);
- method public android.net.sip.SipProfile.Builder setOutboundProxy(String);
- method public android.net.sip.SipProfile.Builder setPassword(String);
- method public android.net.sip.SipProfile.Builder setPort(int) throws java.lang.IllegalArgumentException;
- method public android.net.sip.SipProfile.Builder setProfileName(String);
- method public android.net.sip.SipProfile.Builder setProtocol(String) throws java.lang.IllegalArgumentException;
- method public android.net.sip.SipProfile.Builder setSendKeepAlive(boolean);
+ @Deprecated public static class SipProfile.Builder {
+ ctor @Deprecated public SipProfile.Builder(android.net.sip.SipProfile);
+ ctor @Deprecated public SipProfile.Builder(String) throws java.text.ParseException;
+ ctor @Deprecated public SipProfile.Builder(String, String) throws java.text.ParseException;
+ method @Deprecated public android.net.sip.SipProfile build();
+ method @Deprecated public android.net.sip.SipProfile.Builder setAuthUserName(String);
+ method @Deprecated public android.net.sip.SipProfile.Builder setAutoRegistration(boolean);
+ method @Deprecated public android.net.sip.SipProfile.Builder setDisplayName(String);
+ method @Deprecated public android.net.sip.SipProfile.Builder setOutboundProxy(String);
+ method @Deprecated public android.net.sip.SipProfile.Builder setPassword(String);
+ method @Deprecated public android.net.sip.SipProfile.Builder setPort(int) throws java.lang.IllegalArgumentException;
+ method @Deprecated public android.net.sip.SipProfile.Builder setProfileName(String);
+ method @Deprecated public android.net.sip.SipProfile.Builder setProtocol(String) throws java.lang.IllegalArgumentException;
+ method @Deprecated public android.net.sip.SipProfile.Builder setSendKeepAlive(boolean);
}
- public interface SipRegistrationListener {
- method public void onRegistering(String);
- method public void onRegistrationDone(String, long);
- method public void onRegistrationFailed(String, int, String);
+ @Deprecated public interface SipRegistrationListener {
+ method @Deprecated public void onRegistering(String);
+ method @Deprecated public void onRegistrationDone(String, long);
+ method @Deprecated public void onRegistrationFailed(String, int, String);
}
- public final class SipSession {
- method public void answerCall(String, int);
- method public void changeCall(String, int);
- method public void endCall();
- method public String getCallId();
- method public String getLocalIp();
- method public android.net.sip.SipProfile getLocalProfile();
- method public android.net.sip.SipProfile getPeerProfile();
- method public int getState();
- method public boolean isInCall();
- method public void makeCall(android.net.sip.SipProfile, String, int);
- method public void register(int);
- method public void setListener(android.net.sip.SipSession.Listener);
- method public void unregister();
+ @Deprecated public final class SipSession {
+ method @Deprecated public void answerCall(String, int);
+ method @Deprecated public void changeCall(String, int);
+ method @Deprecated public void endCall();
+ method @Deprecated public String getCallId();
+ method @Deprecated public String getLocalIp();
+ method @Deprecated public android.net.sip.SipProfile getLocalProfile();
+ method @Deprecated public android.net.sip.SipProfile getPeerProfile();
+ method @Deprecated public int getState();
+ method @Deprecated public boolean isInCall();
+ method @Deprecated public void makeCall(android.net.sip.SipProfile, String, int);
+ method @Deprecated public void register(int);
+ method @Deprecated public void setListener(android.net.sip.SipSession.Listener);
+ method @Deprecated public void unregister();
}
- public static class SipSession.Listener {
- ctor public SipSession.Listener();
- method public void onCallBusy(android.net.sip.SipSession);
- method public void onCallChangeFailed(android.net.sip.SipSession, int, String);
- method public void onCallEnded(android.net.sip.SipSession);
- method public void onCallEstablished(android.net.sip.SipSession, String);
- method public void onCalling(android.net.sip.SipSession);
- method public void onError(android.net.sip.SipSession, int, String);
- method public void onRegistering(android.net.sip.SipSession);
- method public void onRegistrationDone(android.net.sip.SipSession, int);
- method public void onRegistrationFailed(android.net.sip.SipSession, int, String);
- method public void onRegistrationTimeout(android.net.sip.SipSession);
- method public void onRinging(android.net.sip.SipSession, android.net.sip.SipProfile, String);
- method public void onRingingBack(android.net.sip.SipSession);
+ @Deprecated public static class SipSession.Listener {
+ ctor @Deprecated public SipSession.Listener();
+ method @Deprecated public void onCallBusy(android.net.sip.SipSession);
+ method @Deprecated public void onCallChangeFailed(android.net.sip.SipSession, int, String);
+ method @Deprecated public void onCallEnded(android.net.sip.SipSession);
+ method @Deprecated public void onCallEstablished(android.net.sip.SipSession, String);
+ method @Deprecated public void onCalling(android.net.sip.SipSession);
+ method @Deprecated public void onError(android.net.sip.SipSession, int, String);
+ method @Deprecated public void onRegistering(android.net.sip.SipSession);
+ method @Deprecated public void onRegistrationDone(android.net.sip.SipSession, int);
+ method @Deprecated public void onRegistrationFailed(android.net.sip.SipSession, int, String);
+ method @Deprecated public void onRegistrationTimeout(android.net.sip.SipSession);
+ method @Deprecated public void onRinging(android.net.sip.SipSession, android.net.sip.SipProfile, String);
+ method @Deprecated public void onRingingBack(android.net.sip.SipSession);
}
- public static class SipSession.State {
- method public static String toString(int);
- field public static final int DEREGISTERING = 2; // 0x2
- field public static final int INCOMING_CALL = 3; // 0x3
- field public static final int INCOMING_CALL_ANSWERING = 4; // 0x4
- field public static final int IN_CALL = 8; // 0x8
- field public static final int NOT_DEFINED = 101; // 0x65
- field public static final int OUTGOING_CALL = 5; // 0x5
- field public static final int OUTGOING_CALL_CANCELING = 7; // 0x7
- field public static final int OUTGOING_CALL_RING_BACK = 6; // 0x6
- field public static final int PINGING = 9; // 0x9
- field public static final int READY_TO_CALL = 0; // 0x0
- field public static final int REGISTERING = 1; // 0x1
+ @Deprecated public static class SipSession.State {
+ method @Deprecated public static String toString(int);
+ field @Deprecated public static final int DEREGISTERING = 2; // 0x2
+ field @Deprecated public static final int INCOMING_CALL = 3; // 0x3
+ field @Deprecated public static final int INCOMING_CALL_ANSWERING = 4; // 0x4
+ field @Deprecated public static final int IN_CALL = 8; // 0x8
+ field @Deprecated public static final int NOT_DEFINED = 101; // 0x65
+ field @Deprecated public static final int OUTGOING_CALL = 5; // 0x5
+ field @Deprecated public static final int OUTGOING_CALL_CANCELING = 7; // 0x7
+ field @Deprecated public static final int OUTGOING_CALL_RING_BACK = 6; // 0x6
+ field @Deprecated public static final int PINGING = 9; // 0x9
+ field @Deprecated public static final int READY_TO_CALL = 0; // 0x0
+ field @Deprecated public static final int REGISTERING = 1; // 0x1
}
}
@@ -25694,17 +25704,14 @@
public final class VcnGatewayConnectionConfig {
method @NonNull public int[] getExposedCapabilities();
method @IntRange(from=android.net.vcn.VcnGatewayConnectionConfig.MIN_MTU_V6) public int getMaxMtu();
- method @NonNull public int[] getRequiredUnderlyingCapabilities();
method @NonNull public long[] getRetryInterval();
}
public static final class VcnGatewayConnectionConfig.Builder {
ctor public VcnGatewayConnectionConfig.Builder(@NonNull android.net.vcn.VcnControlPlaneConfig);
method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder addExposedCapability(int);
- method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder addRequiredUnderlyingCapability(int);
method @NonNull public android.net.vcn.VcnGatewayConnectionConfig build();
method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder removeExposedCapability(int);
- method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder removeRequiredUnderlyingCapability(int);
method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder setMaxMtu(@IntRange(from=android.net.vcn.VcnGatewayConnectionConfig.MIN_MTU_V6) int);
method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder setRetryInterval(@NonNull long[]);
}
@@ -25726,7 +25733,7 @@
public abstract static class VcnManager.VcnStatusCallback {
ctor public VcnManager.VcnStatusCallback();
method public abstract void onGatewayConnectionError(@NonNull int[], int, @Nullable Throwable);
- method public abstract void onVcnStatusChanged(int);
+ method public abstract void onStatusChanged(int);
}
}
@@ -33594,7 +33601,7 @@
field public static final String ACTION_LOCATION_SOURCE_SETTINGS = "android.settings.LOCATION_SOURCE_SETTINGS";
field public static final String ACTION_MANAGE_ALL_APPLICATIONS_SETTINGS = "android.settings.MANAGE_ALL_APPLICATIONS_SETTINGS";
field public static final String ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION = "android.settings.MANAGE_ALL_FILES_ACCESS_PERMISSION";
- field public static final String ACTION_MANAGE_ALL_SUBSCRIPTIONS_SETTINGS = "android.settings.MANAGE_ALL_SUBSCRIPTIONS_SETTINGS";
+ field public static final String ACTION_MANAGE_ALL_SIM_PROFILES_SETTINGS = "android.settings.MANAGE_ALL_SIM_PROFILES_SETTINGS";
field public static final String ACTION_MANAGE_APPLICATIONS_SETTINGS = "android.settings.MANAGE_APPLICATIONS_SETTINGS";
field public static final String ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION = "android.settings.MANAGE_APP_ALL_FILES_ACCESS_PERMISSION";
field public static final String ACTION_MANAGE_DEFAULT_APPS_SETTINGS = "android.settings.MANAGE_DEFAULT_APPS_SETTINGS";
@@ -34222,6 +34229,9 @@
method public static android.net.Uri getUriForSubscriptionIdAndField(int, String);
field public static final String AUTHORITY = "service-state";
field public static final android.net.Uri CONTENT_URI;
+ field public static final String DATA_NETWORK_TYPE = "data_network_type";
+ field public static final String DATA_REG_STATE = "data_reg_state";
+ field public static final String DUPLEX_MODE = "duplex_mode";
field public static final String IS_MANUAL_NETWORK_SELECTION = "is_manual_network_selection";
field public static final String VOICE_OPERATOR_NUMERIC = "voice_operator_numeric";
field public static final String VOICE_REG_STATE = "voice_reg_state";
@@ -38399,22 +38409,22 @@
method public final void conferenceRemoteConnections(android.telecom.RemoteConnection, android.telecom.RemoteConnection);
method public final void connectionServiceFocusReleased();
method @Nullable public final android.telecom.RemoteConference createRemoteIncomingConference(@Nullable android.telecom.PhoneAccountHandle, @Nullable android.telecom.ConnectionRequest);
- method public final android.telecom.RemoteConnection createRemoteIncomingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+ method @Nullable public final android.telecom.RemoteConnection createRemoteIncomingConnection(@NonNull android.telecom.PhoneAccountHandle, @NonNull android.telecom.ConnectionRequest);
method @Nullable public final android.telecom.RemoteConference createRemoteOutgoingConference(@Nullable android.telecom.PhoneAccountHandle, @Nullable android.telecom.ConnectionRequest);
- method public final android.telecom.RemoteConnection createRemoteOutgoingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+ method @Nullable public final android.telecom.RemoteConnection createRemoteOutgoingConnection(@NonNull android.telecom.PhoneAccountHandle, @NonNull android.telecom.ConnectionRequest);
method public final java.util.Collection<android.telecom.Conference> getAllConferences();
method public final java.util.Collection<android.telecom.Connection> getAllConnections();
method public final android.os.IBinder onBind(android.content.Intent);
method public void onConference(android.telecom.Connection, android.telecom.Connection);
method public void onConnectionServiceFocusGained();
method public void onConnectionServiceFocusLost();
- method @Nullable public android.telecom.Conference onCreateIncomingConference(@Nullable android.telecom.PhoneAccountHandle, @Nullable android.telecom.ConnectionRequest);
+ method @Nullable public android.telecom.Conference onCreateIncomingConference(@NonNull android.telecom.PhoneAccountHandle, @NonNull android.telecom.ConnectionRequest);
method public void onCreateIncomingConferenceFailed(@Nullable android.telecom.PhoneAccountHandle, @Nullable android.telecom.ConnectionRequest);
method public android.telecom.Connection onCreateIncomingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public void onCreateIncomingConnectionFailed(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public android.telecom.Connection onCreateIncomingHandoverConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
- method @Nullable public android.telecom.Conference onCreateOutgoingConference(@Nullable android.telecom.PhoneAccountHandle, @Nullable android.telecom.ConnectionRequest);
- method public void onCreateOutgoingConferenceFailed(@Nullable android.telecom.PhoneAccountHandle, @Nullable android.telecom.ConnectionRequest);
+ method @Nullable public android.telecom.Conference onCreateOutgoingConference(@NonNull android.telecom.PhoneAccountHandle, @NonNull android.telecom.ConnectionRequest);
+ method public void onCreateOutgoingConferenceFailed(@NonNull android.telecom.PhoneAccountHandle, @NonNull android.telecom.ConnectionRequest);
method public android.telecom.Connection onCreateOutgoingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public void onCreateOutgoingConnectionFailed(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public android.telecom.Connection onCreateOutgoingHandoverConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
@@ -39099,7 +39109,6 @@
method public static boolean isConfigForIdentifiedCarrier(android.os.PersistableBundle);
method public void notifyConfigChangedForSubId(int);
field public static final String ACTION_CARRIER_CONFIG_CHANGED = "android.telephony.action.CARRIER_CONFIG_CHANGED";
- field public static final int CARRIER_NR_AVAILABILITY_NONE = 0; // 0x0
field public static final int CARRIER_NR_AVAILABILITY_NSA = 1; // 0x1
field public static final int CARRIER_NR_AVAILABILITY_SA = 2; // 0x2
field public static final int DATA_CYCLE_THRESHOLD_DISABLED = -2; // 0xfffffffe
@@ -39160,7 +39169,7 @@
field public static final String KEY_CARRIER_INSTANT_LETTERING_LENGTH_LIMIT_INT = "carrier_instant_lettering_length_limit_int";
field public static final String KEY_CARRIER_NAME_OVERRIDE_BOOL = "carrier_name_override_bool";
field public static final String KEY_CARRIER_NAME_STRING = "carrier_name_string";
- field public static final String KEY_CARRIER_NR_AVAILABILITY_INT = "carrier_nr_availability_int";
+ field public static final String KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY = "carrier_nr_availabilities_int_array";
field public static final String KEY_CARRIER_RCS_PROVISIONING_REQUIRED_BOOL = "carrier_rcs_provisioning_required_bool";
field public static final String KEY_CARRIER_SETTINGS_ACTIVITY_COMPONENT_NAME_STRING = "carrier_settings_activity_component_name_string";
field public static final String KEY_CARRIER_SETTINGS_ENABLE_BOOL = "carrier_settings_enable_bool";
@@ -39229,6 +39238,7 @@
field public static final String KEY_GSM_ROAMING_NETWORKS_STRING_ARRAY = "gsm_roaming_networks_string_array";
field public static final String KEY_HAS_IN_CALL_NOISE_SUPPRESSION_BOOL = "has_in_call_noise_suppression_bool";
field public static final String KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL = "hide_carrier_network_settings_bool";
+ field public static final String KEY_HIDE_ENABLE_2G = "hide_enable_2g_bool";
field public static final String KEY_HIDE_ENHANCED_4G_LTE_BOOL = "hide_enhanced_4g_lte_bool";
field public static final String KEY_HIDE_IMS_APN_BOOL = "hide_ims_apn_bool";
field public static final String KEY_HIDE_LTE_PLUS_DATA_ICON_BOOL = "hide_lte_plus_data_icon_bool";
@@ -39308,6 +39318,7 @@
field public static final String KEY_RTT_SUPPORTED_FOR_VT_BOOL = "rtt_supported_for_vt_bool";
field public static final String KEY_RTT_SUPPORTED_WHILE_ROAMING_BOOL = "rtt_supported_while_roaming_bool";
field public static final String KEY_RTT_UPGRADE_SUPPORTED_BOOL = "rtt_upgrade_supported_bool";
+ field public static final String KEY_RTT_UPGRADE_SUPPORTED_FOR_DOWNGRADED_VT_CALL_BOOL = "rtt_upgrade_supported_for_downgraded_vt_call";
field public static final String KEY_SHOW_4G_FOR_3G_DATA_ICON_BOOL = "show_4g_for_3g_data_icon_bool";
field public static final String KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL = "show_4g_for_lte_data_icon_bool";
field public static final String KEY_SHOW_APN_SETTING_CDMA_BOOL = "show_apn_setting_cdma_bool";
@@ -39350,6 +39361,7 @@
field public static final String KEY_VOICEMAIL_NOTIFICATION_PERSISTENT_BOOL = "voicemail_notification_persistent_bool";
field public static final String KEY_VOICE_PRIVACY_DISABLE_UI_BOOL = "voice_privacy_disable_ui_bool";
field public static final String KEY_VOLTE_REPLACEMENT_RAT_INT = "volte_replacement_rat_int";
+ field public static final String KEY_VT_UPGRADE_SUPPORTED_FOR_DOWNGRADED_RTT_CALL_BOOL = "vt_upgrade_supported_for_downgraded_rtt_call";
field public static final String KEY_VVM_CELLULAR_DATA_REQUIRED_BOOL = "vvm_cellular_data_required_bool";
field public static final String KEY_VVM_CLIENT_PREFIX_STRING = "vvm_client_prefix_string";
field public static final String KEY_VVM_DESTINATION_NUMBER_STRING = "vvm_destination_number_string";
@@ -39392,6 +39404,7 @@
field public static final String KEY_NON_RCS_CAPABILITIES_CACHE_EXPIRATION_SEC_INT = "ims.non_rcs_capabilities_cache_expiration_sec_int";
field public static final String KEY_PREFIX = "ims.";
field public static final String KEY_RCS_BULK_CAPABILITY_EXCHANGE_BOOL = "ims.rcs_bulk_capability_exchange_bool";
+ field public static final String KEY_RCS_FEATURE_TAG_ALLOWED_STRING_ARRAY = "ims.rcs_feature_tag_allowed_string_array";
field public static final String KEY_WIFI_OFF_DEFERRING_TIME_MILLIS_INT = "ims.wifi_off_deferring_time_millis_int";
}
@@ -40663,7 +40676,6 @@
method public static int[] calculateLength(String, boolean);
method @Deprecated public static android.telephony.SmsMessage createFromPdu(byte[]);
method public static android.telephony.SmsMessage createFromPdu(byte[], String);
- method @Nullable public static android.telephony.SmsMessage createSmsSubmitPdu(@NonNull byte[], boolean);
method public String getDisplayMessageBody();
method public String getDisplayOriginatingAddress();
method public String getEmailBody();
@@ -40909,6 +40921,10 @@
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public void onMessageWaitingIndicatorChanged(boolean);
}
+ public static interface TelephonyCallback.PhysicalChannelConfigListener {
+ method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onPhysicalChannelConfigChanged(@NonNull java.util.List<android.telephony.PhysicalChannelConfig>);
+ }
+
public static interface TelephonyCallback.PreciseDataConnectionStateListener {
method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onPreciseDataConnectionStateChanged(@NonNull android.telephony.PreciseDataConnectionState);
}
@@ -41022,6 +41038,7 @@
method @Deprecated public String iccTransmitApduBasicChannel(int, int, int, int, int, String);
method @Deprecated public String iccTransmitApduLogicalChannel(int, int, int, int, int, int, String);
method public boolean isConcurrentVoiceAndDataSupported();
+ method public boolean isDataCapable();
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.READ_PHONE_STATE, "android.permission.READ_PRIVILEGED_PHONE_STATE"}) public boolean isDataConnectionAllowed();
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isDataEnabled();
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isDataEnabledForReason(int);
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index 4d9b4aa..ee53be5 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -20,12 +20,47 @@
}
+package android.content {
+
+ public abstract class Context {
+ field public static final String TEST_NETWORK_SERVICE = "test_network";
+ }
+
+ public class Intent implements java.lang.Cloneable android.os.Parcelable {
+ field public static final String ACTION_CLEAR_DNS_CACHE = "android.intent.action.CLEAR_DNS_CACHE";
+ }
+
+}
+
package android.net {
+ public final class EthernetNetworkSpecifier extends android.net.NetworkSpecifier implements android.os.Parcelable {
+ ctor public EthernetNetworkSpecifier(@NonNull String);
+ method public int describeContents();
+ method @Nullable public String getInterfaceName();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.EthernetNetworkSpecifier> CREATOR;
+ }
+
public static final class IpSecManager.UdpEncapsulationSocket implements java.lang.AutoCloseable {
method public int getResourceId();
}
+ public class NetworkPolicyManager {
+ method @NonNull public static String blockedReasonsToString(int);
+ method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public int getMultipathPreference(@NonNull android.net.Network);
+ method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public int getRestrictBackgroundStatus(int);
+ method public static boolean isUidBlocked(int, boolean);
+ method @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public boolean isUidNetworkingBlocked(int, boolean);
+ method @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public boolean isUidRestrictedOnMeteredNetworks(int);
+ method @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public void registerNetworkPolicyCallback(@Nullable java.util.concurrent.Executor, @NonNull android.net.NetworkPolicyManager.NetworkPolicyCallback);
+ method @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public void unregisterNetworkPolicyCallback(@NonNull android.net.NetworkPolicyManager.NetworkPolicyCallback);
+ }
+
+ public static interface NetworkPolicyManager.NetworkPolicyCallback {
+ method public default void onUidBlockedReasonChanged(int, int);
+ }
+
public final class NetworkStateSnapshot implements android.os.Parcelable {
ctor public NetworkStateSnapshot(@NonNull android.net.Network, @NonNull android.net.NetworkCapabilities, @NonNull android.net.LinkProperties, @Nullable String, int);
method public int describeContents();
@@ -42,6 +77,16 @@
method @Nullable public byte[] getWatchlistConfigHash();
}
+ public class PacProxyManager {
+ method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void addPacProxyInstalledListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.PacProxyManager.PacProxyInstalledListener);
+ method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void removePacProxyInstalledListener(@NonNull android.net.PacProxyManager.PacProxyInstalledListener);
+ method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void setCurrentProxyScriptUrl(@Nullable android.net.ProxyInfo);
+ }
+
+ public static interface PacProxyManager.PacProxyInstalledListener {
+ method public void onPacProxyInstalled(@Nullable android.net.Network, @NonNull android.net.ProxyInfo);
+ }
+
public final class Proxy {
method public static void setHttpProxyConfiguration(@Nullable android.net.ProxyInfo);
}
@@ -56,6 +101,14 @@
field @NonNull public final java.util.List<java.lang.String> underlyingIfaces;
}
+ public class VpnManager {
+ field @Deprecated public static final int TYPE_VPN_LEGACY = 3; // 0x3
+ field public static final int TYPE_VPN_NONE = -1; // 0xffffffff
+ field public static final int TYPE_VPN_OEM = 4; // 0x4
+ field public static final int TYPE_VPN_PLATFORM = 2; // 0x2
+ field public static final int TYPE_VPN_SERVICE = 1; // 0x1
+ }
+
}
package android.os {
@@ -76,6 +129,10 @@
method public default int getStability();
}
+ public class Process {
+ field public static final int VPN_UID = 1016; // 0x3f8
+ }
+
public class StatsServiceManager {
method @NonNull public android.os.StatsServiceManager.ServiceRegisterer getStatsCompanionServiceRegisterer();
method @NonNull public android.os.StatsServiceManager.ServiceRegisterer getStatsManagerServiceRegisterer();
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index dc2e7a7..4676523 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -113,6 +113,7 @@
field public static final String LOOP_RADIO = "android.permission.LOOP_RADIO";
field public static final String MANAGE_ACCESSIBILITY = "android.permission.MANAGE_ACCESSIBILITY";
field public static final String MANAGE_ACTIVITY_STACKS = "android.permission.MANAGE_ACTIVITY_STACKS";
+ field public static final String MANAGE_APP_HIBERNATION = "android.permission.MANAGE_APP_HIBERNATION";
field public static final String MANAGE_APP_OPS_RESTRICTIONS = "android.permission.MANAGE_APP_OPS_RESTRICTIONS";
field public static final String MANAGE_APP_PREDICTIONS = "android.permission.MANAGE_APP_PREDICTIONS";
field public static final String MANAGE_APP_TOKENS = "android.permission.MANAGE_APP_TOKENS";
@@ -160,6 +161,7 @@
field public static final String OBSERVE_NETWORK_POLICY = "android.permission.OBSERVE_NETWORK_POLICY";
field public static final String OBSERVE_ROLE_HOLDERS = "android.permission.OBSERVE_ROLE_HOLDERS";
field public static final String OPEN_ACCESSIBILITY_DETAILS_SETTINGS = "android.permission.OPEN_ACCESSIBILITY_DETAILS_SETTINGS";
+ field public static final String OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD = "android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD";
field public static final String OVERRIDE_WIFI_CONFIG = "android.permission.OVERRIDE_WIFI_CONFIG";
field public static final String PACKAGE_VERIFICATION_AGENT = "android.permission.PACKAGE_VERIFICATION_AGENT";
field public static final String PACKET_KEEPALIVE_OFFLOAD = "android.permission.PACKET_KEEPALIVE_OFFLOAD";
@@ -1124,6 +1126,21 @@
method public static boolean isChangeEnabled(long);
method @RequiresPermission(allOf={"android.permission.READ_COMPAT_CHANGE_CONFIG", "android.permission.LOG_COMPAT_CHANGE"}) public static boolean isChangeEnabled(long, @NonNull String, @NonNull android.os.UserHandle);
method @RequiresPermission(allOf={"android.permission.READ_COMPAT_CHANGE_CONFIG", "android.permission.LOG_COMPAT_CHANGE"}) public static boolean isChangeEnabled(long, int);
+ method @RequiresPermission(android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD) public static void setPackageOverride(@NonNull String, @NonNull java.util.Map<java.lang.Long,android.app.compat.PackageOverride>);
+ }
+
+ public final class PackageOverride {
+ method public long getMaxVersionCode();
+ method public long getMinVersionCode();
+ method public boolean isEnabled();
+ }
+
+ public static final class PackageOverride.Builder {
+ ctor public PackageOverride.Builder();
+ method @NonNull public android.app.compat.PackageOverride build();
+ method @NonNull public android.app.compat.PackageOverride.Builder setEnabled(boolean);
+ method @NonNull public android.app.compat.PackageOverride.Builder setMaxVersionCode(long);
+ method @NonNull public android.app.compat.PackageOverride.Builder setMinVersionCode(long);
}
}
@@ -1421,10 +1438,11 @@
package android.apphibernation {
public final class AppHibernationManager {
- method public boolean isHibernatingForUser(@NonNull String);
- method public boolean isHibernatingGlobally(@NonNull String);
- method public void setHibernatingForUser(@NonNull String, boolean);
- method public void setHibernatingGlobally(@NonNull String, boolean);
+ method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_APP_HIBERNATION) public java.util.List<java.lang.String> getHibernatingPackagesForUser();
+ method @RequiresPermission(android.Manifest.permission.MANAGE_APP_HIBERNATION) public boolean isHibernatingForUser(@NonNull String);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_APP_HIBERNATION) public boolean isHibernatingGlobally(@NonNull String);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_APP_HIBERNATION) public void setHibernatingForUser(@NonNull String, boolean);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_APP_HIBERNATION) public void setHibernatingGlobally(@NonNull String, boolean);
}
}
@@ -1480,6 +1498,7 @@
public final class BluetoothDevice implements android.os.Parcelable {
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean cancelBondProcess();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean createBondOutOfBand(int, @Nullable android.bluetooth.OobData, @Nullable android.bluetooth.OobData);
method @Nullable @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public byte[] getMetadata(int);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getSimAccessPermission();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean isConnected();
@@ -1530,7 +1549,6 @@
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean disconnect(android.bluetooth.BluetoothDevice);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
- method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean setPriority(android.bluetooth.BluetoothDevice, int);
}
public final class BluetoothHearingAid implements android.bluetooth.BluetoothProfile {
@@ -1656,6 +1674,55 @@
field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BufferConstraints> CREATOR;
}
+ public final class OobData implements android.os.Parcelable {
+ method @NonNull public static android.bluetooth.OobData.ClassicBuilder createClassicBuilder(@NonNull byte[], @NonNull byte[], @NonNull byte[]);
+ method @NonNull public static android.bluetooth.OobData.LeBuilder createLeBuilder(@NonNull byte[], @NonNull byte[], int);
+ method @NonNull public byte[] getClassOfDevice();
+ method @NonNull public byte[] getClassicLength();
+ method @NonNull public byte[] getConfirmationHash();
+ method @NonNull public byte[] getDeviceAddressWithType();
+ method @Nullable public byte[] getDeviceName();
+ method @Nullable public byte[] getLeAppearance();
+ method @NonNull public int getLeDeviceRole();
+ method @NonNull public int getLeFlags();
+ method @Nullable public byte[] getLeTemporaryKey();
+ method @NonNull public byte[] getRandomizerHash();
+ field public static final int CLASS_OF_DEVICE_OCTETS = 3; // 0x3
+ field public static final int CONFIRMATION_OCTETS = 16; // 0x10
+ field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.OobData> CREATOR;
+ field public static final int DEVICE_ADDRESS_OCTETS = 7; // 0x7
+ field public static final int LE_APPEARANCE_OCTETS = 2; // 0x2
+ field public static final int LE_DEVICE_FLAG_OCTETS = 1; // 0x1
+ field public static final int LE_DEVICE_ROLE_BOTH_PREFER_CENTRAL = 3; // 0x3
+ field public static final int LE_DEVICE_ROLE_BOTH_PREFER_PERIPHERAL = 2; // 0x2
+ field public static final int LE_DEVICE_ROLE_CENTRAL_ONLY = 1; // 0x1
+ field public static final int LE_DEVICE_ROLE_OCTETS = 1; // 0x1
+ field public static final int LE_DEVICE_ROLE_PERIPHERAL_ONLY = 0; // 0x0
+ field public static final int LE_FLAG_BREDR_NOT_SUPPORTED = 2; // 0x2
+ field public static final int LE_FLAG_GENERAL_DISCOVERY_MODE = 1; // 0x1
+ field public static final int LE_FLAG_LIMITED_DISCOVERY_MODE = 0; // 0x0
+ field public static final int LE_FLAG_SIMULTANEOUS_CONTROLLER = 3; // 0x3
+ field public static final int LE_FLAG_SIMULTANEOUS_HOST = 4; // 0x4
+ field public static final int LE_TK_OCTETS = 16; // 0x10
+ field public static final int OOB_LENGTH_OCTETS = 2; // 0x2
+ field public static final int RANDOMIZER_OCTETS = 16; // 0x10
+ }
+
+ public static final class OobData.ClassicBuilder {
+ method @NonNull public android.bluetooth.OobData build();
+ method @NonNull public android.bluetooth.OobData.ClassicBuilder setClassOfDevice(@NonNull byte[]);
+ method @NonNull public android.bluetooth.OobData.ClassicBuilder setDeviceName(@NonNull byte[]);
+ method @NonNull public android.bluetooth.OobData.ClassicBuilder setRandomizerHash(@NonNull byte[]);
+ }
+
+ public static final class OobData.LeBuilder {
+ method @NonNull public android.bluetooth.OobData build();
+ method @NonNull public android.bluetooth.OobData.LeBuilder setDeviceName(@NonNull byte[]);
+ method @NonNull public android.bluetooth.OobData.LeBuilder setLeFlags(int);
+ method @NonNull public android.bluetooth.OobData.LeBuilder setLeTemporaryKey(@NonNull byte[]);
+ method @NonNull public android.bluetooth.OobData.LeBuilder setRandomizerHash(@NonNull byte[]);
+ }
+
}
package android.bluetooth.le {
@@ -1676,7 +1743,19 @@
field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.le.ResultStorageDescriptor> CREATOR;
}
+ public final class ScanFilter implements android.os.Parcelable {
+ method public int getAddressType();
+ method @Nullable public byte[] getIrk();
+ }
+
+ public static final class ScanFilter.Builder {
+ method @NonNull public android.bluetooth.le.ScanFilter.Builder setDeviceAddress(@NonNull String, int);
+ method @NonNull public android.bluetooth.le.ScanFilter.Builder setDeviceAddress(@NonNull String, int, @NonNull byte[]);
+ field public static final int LEN_IRK_OCTETS = 16; // 0x10
+ }
+
public final class ScanSettings implements android.os.Parcelable {
+ field public static final int SCAN_MODE_AMBIENT_DISCOVERY = 3; // 0x3
field public static final int SCAN_RESULT_TYPE_ABBREVIATED = 1; // 0x1
field public static final int SCAN_RESULT_TYPE_FULL = 0; // 0x0
}
@@ -6373,22 +6452,22 @@
package android.net.sip {
- public class SipAudioCall {
- method @Nullable public android.net.rtp.AudioGroup getAudioGroup();
- method public void setAudioGroup(@NonNull android.net.rtp.AudioGroup);
+ @Deprecated public class SipAudioCall {
+ method @Deprecated @Nullable public android.net.rtp.AudioGroup getAudioGroup();
+ method @Deprecated public void setAudioGroup(@NonNull android.net.rtp.AudioGroup);
}
- public class SipManager {
- method @NonNull public java.util.List<android.net.sip.SipProfile> getProfiles() throws android.net.sip.SipException;
- field public static final String ACTION_SIP_CALL_OPTION_CHANGED = "android.net.sip.action.SIP_CALL_OPTION_CHANGED";
- field public static final String ACTION_SIP_INCOMING_CALL = "android.net.sip.action.SIP_INCOMING_CALL";
- field public static final String ACTION_SIP_REMOVE_PROFILE = "android.net.sip.action.SIP_REMOVE_PROFILE";
- field public static final String ACTION_SIP_SERVICE_UP = "android.net.sip.action.SIP_SERVICE_UP";
- field public static final String ACTION_START_SIP = "android.net.sip.action.START_SIP";
+ @Deprecated public class SipManager {
+ method @Deprecated @NonNull public java.util.List<android.net.sip.SipProfile> getProfiles() throws android.net.sip.SipException;
+ field @Deprecated public static final String ACTION_SIP_CALL_OPTION_CHANGED = "android.net.sip.action.SIP_CALL_OPTION_CHANGED";
+ field @Deprecated public static final String ACTION_SIP_INCOMING_CALL = "android.net.sip.action.SIP_INCOMING_CALL";
+ field @Deprecated public static final String ACTION_SIP_REMOVE_PROFILE = "android.net.sip.action.SIP_REMOVE_PROFILE";
+ field @Deprecated public static final String ACTION_SIP_SERVICE_UP = "android.net.sip.action.SIP_SERVICE_UP";
+ field @Deprecated public static final String ACTION_START_SIP = "android.net.sip.action.START_SIP";
}
- public class SipProfile implements java.lang.Cloneable android.os.Parcelable java.io.Serializable {
- method public int getCallingUid();
+ @Deprecated public class SipProfile implements java.lang.Cloneable android.os.Parcelable java.io.Serializable {
+ method @Deprecated public int getCallingUid();
}
}
@@ -6409,12 +6488,12 @@
package android.net.vcn {
public class VcnManager {
- method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public void addVcnNetworkPolicyListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.vcn.VcnManager.VcnNetworkPolicyListener);
+ method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public void addVcnNetworkPolicyChangeListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.vcn.VcnManager.VcnNetworkPolicyChangeListener);
method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.vcn.VcnNetworkPolicyResult applyVcnNetworkPolicy(@NonNull android.net.NetworkCapabilities, @NonNull android.net.LinkProperties);
- method public void removeVcnNetworkPolicyListener(@NonNull android.net.vcn.VcnManager.VcnNetworkPolicyListener);
+ method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public void removeVcnNetworkPolicyChangeListener(@NonNull android.net.vcn.VcnManager.VcnNetworkPolicyChangeListener);
}
- public static interface VcnManager.VcnNetworkPolicyListener {
+ public static interface VcnManager.VcnNetworkPolicyChangeListener {
method public void onPolicyChanged();
}
@@ -9356,6 +9435,10 @@
field public static final String KEY_SUPPORT_CDMA_1X_VOICE_CALLS_BOOL = "support_cdma_1x_voice_calls_bool";
}
+ public static final class CarrierConfigManager.Ims {
+ field public static final String KEY_PUBLISH_SERVICE_DESC_FEATURE_TAG_MAP_OVERRIDE_STRING_ARRAY = "ims.publish_service_desc_feature_tag_map_override_string_array";
+ }
+
public static final class CarrierConfigManager.Wifi {
field public static final String KEY_HOTSPOT_MAX_CLIENT_COUNT = "wifi.hotspot_maximum_client_count";
field public static final String KEY_PREFIX = "wifi.";
@@ -9471,7 +9554,8 @@
public final class DataSpecificRegistrationInfo implements android.os.Parcelable {
method public int describeContents();
- method @NonNull public android.telephony.LteVopsSupportInfo getLteVopsSupportInfo();
+ method @Deprecated @NonNull public android.telephony.LteVopsSupportInfo getLteVopsSupportInfo();
+ method @Nullable public android.telephony.VopsSupportInfo getVopsSupportInfo();
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.telephony.DataSpecificRegistrationInfo> CREATOR;
}
@@ -9503,14 +9587,29 @@
field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ImsiEncryptionInfo> CREATOR;
}
- public final class LteVopsSupportInfo implements android.os.Parcelable {
- ctor public LteVopsSupportInfo(int, int);
+ public final class LinkCapacityEstimate implements android.os.Parcelable {
+ ctor public LinkCapacityEstimate(int, int, int);
method public int describeContents();
+ method public int getDownlinkCapacityKbps();
+ method public int getType();
+ method public int getUplinkCapacityKbps();
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.LinkCapacityEstimate> CREATOR;
+ field public static final int INVALID = -1; // 0xffffffff
+ field public static final int LCE_TYPE_COMBINED = 2; // 0x2
+ field public static final int LCE_TYPE_PRIMARY = 0; // 0x0
+ field public static final int LCE_TYPE_SECONDARY = 1; // 0x1
+ }
+
+ public final class LteVopsSupportInfo extends android.telephony.VopsSupportInfo {
+ ctor public LteVopsSupportInfo(int, int);
method public int getEmcBearerSupport();
method public int getVopsSupport();
- method public void writeToParcel(android.os.Parcel, int);
+ method public boolean isEmergencyServiceFallbackSupported();
+ method public boolean isEmergencyServiceSupported();
+ method public boolean isVopsSupported();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.telephony.LteVopsSupportInfo> CREATOR;
- field public static final int LTE_STATUS_NOT_AVAILABLE = 1; // 0x1
+ field @Deprecated public static final int LTE_STATUS_NOT_AVAILABLE = 1; // 0x1
field public static final int LTE_STATUS_NOT_SUPPORTED = 3; // 0x3
field public static final int LTE_STATUS_SUPPORTED = 2; // 0x2
}
@@ -9581,6 +9680,29 @@
field public static final int RESULT_SUCCESS = 0; // 0x0
}
+ public final class NrVopsSupportInfo extends android.telephony.VopsSupportInfo {
+ ctor public NrVopsSupportInfo(int, int, int);
+ method public int getEmcSupport();
+ method public int getEmfSupport();
+ method public int getVopsSupport();
+ method public boolean isEmergencyServiceFallbackSupported();
+ method public boolean isEmergencyServiceSupported();
+ method public boolean isVopsSupported();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.NrVopsSupportInfo> CREATOR;
+ field public static final int NR_STATUS_EMC_5GCN_ONLY = 1; // 0x1
+ field public static final int NR_STATUS_EMC_EUTRA_5GCN_ONLY = 2; // 0x2
+ field public static final int NR_STATUS_EMC_NOT_SUPPORTED = 0; // 0x0
+ field public static final int NR_STATUS_EMC_NR_EUTRA_5GCN = 3; // 0x3
+ field public static final int NR_STATUS_EMF_5GCN_ONLY = 1; // 0x1
+ field public static final int NR_STATUS_EMF_EUTRA_5GCN_ONLY = 2; // 0x2
+ field public static final int NR_STATUS_EMF_NOT_SUPPORTED = 0; // 0x0
+ field public static final int NR_STATUS_EMF_NR_EUTRA_5GCN = 3; // 0x3
+ field public static final int NR_STATUS_VOPS_3GPP_SUPPORTED = 1; // 0x1
+ field public static final int NR_STATUS_VOPS_NON_3GPP_SUPPORTED = 2; // 0x2
+ field public static final int NR_STATUS_VOPS_NOT_SUPPORTED = 0; // 0x0
+ }
+
public interface NumberVerificationCallback {
method public default void onCallReceived(@NonNull String);
method public default void onVerificationFailed(int);
@@ -9979,6 +10101,8 @@
field public static final int EVENT_DISPLAY_INFO_CHANGED = 21; // 0x15
field @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public static final int EVENT_EMERGENCY_NUMBER_LIST_CHANGED = 25; // 0x19
field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED = 28; // 0x1c
+ field @RequiresPermission(android.Manifest.permission.READ_CALL_LOG) public static final int EVENT_LEGACY_CALL_STATE_CHANGED = 36; // 0x24
+ field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_LINK_CAPACITY_ESTIMATE_CHANGED = 37; // 0x25
field @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public static final int EVENT_MESSAGE_WAITING_INDICATOR_CHANGED = 3; // 0x3
field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int EVENT_OEM_HOOK_RAW = 15; // 0xf
field @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public static final int EVENT_OUTGOING_EMERGENCY_CALL = 29; // 0x1d
@@ -9998,7 +10122,7 @@
}
public static interface TelephonyCallback.AllowedNetworkTypesListener {
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void onAllowedNetworkTypesChanged(@NonNull java.util.Map<java.lang.Integer,java.lang.Long>);
+ method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void onAllowedNetworkTypesChanged(int, long);
}
public static interface TelephonyCallback.CallAttributesListener {
@@ -10009,6 +10133,10 @@
method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onDataEnabledChanged(boolean, int);
}
+ public static interface TelephonyCallback.LinkCapacityEstimateChangedListener {
+ method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onLinkCapacityEstimateChanged(@NonNull java.util.List<android.telephony.LinkCapacityEstimate>);
+ }
+
public static interface TelephonyCallback.OutgoingEmergencyCallListener {
method @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public void onOutgoingEmergencyCall(@NonNull android.telephony.emergency.EmergencyNumber, int);
}
@@ -10021,10 +10149,6 @@
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void onPhoneCapabilityChanged(@NonNull android.telephony.PhoneCapability);
}
- public static interface TelephonyCallback.PhysicalChannelConfigListener {
- method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onPhysicalChannelConfigChanged(@NonNull java.util.List<android.telephony.PhysicalChannelConfig>);
- }
-
public static interface TelephonyCallback.PreciseCallStateListener {
method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onPreciseCallStateChanged(@NonNull android.telephony.PreciseCallState);
}
@@ -10080,7 +10204,6 @@
method @Nullable @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public android.content.ComponentName getAndUpdateDefaultRespondViaMessageApplication();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getCallForwarding(int, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CallForwardingInfoCallback);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getCallWaitingStatus(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
- method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.CarrierBandwidth getCarrierBandwidth();
method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.ImsiEncryptionInfo getCarrierInfoForImsiEncryption(int);
method public java.util.List<java.lang.String> getCarrierPackageNamesForIntent(android.content.Intent);
method public java.util.List<java.lang.String> getCarrierPackageNamesForIntentAndPhone(android.content.Intent, int);
@@ -10139,7 +10262,7 @@
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isIdle();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isLteCdmaEvdoGsmWcdmaEnabled();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isMobileDataPolicyEnabled(int);
- method public boolean isNrDualConnectivityEnabled();
+ method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isNrDualConnectivityEnabled();
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isOffhook();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isOpportunisticNetworkEnabled();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isPotentialEmergencyNumber(@NonNull String);
@@ -10179,7 +10302,7 @@
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.telephony.PinResult setIccLockEnabled(boolean, @NonNull String);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setMobileDataPolicyEnabledStatus(int, boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setMultiSimCarrierRestriction(boolean);
- method public int setNrDualConnectivityState(int);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setNrDualConnectivityState(int);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setOpportunisticNetworkState(boolean);
method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setPreferredNetworkTypeBitmask(long);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setRadio(boolean);
@@ -10216,6 +10339,7 @@
field public static final String ACTION_SIM_CARD_STATE_CHANGED = "android.telephony.action.SIM_CARD_STATE_CHANGED";
field public static final String ACTION_SIM_SLOT_STATUS_CHANGED = "android.telephony.action.SIM_SLOT_STATUS_CHANGED";
field public static final int ALLOWED_NETWORK_TYPES_REASON_CARRIER = 2; // 0x2
+ field public static final int ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G = 3; // 0x3
field public static final int ALLOWED_NETWORK_TYPES_REASON_POWER = 1; // 0x1
field public static final int ALLOWED_NETWORK_TYPES_REASON_USER = 0; // 0x0
field public static final int CALL_WAITING_STATUS_DISABLED = 2; // 0x2
@@ -10223,7 +10347,9 @@
field public static final int CALL_WAITING_STATUS_NOT_SUPPORTED = 4; // 0x4
field public static final int CALL_WAITING_STATUS_UNKNOWN_ERROR = 3; // 0x3
field public static final String CAPABILITY_ALLOWED_NETWORK_TYPES_USED = "CAPABILITY_ALLOWED_NETWORK_TYPES_USED";
+ field public static final String CAPABILITY_NR_DUAL_CONNECTIVITY_CONFIGURATION_AVAILABLE = "CAPABILITY_NR_DUAL_CONNECTIVITY_CONFIGURATION_AVAILABLE";
field public static final String CAPABILITY_SECONDARY_LINK_BANDWIDTH_VISIBLE = "CAPABILITY_SECONDARY_LINK_BANDWIDTH_VISIBLE";
+ field public static final String CAPABILITY_THERMAL_MITIGATION_DATA_THROTTLING = "CAPABILITY_THERMAL_MITIGATION_DATA_THROTTLING";
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
@@ -10377,6 +10503,16 @@
method public static final void setSmsFilterSettings(android.content.Context, android.telecom.PhoneAccountHandle, android.telephony.VisualVoicemailSmsFilterSettings);
}
+ public abstract class VopsSupportInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method public abstract boolean equals(Object);
+ method public abstract int hashCode();
+ method public abstract boolean isEmergencyServiceFallbackSupported();
+ method public abstract boolean isEmergencyServiceSupported();
+ method public abstract boolean isVopsSupported();
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.VopsSupportInfo> CREATOR;
+ }
+
}
package android.telephony.cdma {
@@ -10565,18 +10701,31 @@
}
public final class EpsBearerQosSessionAttributes implements android.os.Parcelable android.net.QosSessionAttributes {
- method @NonNull public static android.telephony.data.EpsBearerQosSessionAttributes create(@NonNull android.os.Parcel);
method public int describeContents();
- method public long getGuaranteedDownlinkBitRate();
- method public long getGuaranteedUplinkBitRate();
- method public long getMaxDownlinkBitRate();
- method public long getMaxUplinkBitRate();
- method public int getQci();
+ method public long getGuaranteedDownlinkBitRateKbps();
+ method public long getGuaranteedUplinkBitRateKbps();
+ method public long getMaxDownlinkBitRateKbps();
+ method public long getMaxUplinkBitRateKbps();
+ method public int getQosIdentifier();
method @NonNull public java.util.List<java.net.InetSocketAddress> getRemoteAddresses();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.EpsBearerQosSessionAttributes> CREATOR;
}
+ public final class NrQosSessionAttributes implements android.os.Parcelable android.net.QosSessionAttributes {
+ method public int describeContents();
+ method @NonNull public java.time.Duration getBitRateWindowDuration();
+ method public long getGuaranteedDownlinkBitRateKbps();
+ method public long getGuaranteedUplinkBitRateKbps();
+ method public long getMaxDownlinkBitRateKbps();
+ method public long getMaxUplinkBitRateKbps();
+ method @IntRange(from=1, to=63) public int getQosFlowIdentifier();
+ method public int getQosIdentifier();
+ method @NonNull public java.util.List<java.net.InetSocketAddress> getRemoteAddresses();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.NrQosSessionAttributes> CREATOR;
+ }
+
public abstract class QualifiedNetworksService extends android.app.Service {
ctor public QualifiedNetworksService();
method @NonNull public abstract android.telephony.data.QualifiedNetworksService.NetworkAvailabilityProvider onCreateNetworkAvailabilityProvider(int);
@@ -11543,6 +11692,7 @@
method public void onAutoConfigurationErrorReceived(int, @NonNull String);
method public void onConfigurationChanged(@NonNull byte[]);
method public void onConfigurationReset();
+ method public void onPreProvisioningReceived(@NonNull byte[]);
method public void onRemoved();
}
@@ -11567,7 +11717,7 @@
method @NonNull public String getServiceId();
method @NonNull public String getServiceVersion();
method @NonNull public String getStatus();
- method @Nullable public String getTimestamp();
+ method @Nullable public java.time.Instant getTime();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.RcsContactPresenceTuple> CREATOR;
field public static final String SERVICE_ID_CALL_COMPOSER = "org.3gpp.urn:urn-7:3gpp-service.ims.icsi.gsma.callcomposer";
@@ -11594,7 +11744,7 @@
method @NonNull public android.telephony.ims.RcsContactPresenceTuple.Builder setContactUri(@NonNull android.net.Uri);
method @NonNull public android.telephony.ims.RcsContactPresenceTuple.Builder setServiceCapabilities(@NonNull android.telephony.ims.RcsContactPresenceTuple.ServiceCapabilities);
method @NonNull public android.telephony.ims.RcsContactPresenceTuple.Builder setServiceDescription(@NonNull String);
- method @NonNull public android.telephony.ims.RcsContactPresenceTuple.Builder setTimestamp(@NonNull String);
+ method @NonNull public android.telephony.ims.RcsContactPresenceTuple.Builder setTime(@NonNull java.time.Instant);
}
public static final class RcsContactPresenceTuple.ServiceCapabilities implements android.os.Parcelable {
@@ -11624,6 +11774,7 @@
method @Nullable public android.telephony.ims.RcsContactPresenceTuple getCapabilityTuple(@NonNull String);
method @NonNull public java.util.List<android.telephony.ims.RcsContactPresenceTuple> getCapabilityTuples();
method @NonNull public android.net.Uri getContactUri();
+ method @NonNull public java.util.Set<java.lang.String> getFeatureTags();
method public int getRequestResult();
method public int getSourceType();
method public void writeToParcel(@NonNull android.os.Parcel, int);
@@ -11638,6 +11789,14 @@
field public static final int SOURCE_TYPE_NETWORK = 0; // 0x0
}
+ public static final class RcsContactUceCapability.OptionsBuilder {
+ ctor public RcsContactUceCapability.OptionsBuilder(@NonNull android.net.Uri);
+ method @NonNull public android.telephony.ims.RcsContactUceCapability.OptionsBuilder addFeatureTag(@NonNull String);
+ method @NonNull public android.telephony.ims.RcsContactUceCapability.OptionsBuilder addFeatureTags(@NonNull java.util.Set<java.lang.String>);
+ method @NonNull public android.telephony.ims.RcsContactUceCapability build();
+ method @NonNull public android.telephony.ims.RcsContactUceCapability.OptionsBuilder setRequestResult(int);
+ }
+
public static final class RcsContactUceCapability.PresenceBuilder {
ctor public RcsContactUceCapability.PresenceBuilder(@NonNull android.net.Uri, int, int);
method @NonNull public android.telephony.ims.RcsContactUceCapability.PresenceBuilder addCapabilityTuple(@NonNull android.telephony.ims.RcsContactPresenceTuple);
@@ -11650,7 +11809,7 @@
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getUcePublishState() throws android.telephony.ims.ImsException;
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void removeOnPublishStateChangedListener(@NonNull android.telephony.ims.RcsUceAdapter.OnPublishStateChangedListener) throws android.telephony.ims.ImsException;
method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_RCS_USER_CAPABILITY_EXCHANGE, android.Manifest.permission.READ_CONTACTS}) public void requestAvailability(@NonNull android.net.Uri, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RcsUceAdapter.CapabilitiesCallback) throws android.telephony.ims.ImsException;
- method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_RCS_USER_CAPABILITY_EXCHANGE, android.Manifest.permission.READ_CONTACTS}) public void requestCapabilities(@NonNull java.util.List<android.net.Uri>, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RcsUceAdapter.CapabilitiesCallback) throws android.telephony.ims.ImsException;
+ method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_RCS_USER_CAPABILITY_EXCHANGE, android.Manifest.permission.READ_CONTACTS}) public void requestCapabilities(@NonNull java.util.Collection<android.net.Uri>, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RcsUceAdapter.CapabilitiesCallback) throws android.telephony.ims.ImsException;
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setUceSettingEnabled(boolean) throws android.telephony.ims.ImsException;
field public static final int CAPABILITY_TYPE_PRESENCE_UCE = 2; // 0x2
field public static final int CAPABILITY_UPDATE_TRIGGER_ETAG_EXPIRED = 1; // 0x1
@@ -11931,7 +12090,7 @@
package android.telephony.ims.stub {
public interface CapabilityExchangeEventListener {
- method public void onRemoteCapabilityRequest(@NonNull android.net.Uri, @NonNull java.util.List<java.lang.String>, @NonNull android.telephony.ims.stub.CapabilityExchangeEventListener.OptionsRequestCallback) throws android.telephony.ims.ImsException;
+ method public void onRemoteCapabilityRequest(@NonNull android.net.Uri, @NonNull java.util.Set<java.lang.String>, @NonNull android.telephony.ims.stub.CapabilityExchangeEventListener.OptionsRequestCallback) throws android.telephony.ims.ImsException;
method public void onRequestPublishCapabilities(int) throws android.telephony.ims.ImsException;
method public void onUnpublish() throws android.telephony.ims.ImsException;
}
@@ -12012,6 +12171,7 @@
method public int getConfigInt(int);
method public String getConfigString(int);
method public final void notifyAutoConfigurationErrorReceived(int, @NonNull String);
+ method public final void notifyPreProvisioningReceived(@NonNull byte[]);
method public final void notifyProvisionedValueChanged(int, int);
method public final void notifyProvisionedValueChanged(int, String);
method public void notifyRcsAutoConfigurationReceived(@NonNull byte[], boolean);
@@ -12126,8 +12286,8 @@
public class RcsCapabilityExchangeImplBase {
ctor public RcsCapabilityExchangeImplBase(@NonNull java.util.concurrent.Executor);
method public void publishCapabilities(@NonNull String, @NonNull android.telephony.ims.stub.RcsCapabilityExchangeImplBase.PublishResponseCallback);
- method public void sendOptionsCapabilityRequest(@NonNull android.net.Uri, @NonNull java.util.List<java.lang.String>, @NonNull android.telephony.ims.stub.RcsCapabilityExchangeImplBase.OptionsResponseCallback);
- method public void subscribeForCapabilities(@NonNull java.util.List<android.net.Uri>, @NonNull android.telephony.ims.stub.RcsCapabilityExchangeImplBase.SubscribeResponseCallback);
+ method public void sendOptionsCapabilityRequest(@NonNull android.net.Uri, @NonNull java.util.Set<java.lang.String>, @NonNull android.telephony.ims.stub.RcsCapabilityExchangeImplBase.OptionsResponseCallback);
+ method public void subscribeForCapabilities(@NonNull java.util.Collection<android.net.Uri>, @NonNull android.telephony.ims.stub.RcsCapabilityExchangeImplBase.SubscribeResponseCallback);
field public static final int COMMAND_CODE_FETCH_ERROR = 3; // 0x3
field public static final int COMMAND_CODE_GENERIC_FAILURE = 1; // 0x1
field public static final int COMMAND_CODE_INSUFFICIENT_MEMORY = 5; // 0x5
@@ -12295,6 +12455,7 @@
package android.uwb {
public final class AngleMeasurement implements android.os.Parcelable {
+ ctor public AngleMeasurement(@FloatRange(from=-3.141592653589793, to=3.141592653589793) double, @FloatRange(from=0.0, to=3.141592653589793) double, @FloatRange(from=0.0, to=1.0) double);
method public int describeContents();
method @FloatRange(from=0.0, to=1.0) public double getConfidenceLevel();
method @FloatRange(from=0.0, to=3.141592653589793) public double getErrorRadians();
@@ -12303,14 +12464,6 @@
field @NonNull public static final android.os.Parcelable.Creator<android.uwb.AngleMeasurement> CREATOR;
}
- public static final class AngleMeasurement.Builder {
- ctor public AngleMeasurement.Builder();
- method @NonNull public android.uwb.AngleMeasurement build();
- method @NonNull public android.uwb.AngleMeasurement.Builder setConfidenceLevel(double);
- method @NonNull public android.uwb.AngleMeasurement.Builder setErrorRadians(double);
- method @NonNull public android.uwb.AngleMeasurement.Builder setRadians(double);
- }
-
public final class AngleOfArrivalMeasurement implements android.os.Parcelable {
method public int describeContents();
method @Nullable public android.uwb.AngleMeasurement getAltitude();
@@ -12320,10 +12473,9 @@
}
public static final class AngleOfArrivalMeasurement.Builder {
- ctor public AngleOfArrivalMeasurement.Builder();
+ ctor public AngleOfArrivalMeasurement.Builder(@NonNull android.uwb.AngleMeasurement);
method @NonNull public android.uwb.AngleOfArrivalMeasurement build();
method @NonNull public android.uwb.AngleOfArrivalMeasurement.Builder setAltitude(@NonNull android.uwb.AngleMeasurement);
- method @NonNull public android.uwb.AngleOfArrivalMeasurement.Builder setAzimuth(@NonNull android.uwb.AngleMeasurement);
}
public final class DistanceMeasurement implements android.os.Parcelable {
@@ -12423,7 +12575,7 @@
public final class UwbManager {
method @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public long elapsedRealtimeResolutionNanos();
method @NonNull @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public android.os.PersistableBundle getSpecificationInfo();
- method @NonNull @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public AutoCloseable openRangingSession(@NonNull android.os.PersistableBundle, @NonNull java.util.concurrent.Executor, @NonNull android.uwb.RangingSession.Callback);
+ method @NonNull @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public android.os.CancellationSignal openRangingSession(@NonNull android.os.PersistableBundle, @NonNull java.util.concurrent.Executor, @NonNull android.uwb.RangingSession.Callback);
method @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public void registerAdapterStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.uwb.UwbManager.AdapterStateCallback);
method @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public void unregisterAdapterStateCallback(@NonNull android.uwb.UwbManager.AdapterStateCallback);
}
diff --git a/core/api/system-removed.txt b/core/api/system-removed.txt
index 0c02c43..8895494 100644
--- a/core/api/system-removed.txt
+++ b/core/api/system-removed.txt
@@ -48,6 +48,14 @@
}
+package android.bluetooth {
+
+ public final class BluetoothHeadset implements android.bluetooth.BluetoothProfile {
+ method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean setPriority(android.bluetooth.BluetoothDevice, int);
+ }
+
+}
+
package android.content {
public class Intent implements java.lang.Cloneable android.os.Parcelable {
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index b0b4556..1d094c3 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -996,6 +996,8 @@
public class NetworkPolicyManager {
method public boolean getRestrictBackground();
+ method @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public boolean isUidNetworkingBlocked(int, boolean);
+ method @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public boolean isUidRestrictedOnMeteredNetworks(int);
method @NonNull public static String resolveNetworkId(@NonNull android.net.wifi.WifiConfiguration);
method public void setRestrictBackground(boolean);
}
@@ -1604,6 +1606,10 @@
method @NonNull public android.telecom.ConnectionRequest.Builder setVideoState(int);
}
+ public abstract class ConnectionService extends android.app.Service {
+ method public void onBindClient(@Nullable android.content.Intent);
+ }
+
}
package android.telephony {
@@ -1646,6 +1652,7 @@
public class ServiceState implements android.os.Parcelable {
method public void addNetworkRegistrationInfo(android.telephony.NetworkRegistrationInfo);
method public int getDataNetworkType();
+ method public int getDataRegState();
method public void setCdmaSystemAndNetworkId(int, int);
method public void setCellBandwidths(int[]);
method public void setChannelNumber(int);
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index b99d5cd..65f2c02 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -2770,7 +2770,7 @@
memInfo.getTotalPrivateDirty(),
memInfo.getTotalPrivateClean(),
memInfo.hasSwappedOutPss ? memInfo.getTotalSwappedOutPss() :
- memInfo.getTotalSwappedOut(), memInfo.getTotalPss(),
+ memInfo.getTotalSwappedOut(), memInfo.getTotalRss(),
nativeMax+dalvikMax,
nativeAllocated+dalvikAllocated, nativeFree+dalvikFree);
}
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 331a0b1..267d029 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -117,11 +117,13 @@
import android.net.IEthernetManager;
import android.net.IIpSecService;
import android.net.INetworkPolicyManager;
+import android.net.IPacProxyManager;
import android.net.IVpnManager;
import android.net.IpSecManager;
import android.net.NetworkPolicyManager;
import android.net.NetworkScoreManager;
import android.net.NetworkWatchlistManager;
+import android.net.PacProxyManager;
import android.net.TetheringManager;
import android.net.VpnManager;
import android.net.lowpan.ILowpanManager;
@@ -346,6 +348,15 @@
// (which extends it).
SYSTEM_SERVICE_NAMES.put(android.text.ClipboardManager.class, Context.CLIPBOARD_SERVICE);
+ registerService(Context.PAC_PROXY_SERVICE, PacProxyManager.class,
+ new CachedServiceFetcher<PacProxyManager>() {
+ @Override
+ public PacProxyManager createService(ContextImpl ctx) throws ServiceNotFoundException {
+ IBinder b = ServiceManager.getServiceOrThrow(Context.PAC_PROXY_SERVICE);
+ IPacProxyManager service = IPacProxyManager.Stub.asInterface(b);
+ return new PacProxyManager(ctx.getOuterContext(), service);
+ }});
+
registerService(Context.NETD_SERVICE, IBinder.class, new StaticServiceFetcher<IBinder>() {
@Override
public IBinder createService() throws ServiceNotFoundException {
diff --git a/core/java/android/app/compat/CompatChanges.java b/core/java/android/app/compat/CompatChanges.java
index ab38832..74e1ece 100644
--- a/core/java/android/app/compat/CompatChanges.java
+++ b/core/java/android/app/compat/CompatChanges.java
@@ -104,16 +104,15 @@
*
* @param packageName The package name of the app in question.
* @param overrides A map from changeId to the override applied for this change id.
- * @hide
*/
- @RequiresPermission(android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG)
- public static void setPackageOverride(String packageName,
- Map<Long, PackageOverride> overrides) {
+ @RequiresPermission(android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD)
+ public static void setPackageOverride(@NonNull String packageName,
+ @NonNull Map<Long, PackageOverride> overrides) {
IPlatformCompat platformCompat = IPlatformCompat.Stub.asInterface(
ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
CompatibilityOverrideConfig config = new CompatibilityOverrideConfig(overrides);
try {
- platformCompat.setOverridesFromInstaller(config, packageName);
+ platformCompat.setOverridesOnReleaseBuilds(config, packageName);
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
diff --git a/core/java/android/app/compat/PackageOverride.java b/core/java/android/app/compat/PackageOverride.java
index 9f97cd4..59b3555 100644
--- a/core/java/android/app/compat/PackageOverride.java
+++ b/core/java/android/app/compat/PackageOverride.java
@@ -17,8 +17,9 @@
package android.app.compat;
import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
import android.os.Parcel;
-import android.os.Parcelable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -32,15 +33,16 @@
*
* @hide
*/
-public class PackageOverride implements Parcelable {
+@SystemApi
+public final class PackageOverride {
+ /** @hide */
@IntDef({
VALUE_UNDEFINED,
VALUE_ENABLED,
VALUE_DISABLED
})
@Retention(RetentionPolicy.SOURCE)
- /** @hide */
public @interface EvaluatedOverride {
}
@@ -75,10 +77,6 @@
this.mEnabled = enabled;
}
- private PackageOverride(Parcel in) {
- this(in.readLong(), in.readLong(), in.readBoolean());
- }
-
/**
* Evaluate the override for the given {@code versionCode}. If no override is defined for
* the specified version code, {@link #VALUE_UNDEFINED} is returned.
@@ -114,25 +112,23 @@
}
/** Returns the enabled value for the override. */
- public boolean getEnabled() {
+ public boolean isEnabled() {
return mEnabled;
}
/** @hide */
- @Override
- public int describeContents() {
- return 0;
- }
-
- /** @hide */
- @Override
- public void writeToParcel(Parcel dest, int flags) {
+ public void writeToParcel(Parcel dest) {
dest.writeLong(mMinVersionCode);
dest.writeLong(mMaxVersionCode);
dest.writeBoolean(mEnabled);
}
/** @hide */
+ public static PackageOverride createFromParcel(Parcel in) {
+ return new PackageOverride(in.readLong(), in.readLong(), in.readBoolean());
+ }
+
+ /** @hide */
@Override
public String toString() {
if (mMinVersionCode == Long.MIN_VALUE && mMaxVersionCode == Long.MAX_VALUE) {
@@ -141,25 +137,10 @@
return String.format("[%d,%d,%b]", mMinVersionCode, mMaxVersionCode, mEnabled);
}
- /** @hide */
- public static final Creator<PackageOverride> CREATOR =
- new Creator<PackageOverride>() {
-
- @Override
- public PackageOverride createFromParcel(Parcel in) {
- return new PackageOverride(in);
- }
-
- @Override
- public PackageOverride[] newArray(int size) {
- return new PackageOverride[size];
- }
- };
-
/**
* Builder to construct a PackageOverride.
*/
- public static class Builder {
+ public static final class Builder {
private long mMinVersionCode = Long.MIN_VALUE;
private long mMaxVersionCode = Long.MAX_VALUE;
private boolean mEnabled;
@@ -169,6 +150,7 @@
*
* default value: {@code Long.MIN_VALUE}.
*/
+ @NonNull
public Builder setMinVersionCode(long minVersionCode) {
mMinVersionCode = minVersionCode;
return this;
@@ -179,6 +161,7 @@
*
* default value: {@code Long.MAX_VALUE}.
*/
+ @NonNull
public Builder setMaxVersionCode(long maxVersionCode) {
mMaxVersionCode = maxVersionCode;
return this;
@@ -189,6 +172,7 @@
*
* default value: {@code false}.
*/
+ @NonNull
public Builder setEnabled(boolean enabled) {
mEnabled = enabled;
return this;
@@ -200,6 +184,7 @@
* @throws IllegalArgumentException if {@code minVersionCode} is larger than
* {@code maxVersionCode}.
*/
+ @NonNull
public PackageOverride build() {
if (mMinVersionCode > mMaxVersionCode) {
throw new IllegalArgumentException("minVersionCode must not be larger than "
diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java
index 098d8b6..9f1132b 100644
--- a/core/java/android/app/usage/NetworkStatsManager.java
+++ b/core/java/android/app/usage/NetworkStatsManager.java
@@ -24,6 +24,7 @@
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
+import android.annotation.WorkerThread;
import android.app.usage.NetworkStats.Bucket;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
@@ -201,6 +202,7 @@
* default network {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL},
* metered {@link NetworkStats.Bucket#METERED_ALL},
* and roaming {@link NetworkStats.Bucket#ROAMING_ALL}.
+ * This may take a long time, and apps should avoid calling this on their main thread.
*
* @param networkType As defined in {@link ConnectivityManager}, e.g.
* {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI}
@@ -219,6 +221,7 @@
* @return Bucket object or null if permissions are insufficient or error happened during
* statistics collection.
*/
+ @WorkerThread
public Bucket querySummaryForDevice(int networkType, String subscriberId,
long startTime, long endTime) throws SecurityException, RemoteException {
NetworkTemplate template;
@@ -240,6 +243,7 @@
* uid {@link NetworkStats.Bucket#UID_ALL}, tag {@link NetworkStats.Bucket#TAG_NONE},
* metered {@link NetworkStats.Bucket#METERED_ALL}, and roaming
* {@link NetworkStats.Bucket#ROAMING_ALL}.
+ * This may take a long time, and apps should avoid calling this on their main thread.
*
* @param networkType As defined in {@link ConnectivityManager}, e.g.
* {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI}
@@ -258,6 +262,7 @@
* @return Bucket object or null if permissions are insufficient or error happened during
* statistics collection.
*/
+ @WorkerThread
public Bucket querySummaryForUser(int networkType, String subscriberId, long startTime,
long endTime) throws SecurityException, RemoteException {
NetworkTemplate template;
@@ -283,6 +288,7 @@
* means buckets' start and end timestamps are going to be the same as the 'startTime' and
* 'endTime' parameters. State, uid, metered, and roaming are going to vary, and tag is going to
* be the same.
+ * This may take a long time, and apps should avoid calling this on their main thread.
*
* @param networkType As defined in {@link ConnectivityManager}, e.g.
* {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI}
@@ -301,6 +307,7 @@
* @return Statistics object or null if permissions are insufficient or error happened during
* statistics collection.
*/
+ @WorkerThread
public NetworkStats querySummary(int networkType, String subscriberId, long startTime,
long endTime) throws SecurityException, RemoteException {
NetworkTemplate template;
@@ -326,9 +333,11 @@
/**
* Query network usage statistics details for a given uid.
+ * This may take a long time, and apps should avoid calling this on their main thread.
*
* @see #queryDetailsForUidTagState(int, String, long, long, int, int, int)
*/
+ @WorkerThread
public NetworkStats queryDetailsForUid(int networkType, String subscriberId,
long startTime, long endTime, int uid) throws SecurityException {
return queryDetailsForUidTagState(networkType, subscriberId, startTime, endTime, uid,
@@ -344,9 +353,11 @@
/**
* Query network usage statistics details for a given uid and tag.
+ * This may take a long time, and apps should avoid calling this on their main thread.
*
* @see #queryDetailsForUidTagState(int, String, long, long, int, int, int)
*/
+ @WorkerThread
public NetworkStats queryDetailsForUidTag(int networkType, String subscriberId,
long startTime, long endTime, int uid, int tag) throws SecurityException {
return queryDetailsForUidTagState(networkType, subscriberId, startTime, endTime, uid,
@@ -365,6 +376,7 @@
* <p>Only includes buckets that atomically occur in the inclusive time range. Doesn't
* interpolate across partial buckets. Since bucket length is in the order of hours, this
* method cannot be used to measure data usage on a fine grained time scale.
+ * This may take a long time, and apps should avoid calling this on their main thread.
*
* @param networkType As defined in {@link ConnectivityManager}, e.g.
* {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI}
@@ -387,6 +399,7 @@
* @return Statistics object or null if an error happened during statistics collection.
* @throws SecurityException if permissions are insufficient to read network statistics.
*/
+ @WorkerThread
public NetworkStats queryDetailsForUidTagState(int networkType, String subscriberId,
long startTime, long endTime, int uid, int tag, int state) throws SecurityException {
NetworkTemplate template;
@@ -425,6 +438,7 @@
* <p>Only includes buckets that atomically occur in the inclusive time range. Doesn't
* interpolate across partial buckets. Since bucket length is in the order of hours, this
* method cannot be used to measure data usage on a fine grained time scale.
+ * This may take a long time, and apps should avoid calling this on their main thread.
*
* @param networkType As defined in {@link ConnectivityManager}, e.g.
* {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI}
@@ -443,6 +457,7 @@
* @return Statistics object or null if permissions are insufficient or error happened during
* statistics collection.
*/
+ @WorkerThread
public NetworkStats queryDetails(int networkType, String subscriberId, long startTime,
long endTime) throws SecurityException, RemoteException {
NetworkTemplate template;
diff --git a/core/java/android/apphibernation/AppHibernationManager.java b/core/java/android/apphibernation/AppHibernationManager.java
index 7281d50..de77848 100644
--- a/core/java/android/apphibernation/AppHibernationManager.java
+++ b/core/java/android/apphibernation/AppHibernationManager.java
@@ -17,12 +17,15 @@
package android.apphibernation;
import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.content.Context;
import android.os.RemoteException;
import android.os.ServiceManager;
+import java.util.List;
+
/**
* This class provides an API surface for system apps to manipulate the app hibernation
* state of a package for the user provided in the context.
@@ -54,6 +57,7 @@
* @hide
*/
@SystemApi
+ @RequiresPermission(value = android.Manifest.permission.MANAGE_APP_HIBERNATION)
public boolean isHibernatingForUser(@NonNull String packageName) {
try {
return mIAppHibernationService.isHibernatingForUser(packageName, mContext.getUserId());
@@ -68,6 +72,7 @@
* @hide
*/
@SystemApi
+ @RequiresPermission(value = android.Manifest.permission.MANAGE_APP_HIBERNATION)
public void setHibernatingForUser(@NonNull String packageName, boolean isHibernating) {
try {
mIAppHibernationService.setHibernatingForUser(packageName, mContext.getUserId(),
@@ -83,6 +88,7 @@
* @hide
*/
@SystemApi
+ @RequiresPermission(value = android.Manifest.permission.MANAGE_APP_HIBERNATION)
public boolean isHibernatingGlobally(@NonNull String packageName) {
try {
return mIAppHibernationService.isHibernatingGlobally(packageName);
@@ -99,6 +105,7 @@
* @hide
*/
@SystemApi
+ @RequiresPermission(value = android.Manifest.permission.MANAGE_APP_HIBERNATION)
public void setHibernatingGlobally(@NonNull String packageName, boolean isHibernating) {
try {
mIAppHibernationService.setHibernatingGlobally(packageName, isHibernating);
@@ -106,4 +113,20 @@
throw e.rethrowFromSystemServer();
}
}
+
+ /**
+ * Get the hibernating packages for the user. This is equivalent to the list of packages for
+ * the user that return true for {@link #isHibernatingForUser}.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(value = android.Manifest.permission.MANAGE_APP_HIBERNATION)
+ public @NonNull List<String> getHibernatingPackagesForUser() {
+ try {
+ return mIAppHibernationService.getHibernatingPackagesForUser(mContext.getUserId());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/apphibernation/IAppHibernationService.aidl b/core/java/android/apphibernation/IAppHibernationService.aidl
index 6a068ee..afdb3fe 100644
--- a/core/java/android/apphibernation/IAppHibernationService.aidl
+++ b/core/java/android/apphibernation/IAppHibernationService.aidl
@@ -25,4 +25,5 @@
void setHibernatingForUser(String packageName, int userId, boolean isHibernating);
boolean isHibernatingGlobally(String packageName);
void setHibernatingGlobally(String packageName, boolean isHibernating);
+ List<String> getHibernatingPackagesForUser(int userId);
}
\ No newline at end of file
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index cc0b22a..38863c2 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -52,6 +52,8 @@
import android.util.Log;
import android.util.Pair;
+import com.android.internal.util.Preconditions;
+
import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -3118,6 +3120,25 @@
return true;
}
+ /**
+ * Determines whether a String Bluetooth address, such as "00:43:A8:23:10:F0"
+ * is a RANDOM STATIC address.
+ *
+ * RANDOM STATIC: (addr & 0b11) == 0b11
+ * RANDOM RESOLVABLE: (addr & 0b11) == 0b10
+ * RANDOM non-RESOLVABLE: (addr & 0b11) == 0b00
+ *
+ * @param address Bluetooth address as string
+ * @return true if the 2 Least Significant Bits of the address equals 0b11.
+ *
+ * @hide
+ */
+ public static boolean isAddressRandomStatic(@NonNull String address) {
+ Preconditions.checkNotNull(address);
+ return checkBluetoothAddress(address)
+ && (Integer.parseInt(address.split(":")[5], 16) & 0b11) == 0b11;
+ }
+
@UnsupportedAppUsage
/*package*/ IBluetoothManager getBluetoothManager() {
return mManagerService;
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 89030bc..c30b8af 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -1002,6 +1002,24 @@
public static final String EXTRA_MAS_INSTANCE =
"android.bluetooth.device.extra.MAS_INSTANCE";
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(
+ prefix = { "ADDRESS_TYPE_" },
+ value = {
+ /** Hardware MAC Address */
+ ADDRESS_TYPE_PUBLIC,
+ /** Address is either resolvable, non-resolvable or static.*/
+ ADDRESS_TYPE_RANDOM,
+ }
+ )
+ public @interface AddressType {}
+
+ /** Hardware MAC Address of the device */
+ public static final int ADDRESS_TYPE_PUBLIC = 0;
+ /** Address is either resolvable, non-resolvable or static. */
+ public static final int ADDRESS_TYPE_RANDOM = 1;
+
/**
* Lazy initialization. Guaranteed final after first object constructed, or
* getService() called.
@@ -1010,6 +1028,7 @@
private static volatile IBluetooth sService;
private final String mAddress;
+ @AddressType private final int mAddressType;
/*package*/
@UnsupportedAppUsage
@@ -1064,6 +1083,7 @@
}
mAddress = address;
+ mAddressType = ADDRESS_TYPE_PUBLIC;
}
@Override
@@ -1279,7 +1299,6 @@
* the bonding process completes, and its result.
* <p>Android system services will handle the necessary user interactions
* to confirm and complete the bonding process.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
*
* @param transport The transport to use for the pairing procedure.
* @return false on immediate error, true if bonding will begin
@@ -1287,8 +1306,9 @@
* @hide
*/
@UnsupportedAppUsage
+ @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
public boolean createBond(int transport) {
- return createBondOutOfBand(transport, null);
+ return createBondInternal(transport, null, null);
}
/**
@@ -1302,21 +1322,38 @@
* <p>Android system services will handle the necessary user interactions
* to confirm and complete the bonding process.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
+ * <p>There are two possible versions of OOB Data. This data can come in as
+ * P192 or P256. This is a reference to the cryptography used to generate the key.
+ * The caller may pass one or both. If both types of data are passed, then the
+ * P256 data will be preferred, and thus used.
*
* @param transport - Transport to use
- * @param oobData - Out Of Band data
+ * @param remoteP192Data - Out Of Band data (P192) or null
+ * @param remoteP256Data - Out Of Band data (P256) or null
* @return false on immediate error, true if bonding will begin
* @hide
*/
- public boolean createBondOutOfBand(int transport, OobData oobData) {
+ @SystemApi
+ @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ public boolean createBondOutOfBand(int transport, @Nullable OobData remoteP192Data,
+ @Nullable OobData remoteP256Data) {
+ if (remoteP192Data == null && remoteP256Data == null) {
+ throw new IllegalArgumentException(
+ "One or both arguments for the OOB data types are required to not be null."
+ + " Please use createBond() instead if you do not have OOB data to pass.");
+ }
+ return createBondInternal(transport, remoteP192Data, remoteP256Data);
+ }
+
+ private boolean createBondInternal(int transport, @Nullable OobData remoteP192Data,
+ @Nullable OobData remoteP256Data) {
final IBluetooth service = sService;
if (service == null) {
Log.w(TAG, "BT not enabled, createBondOutOfBand failed");
return false;
}
try {
- return service.createBond(this, transport, oobData);
+ return service.createBond(this, transport, remoteP192Data, remoteP256Data);
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
@@ -1347,27 +1384,6 @@
}
/**
- * Set the Out Of Band data for a remote device to be used later
- * in the pairing mechanism. Users can obtain this data through other
- * trusted channels
- *
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
- *
- * @param hash Simple Secure pairing hash
- * @param randomizer The random key obtained using OOB
- * @return false on error; true otherwise
- * @hide
- */
- public boolean setDeviceOutOfBandData(byte[] hash, byte[] randomizer) {
- //TODO(BT)
- /*
- try {
- return sService.setDeviceOutOfBandData(this, hash, randomizer);
- } catch (RemoteException e) {Log.e(TAG, "", e);} */
- return false;
- }
-
- /**
* Cancel an in-progress bonding request started with {@link #createBond}.
*
* @return true on success, false on error
diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java
index 4fb5577..632572d 100644
--- a/core/java/android/bluetooth/BluetoothHeadset.java
+++ b/core/java/android/bluetooth/BluetoothHeadset.java
@@ -567,6 +567,7 @@
* @return true if priority is set, false on error
* @hide
* @deprecated Replaced with {@link #setConnectionPolicy(BluetoothDevice, int)}
+ * @removed
*/
@Deprecated
@SystemApi
diff --git a/core/java/android/bluetooth/OobData.java b/core/java/android/bluetooth/OobData.java
index 0d0c6ab..08d694e 100644
--- a/core/java/android/bluetooth/OobData.java
+++ b/core/java/android/bluetooth/OobData.java
@@ -1,4 +1,4 @@
-/*
+/**
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,88 +16,949 @@
package android.bluetooth;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
+import com.android.internal.util.Preconditions;
+
+import java.lang.IllegalArgumentException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* Out Of Band Data for Bluetooth device pairing.
*
* <p>This object represents optional data obtained from a remote device through
- * an out-of-band channel (eg. NFC).
+ * an out-of-band channel (eg. NFC, QR).
+ *
+ * <p>References:
+ * NFC AD Forum SSP 1.1 (AD)
+ * {@link https://members.nfc-forum.org//apps/group_public/download.php/24620/NFCForum-AD-BTSSP_1_1.pdf}
+ * Core Specification Supplement (CSS) V9
+ *
+ * <p>There are several BR/EDR Examples
+ *
+ * <p>Negotiated Handover:
+ * Bluetooth Carrier Configuration Record:
+ * - OOB Data Length
+ * - Device Address
+ * - Class of Device
+ * - Simple Pairing Hash C
+ * - Simple Pairing Randomizer R
+ * - Service Class UUID
+ * - Bluetooth Local Name
+ *
+ * <p>Static Handover:
+ * Bluetooth Carrier Configuration Record:
+ * - OOB Data Length
+ * - Device Address
+ * - Class of Device
+ * - Service Class UUID
+ * - Bluetooth Local Name
+ *
+ * <p>Simplified Tag Format for Single BT Carrier:
+ * Bluetooth OOB Data Record:
+ * - OOB Data Length
+ * - Device Address
+ * - Class of Device
+ * - Service Class UUID
+ * - Bluetooth Local Name
*
* @hide
*/
-public class OobData implements Parcelable {
- private byte[] mLeBluetoothDeviceAddress;
- private byte[] mSecurityManagerTk;
- private byte[] mLeSecureConnectionsConfirmation;
- private byte[] mLeSecureConnectionsRandom;
+@SystemApi
+public final class OobData implements Parcelable {
- public byte[] getLeBluetoothDeviceAddress() {
- return mLeBluetoothDeviceAddress;
+ private static final String TAG = "OobData";
+ /** The {@link OobData#mClassicLength} may be. (AD 3.1.1) (CSS 1.6.2) @hide */
+ @SystemApi
+ public static final int OOB_LENGTH_OCTETS = 2;
+ /**
+ * The length for the {@link OobData#mDeviceAddressWithType}(6) and Address Type(1).
+ * (AD 3.1.2) (CSS 1.6.2)
+ * @hide
+ */
+ @SystemApi
+ public static final int DEVICE_ADDRESS_OCTETS = 7;
+ /** The Class of Device is 3 octets. (AD 3.1.3) (CSS 1.6.2) @hide */
+ @SystemApi
+ public static final int CLASS_OF_DEVICE_OCTETS = 3;
+ /** The Confirmation data must be 16 octets. (AD 3.2.2) (CSS 1.6.2) @hide */
+ @SystemApi
+ public static final int CONFIRMATION_OCTETS = 16;
+ /** The Randomizer data must be 16 octets. (AD 3.2.3) (CSS 1.6.2) @hide */
+ @SystemApi
+ public static final int RANDOMIZER_OCTETS = 16;
+ /** The LE Device Role length is 1 octet. (AD 3.3.2) (CSS 1.17) @hide */
+ @SystemApi
+ public static final int LE_DEVICE_ROLE_OCTETS = 1;
+ /** The {@link OobData#mLeTemporaryKey} length. (3.4.1) @hide */
+ @SystemApi
+ public static final int LE_TK_OCTETS = 16;
+ /** The {@link OobData#mLeAppearance} length. (3.4.1) @hide */
+ @SystemApi
+ public static final int LE_APPEARANCE_OCTETS = 2;
+ /** The {@link OobData#mLeFlags} length. (3.4.1) @hide */
+ @SystemApi
+ public static final int LE_DEVICE_FLAG_OCTETS = 1; // 1 octet to hold the 0-4 value.
+
+ // Le Roles
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(
+ prefix = { "LE_DEVICE_ROLE_" },
+ value = {
+ LE_DEVICE_ROLE_PERIPHERAL_ONLY,
+ LE_DEVICE_ROLE_CENTRAL_ONLY,
+ LE_DEVICE_ROLE_BOTH_PREFER_PERIPHERAL,
+ LE_DEVICE_ROLE_BOTH_PREFER_CENTRAL
+ }
+ )
+ public @interface LeRole {}
+
+ /** @hide */
+ @SystemApi
+ public static final int LE_DEVICE_ROLE_PERIPHERAL_ONLY = 0x00;
+ /** @hide */
+ @SystemApi
+ public static final int LE_DEVICE_ROLE_CENTRAL_ONLY = 0x01;
+ /** @hide */
+ @SystemApi
+ public static final int LE_DEVICE_ROLE_BOTH_PREFER_PERIPHERAL = 0x02;
+ /** @hide */
+ @SystemApi
+ public static final int LE_DEVICE_ROLE_BOTH_PREFER_CENTRAL = 0x03;
+
+ // Le Flags
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(
+ prefix = { "LE_FLAG_" },
+ value = {
+ LE_FLAG_LIMITED_DISCOVERY_MODE,
+ LE_FLAG_GENERAL_DISCOVERY_MODE,
+ LE_FLAG_BREDR_NOT_SUPPORTED,
+ LE_FLAG_SIMULTANEOUS_CONTROLLER,
+ LE_FLAG_SIMULTANEOUS_HOST
+ }
+ )
+ public @interface LeFlag {}
+
+ /** @hide */
+ @SystemApi
+ public static final int LE_FLAG_LIMITED_DISCOVERY_MODE = 0x00;
+ /** @hide */
+ @SystemApi
+ public static final int LE_FLAG_GENERAL_DISCOVERY_MODE = 0x01;
+ /** @hide */
+ @SystemApi
+ public static final int LE_FLAG_BREDR_NOT_SUPPORTED = 0x02;
+ /** @hide */
+ @SystemApi
+ public static final int LE_FLAG_SIMULTANEOUS_CONTROLLER = 0x03;
+ /** @hide */
+ @SystemApi
+ public static final int LE_FLAG_SIMULTANEOUS_HOST = 0x04;
+
+ /**
+ * Main creation method for creating a Classic version of {@link OobData}.
+ *
+ * <p>This object will allow the caller to call {@link ClassicBuilder#build()}
+ * to build the data object or add any option information to the builder.
+ *
+ * @param confirmationHash byte array consisting of {@link OobData#CONFIRMATION_OCTETS} octets
+ * of data. Data is derived from controller/host stack and is required for pairing OOB.
+ * @param classicLength byte array representing the length of data from 8-65535 across 2
+ * octets (0xXXXX).
+ * @param deviceAddressWithType byte array representing the Bluetooth Address of the device
+ * that owns the OOB data. (i.e. the originator) [6 octets]
+ *
+ * @return a Classic Builder instance with all the given data set or null.
+ *
+ * @throws IllegalArgumentException if any of the values fail to be set.
+ * @throws NullPointerException if any argument is null.
+ *
+ * @hide
+ */
+ @NonNull
+ @SystemApi
+ public static ClassicBuilder createClassicBuilder(@NonNull byte[] confirmationHash,
+ @NonNull byte[] classicLength, @NonNull byte[] deviceAddressWithType) {
+ return new ClassicBuilder(confirmationHash, classicLength, deviceAddressWithType);
}
/**
- * Sets the LE Bluetooth Device Address value to be used during LE pairing.
- * The value shall be 7 bytes. Please see Bluetooth CSSv6, Part A 1.16 for
- * a detailed description.
+ * Main creation method for creating a LE version of {@link OobData}.
+ *
+ * <p>This object will allow the caller to call {@link LeBuilder#build()}
+ * to build the data object or add any option information to the builder.
+ *
+ * @param deviceAddressWithType the LE device address plus the address type (7 octets);
+ * not null.
+ * @param leDeviceRole whether the device supports Peripheral, Central,
+ * Both including preference; not null. (1 octet)
+ * @param confirmationHash Array consisting of {@link OobData#CONFIRMATION_OCTETS} octets
+ * of data. Data is derived from controller/host stack and is
+ * required for pairing OOB.
+ *
+ * <p>Possible LE Device Role Values:
+ * 0x00 Only Peripheral supported
+ * 0x01 Only Central supported
+ * 0x02 Central & Peripheral supported; Peripheral Preferred
+ * 0x03 Only peripheral supported; Central Preferred
+ * 0x04 - 0xFF Reserved
+ *
+ * @return a LeBuilder instance with all the given data set or null.
+ *
+ * @throws IllegalArgumentException if any of the values fail to be set.
+ * @throws NullPointerException if any argument is null.
+ *
+ * @hide
*/
- public void setLeBluetoothDeviceAddress(byte[] leBluetoothDeviceAddress) {
- mLeBluetoothDeviceAddress = leBluetoothDeviceAddress;
- }
-
- public byte[] getSecurityManagerTk() {
- return mSecurityManagerTk;
+ @NonNull
+ @SystemApi
+ public static LeBuilder createLeBuilder(@NonNull byte[] confirmationHash,
+ @NonNull byte[] deviceAddressWithType, @LeRole int leDeviceRole) {
+ return new LeBuilder(confirmationHash, deviceAddressWithType, leDeviceRole);
}
/**
- * Sets the Temporary Key value to be used by the LE Security Manager during
- * LE pairing. The value shall be 16 bytes. Please see Bluetooth CSSv6,
- * Part A 1.8 for a detailed description.
+ * Builds an {@link OobData} object and validates that the required combination
+ * of values are present to create the LE specific OobData type.
+ *
+ * @hide
*/
- public void setSecurityManagerTk(byte[] securityManagerTk) {
- mSecurityManagerTk = securityManagerTk;
+ @SystemApi
+ public static final class LeBuilder {
+
+ /**
+ * It is recommended that this Hash C is generated anew for each
+ * pairing.
+ *
+ * <p>It should be noted that on passive NFC this isn't possible as the data is static
+ * and immutable.
+ */
+ private byte[] mConfirmationHash = null;
+
+ /**
+ * Optional, but adds more validity to the pairing.
+ *
+ * <p>If not present a value of 0 is assumed.
+ */
+ private byte[] mRandomizerHash = new byte[] {
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ };
+
+ /**
+ * The Bluetooth Device user-friendly name presented over Bluetooth Technology.
+ *
+ * <p>This is the name that may be displayed to the device user as part of the UI.
+ */
+ private byte[] mDeviceName = null;
+
+ /**
+ * Sets the Bluetooth Device name to be used for UI purposes.
+ *
+ * <p>Optional attribute.
+ *
+ * @param deviceName byte array representing the name, may be 0 in length, not null.
+ *
+ * @return {@link OobData#ClassicBuilder}
+ *
+ * @throws NullPointerException if deviceName is null.
+ *
+ * @hide
+ */
+ @NonNull
+ @SystemApi
+ public LeBuilder setDeviceName(@NonNull byte[] deviceName) {
+ Preconditions.checkNotNull(deviceName);
+ this.mDeviceName = deviceName;
+ return this;
+ }
+
+ /**
+ * The Bluetooth Device Address is the address to which the OOB data belongs.
+ *
+ * <p>The length MUST be {@link OobData#DEVICE_ADDRESS_OCTETS} octets.
+ *
+ * <p> Address is encoded in Little Endian order.
+ *
+ * <p>e.g. 00:01:02:03:04:05 would be x05x04x03x02x01x00
+ */
+ private final byte[] mDeviceAddressWithType;
+
+ /**
+ * During an LE connection establishment, one must be in the Peripheral mode and the other
+ * in the Central role.
+ *
+ * <p>Possible Values:
+ * {@link LE_DEVICE_ROLE_PERIPHERAL_ONLY} Only Peripheral supported
+ * {@link LE_DEVICE_ROLE_CENTRAL_ONLY} Only Central supported
+ * {@link LE_DEVICE_ROLE_BOTH_PREFER_PERIPHERAL} Central & Peripheral supported;
+ * Peripheral Preferred
+ * {@link LE_DEVICE_ROLE_BOTH_PREFER_CENTRAL} Only peripheral supported; Central Preferred
+ * 0x04 - 0xFF Reserved
+ */
+ private final @LeRole int mLeDeviceRole;
+
+ /**
+ * Temporary key value from the Security Manager.
+ *
+ * <p> Must be {@link LE_TK_OCTETS} in size
+ */
+ private byte[] mLeTemporaryKey = null;
+
+ /**
+ * Defines the representation of the external appearance of the device.
+ *
+ * <p>For example, a mouse, remote control, or keyboard.
+ *
+ * <p>Used for visual on discovering device to represent icon/string/etc...
+ */
+ private byte[] mLeAppearance = null;
+
+ /**
+ * Contains which discoverable mode to use, BR/EDR support and capability.
+ *
+ * <p>Possible LE Flags:
+ * {@link LE_FLAG_LIMITED_DISCOVERY_MODE} LE Limited Discoverable Mode.
+ * {@link LE_FLAG_GENERAL_DISCOVERY_MODE} LE General Discoverable Mode.
+ * {@link LE_FLAG_BREDR_NOT_SUPPORTED} BR/EDR Not Supported. Bit 37 of
+ * LMP Feature Mask Definitions.
+ * {@link LE_FLAG_SIMULTANEOUS_CONTROLLER} Simultaneous LE and BR/EDR to
+ * Same Device Capable (Controller).
+ * Bit 49 of LMP Feature Mask Definitions.
+ * {@link LE_FLAG_SIMULTANEOUS_HOST} Simultaneous LE and BR/EDR to
+ * Same Device Capable (Host).
+ * Bit 55 of LMP Feature Mask Definitions.
+ * <b>0x05- 0x07 Reserved</b>
+ */
+ private @LeFlag int mLeFlags = LE_FLAG_GENERAL_DISCOVERY_MODE; // Invalid default
+
+ /**
+ * Constructing an OobData object for use with LE requires
+ * a LE Device Address and LE Device Role as well as the Confirmation
+ * and optionally, the Randomizer, however it is recommended to use.
+ *
+ * @param confirmationHash byte array consisting of {@link OobData#CONFIRMATION_OCTETS}
+ * octets of data. Data is derived from controller/host stack and is required for
+ * pairing OOB.
+ * @param deviceAddressWithType 7 bytes containing the 6 byte address with the 1 byte
+ * address type.
+ * @param leDeviceRole indicating device's role and preferences (Central or Peripheral)
+ *
+ * <p>Possible Values:
+ * {@link LE_DEVICE_ROLE_PERIPHERAL_ONLY} Only Peripheral supported
+ * {@link LE_DEVICE_ROLE_CENTRAL_ONLY} Only Central supported
+ * {@link LE_DEVICE_ROLE_BOTH_PREFER_PERIPHERAL} Central & Peripheral supported;
+ * Peripheral Preferred
+ * {@link LE_DEVICE_ROLE_BOTH_PREFER_CENTRAL} Only peripheral supported; Central Preferred
+ * 0x04 - 0xFF Reserved
+ *
+ * @throws IllegalArgumentException if deviceAddressWithType is not
+ * {@link LE_DEVICE_ADDRESS_OCTETS} octets
+ * @throws NullPointerException if any argument is null.
+ */
+ private LeBuilder(@NonNull byte[] confirmationHash, @NonNull byte[] deviceAddressWithType,
+ @LeRole int leDeviceRole) {
+ Preconditions.checkNotNull(confirmationHash);
+ Preconditions.checkNotNull(deviceAddressWithType);
+ if (confirmationHash.length != OobData.CONFIRMATION_OCTETS) {
+ throw new IllegalArgumentException("confirmationHash must be "
+ + OobData.CONFIRMATION_OCTETS + " octets in length.");
+ }
+ this.mConfirmationHash = confirmationHash;
+ if (deviceAddressWithType.length != OobData.DEVICE_ADDRESS_OCTETS) {
+ throw new IllegalArgumentException("confirmationHash must be "
+ + OobData.DEVICE_ADDRESS_OCTETS+ " octets in length.");
+ }
+ this.mDeviceAddressWithType = deviceAddressWithType;
+ if (leDeviceRole < LE_DEVICE_ROLE_PERIPHERAL_ONLY
+ || leDeviceRole > LE_DEVICE_ROLE_BOTH_PREFER_CENTRAL) {
+ throw new IllegalArgumentException("leDeviceRole must be a valid value.");
+ }
+ this.mLeDeviceRole = leDeviceRole;
+ }
+
+ /**
+ * Sets the Temporary Key value to be used by the LE Security Manager during
+ * LE pairing.
+ *
+ * @param leTemporaryKey byte array that shall be 16 bytes. Please see Bluetooth CSSv6,
+ * Part A 1.8 for a detailed description.
+ *
+ * @return {@link OobData#Builder}
+ *
+ * @throws IllegalArgumentException if the leTemporaryKey is an invalid format.
+ * @throws NullinterException if leTemporaryKey is null.
+ *
+ * @hide
+ */
+ @NonNull
+ @SystemApi
+ public LeBuilder setLeTemporaryKey(@NonNull byte[] leTemporaryKey) {
+ Preconditions.checkNotNull(leTemporaryKey);
+ if (leTemporaryKey.length != LE_TK_OCTETS) {
+ throw new IllegalArgumentException("leTemporaryKey must be "
+ + LE_TK_OCTETS + " octets in length.");
+ }
+ this.mLeTemporaryKey = leTemporaryKey;
+ return this;
+ }
+
+ /**
+ * @param randomizerHash byte array consisting of {@link OobData#RANDOMIZER_OCTETS} octets
+ * of data. Data is derived from controller/host stack and is required for pairing OOB.
+ * Also, randomizerHash may be all 0s or null in which case it becomes all 0s.
+ *
+ * @throws IllegalArgumentException if null or incorrect length randomizerHash was passed.
+ * @throws NullPointerException if randomizerHash is null.
+ *
+ * @hide
+ */
+ @NonNull
+ @SystemApi
+ public LeBuilder setRandomizerHash(@NonNull byte[] randomizerHash) {
+ Preconditions.checkNotNull(randomizerHash);
+ if (randomizerHash.length != OobData.RANDOMIZER_OCTETS) {
+ throw new IllegalArgumentException("randomizerHash must be "
+ + OobData.RANDOMIZER_OCTETS + " octets in length.");
+ }
+ this.mRandomizerHash = randomizerHash;
+ return this;
+ }
+
+ /**
+ * Sets the LE Flags necessary for the pairing scenario or discovery mode.
+ *
+ * @param leFlags enum value representing the 1 octet of data about discovery modes.
+ *
+ * <p>Possible LE Flags:
+ * {@link LE_FLAG_LIMITED_DISCOVERY_MODE} LE Limited Discoverable Mode.
+ * {@link LE_FLAG_GENERAL_DISCOVERY_MODE} LE General Discoverable Mode.
+ * {@link LE_FLAG_BREDR_NOT_SUPPORTED} BR/EDR Not Supported. Bit 37 of
+ * LMP Feature Mask Definitions.
+ * {@link LE_FLAG_SIMULTANEOUS_CONTROLLER} Simultaneous LE and BR/EDR to
+ * Same Device Capable (Controller) Bit 49 of LMP Feature Mask Definitions.
+ * {@link LE_FLAG_SIMULTANEOUS_HOST} Simultaneous LE and BR/EDR to
+ * Same Device Capable (Host).
+ * Bit 55 of LMP Feature Mask Definitions.
+ * 0x05- 0x07 Reserved
+ *
+ * @throws IllegalArgumentException for invalid flag
+ * @hide
+ */
+ @NonNull
+ @SystemApi
+ public LeBuilder setLeFlags(@LeFlag int leFlags) {
+ if (leFlags < LE_FLAG_LIMITED_DISCOVERY_MODE || leFlags > LE_FLAG_SIMULTANEOUS_HOST) {
+ throw new IllegalArgumentException("leFlags must be a valid value.");
+ }
+ this.mLeFlags = leFlags;
+ return this;
+ }
+
+ /**
+ * Validates and builds the {@link OobData} object for LE Security.
+ *
+ * @return {@link OobData} with given builder values
+ *
+ * @throws IllegalStateException if either of the 2 required fields were not set.
+ *
+ * @hide
+ */
+ @NonNull
+ @SystemApi
+ public OobData build() {
+ final OobData oob =
+ new OobData(this.mDeviceAddressWithType, this.mLeDeviceRole,
+ this.mConfirmationHash);
+
+ // If we have values, set them, otherwise use default
+ oob.mLeTemporaryKey =
+ (this.mLeTemporaryKey != null) ? this.mLeTemporaryKey : oob.mLeTemporaryKey;
+ oob.mLeAppearance = (this.mLeAppearance != null)
+ ? this.mLeAppearance : oob.mLeAppearance;
+ oob.mLeFlags = (this.mLeFlags != 0xF) ? this.mLeFlags : oob.mLeFlags;
+ oob.mDeviceName = (this.mDeviceName != null) ? this.mDeviceName : oob.mDeviceName;
+ oob.mRandomizerHash = this.mRandomizerHash;
+ return oob;
+ }
}
- public byte[] getLeSecureConnectionsConfirmation() {
- return mLeSecureConnectionsConfirmation;
+ /**
+ * Builds an {@link OobData} object and validates that the required combination
+ * of values are present to create the Classic specific OobData type.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final class ClassicBuilder {
+ // Used by both Classic and LE
+ /**
+ * It is recommended that this Hash C is generated anew for each
+ * pairing.
+ *
+ * <p>It should be noted that on passive NFC this isn't possible as the data is static
+ * and immutable.
+ *
+ * @hide
+ */
+ private byte[] mConfirmationHash = null;
+
+ /**
+ * Optional, but adds more validity to the pairing.
+ *
+ * <p>If not present a value of 0 is assumed.
+ *
+ * @hide
+ */
+ private byte[] mRandomizerHash = new byte[] {
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ };
+
+ /**
+ * The Bluetooth Device user-friendly name presented over Bluetooth Technology.
+ *
+ * <p>This is the name that may be displayed to the device user as part of the UI.
+ *
+ * @hide
+ */
+ private byte[] mDeviceName = null;
+
+ /**
+ * This length value provides the absolute length of total OOB data block used for
+ * Bluetooth BR/EDR
+ *
+ * <p>OOB communication, which includes the length field itself and the Bluetooth
+ * Device Address.
+ *
+ * <p>The minimum length that may be represented in this field is 8.
+ *
+ * @hide
+ */
+ private final byte[] mClassicLength;
+
+ /**
+ * The Bluetooth Device Address is the address to which the OOB data belongs.
+ *
+ * <p>The length MUST be {@link OobData#DEVICE_ADDRESS_OCTETS} octets.
+ *
+ * <p> Address is encoded in Little Endian order.
+ *
+ * <p>e.g. 00:01:02:03:04:05 would be x05x04x03x02x01x00
+ *
+ * @hide
+ */
+ private final byte[] mDeviceAddressWithType;
+
+ /**
+ * Class of Device information is to be used to provide a graphical representation
+ * to the user as part of UI involving operations.
+ *
+ * <p>This is not to be used to determine a particular service can be used.
+ *
+ * <p>The length MUST be {@link OobData#CLASS_OF_DEVICE_OCTETS} octets.
+ *
+ * @hide
+ */
+ private byte[] mClassOfDevice = null;
+
+ /**
+ * @param confirmationHash byte array consisting of {@link OobData#CONFIRMATION_OCTETS}
+ * octets of data. Data is derived from controller/host stack and is required for pairing
+ * OOB.
+ * @param randomizerHash byte array consisting of {@link OobData#RANDOMIZER_OCTETS} octets
+ * of data. Data is derived from controller/host stack and is required
+ * for pairing OOB. Also, randomizerHash may be all 0s or null in which case
+ * it becomes all 0s.
+ * @param classicLength byte array representing the length of data from 8-65535 across 2
+ * octets (0xXXXX). Inclusive of this value in the length.
+ * @param deviceAddressWithType byte array representing the Bluetooth Address of the device
+ * that owns the OOB data. (i.e. the originator) [7 octets] this includes the Address Type
+ * as the last octet.
+ *
+ * @throws IllegalArgumentException if any value is not the correct length
+ * @throws NullPointerException if anything passed is null
+ *
+ * @hide
+ */
+ private ClassicBuilder(@NonNull byte[] confirmationHash, @NonNull byte[] classicLength,
+ @NonNull byte[] deviceAddressWithType) {
+ Preconditions.checkNotNull(confirmationHash);
+ Preconditions.checkNotNull(classicLength);
+ Preconditions.checkNotNull(deviceAddressWithType);
+ if (confirmationHash.length != OobData.CONFIRMATION_OCTETS) {
+ throw new IllegalArgumentException("confirmationHash must be "
+ + OobData.CONFIRMATION_OCTETS + " octets in length.");
+ }
+ this.mConfirmationHash = confirmationHash;
+ if (classicLength.length != OOB_LENGTH_OCTETS) {
+ throw new IllegalArgumentException("classicLength must be "
+ + OOB_LENGTH_OCTETS + " octets in length.");
+ }
+ this.mClassicLength = classicLength;
+ if (deviceAddressWithType.length != DEVICE_ADDRESS_OCTETS) {
+ throw new IllegalArgumentException("deviceAddressWithType must be "
+ + DEVICE_ADDRESS_OCTETS + " octets in length.");
+ }
+ this.mDeviceAddressWithType = deviceAddressWithType;
+ }
+
+ /**
+ * @param randomizerHash byte array consisting of {@link OobData#RANDOMIZER_OCTETS} octets
+ * of data. Data is derived from controller/host stack and is required for pairing OOB.
+ * Also, randomizerHash may be all 0s or null in which case it becomes all 0s.
+ *
+ * @throws IllegalArgumentException if null or incorrect length randomizerHash was passed.
+ * @throws NullPointerException if randomizerHash is null.
+ *
+ * @hide
+ */
+ @NonNull
+ @SystemApi
+ public ClassicBuilder setRandomizerHash(@NonNull byte[] randomizerHash) {
+ Preconditions.checkNotNull(randomizerHash);
+ if (randomizerHash.length != OobData.RANDOMIZER_OCTETS) {
+ throw new IllegalArgumentException("randomizerHash must be "
+ + OobData.RANDOMIZER_OCTETS + " octets in length.");
+ }
+ this.mRandomizerHash = randomizerHash;
+ return this;
+ }
+
+ /**
+ * Sets the Bluetooth Device name to be used for UI purposes.
+ *
+ * <p>Optional attribute.
+ *
+ * @param deviceName byte array representing the name, may be 0 in length, not null.
+ *
+ * @return {@link OobData#ClassicBuilder}
+ *
+ * @throws NullPointerException if deviceName is null
+ *
+ * @hide
+ */
+ @NonNull
+ @SystemApi
+ public ClassicBuilder setDeviceName(@NonNull byte[] deviceName) {
+ Preconditions.checkNotNull(deviceName);
+ this.mDeviceName = deviceName;
+ return this;
+ }
+
+ /**
+ * Sets the Bluetooth Class of Device; used for UI purposes only.
+ *
+ * <p>Not an indicator of available services!
+ *
+ * <p>Optional attribute.
+ *
+ * @param classOfDevice byte array of {@link OobData#CLASS_OF_DEVICE_OCTETS} octets.
+ *
+ * @return {@link OobData#ClassicBuilder}
+ *
+ * @throws IllegalArgumentException if length is not equal to
+ * {@link OobData#CLASS_OF_DEVICE_OCTETS} octets.
+ * @throws NullPointerException if classOfDevice is null.
+ *
+ * @hide
+ */
+ @NonNull
+ @SystemApi
+ public ClassicBuilder setClassOfDevice(@NonNull byte[] classOfDevice) {
+ Preconditions.checkNotNull(classOfDevice);
+ if (classOfDevice.length != OobData.CLASS_OF_DEVICE_OCTETS) {
+ throw new IllegalArgumentException("classOfDevice must be "
+ + OobData.CLASS_OF_DEVICE_OCTETS + " octets in length.");
+ }
+ this.mClassOfDevice = classOfDevice;
+ return this;
+ }
+
+ /**
+ * Validates and builds the {@link OobDat object for Classic Security.
+ *
+ * @return {@link OobData} with previously given builder values.
+ *
+ * @hide
+ */
+ @NonNull
+ @SystemApi
+ public OobData build() {
+ final OobData oob =
+ new OobData(this.mClassicLength, this.mDeviceAddressWithType,
+ this.mConfirmationHash);
+ // If we have values, set them, otherwise use default
+ oob.mDeviceName = (this.mDeviceName != null) ? this.mDeviceName : oob.mDeviceName;
+ oob.mClassOfDevice = (this.mClassOfDevice != null)
+ ? this.mClassOfDevice : oob.mClassOfDevice;
+ oob.mRandomizerHash = this.mRandomizerHash;
+ return oob;
+ }
}
- public void setLeSecureConnectionsConfirmation(byte[] leSecureConnectionsConfirmation) {
- mLeSecureConnectionsConfirmation = leSecureConnectionsConfirmation;
+ // Members (Defaults for Optionals must be set or Parceling fails on NPE)
+ // Both
+ private final byte[] mDeviceAddressWithType;
+ private final byte[] mConfirmationHash;
+ private byte[] mRandomizerHash = new byte[] {
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ };
+ // Default the name to "Bluetooth Device"
+ private byte[] mDeviceName = new byte[] {
+ // Bluetooth
+ 0x42, 0x6c, 0x75, 0x65, 0x74, 0x6f, 0x6f, 0x74, 0x68,
+ // <space>Device
+ 0x20, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65
+ };
+
+ // Classic
+ private final byte[] mClassicLength;
+ private byte[] mClassOfDevice = new byte[CLASS_OF_DEVICE_OCTETS];
+
+ // LE
+ private final @LeRole int mLeDeviceRole;
+ private byte[] mLeTemporaryKey = new byte[LE_TK_OCTETS];
+ private byte[] mLeAppearance = new byte[LE_APPEARANCE_OCTETS];
+ private @LeFlag int mLeFlags = LE_FLAG_LIMITED_DISCOVERY_MODE;
+
+ /**
+ * @return byte array representing the MAC address of a bluetooth device.
+ * The Address is 6 octets long with a 1 octet address type associated with the address.
+ *
+ * <p>For classic this will be 6 byte address plus the default of PUBLIC_ADDRESS Address Type.
+ * For LE there are more choices for Address Type.
+ *
+ * @hide
+ */
+ @NonNull
+ @SystemApi
+ public byte[] getDeviceAddressWithType() {
+ return mDeviceAddressWithType;
}
- public byte[] getLeSecureConnectionsRandom() {
- return mLeSecureConnectionsRandom;
+ /**
+ * @return byte array representing the confirmationHash value
+ * which is used to confirm the identity to the controller.
+ *
+ * @hide
+ */
+ @NonNull
+ @SystemApi
+ public byte[] getConfirmationHash() {
+ return mConfirmationHash;
}
- public void setLeSecureConnectionsRandom(byte[] leSecureConnectionsRandom) {
- mLeSecureConnectionsRandom = leSecureConnectionsRandom;
+ /**
+ * @return byte array representing the randomizerHash value
+ * which is used to verify the identity of the controller.
+ *
+ * @hide
+ */
+ @NonNull
+ @SystemApi
+ public byte[] getRandomizerHash() {
+ return mRandomizerHash;
}
- public OobData() {
+ /**
+ * @return Device Name used for displaying name in UI.
+ *
+ * <p>Also, this will be populated with the LE Local Name if the data is for LE.
+ *
+ * @hide
+ */
+ @Nullable
+ @SystemApi
+ public byte[] getDeviceName() {
+ return mDeviceName;
+ }
+
+ /**
+ * @return byte array representing the oob data length which is the length
+ * of all of the data including these octets.
+ *
+ * @hide
+ */
+ @NonNull
+ @SystemApi
+ public byte[] getClassicLength() {
+ return mClassicLength;
+ }
+
+ /**
+ * @return byte array representing the class of device for UI display.
+ *
+ * <p>Does not indicate services available; for display only.
+ *
+ * @hide
+ */
+ @NonNull
+ @SystemApi
+ public byte[] getClassOfDevice() {
+ return mClassOfDevice;
+ }
+
+ /**
+ * @return Temporary Key used for LE pairing.
+ *
+ * @hide
+ */
+ @Nullable
+ @SystemApi
+ public byte[] getLeTemporaryKey() {
+ return mLeTemporaryKey;
+ }
+
+ /**
+ * @return Appearance used for LE pairing. For use in UI situations
+ * when determining what sort of icons or text to display regarding
+ * the device.
+ *
+ * @hide
+ */
+ @Nullable
+ @SystemApi
+ public byte[] getLeAppearance() {
+ return mLeTemporaryKey;
+ }
+
+ /**
+ * @return Flags used to determing discoverable mode to use, BR/EDR Support, and Capability.
+ *
+ * <p>Possible LE Flags:
+ * {@link LE_FLAG_LIMITED_DISCOVERY_MODE} LE Limited Discoverable Mode.
+ * {@link LE_FLAG_GENERAL_DISCOVERY_MODE} LE General Discoverable Mode.
+ * {@link LE_FLAG_BREDR_NOT_SUPPORTED} BR/EDR Not Supported. Bit 37 of
+ * LMP Feature Mask Definitions.
+ * {@link LE_FLAG_SIMULTANEOUS_CONTROLLER} Simultaneous LE and BR/EDR to
+ * Same Device Capable (Controller).
+ * Bit 49 of LMP Feature Mask Definitions.
+ * {@link LE_FLAG_SIMULTANEOUS_HOST} Simultaneous LE and BR/EDR to
+ * Same Device Capable (Host).
+ * Bit 55 of LMP Feature Mask Definitions.
+ * <b>0x05- 0x07 Reserved</b>
+ *
+ * @hide
+ */
+ @NonNull
+ @SystemApi
+ @LeFlag
+ public int getLeFlags() {
+ return mLeFlags;
+ }
+
+ /**
+ * @return the supported and preferred roles of the LE device.
+ *
+ * <p>Possible Values:
+ * {@link LE_DEVICE_ROLE_PERIPHERAL_ONLY} Only Peripheral supported
+ * {@link LE_DEVICE_ROLE_CENTRAL_ONLY} Only Central supported
+ * {@link LE_DEVICE_ROLE_BOTH_PREFER_PERIPHERAL} Central & Peripheral supported;
+ * Peripheral Preferred
+ * {@link LE_DEVICE_ROLE_BOTH_PREFER_CENTRAL} Only peripheral supported; Central Preferred
+ * 0x04 - 0xFF Reserved
+ *
+ * @hide
+ */
+ @NonNull
+ @SystemApi
+ @LeRole
+ public int getLeDeviceRole() {
+ return mLeDeviceRole;
+ }
+
+ /**
+ * Classic Security Constructor
+ */
+ private OobData(@NonNull byte[] classicLength, @NonNull byte[] deviceAddressWithType,
+ @NonNull byte[] confirmationHash) {
+ mClassicLength = classicLength;
+ mDeviceAddressWithType = deviceAddressWithType;
+ mConfirmationHash = confirmationHash;
+ mLeDeviceRole = -1; // Satisfy final
+ }
+
+ /**
+ * LE Security Constructor
+ */
+ private OobData(@NonNull byte[] deviceAddressWithType, @LeRole int leDeviceRole,
+ @NonNull byte[] confirmationHash) {
+ mDeviceAddressWithType = deviceAddressWithType;
+ mLeDeviceRole = leDeviceRole;
+ mConfirmationHash = confirmationHash;
+ mClassicLength = new byte[OOB_LENGTH_OCTETS]; // Satisfy final
}
private OobData(Parcel in) {
- mLeBluetoothDeviceAddress = in.createByteArray();
- mSecurityManagerTk = in.createByteArray();
- mLeSecureConnectionsConfirmation = in.createByteArray();
- mLeSecureConnectionsRandom = in.createByteArray();
+ // Both
+ mDeviceAddressWithType = in.createByteArray();
+ mConfirmationHash = in.createByteArray();
+ mRandomizerHash = in.createByteArray();
+ mDeviceName = in.createByteArray();
+
+ // Classic
+ mClassicLength = in.createByteArray();
+ mClassOfDevice = in.createByteArray();
+
+ // LE
+ mLeDeviceRole = in.readInt();
+ mLeTemporaryKey = in.createByteArray();
+ mLeAppearance = in.createByteArray();
+ mLeFlags = in.readInt();
}
+ /**
+ * @hide
+ */
@Override
public int describeContents() {
return 0;
}
+ /**
+ * @hide
+ */
@Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeByteArray(mLeBluetoothDeviceAddress);
- out.writeByteArray(mSecurityManagerTk);
- out.writeByteArray(mLeSecureConnectionsConfirmation);
- out.writeByteArray(mLeSecureConnectionsRandom);
+ public void writeToParcel(@NonNull Parcel out, int flags) {
+ // Both
+ // Required
+ out.writeByteArray(mDeviceAddressWithType);
+ // Required
+ out.writeByteArray(mConfirmationHash);
+ // Optional
+ out.writeByteArray(mRandomizerHash);
+ // Optional
+ out.writeByteArray(mDeviceName);
+
+ // Classic
+ // Required
+ out.writeByteArray(mClassicLength);
+ // Optional
+ out.writeByteArray(mClassOfDevice);
+
+ // LE
+ // Required
+ out.writeInt(mLeDeviceRole);
+ // Required
+ out.writeByteArray(mLeTemporaryKey);
+ // Optional
+ out.writeByteArray(mLeAppearance);
+ // Optional
+ out.writeInt(mLeFlags);
}
+ // For Parcelable
public static final @android.annotation.NonNull Parcelable.Creator<OobData> CREATOR =
new Parcelable.Creator<OobData>() {
public OobData createFromParcel(Parcel in) {
@@ -108,4 +969,47 @@
return new OobData[size];
}
};
+
+ /**
+ * @return a {@link String} representation of the OobData object.
+ *
+ * @hide
+ */
+ @Override
+ @NonNull
+ public String toString() {
+ return "OobData: \n\t"
+ // Both
+ + "Device Address With Type: " + toHexString(mDeviceAddressWithType) + "\n\t"
+ + "Confirmation: " + toHexString(mConfirmationHash) + "\n\t"
+ + "Randomizer: " + toHexString(mRandomizerHash) + "\n\t"
+ + "Device Name: " + toHexString(mDeviceName) + "\n\t"
+ // Classic
+ + "OobData Length: " + toHexString(mClassicLength) + "\n\t"
+ + "Class of Device: " + toHexString(mClassOfDevice) + "\n\t"
+ // LE
+ + "LE Device Role: " + toHexString(mLeDeviceRole) + "\n\t"
+ + "LE Temporary Key: " + toHexString(mLeTemporaryKey) + "\n\t"
+ + "LE Appearance: " + toHexString(mLeAppearance) + "\n\t"
+ + "LE Flags: " + toHexString(mLeFlags) + "\n\t";
+ }
+
+ @NonNull
+ private String toHexString(@NonNull int b) {
+ return toHexString(new byte[] {(byte) b});
+ }
+
+ @NonNull
+ private String toHexString(@NonNull byte b) {
+ return toHexString(new byte[] {b});
+ }
+
+ @NonNull
+ private String toHexString(@NonNull byte[] array) {
+ StringBuilder builder = new StringBuilder(array.length * 2);
+ for (byte b: array) {
+ builder.append(String.format("%02x", b));
+ }
+ return builder.toString();
+ }
}
diff --git a/core/java/android/bluetooth/le/ScanFilter.java b/core/java/android/bluetooth/le/ScanFilter.java
index 7511fd0..3c20dca 100644
--- a/core/java/android/bluetooth/le/ScanFilter.java
+++ b/core/java/android/bluetooth/le/ScanFilter.java
@@ -16,15 +16,19 @@
package android.bluetooth.le;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothDevice.AddressType;
import android.os.Parcel;
import android.os.ParcelUuid;
import android.os.Parcelable;
import com.android.internal.util.BitUtils;
+import com.android.internal.util.Preconditions;
import java.util.Arrays;
import java.util.List;
@@ -53,6 +57,11 @@
@Nullable
private final String mDeviceAddress;
+ private final @AddressType int mAddressType;
+
+ @Nullable
+ private final byte[] mIrk;
+
@Nullable
private final ParcelUuid mServiceUuid;
@Nullable
@@ -79,12 +88,12 @@
/** @hide */
public static final ScanFilter EMPTY = new ScanFilter.Builder().build();
-
private ScanFilter(String name, String deviceAddress, ParcelUuid uuid,
ParcelUuid uuidMask, ParcelUuid solicitationUuid,
ParcelUuid solicitationUuidMask, ParcelUuid serviceDataUuid,
byte[] serviceData, byte[] serviceDataMask,
- int manufacturerId, byte[] manufacturerData, byte[] manufacturerDataMask) {
+ int manufacturerId, byte[] manufacturerData, byte[] manufacturerDataMask,
+ @AddressType int addressType, @Nullable byte[] irk) {
mDeviceName = name;
mServiceUuid = uuid;
mServiceUuidMask = uuidMask;
@@ -97,6 +106,8 @@
mManufacturerId = manufacturerId;
mManufacturerData = manufacturerData;
mManufacturerDataMask = manufacturerDataMask;
+ mAddressType = addressType;
+ mIrk = irk;
}
@Override
@@ -280,6 +291,23 @@
return mDeviceAddress;
}
+ /**
+ * @hide
+ */
+ @SystemApi
+ public @AddressType int getAddressType() {
+ return mAddressType;
+ }
+
+ /**
+ * @hide
+ */
+ @SystemApi
+ @Nullable
+ public byte[] getIrk() {
+ return mIrk;
+ }
+
@Nullable
public byte[] getServiceData() {
return mServiceData;
@@ -516,8 +544,16 @@
*/
public static final class Builder {
+ /**
+ * @hide
+ */
+ @SystemApi
+ public static final int LEN_IRK_OCTETS = 16;
+
private String mDeviceName;
private String mDeviceAddress;
+ private @AddressType int mAddressType = BluetoothDevice.ADDRESS_TYPE_PUBLIC;
+ private byte[] mIrk;
private ParcelUuid mServiceUuid;
private ParcelUuid mUuidMask;
@@ -546,14 +582,130 @@
*
* @param deviceAddress The device Bluetooth address for the filter. It needs to be in the
* format of "01:02:03:AB:CD:EF". The device address can be validated using {@link
- * BluetoothAdapter#checkBluetoothAddress}.
+ * BluetoothAdapter#checkBluetoothAddress}. The @AddressType is defaulted to {@link
+ * BluetoothDevice#ADDRESS_TYPE_PUBLIC}
* @throws IllegalArgumentException If the {@code deviceAddress} is invalid.
*/
public Builder setDeviceAddress(String deviceAddress) {
- if (deviceAddress != null && !BluetoothAdapter.checkBluetoothAddress(deviceAddress)) {
+ return setDeviceAddress(deviceAddress, BluetoothDevice.ADDRESS_TYPE_PUBLIC);
+ }
+
+ /**
+ * Set filter on Address with AddressType
+ *
+ * <p>This key is used to resolve a private address from a public address.
+ *
+ * @param deviceAddress The device Bluetooth address for the filter. It needs to be in the
+ * format of "01:02:03:AB:CD:EF". The device address can be validated using {@link
+ * BluetoothAdapter#checkBluetoothAddress}. May be any type of address.
+ * @param addressType indication of the type of address
+ * e.g. {@link BluetoothDevice#ADDRESS_TYPE_PUBLIC}
+ * or {@link BluetoothDevice#ADDRESS_TYPE_RANDOM}
+ *
+ * @throws IllegalArgumentException If the {@code deviceAddress} is invalid.
+ * @throws IllegalArgumentException If the {@code addressType} is invalid length
+ * @throws NullPointerException if {@code deviceAddress} is null.
+ *
+ * @hide
+ */
+ @NonNull
+ @SystemApi
+ public Builder setDeviceAddress(@NonNull String deviceAddress,
+ @AddressType int addressType) {
+ return setDeviceAddressInternal(deviceAddress, addressType, null);
+ }
+
+ /**
+ * Set filter on Address with AddressType and the Identity Resolving Key (IRK).
+ *
+ * <p>The IRK is used to resolve a {@link BluetoothDevice#ADDRESS_TYPE_PUBLIC} from
+ * a PRIVATE_ADDRESS type.
+ *
+ * @param deviceAddress The device Bluetooth address for the filter. It needs to be in the
+ * format of "01:02:03:AB:CD:EF". The device address can be validated using {@link
+ * BluetoothAdapter#checkBluetoothAddress}. This Address type must only be PUBLIC OR RANDOM
+ * STATIC.
+ * @param addressType indication of the type of address
+ * e.g. {@link BluetoothDevice#ADDRESS_TYPE_PUBLIC}
+ * or {@link BluetoothDevice#ADDRESS_TYPE_RANDOM}
+ * @param irk non-null byte array representing the Identity Resolving Key
+ *
+ * @throws IllegalArgumentException If the {@code deviceAddress} is invalid.
+ * @throws IllegalArgumentException if the {@code irk} is invalid length.
+ * @throws IllegalArgumentException If the {@code addressType} is invalid length or is not
+ * PUBLIC or RANDOM STATIC when an IRK is present.
+ * @throws NullPointerException if {@code deviceAddress} or {@code irk} is null.
+ *
+ * @hide
+ */
+ @NonNull
+ @SystemApi
+ public Builder setDeviceAddress(@NonNull String deviceAddress,
+ @AddressType int addressType,
+ @NonNull byte[] irk) {
+ Preconditions.checkNotNull(irk);
+ if (irk.length != LEN_IRK_OCTETS) {
+ throw new IllegalArgumentException("'irk' is invalid length!");
+ }
+ return setDeviceAddressInternal(deviceAddress, addressType, irk);
+ }
+
+ /**
+ * Set filter on Address with AddressType and the Identity Resolving Key (IRK).
+ *
+ * <p>Internal setter for the device address
+ *
+ * @param deviceAddress The device Bluetooth address for the filter. It needs to be in the
+ * format of "01:02:03:AB:CD:EF". The device address can be validated using {@link
+ * BluetoothAdapter#checkBluetoothAddress}.
+ * @param addressType indication of the type of address
+ * e.g. {@link BluetoothDevice#ADDRESS_TYPE_PUBLIC}
+ * @param irk non-null byte array representing the Identity Resolving Address; nullable
+ * internally.
+ *
+ * @throws IllegalArgumentException If the {@code deviceAddress} is invalid.
+ * @throws IllegalArgumentException If the {@code addressType} is invalid length.
+ * @throws NullPointerException if {@code deviceAddress} is null.
+ *
+ * @hide
+ */
+ @NonNull
+ private Builder setDeviceAddressInternal(@NonNull String deviceAddress,
+ @AddressType int addressType,
+ @Nullable byte[] irk) {
+
+ // Make sure our deviceAddress is valid!
+ Preconditions.checkNotNull(deviceAddress);
+ if (!BluetoothAdapter.checkBluetoothAddress(deviceAddress)) {
throw new IllegalArgumentException("invalid device address " + deviceAddress);
}
+
+ // Verify type range
+ if (addressType < BluetoothDevice.ADDRESS_TYPE_PUBLIC
+ || addressType > BluetoothDevice.ADDRESS_TYPE_RANDOM) {
+ throw new IllegalArgumentException("'addressType' is invalid!");
+ }
+
+ // IRK can only be used for a PUBLIC or RANDOM (STATIC) Address.
+ if (addressType == BluetoothDevice.ADDRESS_TYPE_RANDOM) {
+ // Don't want a bad combination of address and irk!
+ if (irk != null) {
+ // Since there are 3 possible RANDOM subtypes we must check to make sure
+ // the correct type of address is used.
+ if (!BluetoothAdapter.isAddressRandomStatic(deviceAddress)) {
+ throw new IllegalArgumentException(
+ "Invalid combination: IRK requires either a PUBLIC or "
+ + "RANDOM (STATIC) Address");
+ }
+ }
+ }
+
+ // PUBLIC doesn't require extra work
+ // Without an IRK any address may be accepted
+
mDeviceAddress = deviceAddress;
+ mAddressType = addressType;
+ mIrk = irk;
return this;
}
@@ -727,7 +879,8 @@
mServiceUuid, mUuidMask, mServiceSolicitationUuid,
mServiceSolicitationUuidMask,
mServiceDataUuid, mServiceData, mServiceDataMask,
- mManufacturerId, mManufacturerData, mManufacturerDataMask);
+ mManufacturerId, mManufacturerData, mManufacturerDataMask,
+ mAddressType, mIrk);
}
}
}
diff --git a/core/java/android/bluetooth/le/ScanSettings.java b/core/java/android/bluetooth/le/ScanSettings.java
index 504118e..368d1ee 100644
--- a/core/java/android/bluetooth/le/ScanSettings.java
+++ b/core/java/android/bluetooth/le/ScanSettings.java
@@ -52,6 +52,16 @@
public static final int SCAN_MODE_LOW_LATENCY = 2;
/**
+ * Perform Bluetooth LE scan in ambient discovery mode. This mode has lower duty cycle and more
+ * aggressive scan interval than balanced mode that provides a good trade-off between scan
+ * latency and power consumption.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int SCAN_MODE_AMBIENT_DISCOVERY = 3;
+
+ /**
* Trigger a callback for every Bluetooth advertisement found that matches the filter criteria.
* If no filter is active, all advertisement packets are reported.
*/
@@ -276,10 +286,17 @@
* @throws IllegalArgumentException If the {@code scanMode} is invalid.
*/
public Builder setScanMode(int scanMode) {
- if (scanMode < SCAN_MODE_OPPORTUNISTIC || scanMode > SCAN_MODE_LOW_LATENCY) {
- throw new IllegalArgumentException("invalid scan mode " + scanMode);
+ switch (scanMode) {
+ case SCAN_MODE_OPPORTUNISTIC:
+ case SCAN_MODE_LOW_POWER:
+ case SCAN_MODE_BALANCED:
+ case SCAN_MODE_LOW_LATENCY:
+ case SCAN_MODE_AMBIENT_DISCOVERY:
+ mScanMode = scanMode;
+ break;
+ default:
+ throw new IllegalArgumentException("invalid scan mode " + scanMode);
}
- mScanMode = scanMode;
return this;
}
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 32aa037..d21462e 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -744,7 +744,7 @@
// Always log queries which take 500ms+; shorter queries are
// sampled accordingly.
private static final boolean ENABLE_CONTENT_SAMPLE = false;
- private static final int SLOW_THRESHOLD_MILLIS = 500;
+ private static final int SLOW_THRESHOLD_MILLIS = 500 * Build.HW_TIMEOUT_MULTIPLIER;
private final Random mRandom = new Random(); // guarded by itself
/** @hide */
@@ -758,7 +758,8 @@
* before we decide it must be hung.
* @hide
*/
- public static final int CONTENT_PROVIDER_PUBLISH_TIMEOUT_MILLIS = 10 * 1000;
+ public static final int CONTENT_PROVIDER_PUBLISH_TIMEOUT_MILLIS =
+ 10 * 1000 * Build.HW_TIMEOUT_MULTIPLIER;
/**
* How long we wait for an provider to be published. Should be longer than
@@ -766,10 +767,11 @@
* @hide
*/
public static final int CONTENT_PROVIDER_READY_TIMEOUT_MILLIS =
- CONTENT_PROVIDER_PUBLISH_TIMEOUT_MILLIS + 10 * 1000;
+ CONTENT_PROVIDER_PUBLISH_TIMEOUT_MILLIS + 10 * 1000 * Build.HW_TIMEOUT_MULTIPLIER;
// Timeout given a ContentProvider that has already been started and connected to.
- private static final int CONTENT_PROVIDER_TIMEOUT_MILLIS = 3 * 1000;
+ private static final int CONTENT_PROVIDER_TIMEOUT_MILLIS =
+ 3 * 1000 * Build.HW_TIMEOUT_MULTIPLIER;
// Should be >= {@link #CONTENT_PROVIDER_WAIT_TIMEOUT_MILLIS}, because that's how
// long ActivityManagerService is giving a content provider to get published if a new process
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 9c88566..fe9ed27 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3451,6 +3451,7 @@
VIBRATOR_SERVICE,
//@hide: STATUS_BAR_SERVICE,
CONNECTIVITY_SERVICE,
+ PAC_PROXY_SERVICE,
VCN_MANAGEMENT_SERVICE,
//@hide: IP_MEMORY_STORE_SERVICE,
IPSEC_SERVICE,
@@ -4017,6 +4018,17 @@
public static final String CONNECTIVITY_SERVICE = "connectivity";
/**
+ * Use with {@link #getSystemService(String)} to retrieve a {@link
+ * android.net.PacProxyManager} for handling management of
+ * pac proxy information.
+ *
+ * @see #getSystemService(String)
+ * @see android.net.PacProxyManager
+ * @hide
+ */
+ public static final String PAC_PROXY_SERVICE = "pac_proxy";
+
+ /**
* Use with {@link #getSystemService(String)} to retrieve a {@link android.net.vcn.VcnManager}
* for managing Virtual Carrier Networks
*
@@ -4087,7 +4099,8 @@
* @see #getSystemService(String)
* @hide
*/
- @TestApi public static final String TEST_NETWORK_SERVICE = "test_network";
+ @TestApi @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final String TEST_NETWORK_SERVICE = "test_network";
/**
* Use with {@link #getSystemService(String)} to retrieve a {@link
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 6bfc12d..4d68e90 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2329,6 +2329,7 @@
* @hide
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final String ACTION_CLEAR_DNS_CACHE = "android.intent.action.CLEAR_DNS_CACHE";
/**
* Alarm Changed Action: This is broadcast when the AlarmClock
diff --git a/core/java/android/content/OWNERS b/core/java/android/content/OWNERS
index d0d406a..01b554a 100644
--- a/core/java/android/content/OWNERS
+++ b/core/java/android/content/OWNERS
@@ -8,3 +8,5 @@
per-file AutofillOptions* = file:/core/java/android/service/autofill/OWNERS
per-file ContentCaptureOptions* = file:/core/java/android/service/contentcapture/OWNERS
per-file LocusId* = file:/core/java/android/service/contentcapture/OWNERS
+per-file ComponentCallbacksController = file:/services/core/java/com/android/server/wm/OWNERS
+per-file ComponentCallbacksController = charlesccchen@google.com
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 7e17256..23f5e3a 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3167,8 +3167,57 @@
public static final String FEATURE_VR_HEADTRACKING = "android.hardware.vr.headtracking";
/**
- * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
- * The device has a StrongBox hardware-backed Keystore.
+ * Feature for {@link #getSystemAvailableFeatures} and
+ * {@link #hasSystemFeature(String, int)}: If this feature is supported, the device implements
+ * the Android Keystore backed by an isolated execution environment. The version indicates
+ * which features are implemented in the isolated execution environment:
+ * <ul>
+ * <li>100: Hardware support for ECDH (see {@link javax.crypto.KeyAgreement}) and support
+ * for app-generated attestation keys (see {@link
+ * android.security.keystore.KeyGenParameterSpec.Builder#setAttestKeyAlias(String)}).
+ * <li>41: Hardware enforcement of device-unlocked keys (see {@link
+ * android.security.keystore.KeyGenParameterSpec.Builder#setUnlockedDeviceRequired(boolean)}).
+ * <li>40: Support for wrapped key import (see {@link
+ * android.security.keystore.WrappedKeyEntry}), optional support for ID attestation (see {@link
+ * android.security.keystore.KeyGenParameterSpec.Builder#setDevicePropertiesAttestationIncluded(boolean)}),
+ * attestation (see {@link
+ * android.security.keystore.KeyGenParameterSpec.Builder#setAttestationChallenge(byte[])}),
+ * AES, HMAC, ECDSA and RSA support where the secret or private key never leaves secure
+ * hardware, and support for requiring user authentication before a key can be used.
+ * </ul>
+ * This feature version is guaranteed to be set for all devices launching with Android 12 and
+ * may be set on devices launching with an earlier version. If the feature version is set, it
+ * will at least have the value 40. If it's not set the device may have a version of
+ * hardware-backed keystore but it may not support all features listed above.
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_HARDWARE_KEYSTORE = "android.hardware.hardware_keystore";
+
+ /**
+ * Feature for {@link #getSystemAvailableFeatures}, {@link #hasSystemFeature(String)}, and
+ * {@link #hasSystemFeature(String, int)}: If this feature is supported, the device implements
+ * the Android Keystore backed by a dedicated secure processor referred to as
+ * <a href="https://source.android.com/security/best-practices/hardware#strongbox-keymaster">
+ * StrongBox</a>. If this feature has a version, the version number indicates which features are
+ * implemented in StrongBox:
+ * <ul>
+ * <li>100: Hardware support for ECDH (see {@link javax.crypto.KeyAgreement}) and support
+ * for app-generated attestation keys (see {@link
+ * android.security.keystore.KeyGenParameterSpec.Builder#setAttestKeyAlias(String)}).
+ * <li>41: Hardware enforcement of device-unlocked keys (see {@link
+ * android.security.keystore.KeyGenParameterSpec.Builder#setUnlockedDeviceRequired(boolean)}).
+ * <li>40: Support for wrapped key import (see {@link
+ * android.security.keystore.WrappedKeyEntry}), optional support for ID attestation (see {@link
+ * android.security.keystore.KeyGenParameterSpec.Builder#setDevicePropertiesAttestationIncluded(boolean)}),
+ * attestation (see {@link
+ * android.security.keystore.KeyGenParameterSpec.Builder#setAttestationChallenge(byte[])}),
+ * AES, HMAC, ECDSA and RSA support where the secret or private key never leaves secure
+ * hardware, and support for requiring user authentication before a key can be used.
+ * </ul>
+ * If a device has StrongBox, this feature version number is guaranteed to be set for all
+ * devices launching with Android 12 and may be set on devices launching with an earlier
+ * version. If the feature version is set, it will at least have the value 40. If it's not
+ * set the device may have StrongBox but it may not support all features listed above.
*/
@SdkConstant(SdkConstantType.FEATURE)
public static final String FEATURE_STRONGBOX_KEYSTORE =
diff --git a/core/java/android/ddm/DdmHandleHeap.java b/core/java/android/ddm/DdmHandleHeap.java
index e24aeb2..8fa2352 100644
--- a/core/java/android/ddm/DdmHandleHeap.java
+++ b/core/java/android/ddm/DdmHandleHeap.java
@@ -30,15 +30,7 @@
*/
public class DdmHandleHeap extends ChunkHandler {
- public static final int CHUNK_HPIF = type("HPIF");
- public static final int CHUNK_HPSG = type("HPSG");
- public static final int CHUNK_HPDU = type("HPDU");
- public static final int CHUNK_HPDS = type("HPDS");
- public static final int CHUNK_NHSG = type("NHSG");
public static final int CHUNK_HPGC = type("HPGC");
- public static final int CHUNK_REAE = type("REAE");
- public static final int CHUNK_REAQ = type("REAQ");
- public static final int CHUNK_REAL = type("REAL");
private static DdmHandleHeap mInstance = new DdmHandleHeap();
@@ -50,15 +42,7 @@
* Register for the messages we're interested in.
*/
public static void register() {
- DdmServer.registerHandler(CHUNK_HPIF, mInstance);
- DdmServer.registerHandler(CHUNK_HPSG, mInstance);
- DdmServer.registerHandler(CHUNK_HPDU, mInstance);
- DdmServer.registerHandler(CHUNK_HPDS, mInstance);
- DdmServer.registerHandler(CHUNK_NHSG, mInstance);
DdmServer.registerHandler(CHUNK_HPGC, mInstance);
- DdmServer.registerHandler(CHUNK_REAE, mInstance);
- DdmServer.registerHandler(CHUNK_REAQ, mInstance);
- DdmServer.registerHandler(CHUNK_REAL, mInstance);
}
/**
@@ -81,24 +65,8 @@
Log.v("ddm-heap", "Handling " + name(request.type) + " chunk");
int type = request.type;
- if (type == CHUNK_HPIF) {
- return handleHPIF(request);
- } else if (type == CHUNK_HPSG) {
- return handleHPSGNHSG(request, false);
- } else if (type == CHUNK_HPDU) {
- return handleHPDU(request);
- } else if (type == CHUNK_HPDS) {
- return handleHPDS(request);
- } else if (type == CHUNK_NHSG) {
- return handleHPSGNHSG(request, true);
- } else if (type == CHUNK_HPGC) {
+ if (type == CHUNK_HPGC) {
return handleHPGC(request);
- } else if (type == CHUNK_REAE) {
- return handleREAE(request);
- } else if (type == CHUNK_REAQ) {
- return handleREAQ(request);
- } else if (type == CHUNK_REAL) {
- return handleREAL(request);
} else {
throw new RuntimeException("Unknown packet "
+ ChunkHandler.name(type));
@@ -106,112 +74,6 @@
}
/*
- * Handle a "HeaP InFo" request.
- */
- private Chunk handleHPIF(Chunk request) {
- ByteBuffer in = wrapChunk(request);
-
- int when = in.get();
- if (false)
- Log.v("ddm-heap", "Heap segment enable: when=" + when);
-
- boolean ok = DdmVmInternal.heapInfoNotify(when);
- if (!ok) {
- return createFailChunk(1, "Unsupported HPIF what");
- } else {
- return null; // empty response
- }
- }
-
- /*
- * Handle a "HeaP SeGment" or "Native Heap SeGment" request.
- */
- private Chunk handleHPSGNHSG(Chunk request, boolean isNative) {
- ByteBuffer in = wrapChunk(request);
-
- int when = in.get();
- int what = in.get();
- if (false)
- Log.v("ddm-heap", "Heap segment enable: when=" + when
- + ", what=" + what + ", isNative=" + isNative);
-
- boolean ok = DdmVmInternal.heapSegmentNotify(when, what, isNative);
- if (!ok) {
- return createFailChunk(1, "Unsupported HPSG what/when");
- } else {
- // TODO: if "when" is non-zero and we want to see a dump
- // right away, initiate a GC.
- return null; // empty response
- }
- }
-
- /*
- * Handle a "HeaP DUmp" request.
- *
- * This currently just returns a result code. We could pull up
- * the entire contents of the file and return them, but hprof dump
- * files can be a few megabytes.
- */
- private Chunk handleHPDU(Chunk request) {
- ByteBuffer in = wrapChunk(request);
- byte result;
-
- /* get the filename for the output file */
- int len = in.getInt();
- String fileName = getString(in, len);
- if (false)
- Log.d("ddm-heap", "Heap dump: file='" + fileName + "'");
-
- try {
- Debug.dumpHprofData(fileName);
- result = 0;
- } catch (UnsupportedOperationException uoe) {
- Log.w("ddm-heap", "hprof dumps not supported in this VM");
- result = -1;
- } catch (IOException ioe) {
- result = -1;
- } catch (RuntimeException re) {
- result = -1;
- }
-
- /* create a non-empty reply so the handler fires on completion */
- byte[] reply = { result };
- return new Chunk(CHUNK_HPDU, reply, 0, reply.length);
- }
-
- /*
- * Handle a "HeaP Dump Streaming" request.
- *
- * This tells the VM to create a heap dump and send it directly to
- * DDMS. The dumps are large enough that we don't want to copy the
- * data into a byte[] and send it from here.
- */
- private Chunk handleHPDS(Chunk request) {
- ByteBuffer in = wrapChunk(request);
- byte result;
-
- /* get the filename for the output file */
- if (false)
- Log.d("ddm-heap", "Heap dump: [DDMS]");
-
- String failMsg = null;
- try {
- Debug.dumpHprofDataDdms();
- } catch (UnsupportedOperationException uoe) {
- failMsg = "hprof dumps not supported in this VM";
- } catch (RuntimeException re) {
- failMsg = "Exception: " + re.getMessage();
- }
-
- if (failMsg != null) {
- Log.w("ddm-heap", failMsg);
- return createFailChunk(1, failMsg);
- } else {
- return null;
- }
- }
-
- /*
* Handle a "HeaP Garbage Collection" request.
*/
private Chunk handleHPGC(Chunk request) {
@@ -223,47 +85,4 @@
return null; // empty response
}
-
- /*
- * Handle a "REcent Allocation Enable" request.
- */
- private Chunk handleREAE(Chunk request) {
- ByteBuffer in = wrapChunk(request);
- boolean enable;
-
- enable = (in.get() != 0);
-
- if (false)
- Log.d("ddm-heap", "Recent allocation enable request: " + enable);
-
- DdmVmInternal.enableRecentAllocations(enable);
-
- return null; // empty response
- }
-
- /*
- * Handle a "REcent Allocation Query" request.
- */
- private Chunk handleREAQ(Chunk request) {
- //ByteBuffer in = wrapChunk(request);
-
- byte[] reply = new byte[1];
- reply[0] = DdmVmInternal.getRecentAllocationStatus() ? (byte)1 :(byte)0;
- return new Chunk(CHUNK_REAQ, reply, 0, reply.length);
- }
-
- /*
- * Handle a "REcent ALlocations" request.
- */
- private Chunk handleREAL(Chunk request) {
- //ByteBuffer in = wrapChunk(request);
-
- if (false)
- Log.d("ddm-heap", "Recent allocations request");
-
- /* generate the reply in a ready-to-go format */
- byte[] reply = DdmVmInternal.getRecentAllocations();
- return new Chunk(CHUNK_REAL, reply, 0, reply.length);
- }
}
-
diff --git a/core/java/android/ddm/DdmHandleThread.java b/core/java/android/ddm/DdmHandleThread.java
deleted file mode 100644
index 613ab75..0000000
--- a/core/java/android/ddm/DdmHandleThread.java
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * Copyright (C) 2007 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.ddm;
-
-import org.apache.harmony.dalvik.ddmc.Chunk;
-import org.apache.harmony.dalvik.ddmc.ChunkHandler;
-import org.apache.harmony.dalvik.ddmc.DdmServer;
-import org.apache.harmony.dalvik.ddmc.DdmVmInternal;
-import android.util.Log;
-import java.nio.ByteBuffer;
-
-/**
- * Handle thread-related traffic.
- */
-public class DdmHandleThread extends ChunkHandler {
-
- public static final int CHUNK_THEN = type("THEN");
- public static final int CHUNK_THCR = type("THCR");
- public static final int CHUNK_THDE = type("THDE");
- public static final int CHUNK_THST = type("THST");
- public static final int CHUNK_STKL = type("STKL");
-
- private static DdmHandleThread mInstance = new DdmHandleThread();
-
-
- /* singleton, do not instantiate */
- private DdmHandleThread() {}
-
- /**
- * Register for the messages we're interested in.
- */
- public static void register() {
- DdmServer.registerHandler(CHUNK_THEN, mInstance);
- DdmServer.registerHandler(CHUNK_THST, mInstance);
- DdmServer.registerHandler(CHUNK_STKL, mInstance);
- }
-
- /**
- * Called when the DDM server connects. The handler is allowed to
- * send messages to the server.
- */
- public void connected() {}
-
- /**
- * Called when the DDM server disconnects. Can be used to disable
- * periodic transmissions or clean up saved state.
- */
- public void disconnected() {}
-
- /**
- * Handle a chunk of data.
- */
- public Chunk handleChunk(Chunk request) {
- if (false)
- Log.v("ddm-thread", "Handling " + name(request.type) + " chunk");
- int type = request.type;
-
- if (type == CHUNK_THEN) {
- return handleTHEN(request);
- } else if (type == CHUNK_THST) {
- return handleTHST(request);
- } else if (type == CHUNK_STKL) {
- return handleSTKL(request);
- } else {
- throw new RuntimeException("Unknown packet "
- + ChunkHandler.name(type));
- }
- }
-
- /*
- * Handle a "THread notification ENable" request.
- */
- private Chunk handleTHEN(Chunk request) {
- ByteBuffer in = wrapChunk(request);
-
- boolean enable = (in.get() != 0);
- //Log.i("ddm-thread", "Thread notify enable: " + enable);
-
- DdmVmInternal.threadNotify(enable);
- return null; // empty response
- }
-
- /*
- * Handle a "THread STatus" request. This is constructed by the VM.
- */
- private Chunk handleTHST(Chunk request) {
- ByteBuffer in = wrapChunk(request);
- // currently nothing to read from "in"
-
- //Log.d("ddm-thread", "Thread status request");
-
- byte[] status = DdmVmInternal.getThreadStats();
- if (status != null)
- return new Chunk(CHUNK_THST, status, 0, status.length);
- else
- return createFailChunk(1, "Can't build THST chunk");
- }
-
- /*
- * Handle a STacK List request.
- *
- * This is done by threadId, which isn't great since those are
- * recycled. We need a thread serial ID. The Linux tid is an okay
- * answer as it's unlikely to recycle at the exact wrong moment.
- * However, we're using the short threadId in THST messages, so we
- * use them here for consistency. (One thought is to keep the current
- * thread ID in the low 16 bits and somehow serialize the top 16 bits.)
- */
- private Chunk handleSTKL(Chunk request) {
- ByteBuffer in = wrapChunk(request);
- int threadId;
-
- threadId = in.getInt();
-
- //Log.d("ddm-thread", "Stack list request " + threadId);
-
- StackTraceElement[] trace = DdmVmInternal.getStackTraceById(threadId);
- if (trace == null) {
- return createFailChunk(1, "Stack trace unavailable");
- } else {
- return createStackChunk(trace, threadId);
- }
- }
-
- /*
- * Serialize a StackTraceElement[] into an STKL chunk.
- *
- * We include the threadId in the response so the other side doesn't have
- * to match up requests and responses as carefully.
- */
- private Chunk createStackChunk(StackTraceElement[] trace, int threadId) {
- int bufferSize = 0;
-
- bufferSize += 4; // version, flags, whatever
- bufferSize += 4; // thread ID
- bufferSize += 4; // frame count
- for (StackTraceElement elem : trace) {
- bufferSize += 4 + elem.getClassName().length() * 2;
- bufferSize += 4 + elem.getMethodName().length() * 2;
- bufferSize += 4;
- if (elem.getFileName() != null)
- bufferSize += elem.getFileName().length() * 2;
- bufferSize += 4; // line number
- }
-
- ByteBuffer out = ByteBuffer.allocate(bufferSize);
- out.putInt(0);
- out.putInt(threadId);
- out.putInt(trace.length);
- for (StackTraceElement elem : trace) {
- out.putInt(elem.getClassName().length());
- putString(out, elem.getClassName());
- out.putInt(elem.getMethodName().length());
- putString(out, elem.getMethodName());
- if (elem.getFileName() != null) {
- out.putInt(elem.getFileName().length());
- putString(out, elem.getFileName());
- } else {
- out.putInt(0);
- }
- out.putInt(elem.getLineNumber());
- }
-
- return new Chunk(CHUNK_STKL, out);
- }
-}
-
diff --git a/core/java/android/ddm/DdmRegister.java b/core/java/android/ddm/DdmRegister.java
index e0faa51..ca10312 100644
--- a/core/java/android/ddm/DdmRegister.java
+++ b/core/java/android/ddm/DdmRegister.java
@@ -16,9 +16,10 @@
package android.ddm;
-import org.apache.harmony.dalvik.ddmc.DdmServer;
import android.util.Log;
+import org.apache.harmony.dalvik.ddmc.DdmServer;
+
/**
* Just a place to stick handler registrations, instead of scattering
* them around.
@@ -46,7 +47,6 @@
if (false)
Log.v("ddm", "Registering DDM message handlers");
DdmHandleHello.register();
- DdmHandleThread.register();
DdmHandleHeap.register();
DdmHandleNativeHeap.register();
DdmHandleProfiling.register();
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 7f834af..933dee3 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -2024,7 +2024,9 @@
// Tell listeners that the cameras and torch modes are unavailable and schedule a
// reconnection to camera service. When camera service is reconnected, the camera
// and torch statuses will be updated.
- for (int i = 0; i < mDeviceStatus.size(); i++) {
+ // Iterate from the end to the beginning befcause onStatusChangedLocked removes
+ // entries from the ArrayMap.
+ for (int i = mDeviceStatus.size() - 1; i >= 0; i--) {
String cameraId = mDeviceStatus.keyAt(i);
onStatusChangedLocked(ICameraServiceListener.STATUS_NOT_PRESENT, cameraId);
}
diff --git a/core/java/android/net/EthernetNetworkSpecifier.java b/core/java/android/net/EthernetNetworkSpecifier.java
new file mode 100644
index 0000000..e168588
--- /dev/null
+++ b/core/java/android/net/EthernetNetworkSpecifier.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.Objects;
+
+/**
+ * A {@link NetworkSpecifier} used to identify ethernet interfaces.
+ *
+ * @see EthernetManager
+ * @hide
+ */
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+public final class EthernetNetworkSpecifier extends NetworkSpecifier implements Parcelable {
+
+ /**
+ * Name of the network interface.
+ */
+ @NonNull
+ private final String mInterfaceName;
+
+ public EthernetNetworkSpecifier(@NonNull String interfaceName) {
+ Preconditions.checkStringNotEmpty(interfaceName);
+ mInterfaceName = interfaceName;
+ }
+
+ // This may be null in the future to support specifiers based on data other than the interface
+ // name.
+ @Nullable
+ public String getInterfaceName() {
+ return mInterfaceName;
+ }
+
+ @Override
+ public boolean canBeSatisfiedBy(@Nullable NetworkSpecifier other) {
+ return equals(other);
+ }
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (!(o instanceof EthernetNetworkSpecifier)) return false;
+ return TextUtils.equals(mInterfaceName, ((EthernetNetworkSpecifier) o).mInterfaceName);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(mInterfaceName);
+ }
+
+ @Override
+ public String toString() {
+ return "EthernetNetworkSpecifier (" + mInterfaceName + ")";
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeString(mInterfaceName);
+ }
+
+ public static final @NonNull Parcelable.Creator<EthernetNetworkSpecifier> CREATOR =
+ new Parcelable.Creator<EthernetNetworkSpecifier>() {
+ public EthernetNetworkSpecifier createFromParcel(Parcel in) {
+ return new EthernetNetworkSpecifier(in.readString());
+ }
+ public EthernetNetworkSpecifier[] newArray(int size) {
+ return new EthernetNetworkSpecifier[size];
+ }
+ };
+}
diff --git a/core/java/android/net/INetworkPolicyListener.aidl b/core/java/android/net/INetworkPolicyListener.aidl
index dfb1e99..00c6913 100644
--- a/core/java/android/net/INetworkPolicyListener.aidl
+++ b/core/java/android/net/INetworkPolicyListener.aidl
@@ -25,4 +25,5 @@
void onUidPoliciesChanged(int uid, int uidPolicies);
void onSubscriptionOverride(int subId, int overrideMask, int overrideValue, in int[] networkTypes);
void onSubscriptionPlansChanged(int subId, in SubscriptionPlan[] plans);
+ void onBlockedReasonChanged(int uid, int oldBlockedReason, int newBlockedReason);
}
diff --git a/core/java/android/net/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl
index 9bf791b..171c6a2 100644
--- a/core/java/android/net/INetworkPolicyManager.aidl
+++ b/core/java/android/net/INetworkPolicyManager.aidl
@@ -62,6 +62,7 @@
3 - enabled
*/
int getRestrictBackgroundByCaller();
+ int getRestrictBackgroundStatus(int uid);
void setDeviceIdleMode(boolean enabled);
void setWifiMeteredOverride(String networkId, int meteredOverride);
diff --git a/packages/Connectivity/framework/src/android/net/IOnSetOemNetworkPreferenceListener.aidl b/core/java/android/net/IPacProxyInstalledListener.aidl
similarity index 70%
copy from packages/Connectivity/framework/src/android/net/IOnSetOemNetworkPreferenceListener.aidl
copy to core/java/android/net/IPacProxyInstalledListener.aidl
index 7979afc..b1f946e 100644
--- a/packages/Connectivity/framework/src/android/net/IOnSetOemNetworkPreferenceListener.aidl
+++ b/core/java/android/net/IPacProxyInstalledListener.aidl
@@ -1,12 +1,11 @@
-/**
- *
+/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * 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,
@@ -17,7 +16,10 @@
package android.net;
-/** @hide */
-oneway interface IOnSetOemNetworkPreferenceListener {
- void onComplete();
+import android.net.Network;
+import android.net.ProxyInfo;
+
+/** {@hide} */
+oneway interface IPacProxyInstalledListener {
+ void onPacProxyInstalled(in Network network, in ProxyInfo proxy);
}
diff --git a/core/java/android/net/IPacProxyManager.aidl b/core/java/android/net/IPacProxyManager.aidl
new file mode 100644
index 0000000..8f65c56
--- /dev/null
+++ b/core/java/android/net/IPacProxyManager.aidl
@@ -0,0 +1,28 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing perNmissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.net.IPacProxyInstalledListener;
+import android.net.ProxyInfo;
+
+/** {@hide} */
+interface IPacProxyManager
+{
+ void addListener(IPacProxyInstalledListener listener);
+ void removeListener(IPacProxyInstalledListener listener);
+ void setCurrentProxyScriptUrl(in ProxyInfo proxyInfo);
+}
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index 1c56954..3971329 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -18,11 +18,14 @@
import static android.app.ActivityManager.procStateToString;
import static android.content.pm.PackageManager.GET_SIGNATURES;
+import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_MASK;
+import static android.net.ConnectivityManager.BLOCKED_REASON_NONE;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
import android.app.ActivityManager;
@@ -44,6 +47,8 @@
import android.util.Pair;
import android.util.Range;
+import com.android.internal.util.function.pooled.PooledLambda;
+
import com.google.android.collect.Sets;
import java.lang.annotation.Retention;
@@ -53,6 +58,7 @@
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executor;
/**
* Manager for creating and modifying network policy rules.
@@ -60,6 +66,7 @@
* @hide
*/
@TestApi
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
@SystemService(Context.NETWORK_POLICY_SERVICE)
public class NetworkPolicyManager {
@@ -198,12 +205,80 @@
})
public @interface SubscriptionOverrideMask {}
+ /**
+ * Flag to indicate that app is not exempt from any network restrictions.
+ *
+ * @hide
+ */
+ public static final int ALLOWED_REASON_NONE = 0;
+ /**
+ * Flag to indicate that app is exempt from certain network restrictions because of it being a
+ * system component.
+ *
+ * @hide
+ */
+ public static final int ALLOWED_REASON_SYSTEM = 1 << 0;
+ /**
+ * Flag to indicate that app is exempt from certain network restrictions because of it being
+ * in the foreground.
+ *
+ * @hide
+ */
+ public static final int ALLOWED_REASON_FOREGROUND = 1 << 1;
+ /**
+ * Flag to indicate that app is exempt from certain network restrictions because of it being
+ * in the {@code allow-in-power-save} list.
+ *
+ * @hide
+ */
+ public static final int ALLOWED_REASON_POWER_SAVE_ALLOWLIST = 1 << 2;
+ /**
+ * Flag to indicate that app is exempt from certain network restrictions because of it being
+ * in the {@code allow-in-power-save-except-idle} list.
+ *
+ * @hide
+ */
+ public static final int ALLOWED_REASON_POWER_SAVE_EXCEPT_IDLE_ALLOWLIST = 1 << 3;
+ /**
+ * Flag to indicate that app is exempt from certain network restrictions because of it holding
+ * certain privileged permissions.
+ *
+ * @hide
+ */
+ public static final int ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS = 1 << 4;
+ /**
+ * Flag to indicate that app is exempt from certain metered network restrictions because user
+ * explicitly exempted it.
+ *
+ * @hide
+ */
+ public static final int ALLOWED_METERED_REASON_USER_EXEMPTED = 1 << 16;
+ /**
+ * Flag to indicate that app is exempt from certain metered network restrictions because of it
+ * being a system component.
+ *
+ * @hide
+ */
+ public static final int ALLOWED_METERED_REASON_SYSTEM = 1 << 17;
+ /**
+ * Flag to indicate that app is exempt from certain metered network restrictions because of it
+ * being in the foreground.
+ *
+ * @hide
+ */
+ public static final int ALLOWED_METERED_REASON_FOREGROUND = 1 << 18;
+
+ /** @hide */
+ public static final int ALLOWED_METERED_REASON_MASK = 0xffff0000;
+
private final Context mContext;
@UnsupportedAppUsage
private INetworkPolicyManager mService;
private final Map<SubscriptionCallback, SubscriptionCallbackProxy>
- mCallbackMap = new ConcurrentHashMap<>();
+ mSubscriptionCallbackMap = new ConcurrentHashMap<>();
+ private final Map<NetworkPolicyCallback, NetworkPolicyCallbackProxy>
+ mNetworkPolicyCallbackMap = new ConcurrentHashMap<>();
/** @hide */
public NetworkPolicyManager(Context context, INetworkPolicyManager service) {
@@ -318,7 +393,7 @@
}
final SubscriptionCallbackProxy callbackProxy = new SubscriptionCallbackProxy(callback);
- if (null != mCallbackMap.putIfAbsent(callback, callbackProxy)) {
+ if (null != mSubscriptionCallbackMap.putIfAbsent(callback, callbackProxy)) {
throw new IllegalArgumentException("Callback is already registered.");
}
registerListener(callbackProxy);
@@ -331,7 +406,7 @@
throw new NullPointerException("Callback cannot be null.");
}
- final SubscriptionCallbackProxy callbackProxy = mCallbackMap.remove(callback);
+ final SubscriptionCallbackProxy callbackProxy = mSubscriptionCallbackMap.remove(callback);
if (callbackProxy == null) return;
unregisterListener(callbackProxy);
@@ -379,6 +454,26 @@
}
/**
+ * Determines if an UID is subject to metered network restrictions while running in background.
+ *
+ * @param uid The UID whose status needs to be checked.
+ * @return {@link ConnectivityManager#RESTRICT_BACKGROUND_STATUS_DISABLED},
+ * {@link ConnectivityManager##RESTRICT_BACKGROUND_STATUS_ENABLED},
+ * or {@link ConnectivityManager##RESTRICT_BACKGROUND_STATUS_WHITELISTED} to denote
+ * the current status of the UID.
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @RequiresPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK)
+ public int getRestrictBackgroundStatus(int uid) {
+ try {
+ return mService.getRestrictBackgroundStatus(uid);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Override connections to be temporarily marked as either unmetered or congested,
* along with automatic timeouts if desired.
*
@@ -460,9 +555,8 @@
* @param meteredNetwork True if the network is metered.
* @return true if networking is blocked for the given uid according to current networking
* policies.
- *
- * @hide
*/
+ @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY)
public boolean isUidNetworkingBlocked(int uid, boolean meteredNetwork) {
try {
return mService.isUidNetworkingBlocked(uid, meteredNetwork);
@@ -501,9 +595,8 @@
*
* @param uid The target uid.
* @return true if the given uid is restricted from doing networking on metered networks.
- *
- * @hide
*/
+ @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY)
public boolean isUidRestrictedOnMeteredNetworks(int uid) {
try {
return mService.isUidRestrictedOnMeteredNetworks(uid);
@@ -513,11 +606,15 @@
}
/**
- * Get multipath preference for the given network.
+ * Gets a hint on whether it is desirable to use multipath data transfer on the given network.
+ *
+ * @return One of the ConnectivityManager.MULTIPATH_PREFERENCE_* constants.
*
* @hide
*/
- public int getMultipathPreference(Network network) {
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @RequiresPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK)
+ public int getMultipathPreference(@NonNull Network network) {
try {
return mService.getMultipathPreference(network);
} catch (RemoteException e) {
@@ -689,6 +786,142 @@
return WifiInfo.sanitizeSsid(ssid);
}
+ /**
+ * Returns whether network access of an UID is blocked or not based on {@code blockedReasons}
+ * corresponding to it.
+ *
+ * {@code blockedReasons} would be a bitwise {@code OR} combination of the
+ * {@code BLOCKED_REASON_*} and/or {@code BLOCKED_METERED_REASON_*} constants.
+ *
+ * @param blockedReasons Value indicating the reasons for why the network access of an UID is
+ * blocked. If the value is equal to
+ * {@link ConnectivityManager#BLOCKED_REASON_NONE}, then
+ * it indicates that an app's network access is not blocked.
+ * @param meteredNetwork Value indicating whether the network is metered or not.
+ * @return Whether network access is blocked or not.
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static boolean isUidBlocked(int blockedReasons, boolean meteredNetwork) {
+ if (blockedReasons == BLOCKED_REASON_NONE) {
+ return false;
+ }
+ final int blockedOnAllNetworksReason = (blockedReasons & ~BLOCKED_METERED_REASON_MASK);
+ if (blockedOnAllNetworksReason != BLOCKED_REASON_NONE) {
+ return true;
+ }
+ if (meteredNetwork) {
+ return blockedReasons != BLOCKED_REASON_NONE;
+ }
+ return false;
+ }
+
+ /**
+ * Returns the {@code string} representation of {@code blockedReasons} argument.
+ *
+ * @param blockedReasons Value indicating the reasons for why the network access of an UID is
+ * blocked.
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @NonNull
+ public static String blockedReasonsToString(int blockedReasons) {
+ return DebugUtils.flagsToString(NetworkPolicyManager.class, "BLOCKED_", blockedReasons);
+ }
+
+ /**
+ * Register a {@link NetworkPolicyCallback} to listen for changes to network blocked status
+ * of apps.
+ *
+ * Note that when a caller tries to register a new callback, it might replace a previously
+ * registered callback if it is considered equal to the new one, based on the
+ * {@link Object#equals(Object)} check.
+ *
+ * @param executor The {@link Executor} to run the callback on.
+ * @param callback The {@link NetworkPolicyCallback} to be registered.
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY)
+ public void registerNetworkPolicyCallback(@Nullable Executor executor,
+ @NonNull NetworkPolicyCallback callback) {
+ if (callback == null) {
+ throw new NullPointerException("Callback cannot be null.");
+ }
+
+ final NetworkPolicyCallbackProxy callbackProxy = new NetworkPolicyCallbackProxy(
+ executor, callback);
+ registerListener(callbackProxy);
+ mNetworkPolicyCallbackMap.put(callback, callbackProxy);
+ }
+
+ /**
+ * Unregister a previously registered {@link NetworkPolicyCallback}.
+ *
+ * @param callback The {@link NetworkPolicyCallback} to be unregistered.
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY)
+ public void unregisterNetworkPolicyCallback(@NonNull NetworkPolicyCallback callback) {
+ if (callback == null) {
+ throw new NullPointerException("Callback cannot be null.");
+ }
+
+ final NetworkPolicyCallbackProxy callbackProxy = mNetworkPolicyCallbackMap.remove(callback);
+ if (callbackProxy == null) return;
+ unregisterListener(callbackProxy);
+ }
+
+ /**
+ * Interface for the callback to listen for changes to network blocked status of apps.
+ *
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public interface NetworkPolicyCallback {
+ /**
+ * Called when the reason for why the network access of an UID is blocked changes.
+ *
+ * @param uid The UID for which the blocked status changed.
+ * @param blockedReasons Value indicating the reasons for why the network access of an
+ * UID is blocked.
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ default void onUidBlockedReasonChanged(int uid, int blockedReasons) {}
+ }
+
+ /** @hide */
+ public static class NetworkPolicyCallbackProxy extends Listener {
+ private final Executor mExecutor;
+ private final NetworkPolicyCallback mCallback;
+
+ NetworkPolicyCallbackProxy(@Nullable Executor executor,
+ @NonNull NetworkPolicyCallback callback) {
+ mExecutor = executor;
+ mCallback = callback;
+ }
+
+ @Override
+ public void onBlockedReasonChanged(int uid, int oldBlockedReasons, int newBlockedReasons) {
+ if (oldBlockedReasons != newBlockedReasons) {
+ dispatchOnUidBlockedReasonChanged(mExecutor, mCallback, uid, newBlockedReasons);
+ }
+ }
+ }
+
+ private static void dispatchOnUidBlockedReasonChanged(@Nullable Executor executor,
+ @NonNull NetworkPolicyCallback callback, int uid, int blockedReasons) {
+ if (executor == null) {
+ callback.onUidBlockedReasonChanged(uid, blockedReasons);
+ } else {
+ executor.execute(PooledLambda.obtainRunnable(
+ NetworkPolicyCallback::onUidBlockedReasonChanged,
+ callback, uid, blockedReasons).recycleOnUse());
+ }
+ }
+
/** @hide */
public static class SubscriptionCallback {
/**
@@ -743,5 +976,7 @@
@Override public void onSubscriptionOverride(int subId, int overrideMask,
int overrideValue, int[] networkTypes) { }
@Override public void onSubscriptionPlansChanged(int subId, SubscriptionPlan[] plans) { }
+ @Override public void onBlockedReasonChanged(int uid,
+ int oldBlockedReasons, int newBlockedReasons) { }
}
}
diff --git a/core/java/android/net/PacProxyManager.java b/core/java/android/net/PacProxyManager.java
new file mode 100644
index 0000000..8f7ad8c
--- /dev/null
+++ b/core/java/android/net/PacProxyManager.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.annotation.SystemService;
+import android.content.Context;
+import android.os.Binder;
+import android.os.RemoteException;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.HashMap;
+import java.util.Objects;
+import java.util.concurrent.Executor;
+
+/**
+ * @hide
+ */
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+@SystemService(Context.PAC_PROXY_SERVICE)
+public class PacProxyManager {
+ private final Context mContext;
+ private final IPacProxyManager mService;
+ @GuardedBy("mListenerMap")
+ private final HashMap<PacProxyInstalledListener, PacProxyInstalledListenerProxy>
+ mListenerMap = new HashMap<>();
+
+ /** @hide */
+ public PacProxyManager(Context context, IPacProxyManager service) {
+ Objects.requireNonNull(service, "missing IPacProxyManager");
+ mContext = context;
+ mService = service;
+ }
+
+ /**
+ * Add a listener to start monitoring events reported by PacProxyService.
+ */
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.NETWORK_STACK,
+ NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
+ android.Manifest.permission.NETWORK_SETTINGS})
+ public void addPacProxyInstalledListener(@NonNull Executor executor,
+ @NonNull PacProxyInstalledListener listener) {
+ try {
+ synchronized (mListenerMap) {
+ final PacProxyInstalledListenerProxy listenerProxy =
+ new PacProxyInstalledListenerProxy(executor, listener);
+
+ if (null != mListenerMap.putIfAbsent(listener, listenerProxy)) {
+ throw new IllegalStateException("Listener is already added.");
+ }
+ mService.addListener(listenerProxy);
+ }
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Remove the listener to stop monitoring the event of PacProxyInstalledListener.
+ */
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.NETWORK_STACK,
+ NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
+ android.Manifest.permission.NETWORK_SETTINGS})
+ public void removePacProxyInstalledListener(@NonNull PacProxyInstalledListener listener) {
+ try {
+ synchronized (mListenerMap) {
+ final PacProxyInstalledListenerProxy listenerProxy = mListenerMap.remove(listener);
+ if (listenerProxy == null) return;
+ mService.removeListener(listenerProxy);
+ }
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Updates the PAC Proxy Installer with current Proxy information.
+ */
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.NETWORK_STACK,
+ NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
+ android.Manifest.permission.NETWORK_SETTINGS})
+ public void setCurrentProxyScriptUrl(@Nullable ProxyInfo proxy) {
+ try {
+ mService.setCurrentProxyScriptUrl(proxy);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * A callback interface for monitoring changes of PAC proxy information.
+ */
+ public interface PacProxyInstalledListener {
+ /**
+ * Notify that the PAC proxy has been installed. Note that this method will be called with
+ * a ProxyInfo with an empty PAC URL when the PAC proxy is removed.
+ *
+ * This method supports different PAC proxies per-network but not all devices might support
+ * per-network proxies. In that case it will be applied globally.
+ *
+ * @param network the network for which this proxy installed.
+ * @param proxy the installed proxy.
+ */
+ void onPacProxyInstalled(@Nullable Network network, @NonNull ProxyInfo proxy);
+ }
+
+ /**
+ * PacProxyInstalledListener proxy for PacProxyInstalledListener object.
+ * @hide
+ */
+ public class PacProxyInstalledListenerProxy extends IPacProxyInstalledListener.Stub {
+ private final Executor mExecutor;
+ private final PacProxyInstalledListener mListener;
+
+ PacProxyInstalledListenerProxy(Executor executor, PacProxyInstalledListener listener) {
+ mExecutor = executor;
+ mListener = listener;
+ }
+
+ @Override
+ public void onPacProxyInstalled(Network network, ProxyInfo proxy) {
+ Binder.withCleanCallingIdentity(() -> {
+ mExecutor.execute(() -> {
+ mListener.onPacProxyInstalled(network, proxy);
+ });
+ });
+ }
+ }
+}
diff --git a/core/java/android/net/PacProxySelector.java b/core/java/android/net/PacProxySelector.java
index 326943a..84b7eec 100644
--- a/core/java/android/net/PacProxySelector.java
+++ b/core/java/android/net/PacProxySelector.java
@@ -51,7 +51,7 @@
ServiceManager.getService(PROXY_SERVICE));
if (mProxyService == null) {
// Added because of b10267814 where mako is restarting.
- Log.e(TAG, "PacProxyInstaller: no proxy service");
+ Log.e(TAG, "PacProxyService: no proxy service");
}
mDefaultList = Lists.newArrayList(java.net.Proxy.NO_PROXY);
}
diff --git a/core/java/android/net/VpnManager.java b/core/java/android/net/VpnManager.java
index f472ed4..5f65d46 100644
--- a/core/java/android/net/VpnManager.java
+++ b/core/java/android/net/VpnManager.java
@@ -16,12 +16,15 @@
package android.net;
+import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
+
import static com.android.internal.util.Preconditions.checkNotNull;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
import android.annotation.UserIdInt;
import android.app.Activity;
import android.content.ComponentName;
@@ -56,18 +59,21 @@
*/
public class VpnManager {
/** Type representing a lack of VPN @hide */
+ @SystemApi(client = MODULE_LIBRARIES)
public static final int TYPE_VPN_NONE = -1;
/**
* A VPN created by an app using the {@link VpnService} API.
* @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
public static final int TYPE_VPN_SERVICE = 1;
/**
* A VPN created using a {@link VpnManager} API such as {@link #startProvisionedVpnProfile}.
* @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
public static final int TYPE_VPN_PLATFORM = 2;
/**
@@ -76,16 +82,25 @@
* @hide
*/
@Deprecated
+ @SystemApi(client = MODULE_LIBRARIES)
public static final int TYPE_VPN_LEGACY = 3;
/**
+ * An VPN created by OEM code through other means than {@link VpnService} or {@link VpnManager}.
+ * @hide
+ */
+ @SystemApi(client = MODULE_LIBRARIES)
+ public static final int TYPE_VPN_OEM = 4;
+
+ /**
* Channel for VPN notifications.
* @hide
*/
public static final String NOTIFICATION_CHANNEL_VPN = "VPN";
/** @hide */
- @IntDef(value = {TYPE_VPN_NONE, TYPE_VPN_SERVICE, TYPE_VPN_PLATFORM, TYPE_VPN_LEGACY})
+ @IntDef(value = {TYPE_VPN_NONE, TYPE_VPN_SERVICE, TYPE_VPN_PLATFORM, TYPE_VPN_LEGACY,
+ TYPE_VPN_OEM})
@Retention(RetentionPolicy.SOURCE)
public @interface VpnType {}
diff --git a/core/java/android/net/vcn/IVcnManagementService.aidl b/core/java/android/net/vcn/IVcnManagementService.aidl
index 6a3cb42..5b79f73 100644
--- a/core/java/android/net/vcn/IVcnManagementService.aidl
+++ b/core/java/android/net/vcn/IVcnManagementService.aidl
@@ -29,7 +29,7 @@
*/
interface IVcnManagementService {
void setVcnConfig(in ParcelUuid subscriptionGroup, in VcnConfig config, in String opPkgName);
- void clearVcnConfig(in ParcelUuid subscriptionGroup);
+ void clearVcnConfig(in ParcelUuid subscriptionGroup, in String opPkgName);
void addVcnUnderlyingNetworkPolicyListener(in IVcnUnderlyingNetworkPolicyListener listener);
void removeVcnUnderlyingNetworkPolicyListener(in IVcnUnderlyingNetworkPolicyListener listener);
diff --git a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
index 9f83b21..d4e8e2d 100644
--- a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
+++ b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
@@ -52,13 +52,12 @@
* Network}s.
*
* <p>A VCN connection based on this configuration will be brought up dynamically based on device
- * settings, and filed NetworkRequests. Underlying networks will be selected based on the services
- * required by this configuration (as represented by network capabilities), and must be part of the
- * subscription group under which this configuration is registered (see {@link
+ * settings, and filed NetworkRequests. Underlying Networks must provide INTERNET connectivity, and
+ * must be part of the subscription group under which this configuration is registered (see {@link
* VcnManager#setVcnConfig}).
*
- * <p>As an abstraction of a cellular network, services that can be provided by a VCN network, or
- * required for underlying networks are limited to services provided by cellular networks:
+ * <p>As an abstraction of a cellular network, services that can be provided by a VCN network are
+ * limited to services provided by cellular networks:
*
* <ul>
* <li>{@link NetworkCapabilities#NET_CAPABILITY_MMS}
@@ -214,13 +213,6 @@
checkValidCapability(cap);
}
- Preconditions.checkArgument(
- mUnderlyingCapabilities != null && !mUnderlyingCapabilities.isEmpty(),
- "underlyingCapabilities was null or empty");
- for (Integer cap : getAllUnderlyingCapabilities()) {
- checkValidCapability(cap);
- }
-
Objects.requireNonNull(mRetryIntervalsMs, "retryIntervalsMs was null");
validateRetryInterval(mRetryIntervalsMs);
@@ -295,7 +287,9 @@
*
* @see Builder#addRequiredUnderlyingCapability(int)
* @see Builder#removeRequiredUnderlyingCapability(int)
+ * @hide
*/
+ // TODO(b/182219992): Remove, and add when per-transport capabilities are supported
@NonNull
public int[] getRequiredUnderlyingCapabilities() {
// Sorted set guarantees ordering
@@ -470,7 +464,9 @@
* @return this {@link Builder} instance, for chaining
* @see VcnGatewayConnectionConfig for a list of capabilities may be required of underlying
* networks
+ * @hide
*/
+ // TODO(b/182219992): Remove, and add when per-transport capabilities are supported
@NonNull
public Builder addRequiredUnderlyingCapability(
@VcnSupportedCapability int underlyingCapability) {
@@ -492,7 +488,9 @@
* @return this {@link Builder} instance, for chaining
* @see VcnGatewayConnectionConfig for a list of capabilities may be required of underlying
* networks
+ * @hide
*/
+ // TODO(b/182219992): Remove, and add when per-transport capabilities are supported
@NonNull
@SuppressLint("BuilderSetStyle") // For consistency with NetCaps.Builder add/removeCap
public Builder removeRequiredUnderlyingCapability(
diff --git a/core/java/android/net/vcn/VcnManager.java b/core/java/android/net/vcn/VcnManager.java
index 8ebf757..abd41da 100644
--- a/core/java/android/net/vcn/VcnManager.java
+++ b/core/java/android/net/vcn/VcnManager.java
@@ -73,7 +73,8 @@
public class VcnManager {
@NonNull private static final String TAG = VcnManager.class.getSimpleName();
- private static final Map<VcnNetworkPolicyListener, VcnUnderlyingNetworkPolicyListenerBinder>
+ private static final Map<
+ VcnNetworkPolicyChangeListener, VcnUnderlyingNetworkPolicyListenerBinder>
REGISTERED_POLICY_LISTENERS = new ConcurrentHashMap<>();
@NonNull private final Context mContext;
@@ -93,13 +94,13 @@
}
/**
- * Get all currently registered VcnNetworkPolicyListeners for testing purposes.
+ * Get all currently registered VcnNetworkPolicyChangeListeners for testing purposes.
*
* @hide
*/
@VisibleForTesting(visibility = Visibility.PRIVATE)
@NonNull
- public static Map<VcnNetworkPolicyListener, VcnUnderlyingNetworkPolicyListenerBinder>
+ public static Map<VcnNetworkPolicyChangeListener, VcnUnderlyingNetworkPolicyListenerBinder>
getAllPolicyListeners() {
return Collections.unmodifiableMap(REGISTERED_POLICY_LISTENERS);
}
@@ -153,7 +154,7 @@
requireNonNull(subscriptionGroup, "subscriptionGroup was null");
try {
- mService.clearVcnConfig(subscriptionGroup);
+ mService.clearVcnConfig(subscriptionGroup, mContext.getOpPackageName());
} catch (ServiceSpecificException e) {
throw new IOException(e);
} catch (RemoteException e) {
@@ -162,14 +163,14 @@
}
// TODO(b/180537630): remove all VcnUnderlyingNetworkPolicyListener refs once Telephony is using
- // the new VcnNetworkPolicyListener API
+ // the new VcnNetworkPolicyChangeListener API
/**
* VcnUnderlyingNetworkPolicyListener is the interface through which internal system components
* can register to receive updates for VCN-underlying Network policies from the System Server.
*
* @hide
*/
- public interface VcnUnderlyingNetworkPolicyListener extends VcnNetworkPolicyListener {}
+ public interface VcnUnderlyingNetworkPolicyListener extends VcnNetworkPolicyChangeListener {}
/**
* Add a listener for VCN-underlying network policy updates.
@@ -185,7 +186,7 @@
@RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
public void addVcnUnderlyingNetworkPolicyListener(
@NonNull Executor executor, @NonNull VcnUnderlyingNetworkPolicyListener listener) {
- addVcnNetworkPolicyListener(executor, listener);
+ addVcnNetworkPolicyChangeListener(executor, listener);
}
/**
@@ -198,7 +199,7 @@
*/
public void removeVcnUnderlyingNetworkPolicyListener(
@NonNull VcnUnderlyingNetworkPolicyListener listener) {
- removeVcnNetworkPolicyListener(listener);
+ removeVcnNetworkPolicyChangeListener(listener);
}
/**
@@ -233,20 +234,20 @@
}
/**
- * VcnNetworkPolicyListener is the interface through which internal system components (e.g.
- * Network Factories) can register to receive updates for VCN-underlying Network policies from
- * the System Server.
+ * VcnNetworkPolicyChangeListener is the interface through which internal system components
+ * (e.g. Network Factories) can register to receive updates for VCN-underlying Network policies
+ * from the System Server.
*
* <p>Any Network Factory that brings up Networks capable of being VCN-underlying Networks
- * should register a VcnNetworkPolicyListener. VcnManager will then use this listener to notify
- * the registrant when VCN Network policies change. Upon receiving this signal, the listener
- * must check {@link VcnManager} for the current Network policy result for each of its Networks
- * via {@link #applyVcnNetworkPolicy(NetworkCapabilities, LinkProperties)}.
+ * should register a VcnNetworkPolicyChangeListener. VcnManager will then use this listener to
+ * notify the registrant when VCN Network policies change. Upon receiving this signal, the
+ * listener must check {@link VcnManager} for the current Network policy result for each of its
+ * Networks via {@link #applyVcnNetworkPolicy(NetworkCapabilities, LinkProperties)}.
*
* @hide
*/
@SystemApi
- public interface VcnNetworkPolicyListener {
+ public interface VcnNetworkPolicyChangeListener {
/**
* Notifies the implementation that the VCN's underlying Network policy has changed.
*
@@ -260,20 +261,21 @@
/**
* Add a listener for VCN-underlying Network policy updates.
*
- * <p>A {@link VcnNetworkPolicyListener} is eligible to begin receiving callbacks once it is
- * registered. No callbacks are guaranteed upon registration.
+ * <p>A {@link VcnNetworkPolicyChangeListener} is eligible to begin receiving callbacks once it
+ * is registered. No callbacks are guaranteed upon registration.
*
* @param executor the Executor that will be used for invoking all calls to the specified
* Listener
- * @param listener the VcnNetworkPolicyListener to be added
+ * @param listener the VcnNetworkPolicyChangeListener to be added
* @throws SecurityException if the caller does not have permission NETWORK_FACTORY
- * @throws IllegalStateException if the specified VcnNetworkPolicyListener is already registered
+ * @throws IllegalStateException if the specified VcnNetworkPolicyChangeListener is already
+ * registered
* @hide
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
- public void addVcnNetworkPolicyListener(
- @NonNull Executor executor, @NonNull VcnNetworkPolicyListener listener) {
+ public void addVcnNetworkPolicyChangeListener(
+ @NonNull Executor executor, @NonNull VcnNetworkPolicyChangeListener listener) {
requireNonNull(executor, "executor must not be null");
requireNonNull(listener, "listener must not be null");
@@ -292,15 +294,18 @@
}
/**
- * Remove the specified VcnNetworkPolicyListener from VcnManager.
+ * Remove the specified VcnNetworkPolicyChangeListener from VcnManager.
*
* <p>If the specified listener is not currently registered, this is a no-op.
*
- * @param listener the VcnNetworkPolicyListener that will be removed
+ * @param listener the VcnNetworkPolicyChangeListener that will be removed
+ * @throws SecurityException if the caller does not have permission NETWORK_FACTORY
* @hide
*/
@SystemApi
- public void removeVcnNetworkPolicyListener(@NonNull VcnNetworkPolicyListener listener) {
+ @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
+ public void removeVcnNetworkPolicyChangeListener(
+ @NonNull VcnNetworkPolicyChangeListener listener) {
requireNonNull(listener, "listener must not be null");
VcnUnderlyingNetworkPolicyListenerBinder binder =
@@ -320,8 +325,9 @@
* Applies the network policy for a {@link android.net.Network} with the given parameters.
*
* <p>Prior to a new NetworkAgent being registered, or upon notification that Carrier VCN policy
- * may have changed via {@link VcnNetworkPolicyListener#onPolicyChanged()}, a Network Provider
- * MUST poll for the updated Network policy based on that Network's capabilities and properties.
+ * may have changed via {@link VcnNetworkPolicyChangeListener#onPolicyChanged()}, a Network
+ * Provider MUST poll for the updated Network policy based on that Network's capabilities and
+ * properties.
*
* @param networkCapabilities the NetworkCapabilities to be used in determining the Network
* policy result for this Network.
@@ -433,7 +439,7 @@
* @param statusCode the code for the status change encountered by this {@link
* VcnStatusCallback}'s subscription group.
*/
- public abstract void onVcnStatusChanged(@VcnStatusCode int statusCode);
+ public abstract void onStatusChanged(@VcnStatusCode int statusCode);
/**
* Invoked when a VCN Gateway Connection corresponding to this callback's subscription group
@@ -442,7 +448,7 @@
* @param networkCapabilities an array of NetworkCapabilities.NET_CAPABILITY_* capabilities
* for the Gateway Connection that encountered the error, for identification purposes.
* These will be a sorted list with no duplicates and will match {@link
- * VcnGatewayConnectionConfig#getRequiredUnderlyingCapabilities()} for one of the {@link
+ * VcnGatewayConnectionConfig#getExposedCapabilities()} for one of the {@link
* VcnGatewayConnectionConfig}s set in the {@link VcnConfig} for this subscription
* group.
* @param errorCode the code to indicate the error that occurred
@@ -470,7 +476,7 @@
* and there is a VCN active for its specified subscription group (this may happen after the
* callback is registered).
*
- * <p>{@link VcnStatusCallback#onVcnStatusChanged(int)} will be invoked on registration with the
+ * <p>{@link VcnStatusCallback#onStatusChanged(int)} will be invoked on registration with the
* current status for the specified subscription group's VCN. If the registrant is not
* privileged for this subscription group, {@link #VCN_STATUS_CODE_NOT_CONFIGURED} will be
* returned.
@@ -532,17 +538,18 @@
}
/**
- * Binder wrapper for added VcnNetworkPolicyListeners to receive signals from System Server.
+ * Binder wrapper for added VcnNetworkPolicyChangeListeners to receive signals from System
+ * Server.
*
* @hide
*/
private static class VcnUnderlyingNetworkPolicyListenerBinder
extends IVcnUnderlyingNetworkPolicyListener.Stub {
@NonNull private final Executor mExecutor;
- @NonNull private final VcnNetworkPolicyListener mListener;
+ @NonNull private final VcnNetworkPolicyChangeListener mListener;
private VcnUnderlyingNetworkPolicyListenerBinder(
- Executor executor, VcnNetworkPolicyListener listener) {
+ Executor executor, VcnNetworkPolicyChangeListener listener) {
mExecutor = executor;
mListener = listener;
}
@@ -573,7 +580,7 @@
@Override
public void onVcnStatusChanged(@VcnStatusCode int statusCode) {
Binder.withCleanCallingIdentity(
- () -> mExecutor.execute(() -> mCallback.onVcnStatusChanged(statusCode)));
+ () -> mExecutor.execute(() -> mCallback.onStatusChanged(statusCode)));
}
// TODO(b/180521637): use ServiceSpecificException for safer Exception 'parceling'
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index 6425c25..f5130bc 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -543,6 +543,16 @@
public final native void markVintfStability();
/**
+ * Use a VINTF-stability binder w/o VINTF requirements. Should be called
+ * on a binder before it is sent out of process.
+ *
+ * This must be called before the object is sent to another process.
+ *
+ * @hide
+ */
+ public final native void forceDowngradeToSystemStability();
+
+ /**
* Flush any Binder commands pending in the current thread to the kernel
* driver. This can be
* useful to call before performing an operation that may block for a long
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index d7d3e58..189a8ac 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -138,7 +138,7 @@
*/
@UnsupportedAppUsage
@TestApi
- public static final boolean IS_EMULATOR = getString("ro.kernel.qemu").equals("1");
+ public static final boolean IS_EMULATOR = getString("ro.boot.qemu").equals("1");
/**
* A hardware serial number, if available. Alphanumeric only, case-insensitive.
@@ -1116,6 +1116,18 @@
}
/**
+ * A multiplier for various timeouts on the system.
+ *
+ * The intent is that products targeting software emulators that are orders of magnitude slower
+ * than real hardware may set this to a large number. On real devices and hardware-accelerated
+ * virtualized devices this should not be set.
+ *
+ * @hide
+ */
+ public static final int HW_TIMEOUT_MULTIPLIER =
+ SystemProperties.getInt("ro.hw_timeout_multiplier", 1);
+
+ /**
* True if Treble is enabled and required for this device.
*
* @hide
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index a4d6c38..0264d23 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -1235,9 +1235,9 @@
}
/**
- * Creates a directory with name {@code name} under an existing directory {@code baseDir}.
- * Returns a {@code File} object representing the directory on success, {@code null} on
- * failure.
+ * Creates a directory with name {@code name} under an existing directory {@code baseDir} if it
+ * doesn't exist already. Returns a {@code File} object representing the directory if it exists
+ * and {@code null} if not.
*
* @hide
*/
@@ -1247,13 +1247,23 @@
return createDir(dir) ? dir : null;
}
- /** @hide */
+ /**
+ * Ensure the given directory exists, creating it if needed. This method is threadsafe.
+ *
+ * @return false if the directory doesn't exist and couldn't be created
+ *
+ * @hide
+ */
public static boolean createDir(File dir) {
+ if (dir.mkdir()) {
+ return true;
+ }
+
if (dir.exists()) {
return dir.isDirectory();
}
- return dir.mkdir();
+ return false;
}
/**
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 8c2ca6d..9d16f18 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -16,8 +16,11 @@
package android.os;
+import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.system.ErrnoException;
@@ -104,6 +107,7 @@
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @SystemApi(client = MODULE_LIBRARIES)
public static final int VPN_UID = 1016;
/**
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 6d3b58c..385a815 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1009,8 +1009,8 @@
* Output: Nothing.
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
- public static final String ACTION_MANAGE_ALL_SUBSCRIPTIONS_SETTINGS =
- "android.settings.MANAGE_ALL_SUBSCRIPTIONS_SETTINGS";
+ public static final String ACTION_MANAGE_ALL_SIM_PROFILES_SETTINGS =
+ "android.settings.MANAGE_ALL_SIM_PROFILES_SETTINGS";
/**
* Activity Action: Show screen for controlling which apps can draw on top of other apps.
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index 9cb76c1..a3a910a 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -4557,6 +4557,15 @@
public static final String VOICE_REG_STATE = "voice_reg_state";
/**
+ * An integer value indicating the current data service state.
+ * <p>
+ * Valid values: {@link ServiceState#STATE_IN_SERVICE},
+ * {@link ServiceState#STATE_OUT_OF_SERVICE}, {@link ServiceState#STATE_EMERGENCY_ONLY},
+ * {@link ServiceState#STATE_POWER_OFF}.
+ */
+ public static final String DATA_REG_STATE = "data_reg_state";
+
+ /**
* The current registered operator numeric id.
* <p>
* In GSM/UMTS, numeric format is 3 digit country code plus 2 or 3 digit
@@ -4572,6 +4581,24 @@
* This is the same as {@link ServiceState#getIsManualSelection()}.
*/
public static final String IS_MANUAL_NETWORK_SELECTION = "is_manual_network_selection";
+
+ /**
+ * The current data network type.
+ * <p>
+ * This is the same as {@link TelephonyManager#getDataNetworkType()}.
+ */
+ public static final String DATA_NETWORK_TYPE = "data_network_type";
+
+ /**
+ * An integer value indicating the current duplex mode if the radio technology is LTE,
+ * LTE-CA or NR.
+ * <p>
+ * Valid values: {@link ServiceState#DUPLEX_MODE_UNKNOWN},
+ * {@link ServiceState#DUPLEX_MODE_FDD}, {@link ServiceState#DUPLEX_MODE_TDD}.
+ * <p>
+ * This is the same as {@link ServiceState#getDuplexMode()}.
+ */
+ public static final String DUPLEX_MODE = "duplex_mode";
}
/**
@@ -5284,7 +5311,8 @@
* which network types are allowed for
* {@link TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_USER},
* {@link TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_POWER},
- * {@link TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_CARRIER}.
+ * {@link TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_CARRIER},
+ * {@link TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G}.
* <P>Type: TEXT </P>
*
* @hide
diff --git a/core/java/android/telephony/PhoneStateListener.java b/core/java/android/telephony/PhoneStateListener.java
index 0ae5ed7..bbb1d0ca 100644
--- a/core/java/android/telephony/PhoneStateListener.java
+++ b/core/java/android/telephony/PhoneStateListener.java
@@ -21,7 +21,6 @@
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.TestApi;
-import android.compat.annotation.ChangeId;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Binder;
import android.os.Build;
@@ -1265,6 +1264,8 @@
// default implementation empty
}
+
+
/**
* The callback methods need to be called on the handler thread where
* this object was created. If the binder did that for us it'd be nice.
@@ -1576,7 +1577,12 @@
// default implementation empty
}
- public void onAllowedNetworkTypesChanged(Map allowedNetworkTypesList) {
+ public void onAllowedNetworkTypesChanged(int reason, long allowedNetworkType) {
+ // default implementation empty
+ }
+
+ public void onLinkCapacityEstimateChanged(
+ List<LinkCapacityEstimate> linkCapacityEstimateList) {
// default implementation empty
}
}
diff --git a/core/java/android/telephony/TelephonyCallback.java b/core/java/android/telephony/TelephonyCallback.java
index a2584cae..e49c82c 100644
--- a/core/java/android/telephony/TelephonyCallback.java
+++ b/core/java/android/telephony/TelephonyCallback.java
@@ -24,7 +24,6 @@
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.compat.annotation.ChangeId;
-import android.compat.annotation.UnsupportedAppUsage;
import android.os.Binder;
import android.os.Build;
import android.telephony.emergency.EmergencyNumber;
@@ -545,9 +544,6 @@
/**
* Event for changes to allowed network list based on all active subscriptions.
*
- * <p>Requires permission {@link android.Manifest.permission#READ_PHONE_STATE} or the calling
- * app has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges}).
- *
* @hide
* @see AllowedNetworkTypesListener#onAllowedNetworkTypesChanged
*/
@@ -556,6 +552,33 @@
public static final int EVENT_ALLOWED_NETWORK_TYPE_LIST_CHANGED = 35;
/**
+ * Event for changes to the legacy call state changed listener implemented by
+ * {@link PhoneStateListener#onCallStateChanged(int, String)}. This listener variant is similar
+ * to the new {@link CallStateListener#onCallStateChanged(int)} with the important distinction
+ * that it CAN provide the phone number associated with a call.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_CALL_LOG)
+ public static final int EVENT_LEGACY_CALL_STATE_CHANGED = 36;
+
+
+ /**
+ * Event for changes to the link capacity estimate (LCE)
+ *
+ * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}
+ *
+ * @see LinkCapacityEstimateChangedListener#onLinkCapacityEstimateChanged
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
+ public static final int EVENT_LINK_CAPACITY_ESTIMATE_CHANGED = 37;
+
+
+ /**
* @hide
*/
@IntDef(prefix = {"EVENT_"}, value = {
@@ -593,7 +616,9 @@
EVENT_BARRING_INFO_CHANGED,
EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED,
EVENT_DATA_ENABLED_CHANGED,
- EVENT_ALLOWED_NETWORK_TYPE_LIST_CHANGED
+ EVENT_ALLOWED_NETWORK_TYPE_LIST_CHANGED,
+ EVENT_LEGACY_CALL_STATE_CHANGED,
+ EVENT_LINK_CAPACITY_ESTIMATE_CHANGED
})
@Retention(RetentionPolicy.SOURCE)
public @interface TelephonyEvent {
@@ -1259,30 +1284,34 @@
public interface AllowedNetworkTypesListener {
/**
* Callback invoked when the current allowed network type list has changed on the
- * registered subscription.
+ * registered subscription for a specified reason.
* Note, the registered subscription is associated with {@link TelephonyManager} object
- * on which
- * {@link TelephonyManager#registerTelephonyCallback(Executor, TelephonyCallback)}
+ * on which {@link TelephonyManager#registerTelephonyCallback(Executor, TelephonyCallback)}
* was called.
* If this TelephonyManager object was created with
* {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
* given subscription ID. Otherwise, this callback applies to
* {@link SubscriptionManager#getDefaultSubscriptionId()}.
*
- * @param allowedNetworkTypesList Map associating all allowed network type reasons
- * ({@link TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_USER},
- * {@link TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_POWER},
- * {@link TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_CARRIER}, and
- * {@link TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G}) with reason's allowed
- * network type values.
+ * @param reason an allowed network type reasons.
+ * @see TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_USER
+ * @see TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_POWER
+ * @see TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_CARRIER
+ * @see TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G
+ *
+ * @param allowedNetworkType an allowed network type bitmask value. (for example,
+ * the long bitmask value is {{@link TelephonyManager#NETWORK_TYPE_BITMASK_NR}|
+ * {@link TelephonyManager#NETWORK_TYPE_BITMASK_LTE}})
+ *
* For example:
- * map{{TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_USER, long type value},
- * {TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_POWER, long type value},
- * {TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_CARRIER, long type value},
- * {TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G, long type value}}
+ * If the latest allowed network type is changed by user, then the system
+ * notifies the {@link TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_USER} and
+ * long type value}.
*/
@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
- void onAllowedNetworkTypesChanged(@NonNull Map<Integer, Long> allowedNetworkTypesList);
+ void onAllowedNetworkTypesChanged(
+ @TelephonyManager.AllowedNetworkTypesReason int reason,
+ @TelephonyManager.NetworkTypeBitMask long allowedNetworkType);
}
/**
@@ -1330,10 +1359,7 @@
/**
* Interface for current physical channel configuration listener.
- *
- * @hide
*/
- @SystemApi
public interface PhysicalChannelConfigListener {
/**
* Callback invoked when the current physical channel configuration has changed
@@ -1363,6 +1389,25 @@
@TelephonyManager.DataEnabledReason int reason);
}
+ /**
+ * Interface for link capacity estimate changed listener.
+ *
+ * @hide
+ */
+ @SystemApi
+ public interface LinkCapacityEstimateChangedListener {
+ /**
+ * Callback invoked when the link capacity estimate (LCE) changes
+ *
+ * @param linkCapacityEstimateList a list of {@link LinkCapacityEstimate}
+ * The list size is at least 1.
+ * In case of a dual connected network, the list size could be 2.
+ * Use {@link LinkCapacityEstimate#getType()} to get the type of each element.
+ */
+ @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
+ void onLinkCapacityEstimateChanged(
+ @NonNull List<LinkCapacityEstimate> linkCapacityEstimateList);
+ }
/**
* The callback methods need to be called on the handler thread where
@@ -1697,14 +1742,26 @@
enabled, reason)));
}
- public void onAllowedNetworkTypesChanged(Map allowedNetworkTypesList) {
+ public void onAllowedNetworkTypesChanged(int reason, long allowedNetworkType) {
AllowedNetworkTypesListener listener =
(AllowedNetworkTypesListener) mTelephonyCallbackWeakRef.get();
if (listener == null) return;
Binder.withCleanCallingIdentity(
() -> mExecutor.execute(
- () -> listener.onAllowedNetworkTypesChanged(allowedNetworkTypesList)));
+ () -> listener.onAllowedNetworkTypesChanged(reason,
+ allowedNetworkType)));
+ }
+
+ public void onLinkCapacityEstimateChanged(
+ List<LinkCapacityEstimate> linkCapacityEstimateList) {
+ LinkCapacityEstimateChangedListener listener =
+ (LinkCapacityEstimateChangedListener) mTelephonyCallbackWeakRef.get();
+ if (listener == null) return;
+
+ Binder.withCleanCallingIdentity(
+ () -> mExecutor.execute(() -> listener.onLinkCapacityEstimateChanged(
+ linkCapacityEstimateList)));
}
}
}
diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java
index 15d1a59..b111ec3 100644
--- a/core/java/android/telephony/TelephonyRegistryManager.java
+++ b/core/java/android/telephony/TelephonyRegistryManager.java
@@ -825,24 +825,40 @@
}
/**
- * Notify emergency number list changed on certain subscription.
- *
- * @param slotIndex for which emergency number list changed. Can be derived from subId except
- * when subId is invalid.
- * @param subId for which emergency number list changed.
+ * Notify the allowed network types has changed for a specific subscription and the specific
+ * reason.
+ * @param slotIndex for which allowed network types changed.
+ * @param subId for which allowed network types changed.
+ * @param reason an allowed network type reasons.
+ * @param allowedNetworkType an allowed network type bitmask value.
*/
public void notifyAllowedNetworkTypesChanged(int slotIndex, int subId,
- Map<Integer, Long> allowedNetworkTypeList) {
+ int reason, long allowedNetworkType) {
try {
- sRegistry.notifyAllowedNetworkTypesChanged(slotIndex, subId, allowedNetworkTypeList);
+ sRegistry.notifyAllowedNetworkTypesChanged(slotIndex, subId, reason,
+ allowedNetworkType);
} catch (RemoteException ex) {
// system process is dead
}
}
+ /**
+ * Notify that the link capacity estimate has changed.
+ * @param slotIndex for the phone object that gets the updated link capacity estimate
+ * @param subId for subscription that gets the updated link capacity estimate
+ * @param linkCapacityEstimateList a list of {@link LinkCapacityEstimate}
+ */
+ public void notifyLinkCapacityEstimateChanged(int slotIndex, int subId,
+ List<LinkCapacityEstimate> linkCapacityEstimateList) {
+ try {
+ sRegistry.notifyLinkCapacityEstimateChanged(slotIndex, subId, linkCapacityEstimateList);
+ } catch (RemoteException ex) {
+ // system server crash
+ }
+ }
+
public @NonNull Set<Integer> getEventsFromCallback(
@NonNull TelephonyCallback telephonyCallback) {
-
Set<Integer> eventList = new ArraySet<>();
if (telephonyCallback instanceof TelephonyCallback.ServiceStateListener) {
@@ -973,6 +989,10 @@
eventList.add(TelephonyCallback.EVENT_ALLOWED_NETWORK_TYPE_LIST_CHANGED);
}
+ if (telephonyCallback instanceof TelephonyCallback.LinkCapacityEstimateChangedListener) {
+ eventList.add(TelephonyCallback.EVENT_LINK_CAPACITY_ESTIMATE_CHANGED);
+ }
+
return eventList;
}
diff --git a/core/java/android/uwb/AngleMeasurement.java b/core/java/android/uwb/AngleMeasurement.java
index 9df213b..3d60373 100644
--- a/core/java/android/uwb/AngleMeasurement.java
+++ b/core/java/android/uwb/AngleMeasurement.java
@@ -38,9 +38,33 @@
private final double mErrorRadians;
private final double mConfidenceLevel;
- private AngleMeasurement(double radians, double errorRadians, double confidenceLevel) {
+ /**
+ * Constructs a new {@link AngleMeasurement} object
+ *
+ * @param radians the angle in radians
+ * @param errorRadians the error of the angle measurement in radians
+ * @param confidenceLevel confidence level of the angle measurement
+ *
+ * @throws IllegalArgumentException if the radians, errorRadians, or confidenceLevel is out of
+ * allowed range
+ */
+ public AngleMeasurement(
+ @FloatRange(from = -Math.PI, to = +Math.PI) double radians,
+ @FloatRange(from = 0.0, to = +Math.PI) double errorRadians,
+ @FloatRange(from = 0.0, to = 1.0) double confidenceLevel) {
+ if (radians < -Math.PI || radians > Math.PI) {
+ throw new IllegalArgumentException("Invalid radians: " + radians);
+ }
mRadians = radians;
+
+ if (errorRadians < 0.0 || errorRadians > Math.PI) {
+ throw new IllegalArgumentException("Invalid error radians: " + errorRadians);
+ }
mErrorRadians = errorRadians;
+
+ if (confidenceLevel < 0.0 || confidenceLevel > 1.0) {
+ throw new IllegalArgumentException("Invalid confidence level: " + confidenceLevel);
+ }
mConfidenceLevel = confidenceLevel;
}
@@ -122,11 +146,7 @@
new Creator<AngleMeasurement>() {
@Override
public AngleMeasurement createFromParcel(Parcel in) {
- Builder builder = new Builder();
- builder.setRadians(in.readDouble());
- builder.setErrorRadians(in.readDouble());
- builder.setConfidenceLevel(in.readDouble());
- return builder.build();
+ return new AngleMeasurement(in.readDouble(), in.readDouble(), in.readDouble());
}
@Override
@@ -134,82 +154,4 @@
return new AngleMeasurement[size];
}
};
-
- /**
- * Builder class for {@link AngleMeasurement}.
- */
- public static final class Builder {
- private double mRadians = Double.NaN;
- private double mErrorRadians = Double.NaN;
- private double mConfidenceLevel = Double.NaN;
-
- /**
- * Set the angle in radians
- *
- * @param radians angle in radians
- * @throws IllegalArgumentException if angle exceeds allowed limits of [-Math.PI, +Math.PI]
- */
- @NonNull
- public Builder setRadians(double radians) {
- if (radians < -Math.PI || radians > Math.PI) {
- throw new IllegalArgumentException("Invalid radians: " + radians);
- }
- mRadians = radians;
- return this;
- }
-
- /**
- * Set the angle error in radians
- *
- * @param errorRadians error of the angle in radians
- * @throws IllegalArgumentException if the error exceeds the allowed limits of [0, +Math.PI]
- */
- @NonNull
- public Builder setErrorRadians(double errorRadians) {
- if (errorRadians < 0.0 || errorRadians > Math.PI) {
- throw new IllegalArgumentException(
- "Invalid error radians: " + errorRadians);
- }
- mErrorRadians = errorRadians;
- return this;
- }
-
- /**
- * Set the angle confidence level
- *
- * @param confidenceLevel level of confidence of the angle measurement
- * @throws IllegalArgumentException if the error exceeds the allowed limits of [0.0, 1.0]
- */
- @NonNull
- public Builder setConfidenceLevel(double confidenceLevel) {
- if (confidenceLevel < 0.0 || confidenceLevel > 1.0) {
- throw new IllegalArgumentException(
- "Invalid confidence level: " + confidenceLevel);
- }
- mConfidenceLevel = confidenceLevel;
- return this;
- }
-
- /**
- * Build the {@link AngleMeasurement} object
- *
- * @throws IllegalStateException if angle, error, or confidence values are missing
- */
- @NonNull
- public AngleMeasurement build() {
- if (Double.isNaN(mRadians)) {
- throw new IllegalStateException("Angle is not set");
- }
-
- if (Double.isNaN(mErrorRadians)) {
- throw new IllegalStateException("Angle error is not set");
- }
-
- if (Double.isNaN(mConfidenceLevel)) {
- throw new IllegalStateException("Angle confidence level is not set");
- }
-
- return new AngleMeasurement(mRadians, mErrorRadians, mConfidenceLevel);
- }
- }
}
diff --git a/core/java/android/uwb/AngleOfArrivalMeasurement.java b/core/java/android/uwb/AngleOfArrivalMeasurement.java
index 3d8626b..db04ad1 100644
--- a/core/java/android/uwb/AngleOfArrivalMeasurement.java
+++ b/core/java/android/uwb/AngleOfArrivalMeasurement.java
@@ -116,9 +116,8 @@
new Creator<AngleOfArrivalMeasurement>() {
@Override
public AngleOfArrivalMeasurement createFromParcel(Parcel in) {
- Builder builder = new Builder();
-
- builder.setAzimuth(in.readParcelable(AngleMeasurement.class.getClassLoader()));
+ Builder builder =
+ new Builder(in.readParcelable(AngleMeasurement.class.getClassLoader()));
builder.setAltitude(in.readParcelable(AngleMeasurement.class.getClassLoader()));
@@ -135,18 +134,16 @@
* Builder class for {@link AngleOfArrivalMeasurement}.
*/
public static final class Builder {
- private AngleMeasurement mAzimuthAngleMeasurement = null;
+ private final AngleMeasurement mAzimuthAngleMeasurement;
private AngleMeasurement mAltitudeAngleMeasurement = null;
/**
- * Set the azimuth angle
+ * Constructs an {@link AngleOfArrivalMeasurement} object
*
- * @param azimuthAngle azimuth angle
+ * @param azimuthAngle the azimuth angle of the measurement
*/
- @NonNull
- public Builder setAzimuth(@NonNull AngleMeasurement azimuthAngle) {
+ public Builder(@NonNull AngleMeasurement azimuthAngle) {
mAzimuthAngleMeasurement = azimuthAngle;
- return this;
}
/**
@@ -162,15 +159,9 @@
/**
* Build the {@link AngleOfArrivalMeasurement} object
- *
- * @throws IllegalStateException if the required azimuth angle is not provided
*/
@NonNull
public AngleOfArrivalMeasurement build() {
- if (mAzimuthAngleMeasurement == null) {
- throw new IllegalStateException("Azimuth angle measurement is not set");
- }
-
return new AngleOfArrivalMeasurement(mAzimuthAngleMeasurement,
mAltitudeAngleMeasurement);
}
diff --git a/core/java/android/uwb/IUwbAdapter.aidl b/core/java/android/uwb/IUwbAdapter.aidl
index 468a69c..4036892 100644
--- a/core/java/android/uwb/IUwbAdapter.aidl
+++ b/core/java/android/uwb/IUwbAdapter.aidl
@@ -62,9 +62,6 @@
/**
* Request to open a new ranging session
*
- * This function must return before calling any functions in
- * IUwbAdapterCallbacks.
- *
* This function does not start the ranging session, but all necessary
* components must be initialized and ready to start a new ranging
* session prior to calling IUwbAdapterCallback#onRangingOpened.
@@ -77,12 +74,16 @@
* RANGING_SESSION_OPEN_THRESHOLD_MS milliseconds of #openRanging being called
* if the ranging session fails to be opened.
*
+ * If the provided sessionHandle is already open for the calling client, then
+ * #onRangingOpenFailed must be called and the new session must not be opened.
+ *
+ * @param sessionHandle the session handle to open ranging for
* @param rangingCallbacks the callbacks used to deliver ranging information
* @param parameters the configuration to use for ranging
- * @return a SessionHandle used to identify this ranging request
*/
- SessionHandle openRanging(in IUwbRangingCallbacks rangingCallbacks,
- in PersistableBundle parameters);
+ void openRanging(in SessionHandle sessionHandle,
+ in IUwbRangingCallbacks rangingCallbacks,
+ in PersistableBundle parameters);
/**
* Request to start ranging
diff --git a/core/java/android/uwb/RangingManager.java b/core/java/android/uwb/RangingManager.java
index c0d8187..85f2c1c 100644
--- a/core/java/android/uwb/RangingManager.java
+++ b/core/java/android/uwb/RangingManager.java
@@ -17,6 +17,7 @@
package android.uwb;
import android.annotation.NonNull;
+import android.os.CancellationSignal;
import android.os.PersistableBundle;
import android.os.RemoteException;
import android.util.Log;
@@ -32,6 +33,7 @@
private final IUwbAdapter mAdapter;
private final Hashtable<SessionHandle, RangingSession> mRangingSessionTable = new Hashtable<>();
+ private int mNextSessionId = 1;
public RangingManager(IUwbAdapter adapter) {
mAdapter = adapter;
@@ -44,29 +46,26 @@
* @param executor {@link Executor} to run callbacks
* @param callbacks {@link RangingSession.Callback} to associate with the {@link RangingSession}
* that is being opened.
- * @return a new {@link RangingSession}
+ * @return a {@link CancellationSignal} that may be used to cancel the opening of the
+ * {@link RangingSession}.
*/
- public RangingSession openSession(@NonNull PersistableBundle params, @NonNull Executor executor,
+ public CancellationSignal openSession(@NonNull PersistableBundle params,
+ @NonNull Executor executor,
@NonNull RangingSession.Callback callbacks) {
- SessionHandle sessionHandle;
- try {
- sessionHandle = mAdapter.openRanging(this, params);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
-
synchronized (this) {
- if (hasSession(sessionHandle)) {
- Log.w(TAG, "Newly created session unexpectedly reuses an active SessionHandle");
- executor.execute(() -> callbacks.onClosed(
- RangingSession.Callback.REASON_GENERIC_ERROR,
- new PersistableBundle()));
- }
-
+ SessionHandle sessionHandle = new SessionHandle(mNextSessionId++);
RangingSession session =
new RangingSession(executor, callbacks, mAdapter, sessionHandle);
mRangingSessionTable.put(sessionHandle, session);
- return session;
+ try {
+ mAdapter.openRanging(sessionHandle, this, params);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+
+ CancellationSignal cancellationSignal = new CancellationSignal();
+ cancellationSignal.setOnCancelListener(() -> session.close());
+ return cancellationSignal;
}
}
diff --git a/core/java/android/uwb/UwbManager.java b/core/java/android/uwb/UwbManager.java
index 63a6d05..844bbbe 100644
--- a/core/java/android/uwb/UwbManager.java
+++ b/core/java/android/uwb/UwbManager.java
@@ -25,6 +25,7 @@
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.content.Context;
+import android.os.CancellationSignal;
import android.os.IBinder;
import android.os.PersistableBundle;
import android.os.RemoteException;
@@ -228,14 +229,14 @@
* @param callbacks {@link RangingSession.Callback} to associate with the
* {@link RangingSession} that is being opened.
*
- * @return an {@link AutoCloseable} that is able to be used to close or cancel the opening of a
+ * @return an {@link CancellationSignal} that is able to be used to cancel the opening of a
* {@link RangingSession} that has been requested through {@link #openRangingSession}
* but has not yet been made available by
* {@link RangingSession.Callback#onOpened(RangingSession)}.
*/
@NonNull
@RequiresPermission(Manifest.permission.UWB_PRIVILEGED)
- public AutoCloseable openRangingSession(@NonNull PersistableBundle parameters,
+ public CancellationSignal openRangingSession(@NonNull PersistableBundle parameters,
@NonNull @CallbackExecutor Executor executor,
@NonNull RangingSession.Callback callbacks) {
return mRangingManager.openSession(parameters, executor, callbacks);
diff --git a/core/java/android/view/OWNERS b/core/java/android/view/OWNERS
index a86984f..4a1d685 100644
--- a/core/java/android/view/OWNERS
+++ b/core/java/android/view/OWNERS
@@ -9,6 +9,7 @@
ogunwale@google.com
jjaggi@google.com
roosa@google.com
+jreck@google.com
# Display
per-file Display*.java = file:/services/core/java/com/android/server/display/OWNERS
@@ -80,5 +81,6 @@
per-file Window*.aidl = file:/services/core/java/com/android/server/wm/OWNERS
# Scroll Capture
+per-file *ScrollCapture*.aidl = file:/packages/SystemUI/src/com/android/systemui/screenshot/OWNERS
per-file *ScrollCapture*.java = file:/packages/SystemUI/src/com/android/systemui/screenshot/OWNERS
per-file *CaptureHelper*.java = file:/packages/SystemUI/src/com/android/systemui/screenshot/OWNERS
diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java
index 10f6c61..96818fa 100644
--- a/core/java/android/view/contentcapture/ContentCaptureManager.java
+++ b/core/java/android/view/contentcapture/ContentCaptureManager.java
@@ -67,7 +67,7 @@
* <p>Content capture provides real-time, continuous capture of application activity, display and
* events to an intelligence service that is provided by the Android system. The intelligence
* service then uses that info to mediate and speed user journey through different apps. For
- * example, when the user receives a restaurant address in a chat app and switchs to a map app
+ * example, when the user receives a restaurant address in a chat app and switches to a map app
* to search for that restaurant, the intelligence service could offer an autofill dialog to
* let the user automatically select its address.
*
diff --git a/core/java/android/widget/OWNERS b/core/java/android/widget/OWNERS
index 718076b..64570a8 100644
--- a/core/java/android/widget/OWNERS
+++ b/core/java/android/widget/OWNERS
@@ -5,6 +5,8 @@
adamp@google.com
aurimas@google.com
siyamed@google.com
+mount@google.com
+njawad@google.com
per-file TextView.java, EditText.java, Editor.java = siyamed@google.com, nona@google.com, clarabayarri@google.com
diff --git a/core/java/com/android/internal/app/OWNERS b/core/java/com/android/internal/app/OWNERS
index 7ade05c..e6c911e 100644
--- a/core/java/com/android/internal/app/OWNERS
+++ b/core/java/com/android/internal/app/OWNERS
@@ -3,6 +3,9 @@
per-file *Chooser* = file:/packages/SystemUI/OWNERS
per-file SimpleIconFactory.java = file:/packages/SystemUI/OWNERS
per-file NetInitiatedActivity.java = file:/location/java/android/location/OWNERS
-per-file IVoice* = file:/core/java/android/service/voice/OWNERS
-per-file *Hotword* = file:/core/java/android/service/voice/OWNERS
per-file *BatteryStats* = file:/BATTERY_STATS_OWNERS
+
+# Voice Interaction
+per-file *Assist* = file:/core/java/android/service/voice/OWNERS
+per-file *Hotword* = file:/core/java/android/service/voice/OWNERS
+per-file *Voice* = file:/core/java/android/service/voice/OWNERS
diff --git a/core/java/com/android/internal/compat/AndroidBuildClassifier.java b/core/java/com/android/internal/compat/AndroidBuildClassifier.java
index 0b937fa..364db06 100644
--- a/core/java/com/android/internal/compat/AndroidBuildClassifier.java
+++ b/core/java/com/android/internal/compat/AndroidBuildClassifier.java
@@ -31,4 +31,14 @@
public boolean isFinalBuild() {
return "REL".equals(Build.VERSION.CODENAME);
}
+
+ /**
+ * The current platform SDK version.
+ */
+ public int platformTargetSdk() {
+ if (isFinalBuild()) {
+ return Build.VERSION.SDK_INT;
+ }
+ return Build.VERSION_CODES.CUR_DEVELOPMENT;
+ }
}
diff --git a/core/java/com/android/internal/compat/CompatibilityOverrideConfig.java b/core/java/com/android/internal/compat/CompatibilityOverrideConfig.java
index 1c222a7..9a02b7b 100644
--- a/core/java/com/android/internal/compat/CompatibilityOverrideConfig.java
+++ b/core/java/com/android/internal/compat/CompatibilityOverrideConfig.java
@@ -40,8 +40,7 @@
overrides = new HashMap<>();
for (int i = 0; i < keyCount; i++) {
long key = in.readLong();
- PackageOverride override = in.readParcelable(PackageOverride.class.getClassLoader());
- overrides.put(key, override);
+ overrides.put(key, PackageOverride.createFromParcel(in));
}
}
@@ -55,7 +54,7 @@
dest.writeInt(overrides.size());
for (Long key : overrides.keySet()) {
dest.writeLong(key);
- dest.writeParcelable(overrides.get(key), 0);
+ overrides.get(key).writeToParcel(dest);
}
}
diff --git a/core/java/com/android/internal/compat/IPlatformCompat.aidl b/core/java/com/android/internal/compat/IPlatformCompat.aidl
index 60213e4..78d1d22 100644
--- a/core/java/com/android/internal/compat/IPlatformCompat.aidl
+++ b/core/java/com/android/internal/compat/IPlatformCompat.aidl
@@ -151,15 +151,23 @@
void setOverrides(in CompatibilityChangeConfig overrides, in String packageName);
/**
- * Adds overrides to compatibility changes.
+ * Adds overrides to compatibility changes on release builds.
*
- * <p>Kills the app to allow the changes to take effect.
+ * <p>The caller to this API needs to hold
+ * {@code android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD} and all change ids
+ * in {@code overrides} need to annotated with {@link android.compat.annotation.Overridable}.
+ *
+ * A release build in this definition means that {@link android.os.Build#IS_DEBUGGABLE} needs to
+ * be {@code false}.
+ *
+ * <p>Note that this does not kill the app, and therefore overrides read from the app process
+ * will not be updated. Overrides read from the system process do take effect.
*
* @param overrides parcelable containing the compat change overrides to be applied
* @param packageName the package name of the app whose changes will be overridden
* @throws SecurityException if overriding changes is not permitted
*/
- void setOverridesFromInstaller(in CompatibilityOverrideConfig overrides, in String packageName);
+ void setOverridesOnReleaseBuilds(in CompatibilityOverrideConfig overrides, in String packageName);
/**
* Adds overrides to compatibility changes.
diff --git a/core/java/com/android/internal/compat/OverrideAllowedState.java b/core/java/com/android/internal/compat/OverrideAllowedState.java
index c0bbe50..e408be2 100644
--- a/core/java/com/android/internal/compat/OverrideAllowedState.java
+++ b/core/java/com/android/internal/compat/OverrideAllowedState.java
@@ -34,7 +34,8 @@
DISABLED_NON_TARGET_SDK,
DISABLED_TARGET_SDK_TOO_HIGH,
DEFERRED_VERIFICATION,
- LOGGING_ONLY_CHANGE
+ LOGGING_ONLY_CHANGE,
+ PLATFORM_TOO_OLD
})
@Retention(RetentionPolicy.SOURCE)
public @interface State {
@@ -65,6 +66,10 @@
* Change is marked as logging only, and cannot be toggled.
*/
public static final int LOGGING_ONLY_CHANGE = 5;
+ /**
+ * Change is gated by a target sdk version newer than the current platform sdk version.
+ */
+ public static final int PLATFORM_TOO_OLD = 6;
@State
public final int state;
@@ -123,6 +128,11 @@
throw new SecurityException(String.format(
"Cannot override %1$d because it is marked as a logging-only change.",
changeId));
+ case PLATFORM_TOO_OLD:
+ throw new SecurityException(String.format(
+ "Cannot override %1$d for %2$s because the change's targetSdk threshold "
+ + "(%3$d) is above the platform sdk.",
+ changeId, packageName, changeIdTargetSdk));
}
}
@@ -170,6 +180,8 @@
return "DEFERRED_VERIFICATION";
case LOGGING_ONLY_CHANGE:
return "LOGGING_ONLY_CHANGE";
+ case PLATFORM_TOO_OLD:
+ return "PLATFORM_TOO_OLD";
}
return "UNKNOWN";
}
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index c220428..5fea76a 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -41,7 +41,6 @@
import android.os.ZygoteProcess;
import android.os.storage.StorageManager;
import android.provider.DeviceConfig;
-import android.security.keystore.AndroidKeyStoreProvider;
import android.system.ErrnoException;
import android.system.Os;
import android.system.OsConstants;
@@ -74,7 +73,6 @@
import java.io.InputStreamReader;
import java.security.Provider;
import java.security.Security;
-import java.util.Optional;
/**
* Startup class for the zygote process.
@@ -227,17 +225,7 @@
// AndroidKeyStoreProvider.install() manipulates the list of JCA providers to insert
// preferred providers. Note this is not done via security.properties as the JCA providers
// are not on the classpath in the case of, for example, raw dalvikvm runtimes.
- // TODO b/171305684 This code is used to conditionally enable the installation of the
- // Keystore 2.0 provider to enable teams adjusting to Keystore 2.0 at their own
- // pace. This code will be removed when all calling code was adjusted to
- // Keystore 2.0.
- Optional<Boolean> keystore2_enabled =
- android.sysprop.Keystore2Properties.keystore2_enabled();
- if (keystore2_enabled.isPresent() && keystore2_enabled.get()) {
- android.security.keystore2.AndroidKeyStoreProvider.install();
- } else {
- AndroidKeyStoreProvider.install();
- }
+ android.security.keystore2.AndroidKeyStoreProvider.install();
Log.i(TAG, "Installed AndroidKeyStoreProvider in "
+ (SystemClock.uptimeMillis() - startTime) + "ms.");
Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
diff --git a/core/java/com/android/internal/telephony/IPhoneStateListener.aidl b/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
index ee94ef8..b90722c 100644
--- a/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
+++ b/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
@@ -21,6 +21,7 @@
import android.telephony.CellIdentity;
import android.telephony.CellInfo;
import android.telephony.DataConnectionRealTimeInfo;
+import android.telephony.LinkCapacityEstimate;
import android.telephony.TelephonyDisplayInfo;
import android.telephony.PhoneCapability;
import android.telephony.PhysicalChannelConfig;
@@ -71,5 +72,6 @@
void onBarringInfoChanged(in BarringInfo barringInfo);
void onPhysicalChannelConfigChanged(in List<PhysicalChannelConfig> configs);
void onDataEnabledChanged(boolean enabled, int reason);
- void onAllowedNetworkTypesChanged(in Map allowedNetworkTypeList);
+ void onAllowedNetworkTypesChanged(in int reason, in long allowedNetworkType);
+ void onLinkCapacityEstimateChanged(in List<LinkCapacityEstimate> linkCapacityEstimateList);
}
diff --git a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index 8d69158..0e35c84 100644
--- a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -23,6 +23,7 @@
import android.telephony.CallQuality;
import android.telephony.CellIdentity;
import android.telephony.CellInfo;
+import android.telephony.LinkCapacityEstimate;
import android.telephony.TelephonyDisplayInfo;
import android.telephony.ims.ImsReasonInfo;
import android.telephony.PhoneCapability;
@@ -94,5 +95,7 @@
void notifyPhysicalChannelConfigForSubscriber(in int subId,
in List<PhysicalChannelConfig> configs);
void notifyDataEnabled(in int phoneId, int subId, boolean enabled, int reason);
- void notifyAllowedNetworkTypesChanged(in int phoneId, in int subId, in Map allowedNetworkTypeList);
+ void notifyAllowedNetworkTypesChanged(in int phoneId, in int subId, in int reason, in long allowedNetworkType);
+ void notifyLinkCapacityEstimateChanged(in int phoneId, in int subId,
+ in List<LinkCapacityEstimate> linkCapacityEstimateList);
}
diff --git a/core/java/com/android/internal/util/LocationPermissionChecker.java b/core/java/com/android/internal/util/LocationPermissionChecker.java
deleted file mode 100644
index d67bd7a..0000000
--- a/core/java/com/android/internal/util/LocationPermissionChecker.java
+++ /dev/null
@@ -1,303 +0,0 @@
-/*
- * 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.internal.util;
-
-import android.Manifest;
-import android.annotation.IntDef;
-import android.annotation.Nullable;
-import android.app.ActivityManager;
-import android.app.AppOpsManager;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.location.LocationManager;
-import android.net.NetworkStack;
-import android.os.Binder;
-import android.os.Build;
-import android.os.UserHandle;
-import android.util.Log;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-
-/**
- * The methods used for location permission and location mode checking.
- *
- * @hide
- */
-public class LocationPermissionChecker {
-
- private static final String TAG = "LocationPermissionChecker";
-
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(prefix = {"LOCATION_PERMISSION_CHECK_STATUS_"}, value = {
- SUCCEEDED,
- ERROR_LOCATION_MODE_OFF,
- ERROR_LOCATION_PERMISSION_MISSING,
- })
- public @interface LocationPermissionCheckStatus{}
-
- // The location permission check succeeded.
- public static final int SUCCEEDED = 0;
- // The location mode turns off for the caller.
- public static final int ERROR_LOCATION_MODE_OFF = 1;
- // The location permission isn't granted for the caller.
- public static final int ERROR_LOCATION_PERMISSION_MISSING = 2;
-
- private final Context mContext;
- private final AppOpsManager mAppOpsManager;
-
- public LocationPermissionChecker(Context context) {
- mContext = context;
- mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
- }
-
- /**
- * Check location permission granted by the caller.
- *
- * This API check if the location mode enabled for the caller and the caller has
- * ACCESS_COARSE_LOCATION permission is targetSDK<29, otherwise, has ACCESS_FINE_LOCATION.
- *
- * @param pkgName package name of the application requesting access
- * @param featureId The feature in the package
- * @param uid The uid of the package
- * @param message A message describing why the permission was checked. Only needed if this is
- * not inside of a two-way binder call from the data receiver
- *
- * @return {@code true} returns if the caller has location permission and the location mode is
- * enabled.
- */
- public boolean checkLocationPermission(String pkgName, @Nullable String featureId,
- int uid, @Nullable String message) {
- return checkLocationPermissionInternal(pkgName, featureId, uid, message) == SUCCEEDED;
- }
-
- /**
- * Check location permission granted by the caller.
- *
- * This API check if the location mode enabled for the caller and the caller has
- * ACCESS_COARSE_LOCATION permission is targetSDK<29, otherwise, has ACCESS_FINE_LOCATION.
- * Compared with {@link #checkLocationPermission(String, String, int, String)}, this API returns
- * the detail information about the checking result, including the reason why it's failed and
- * logs the error for the caller.
- *
- * @param pkgName package name of the application requesting access
- * @param featureId The feature in the package
- * @param uid The uid of the package
- * @param message A message describing why the permission was checked. Only needed if this is
- * not inside of a two-way binder call from the data receiver
- *
- * @return {@link LocationPermissionCheckStatus} the result of the location permission check.
- */
- public @LocationPermissionCheckStatus int checkLocationPermissionWithDetailInfo(
- String pkgName, @Nullable String featureId, int uid, @Nullable String message) {
- final int result = checkLocationPermissionInternal(pkgName, featureId, uid, message);
- switch (result) {
- case ERROR_LOCATION_MODE_OFF:
- Log.e(TAG, "Location mode is disabled for the device");
- break;
- case ERROR_LOCATION_PERMISSION_MISSING:
- Log.e(TAG, "UID " + uid + " has no location permission");
- break;
- }
- return result;
- }
-
- /**
- * Enforce the caller has location permission.
- *
- * This API determines if the location mode enabled for the caller and the caller has
- * ACCESS_COARSE_LOCATION permission is targetSDK<29, otherwise, has ACCESS_FINE_LOCATION.
- * SecurityException is thrown if the caller has no permission or the location mode is disabled.
- *
- * @param pkgName package name of the application requesting access
- * @param featureId The feature in the package
- * @param uid The uid of the package
- * @param message A message describing why the permission was checked. Only needed if this is
- * not inside of a two-way binder call from the data receiver
- */
- public void enforceLocationPermission(String pkgName, @Nullable String featureId, int uid,
- @Nullable String message) throws SecurityException {
- final int result = checkLocationPermissionInternal(pkgName, featureId, uid, message);
-
- switch (result) {
- case ERROR_LOCATION_MODE_OFF:
- throw new SecurityException("Location mode is disabled for the device");
- case ERROR_LOCATION_PERMISSION_MISSING:
- throw new SecurityException("UID " + uid + " has no location permission");
- }
- }
-
- private int checkLocationPermissionInternal(String pkgName, @Nullable String featureId,
- int uid, @Nullable String message) {
- checkPackage(uid, pkgName);
-
- // Apps with NETWORK_SETTINGS, NETWORK_SETUP_WIZARD, NETWORK_STACK & MAINLINE_NETWORK_STACK
- // are granted a bypass.
- if (checkNetworkSettingsPermission(uid) || checkNetworkSetupWizardPermission(uid)
- || checkNetworkStackPermission(uid) || checkMainlineNetworkStackPermission(uid)) {
- return SUCCEEDED;
- }
-
- // Location mode must be enabled
- if (!isLocationModeEnabled()) {
- return ERROR_LOCATION_MODE_OFF;
- }
-
- // LocationAccess by App: caller must have Coarse/Fine Location permission to have access to
- // location information.
- if (!checkCallersLocationPermission(pkgName, featureId, uid,
- true /* coarseForTargetSdkLessThanQ */, message)) {
- return ERROR_LOCATION_PERMISSION_MISSING;
- }
- return SUCCEEDED;
- }
-
- /**
- * Checks that calling process has android.Manifest.permission.ACCESS_FINE_LOCATION or
- * android.Manifest.permission.ACCESS_COARSE_LOCATION (depending on config/targetSDK level)
- * and a corresponding app op is allowed for this package and uid.
- *
- * @param pkgName PackageName of the application requesting access
- * @param featureId The feature in the package
- * @param uid The uid of the package
- * @param coarseForTargetSdkLessThanQ If true and the targetSDK < Q then will check for COARSE
- * else (false or targetSDK >= Q) then will check for FINE
- * @param message A message describing why the permission was checked. Only needed if this is
- * not inside of a two-way binder call from the data receiver
- */
- public boolean checkCallersLocationPermission(String pkgName, @Nullable String featureId,
- int uid, boolean coarseForTargetSdkLessThanQ, @Nullable String message) {
-
- boolean isTargetSdkLessThanQ = isTargetSdkLessThan(pkgName, Build.VERSION_CODES.Q, uid);
-
- String permissionType = Manifest.permission.ACCESS_FINE_LOCATION;
- if (coarseForTargetSdkLessThanQ && isTargetSdkLessThanQ) {
- // Having FINE permission implies having COARSE permission (but not the reverse)
- permissionType = Manifest.permission.ACCESS_COARSE_LOCATION;
- }
- if (getUidPermission(permissionType, uid) == PackageManager.PERMISSION_DENIED) {
- return false;
- }
-
- // Always checking FINE - even if will not enforce. This will record the request for FINE
- // so that a location request by the app is surfaced to the user.
- boolean isFineLocationAllowed = noteAppOpAllowed(
- AppOpsManager.OPSTR_FINE_LOCATION, pkgName, featureId, uid, message);
- if (isFineLocationAllowed) {
- return true;
- }
- if (coarseForTargetSdkLessThanQ && isTargetSdkLessThanQ) {
- return noteAppOpAllowed(AppOpsManager.OPSTR_COARSE_LOCATION, pkgName, featureId, uid,
- message);
- }
- return false;
- }
-
- /**
- * Retrieves a handle to LocationManager (if not already done) and check if location is enabled.
- */
- public boolean isLocationModeEnabled() {
- final LocationManager LocationManager =
- (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
- try {
- return LocationManager.isLocationEnabledForUser(UserHandle.of(
- getCurrentUser()));
- } catch (Exception e) {
- Log.e(TAG, "Failure to get location mode via API, falling back to settings", e);
- return false;
- }
- }
-
- private boolean isTargetSdkLessThan(String packageName, int versionCode, int callingUid) {
- final long ident = Binder.clearCallingIdentity();
- try {
- if (mContext.getPackageManager().getApplicationInfoAsUser(
- packageName, 0,
- UserHandle.getUserHandleForUid(callingUid)).targetSdkVersion
- < versionCode) {
- return true;
- }
- } catch (PackageManager.NameNotFoundException e) {
- // In case of exception, assume unknown app (more strict checking)
- // Note: This case will never happen since checkPackage is
- // called to verify validity before checking App's version.
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- return false;
- }
-
- private boolean noteAppOpAllowed(String op, String pkgName, @Nullable String featureId,
- int uid, @Nullable String message) {
- return mAppOpsManager.noteOp(op, uid, pkgName, featureId, message)
- == AppOpsManager.MODE_ALLOWED;
- }
-
- private void checkPackage(int uid, String pkgName)
- throws SecurityException {
- if (pkgName == null) {
- throw new SecurityException("Checking UID " + uid + " but Package Name is Null");
- }
- mAppOpsManager.checkPackage(uid, pkgName);
- }
-
- @VisibleForTesting
- protected int getCurrentUser() {
- return ActivityManager.getCurrentUser();
- }
-
- private int getUidPermission(String permissionType, int uid) {
- // We don't care about pid, pass in -1
- return mContext.checkPermission(permissionType, -1, uid);
- }
-
- /**
- * Returns true if the |uid| holds NETWORK_SETTINGS permission.
- */
- public boolean checkNetworkSettingsPermission(int uid) {
- return getUidPermission(android.Manifest.permission.NETWORK_SETTINGS, uid)
- == PackageManager.PERMISSION_GRANTED;
- }
-
- /**
- * Returns true if the |uid| holds NETWORK_SETUP_WIZARD permission.
- */
- public boolean checkNetworkSetupWizardPermission(int uid) {
- return getUidPermission(android.Manifest.permission.NETWORK_SETUP_WIZARD, uid)
- == PackageManager.PERMISSION_GRANTED;
- }
-
- /**
- * Returns true if the |uid| holds NETWORK_STACK permission.
- */
- public boolean checkNetworkStackPermission(int uid) {
- return getUidPermission(android.Manifest.permission.NETWORK_STACK, uid)
- == PackageManager.PERMISSION_GRANTED;
- }
-
- /**
- * Returns true if the |uid| holds MAINLINE_NETWORK_STACK permission.
- */
- public boolean checkMainlineNetworkStackPermission(int uid) {
- return getUidPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, uid)
- == PackageManager.PERMISSION_GRANTED;
- }
-
-}
diff --git a/core/java/com/android/internal/util/Protocol.java b/core/java/com/android/internal/util/Protocol.java
index 276cad9..bbd738b 100644
--- a/core/java/com/android/internal/util/Protocol.java
+++ b/core/java/com/android/internal/util/Protocol.java
@@ -59,8 +59,6 @@
public static final int BASE_TETHERING = 0x00050000;
public static final int BASE_NSD_MANAGER = 0x00060000;
public static final int BASE_NETWORK_STATE_TRACKER = 0x00070000;
- public static final int BASE_CONNECTIVITY_MANAGER = 0x00080000;
- public static final int BASE_NETWORK_AGENT = 0x00081000;
public static final int BASE_NETWORK_FACTORY = 0x00083000;
public static final int BASE_ETHERNET = 0x00084000;
public static final int BASE_LOWPAN = 0x00085000;
diff --git a/core/java/com/android/internal/view/inline/OWNERS b/core/java/com/android/internal/view/inline/OWNERS
new file mode 100644
index 0000000..edfb211
--- /dev/null
+++ b/core/java/com/android/internal/view/inline/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/view/autofill/OWNERS
diff --git a/core/java/com/android/internal/widget/OWNERS b/core/java/com/android/internal/widget/OWNERS
index d284d51..8e68be0 100644
--- a/core/java/com/android/internal/widget/OWNERS
+++ b/core/java/com/android/internal/widget/OWNERS
@@ -1,4 +1,6 @@
per-file PointerLocationView.java = michaelwr@google.com, svv@google.com
+per-file RecyclerView.java = mount@google.com
+per-file ViewPager.java = mount@google.com
# LockSettings related
per-file *LockPattern* = file:/services/core/java/com/android/server/locksettings/OWNERS
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index c01f741..ed84434 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -630,6 +630,12 @@
char saveResolvedClassesDelayMsOptsBuf[
sizeof("-Xps-save-resolved-classes-delay-ms:")-1 + PROPERTY_VALUE_MAX];
char madviseRandomOptsBuf[sizeof("-XX:MadviseRandomAccess:")-1 + PROPERTY_VALUE_MAX];
+ char madviseWillNeedFileSizeVdex[
+ sizeof("-XMadviseWillNeedVdexFileSize:")-1 + PROPERTY_VALUE_MAX];
+ char madviseWillNeedFileSizeOdex[
+ sizeof("-XMadviseWillNeedOdexFileSize:")-1 + PROPERTY_VALUE_MAX];
+ char madviseWillNeedFileSizeArt[
+ sizeof("-XMadviseWillNeedArtFileSize:")-1 + PROPERTY_VALUE_MAX];
char gctypeOptsBuf[sizeof("-Xgc:")-1 + PROPERTY_VALUE_MAX];
char backgroundgcOptsBuf[sizeof("-XX:BackgroundGC=")-1 + PROPERTY_VALUE_MAX];
char heaptargetutilizationOptsBuf[sizeof("-XX:HeapTargetUtilization=")-1 + PROPERTY_VALUE_MAX];
@@ -838,6 +844,22 @@
parseRuntimeOption("dalvik.vm.madvise-random", madviseRandomOptsBuf, "-XX:MadviseRandomAccess:");
/*
+ * Use default platform configuration as limits for madvising,
+ * when no properties are specified.
+ */
+ parseRuntimeOption("dalvik.vm.madvise.vdexfile.size",
+ madviseWillNeedFileSizeVdex,
+ "-XMadviseWillNeedVdexFileSize:");
+
+ parseRuntimeOption("dalvik.vm.madvise.odexfile.size",
+ madviseWillNeedFileSizeOdex,
+ "-XMadviseWillNeedOdexFileSize:");
+
+ parseRuntimeOption("dalvik.vm.madvise.artfile.size",
+ madviseWillNeedFileSizeArt,
+ "-XMadviseWillNeedArtFileSize:");
+
+ /*
* Profile related options.
*/
parseRuntimeOption("dalvik.vm.hot-startup-method-samples", hotstartupsamplesOptsBuf,
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index 065c79b..452f55a 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -1419,6 +1419,42 @@
return nativeToJavaStatus(status);
}
+static jint android_media_AudioTrack_getStartThresholdInFrames(JNIEnv *env, jobject thiz) {
+ sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
+ if (lpTrack == nullptr) {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Unable to retrieve AudioTrack pointer for getStartThresholdInFrames()");
+ return (jint)AUDIO_JAVA_ERROR;
+ }
+ const ssize_t result = lpTrack->getStartThresholdInFrames();
+ if (result <= 0) {
+ jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
+ "Internal error detected in getStartThresholdInFrames() = %zd",
+ result);
+ return (jint)AUDIO_JAVA_ERROR;
+ }
+ return (jint)result; // this should be a positive value.
+}
+
+static jint android_media_AudioTrack_setStartThresholdInFrames(JNIEnv *env, jobject thiz,
+ jint startThresholdInFrames) {
+ sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
+ if (lpTrack == nullptr) {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Unable to retrieve AudioTrack pointer for setStartThresholdInFrames()");
+ return (jint)AUDIO_JAVA_ERROR;
+ }
+ // non-positive values of startThresholdInFrames are not allowed by the Java layer.
+ const ssize_t result = lpTrack->setStartThresholdInFrames(startThresholdInFrames);
+ if (result <= 0) {
+ jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
+ "Internal error detected in setStartThresholdInFrames() = %zd",
+ result);
+ return (jint)AUDIO_JAVA_ERROR;
+ }
+ return (jint)result; // this should be a positive value.
+}
+
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
static const JNINativeMethod gMethods[] = {
@@ -1496,6 +1532,10 @@
(void *)android_media_AudioTrack_getAudioDescriptionMixLeveldB},
{"native_set_dual_mono_mode", "(I)I", (void *)android_media_AudioTrack_setDualMonoMode},
{"native_get_dual_mono_mode", "([I)I", (void *)android_media_AudioTrack_getDualMonoMode},
+ {"native_setStartThresholdInFrames", "(I)I",
+ (void *)android_media_AudioTrack_setStartThresholdInFrames},
+ {"native_getStartThresholdInFrames", "()I",
+ (void *)android_media_AudioTrack_getStartThresholdInFrames},
};
// field names found in android/media/AudioTrack.java
diff --git a/core/jni/android_net_NetworkUtils.cpp b/core/jni/android_net_NetworkUtils.cpp
index 7508108..1cee895 100644
--- a/core/jni/android_net_NetworkUtils.cpp
+++ b/core/jni/android_net_NetworkUtils.cpp
@@ -52,27 +52,6 @@
// FrameworkListener limits the size of commands to 4096 bytes.
constexpr int MAXCMDSIZE = 4096;
-static void throwErrnoException(JNIEnv* env, const char* functionName, int error) {
- ScopedLocalRef<jstring> detailMessage(env, env->NewStringUTF(functionName));
- if (detailMessage.get() == NULL) {
- // Not really much we can do here. We're probably dead in the water,
- // but let's try to stumble on...
- env->ExceptionClear();
- }
- static jclass errnoExceptionClass =
- MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/system/ErrnoException"));
-
- static jmethodID errnoExceptionCtor =
- GetMethodIDOrDie(env, errnoExceptionClass,
- "<init>", "(Ljava/lang/String;I)V");
-
- jobject exception = env->NewObject(errnoExceptionClass,
- errnoExceptionCtor,
- detailMessage.get(),
- error);
- env->Throw(reinterpret_cast<jthrowable>(exception));
-}
-
static void android_net_utils_attachDropAllBPFFilter(JNIEnv *env, jobject clazz, jobject javaFd)
{
struct sock_filter filter_code[] = {
@@ -123,11 +102,6 @@
return setNetworkForSocket(netId, AFileDescriptor_getFD(env, javaFd));
}
-static jboolean android_net_utils_queryUserAccess(JNIEnv *env, jobject thiz, jint uid, jint netId)
-{
- return (jboolean) !queryUserAccess(uid, netId);
-}
-
static bool checkLenAndCopy(JNIEnv* env, const jbyteArray& addr, int len, void* dst)
{
if (env->GetArrayLength(addr) != len) {
@@ -150,7 +124,7 @@
int fd = resNetworkQuery(netId, queryname.data(), ns_class, ns_type, flags);
if (fd < 0) {
- throwErrnoException(env, "resNetworkQuery", -fd);
+ jniThrowErrnoException(env, "resNetworkQuery", -fd);
return nullptr;
}
@@ -165,7 +139,7 @@
int fd = resNetworkSend(netId, data, msgLen, flags);
if (fd < 0) {
- throwErrnoException(env, "resNetworkSend", -fd);
+ jniThrowErrnoException(env, "resNetworkSend", -fd);
return nullptr;
}
@@ -180,13 +154,13 @@
int res = resNetworkResult(fd, &rcode, buf.data(), MAXPACKETSIZE);
jniSetFileDescriptorOfFD(env, javaFd, -1);
if (res < 0) {
- throwErrnoException(env, "resNetworkResult", -res);
+ jniThrowErrnoException(env, "resNetworkResult", -res);
return nullptr;
}
jbyteArray answer = env->NewByteArray(res);
if (answer == nullptr) {
- throwErrnoException(env, "resNetworkResult", ENOMEM);
+ jniThrowErrnoException(env, "resNetworkResult", ENOMEM);
return nullptr;
} else {
env->SetByteArrayRegion(answer, 0, res,
@@ -208,7 +182,7 @@
static jobject android_net_utils_getDnsNetwork(JNIEnv *env, jobject thiz) {
unsigned dnsNetId = 0;
if (int res = getNetworkForDns(&dnsNetId) < 0) {
- throwErrnoException(env, "getDnsNetId", -res);
+ jniThrowErrnoException(env, "getDnsNetId", -res);
return nullptr;
}
bool privateDnsBypass = dnsNetId & NETID_USE_LOCAL_NAMESERVERS;
@@ -233,8 +207,8 @@
// Obtain the parameters of the TCP repair window.
int rc = getsockopt(fd, IPPROTO_TCP, TCP_REPAIR_WINDOW, &trw, &size);
if (rc == -1) {
- throwErrnoException(env, "getsockopt : TCP_REPAIR_WINDOW", errno);
- return NULL;
+ jniThrowErrnoException(env, "getsockopt : TCP_REPAIR_WINDOW", errno);
+ return NULL;
}
struct tcp_info tcpinfo = {};
@@ -244,8 +218,8 @@
// should be applied to the window size.
rc = getsockopt(fd, IPPROTO_TCP, TCP_INFO, &tcpinfo, &tcpinfo_size);
if (rc == -1) {
- throwErrnoException(env, "getsockopt : TCP_INFO", errno);
- return NULL;
+ jniThrowErrnoException(env, "getsockopt : TCP_INFO", errno);
+ return NULL;
}
jclass class_TcpRepairWindow = env->FindClass("android/net/TcpRepairWindow");
@@ -267,7 +241,6 @@
{ "getBoundNetworkForProcess", "()I", (void*) android_net_utils_getBoundNetworkForProcess },
{ "bindProcessToNetworkForHostResolution", "(I)Z", (void*) android_net_utils_bindProcessToNetworkForHostResolution },
{ "bindSocketToNetwork", "(Ljava/io/FileDescriptor;I)I", (void*) android_net_utils_bindSocketToNetwork },
- { "queryUserAccess", "(II)Z", (void*)android_net_utils_queryUserAccess },
{ "attachDropAllBPFFilter", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_attachDropAllBPFFilter },
{ "detachBPFFilter", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_detachBPFFilter },
{ "getTcpRepairWindow", "(Ljava/io/FileDescriptor;)Landroid/net/TcpRepairWindow;", (void*) android_net_utils_getTcpRepairWindow },
diff --git a/core/jni/android_os_SharedMemory.cpp b/core/jni/android_os_SharedMemory.cpp
index dc86187..fe375f4 100644
--- a/core/jni/android_os_SharedMemory.cpp
+++ b/core/jni/android_os_SharedMemory.cpp
@@ -35,21 +35,6 @@
jclass errnoExceptionClass;
jmethodID errnoExceptionCtor; // MethodID for ErrnoException.<init>(String,I)
-void throwErrnoException(JNIEnv* env, const char* functionName, int error) {
- ScopedLocalRef<jstring> detailMessage(env, env->NewStringUTF(functionName));
- if (detailMessage.get() == NULL) {
- // Not really much we can do here. We're probably dead in the water,
- // but let's try to stumble on...
- env->ExceptionClear();
- }
-
- jobject exception = env->NewObject(errnoExceptionClass,
- errnoExceptionCtor,
- detailMessage.get(),
- error);
- env->Throw(reinterpret_cast<jthrowable>(exception));
-}
-
jobject SharedMemory_nCreate(JNIEnv* env, jobject, jstring jname, jint size) {
// Name is optional so we can't use ScopedUtfChars for this as it throws NPE on null
@@ -65,7 +50,7 @@
}
if (fd < 0) {
- throwErrnoException(env, "SharedMemory_create", err);
+ jniThrowErrnoException(env, "SharedMemory_create", err);
return nullptr;
}
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index f71b42c..e4dddd2 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -486,9 +486,15 @@
}
void markVintf() {
+ AutoMutex _l(mLock);
mVintf = true;
}
+ void forceDowngradeToSystemStability() {
+ AutoMutex _l(mLock);
+ mVintf = false;
+ }
+
sp<IBinder> getExtension() {
AutoMutex _l(mLock);
sp<JavaBBinder> b = mBinder.promote();
@@ -1013,6 +1019,12 @@
jbh->markVintf();
}
+static void android_os_Binder_forceDowngradeToSystemStability(JNIEnv* env, jobject clazz) {
+ JavaBBinderHolder* jbh =
+ (JavaBBinderHolder*) env->GetLongField(clazz, gBinderOffsets.mObject);
+ jbh->forceDowngradeToSystemStability();
+}
+
static void android_os_Binder_flushPendingCommands(JNIEnv* env, jobject clazz)
{
IPCThreadState::self()->flushCommands();
@@ -1076,6 +1088,7 @@
{ "clearCallingWorkSource", "()J", (void*)android_os_Binder_clearCallingWorkSource },
{ "restoreCallingWorkSource", "(J)V", (void*)android_os_Binder_restoreCallingWorkSource },
{ "markVintfStability", "()V", (void*)android_os_Binder_markVintfStability},
+ { "forceDowngradeToSystemStability", "()V", (void*)android_os_Binder_forceDowngradeToSystemStability},
{ "flushPendingCommands", "()V", (void*)android_os_Binder_flushPendingCommands },
{ "getNativeBBinderHolder", "()J", (void*)android_os_Binder_getNativeBBinderHolder },
{ "getNativeFinalizer", "()J", (void*)android_os_Binder_getNativeFinalizer },
@@ -1516,7 +1529,9 @@
res = JNI_TRUE;
} else {
jniThrowException(env, "java/util/NoSuchElementException",
- "Death link does not exist");
+ base::StringPrintf("Death link does not exist (%s)",
+ statusToString(err).c_str())
+ .c_str());
}
}
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index 6becb07..6374305 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -52,6 +52,7 @@
#include <string.h>
#include <sys/epoll.h>
#include <sys/errno.h>
+#include <sys/pidfd.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/syscall.h>
@@ -1290,34 +1291,10 @@
return removeAllProcessGroups();
}
-static void throwErrnoException(JNIEnv* env, const char* functionName, int error) {
- ScopedLocalRef<jstring> detailMessage(env, env->NewStringUTF(functionName));
- if (detailMessage.get() == NULL) {
- // Not really much we can do here. We're probably dead in the water,
- // but let's try to stumble on...
- env->ExceptionClear();
- }
- static jclass errnoExceptionClass =
- MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/system/ErrnoException"));
-
- static jmethodID errnoExceptionCtor =
- GetMethodIDOrDie(env, errnoExceptionClass, "<init>", "(Ljava/lang/String;I)V");
-
- jobject exception =
- env->NewObject(errnoExceptionClass, errnoExceptionCtor, detailMessage.get(), error);
- env->Throw(reinterpret_cast<jthrowable>(exception));
-}
-
-// Wrapper function to the syscall pidfd_open, which creates a file
-// descriptor that refers to the process whose PID is specified in pid.
-static inline int sys_pidfd_open(pid_t pid, unsigned int flags) {
- return syscall(__NR_pidfd_open, pid, flags);
-}
-
static jint android_os_Process_nativePidFdOpen(JNIEnv* env, jobject, jint pid, jint flags) {
- int fd = sys_pidfd_open(pid, flags);
+ int fd = pidfd_open(pid, flags);
if (fd < 0) {
- throwErrnoException(env, "nativePidFdOpen", errno);
+ jniThrowErrnoException(env, "nativePidFdOpen", errno);
return -1;
}
return fd;
diff --git a/core/proto/android/app/OWNERS b/core/proto/android/app/OWNERS
index 296abd1..cc479e6 100644
--- a/core/proto/android/app/OWNERS
+++ b/core/proto/android/app/OWNERS
@@ -1 +1 @@
-per-file location_time_zone_manager.proto = nfuller@google.com, mingaleev@google.com
+per-file location_time_zone_manager.proto, time_zone_detector.proto = nfuller@google.com, mingaleev@google.com
diff --git a/core/proto/android/app/location_time_zone_manager.proto b/core/proto/android/app/location_time_zone_manager.proto
index f44d549..891e9fc 100644
--- a/core/proto/android/app/location_time_zone_manager.proto
+++ b/core/proto/android/app/location_time_zone_manager.proto
@@ -17,6 +17,7 @@
syntax = "proto2";
package android.app.time;
+import "frameworks/base/core/proto/android/app/time_zone_detector.proto";
import "frameworks/base/core/proto/android/privacy.proto";
option java_multiple_files = true;
@@ -31,15 +32,6 @@
repeated TimeZoneProviderStateProto secondary_provider_states = 3;
}
-// Represents a GeolocationTimeZoneSuggestion that can be / has been passed to the time zone
-// detector.
-message GeolocationTimeZoneSuggestionProto {
- option (android.msg_privacy).dest = DEST_AUTOMATIC;
-
- repeated string zone_ids = 1;
- repeated string debug_info = 2;
-}
-
// The state tracked for a LocationTimeZoneProvider.
message TimeZoneProviderStateProto {
option (android.msg_privacy).dest = DEST_AUTOMATIC;
diff --git a/core/proto/android/app/time_zone_detector.proto b/core/proto/android/app/time_zone_detector.proto
new file mode 100644
index 0000000..b33ca1d
--- /dev/null
+++ b/core/proto/android/app/time_zone_detector.proto
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+package android.app.time;
+
+import "frameworks/base/core/proto/android/privacy.proto";
+
+option java_multiple_files = true;
+option java_outer_classname = "TimeZoneDetectorProto";
+
+// Represents a GeolocationTimeZoneSuggestion that can be / has been passed to the time zone
+// detector.
+message GeolocationTimeZoneSuggestionProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ repeated string zone_ids = 1;
+ repeated string debug_info = 2;
+}
+
+/*
+ * An obfuscated and simplified time zone suggestion for metrics use.
+ *
+ * The suggestion's time zone IDs (which relate to location) are obfuscated by
+ * mapping them to an ordinal. When the ordinal is assigned consistently across
+ * several objects (i.e. so the same time zone ID is always mapped to the same
+ * ordinal), this allows comparisons between those objects. For example, we can
+ * answer "did these two suggestions agree?", "does the suggestion match the
+ * device's current time zone?", without leaking knowledge of location. Ordinals
+ * are also significantly more compact than full IANA TZDB IDs, albeit highly
+ * unstable and of limited use.
+ */
+message MetricsTimeZoneSuggestion {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ enum Type {
+ CERTAIN = 1;
+ UNCERTAIN = 2;
+ }
+ optional Type type = 1;
+
+ // The ordinals for time zone(s) in the suggestion. Always empty for
+ // UNCERTAIN, and can be empty for CERTAIN, for example when the device is in
+ // a disputed area / on an ocean.
+ repeated uint32 time_zone_ordinals = 2;
+}
diff --git a/core/proto/android/net/networkcapabilities.proto b/core/proto/android/net/networkcapabilities.proto
new file mode 100644
index 0000000..edb6c04
--- /dev/null
+++ b/core/proto/android/net/networkcapabilities.proto
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+
+package android.net;
+
+option java_multiple_files = true;
+
+import "frameworks/base/core/proto/android/privacy.proto";
+import "frameworks/proto_logging/stats/enums/net/enums.proto";
+
+/**
+ * An android.net.NetworkCapabilities object.
+ */
+message NetworkCapabilitiesProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ repeated Transport transports = 1;
+
+ enum NetCapability {
+ // Indicates this is a network that has the ability to reach the
+ // carrier's MMSC for sending and receiving MMS messages.
+ NET_CAPABILITY_MMS = 0;
+ // Indicates this is a network that has the ability to reach the
+ // carrier's SUPL server, used to retrieve GPS information.
+ NET_CAPABILITY_SUPL = 1;
+ // Indicates this is a network that has the ability to reach the
+ // carrier's DUN or tethering gateway.
+ NET_CAPABILITY_DUN = 2;
+ // Indicates this is a network that has the ability to reach the
+ // carrier's FOTA portal, used for over the air updates.
+ NET_CAPABILITY_FOTA = 3;
+ // Indicates this is a network that has the ability to reach the
+ // carrier's IMS servers, used for network registration and signaling.
+ NET_CAPABILITY_IMS = 4;
+ // Indicates this is a network that has the ability to reach the
+ // carrier's CBS servers, used for carrier specific services.
+ NET_CAPABILITY_CBS = 5;
+ // Indicates this is a network that has the ability to reach a Wi-Fi
+ // direct peer.
+ NET_CAPABILITY_WIFI_P2P = 6;
+ // Indicates this is a network that has the ability to reach a carrier's
+ // Initial Attach servers.
+ NET_CAPABILITY_IA = 7;
+ // Indicates this is a network that has the ability to reach a carrier's
+ // RCS servers, used for Rich Communication Services.
+ NET_CAPABILITY_RCS = 8;
+ // Indicates this is a network that has the ability to reach a carrier's
+ // XCAP servers, used for configuration and control.
+ NET_CAPABILITY_XCAP = 9;
+ // Indicates this is a network that has the ability to reach a carrier's
+ // Emergency IMS servers or other services, used for network signaling
+ // during emergency calls.
+ NET_CAPABILITY_EIMS = 10;
+ // Indicates that this network is unmetered.
+ NET_CAPABILITY_NOT_METERED = 11;
+ // Indicates that this network should be able to reach the internet.
+ NET_CAPABILITY_INTERNET = 12;
+ // Indicates that this network is available for general use. If this is
+ // not set applications should not attempt to communicate on this
+ // network. Note that this is simply informative and not enforcement -
+ // enforcement is handled via other means. Set by default.
+ NET_CAPABILITY_NOT_RESTRICTED = 13;
+ // Indicates that the user has indicated implicit trust of this network.
+ // This generally means it's a sim-selected carrier, a plugged in
+ // ethernet, a paired BT device or a wifi the user asked to connect to.
+ // Untrusted networks are probably limited to unknown wifi AP. Set by
+ // default.
+ NET_CAPABILITY_TRUSTED = 14;
+ // Indicates that this network is not a VPN. This capability is set by
+ // default and should be explicitly cleared for VPN networks.
+ NET_CAPABILITY_NOT_VPN = 15;
+ // Indicates that connectivity on this network was successfully
+ // validated. For example, for a network with NET_CAPABILITY_INTERNET,
+ // it means that Internet connectivity was successfully detected.
+ NET_CAPABILITY_VALIDATED = 16;
+ // Indicates that this network was found to have a captive portal in
+ // place last time it was probed.
+ NET_CAPABILITY_CAPTIVE_PORTAL = 17;
+ // Indicates that this network is not roaming.
+ NET_CAPABILITY_NOT_ROAMING = 18;
+ // Indicates that this network is available for use by apps, and not a
+ // network that is being kept up in the background to facilitate fast
+ // network switching.
+ NET_CAPABILITY_FOREGROUND = 19;
+ }
+ repeated NetCapability capabilities = 2;
+
+ // Passive link bandwidth. This is a rough guide of the expected peak
+ // bandwidth for the first hop on the given transport. It is not measured,
+ // but may take into account link parameters (Radio technology, allocated
+ // channels, etc).
+ optional int32 link_up_bandwidth_kbps = 3;
+ optional int32 link_down_bandwidth_kbps = 4;
+
+ optional string network_specifier = 5 [ (.android.privacy).dest = DEST_EXPLICIT ];
+
+ // True if this object specifies a signal strength.
+ optional bool can_report_signal_strength = 6;
+ // This is a signed integer, and higher values indicate better signal. The
+ // exact units are bearer-dependent. For example, Wi-Fi uses RSSI.
+ // Only valid if can_report_signal_strength is true.
+ optional sint32 signal_strength = 7;
+}
diff --git a/core/proto/android/net/networkrequest.proto b/core/proto/android/net/networkrequest.proto
index 0041f19..57b9f71 100644
--- a/core/proto/android/net/networkrequest.proto
+++ b/core/proto/android/net/networkrequest.proto
@@ -20,8 +20,8 @@
option java_multiple_files = true;
+import "frameworks/base/core/proto/android/net/networkcapabilities.proto";
import "frameworks/base/core/proto/android/privacy.proto";
-import "frameworks/proto_logging/stats/enums/net/networkcapabilities.proto";
/**
* An android.net.NetworkRequest object.
diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto
index e97b1a8..64cf75d 100644
--- a/core/proto/android/os/incident.proto
+++ b/core/proto/android/os/incident.proto
@@ -55,13 +55,13 @@
import "frameworks/base/core/proto/android/service/procstats.proto";
import "frameworks/base/core/proto/android/service/restricted_image.proto";
import "frameworks/base/core/proto/android/service/sensor_service.proto";
+import "frameworks/base/core/proto/android/service/usb.proto";
import "frameworks/base/core/proto/android/util/event_log_tags.proto";
import "frameworks/base/core/proto/android/util/log.proto";
import "frameworks/base/core/proto/android/util/textdump.proto";
import "frameworks/base/core/proto/android/privacy.proto";
import "frameworks/base/core/proto/android/section.proto";
import "frameworks/base/proto/src/ipconnectivity.proto";
-import "frameworks/proto_logging/stats/enums/service/usb.proto";
package android.os;
diff --git a/core/proto/android/service/enums.proto b/core/proto/android/service/enums.proto
deleted file mode 100644
index b64e685..0000000
--- a/core/proto/android/service/enums.proto
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-syntax = "proto2";
-package android.service;
-
-option java_outer_classname = "ServiceProtoEnums";
-option java_multiple_files = true;
-
-enum UsbEndPointType {
- USB_ENDPOINT_TYPE_XFER_CONTROL = 0;
- USB_ENDPOINT_TYPE_XFER_ISOC = 1;
- USB_ENDPOINT_TYPE_XFER_BULK = 2;
- USB_ENDPOINT_TYPE_XFER_INT = 3;
-}
-
-enum UsbEndPointDirection {
- USB_ENDPOINT_DIR_OUT = 0;
- USB_ENDPOINT_DIR_IN = 0x80;
-}
-
-enum UsbConnectionRecordMode {
- USB_CONNECTION_RECORD_MODE_CONNECT = 0;
- USB_CONNECTION_RECORD_MODE_CONNECT_BADPARSE = 1;
- USB_CONNECTION_RECORD_MODE_CONNECT_BADDEVICE = 2;
- USB_CONNECTION_RECORD_MODE_DISCONNECT = -1;
-}
\ No newline at end of file
diff --git a/core/proto/android/service/usb.proto b/core/proto/android/service/usb.proto
new file mode 100644
index 0000000..dd313aa
--- /dev/null
+++ b/core/proto/android/service/usb.proto
@@ -0,0 +1,431 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+syntax = "proto2";
+package android.service.usb;
+
+option java_multiple_files = true;
+option java_outer_classname = "UsbServiceProto";
+
+import "frameworks/base/core/proto/android/content/component_name.proto";
+import "frameworks/base/core/proto/android/privacy.proto";
+import "frameworks/proto_logging/stats/enums/service/enums.proto";
+
+message UsbServiceDumpProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional UsbDeviceManagerProto device_manager = 1;
+ optional UsbHostManagerProto host_manager = 2;
+ optional UsbPortManagerProto port_manager = 3;
+ optional UsbAlsaManagerProto alsa_manager = 4;
+ optional UsbSettingsManagerProto settings_manager = 5;
+ optional UsbPermissionsManagerProto permissions_manager = 6;
+}
+
+message UsbDeviceManagerProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional UsbHandlerProto handler = 1;
+ optional UsbDebuggingManagerProto debugging_manager = 2;
+}
+
+message UsbHandlerProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ /* Same as android.hardware.usb.gadget.V1_0.GadgetFunction.* */
+ enum Function {
+ FUNCTION_ADB = 1;
+ FUNCTION_ACCESSORY = 2;
+ FUNCTION_MTP = 4;
+ FUNCTION_MIDI = 8;
+ FUNCTION_PTP = 16;
+ FUNCTION_RNDIS = 32;
+ FUNCTION_AUDIO_SOURCE = 64;
+ }
+
+ repeated Function current_functions = 1;
+ optional bool current_functions_applied = 2;
+ repeated Function screen_unlocked_functions = 3;
+ optional bool screen_locked = 4;
+ optional bool connected = 5;
+ optional bool configured = 6;
+ optional UsbAccessoryProto current_accessory = 7;
+ optional bool host_connected = 8;
+ optional bool source_power = 9;
+ optional bool sink_power = 10;
+ optional bool usb_charging = 11;
+ optional bool hide_usb_notification = 12;
+ optional bool audio_accessory_connected = 13;
+ optional bool adb_enabled = 14;
+ optional string kernel_state = 15;
+ optional string kernel_function_list = 16;
+}
+
+message UsbAccessoryProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional string manufacturer = 1;
+ optional string model = 2;
+ // For "classical" USB-accessories the manufacturer bakes this into the
+ // firmware of the device. If an Android phone is configured as accessory, the
+ // app that sets up the accessory side of the connection set this. Either way,
+ // these are part of the detection protocol, and so they cannot be user set or
+ // unique.
+ optional string description = 3;
+ optional string version = 4;
+ optional string uri = 5 [ (android.privacy).dest = DEST_EXPLICIT ];
+ // Non-resettable hardware ID.
+ optional string serial = 6 [ (android.privacy).dest = DEST_LOCAL ];
+}
+
+message UsbDebuggingManagerProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional bool connected_to_adb = 1;
+ // A workstation that connects to the phone for debugging is identified by
+ // this key.
+ optional string last_key_received = 2 [ (android.privacy).dest = DEST_EXPLICIT ];
+ optional string user_keys = 3 [ (android.privacy).dest = DEST_LOCAL ];
+ optional string system_keys = 4 [ (android.privacy).dest = DEST_LOCAL ];
+}
+
+message UsbHostManagerProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional android.content.ComponentNameProto default_usb_host_connection_handler = 1;
+ repeated UsbDeviceProto devices = 2;
+ optional int32 num_connects = 3;
+ repeated UsbConnectionRecordProto connections = 4;
+}
+
+message UsbDeviceProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ // Generic USB name, not user-provided.
+ optional string name = 1;
+ // ID specific to the vendor, not the device.
+ optional int32 vendor_id = 2;
+ // ID of this product type: Each vendor gives each product a unique ID. E.g.
+ // all mice of the same model would have the same ID.
+ optional int32 product_id = 3;
+ optional int32 class = 4;
+ optional int32 subclass = 5;
+ optional int32 protocol = 6;
+ optional string manufacturer_name = 7;
+ optional string product_name = 8;
+ optional string version = 9;
+ // Non-resettable hardware ID.
+ optional string serial_number = 10 [ (android.privacy).dest = DEST_LOCAL ];
+ repeated UsbConfigurationProto configurations = 11;
+}
+
+message UsbConfigurationProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ // A single USB device can have several configurations and the app accessing
+ // the USB device can switch between them. At any time only one can be active.
+ // Each configuration can present completely different interfaces end
+ // endpoints, i.e. a completely different behavior.
+ optional int32 id = 1;
+ // Hardware-defined name, not set by the user.
+ optional string name = 2;
+ optional uint32 attributes = 3;
+ optional int32 max_power = 4;
+ repeated UsbInterfaceProto interfaces = 5;
+}
+
+message UsbInterfaceProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ // Hardware defined. This is the id used by the app to identify the interface.
+ optional int32 id = 1;
+ optional int32 alternate_settings = 2;
+ optional string name = 3;
+ optional int32 class = 4;
+ optional int32 subclass = 5;
+ optional int32 protocol = 6;
+ repeated UsbEndPointProto endpoints = 7;
+}
+
+message UsbEndPointProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional int32 endpoint_number = 1;
+ optional android.service.UsbEndPointDirection direction = 2;
+ // The address of the endpoint. Needed to read and write to the endpoint.
+ optional int32 address = 3;
+ optional android.service.UsbEndPointType type = 4;
+ optional uint32 attributes = 5;
+ optional int32 max_packet_size = 6;
+ optional int32 interval = 7;
+}
+
+message UsbConnectionRecordProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ // usb device's address, e.g. 001/002, nothing about the phone
+ optional string device_address = 1;
+ optional android.service.UsbConnectionRecordMode mode = 2;
+ optional int64 timestamp = 3;
+ optional int32 manufacturer = 4;
+ optional int32 product = 5;
+ optional UsbIsHeadsetProto is_headset = 6;
+}
+
+message UsbIsHeadsetProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional bool in = 1;
+ optional bool out = 2;
+}
+
+message UsbPortManagerProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional bool is_simulation_active = 1;
+ repeated UsbPortInfoProto usb_ports = 2;
+}
+
+message UsbPortInfoProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional UsbPortProto port = 1;
+ optional UsbPortStatusProto status = 2;
+ optional bool can_change_mode = 3;
+ optional bool can_change_power_role = 4;
+ optional bool can_change_data_role = 5;
+ optional int64 connected_at_millis = 6;
+ optional int64 last_connect_duration_millis = 7;
+}
+
+message UsbPortProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ /* Same as android.hardware.usb.V1_1.Constants.PortMode_1_1 */
+ enum Mode {
+ MODE_NONE = 0;
+ MODE_UFP = 1;
+ MODE_DFP = 2;
+ MODE_DRP = 3;
+ MODE_AUDIO_ACCESSORY = 4;
+ MODE_DEBUG_ACCESSORY = 8;
+ }
+
+ // ID of the port. A device (eg: Chromebooks) might have multiple ports.
+ optional string id = 1;
+ repeated Mode supported_modes = 2;
+}
+
+message UsbPortStatusProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ /* Same as android.hardware.usb.V1_0.Constants.PortPowerRole */
+ enum PowerRole {
+ POWER_ROLE_NONE = 0;
+ POWER_ROLE_SOURCE = 1;
+ POWER_ROLE_SINK = 2;
+ }
+
+ /* Same as android.hardware.usb.V1_0.Constants.PortDataRole */
+ enum DataRole {
+ DATA_ROLE_NONE = 0;
+ DATA_ROLE_HOST = 1;
+ DATA_ROLE_DEVICE = 2;
+ }
+
+ optional bool connected = 1;
+ optional UsbPortProto.Mode current_mode = 2;
+ optional PowerRole power_role = 3;
+ optional DataRole data_role = 4;
+ repeated UsbPortStatusRoleCombinationProto role_combinations = 5;
+ optional android.service.ContaminantPresenceStatus contaminant_presence_status = 6;
+}
+
+message UsbPortStatusRoleCombinationProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional UsbPortStatusProto.PowerRole power_role = 1;
+ optional UsbPortStatusProto.DataRole data_role = 2;
+}
+
+message UsbAlsaManagerProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional int32 cards_parser = 1;
+ repeated UsbAlsaDeviceProto alsa_devices = 2;
+ repeated UsbMidiDeviceProto midi_devices = 3;
+}
+
+message UsbAlsaDeviceProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional int32 card = 1;
+ optional int32 device = 2;
+ optional string name = 3;
+ optional bool has_playback = 4;
+ optional bool has_capture = 5;
+ // usb device's address, e.g. 001/002, nothing about the phone
+ optional string address = 6;
+}
+
+message UsbMidiDeviceProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional int32 card = 1;
+ optional int32 device = 2;
+ // usb device's address, e.g. 001/002, nothing about the phone
+ optional string device_address = 3;
+}
+
+message UsbSettingsManagerProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ repeated UsbUserSettingsManagerProto user_settings = 1;
+ repeated UsbProfileGroupSettingsManagerProto profile_group_settings = 2;
+}
+
+message UsbUserSettingsManagerProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional int32 user_id = 1;
+ reserved 2; // previously device_permissions, now unused
+ reserved 3; // previously accessory_permissions, now unused
+ repeated UsbDeviceAttachedActivities device_attached_activities = 4;
+ repeated UsbAccessoryAttachedActivities accessory_attached_activities = 5;
+}
+
+message UsbProfileGroupSettingsManagerProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ // The user id of the personal profile if the device has a work profile.
+ optional int32 parent_user_id = 1;
+ repeated UsbSettingsDevicePreferenceProto device_preferences = 2;
+ repeated UsbSettingsAccessoryPreferenceProto accessory_preferences = 3;
+}
+
+message UsbSettingsDevicePreferenceProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional UsbDeviceFilterProto filter = 1;
+ optional UserPackageProto user_package = 2;
+}
+
+message UsbPermissionsManagerProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ repeated UsbUserPermissionsManagerProto user_permissions = 1;
+}
+
+message UsbUserPermissionsManagerProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional int32 user_id = 1;
+
+ repeated UsbDevicePermissionProto device_permissions = 2;
+ repeated UsbAccessoryPermissionProto accessory_permissions = 3;
+
+ repeated UsbDevicePersistentPermissionProto device_persistent_permissions = 4;
+ repeated UsbAccessoryPersistentPermissionProto accessory_persistent_permissions = 5;
+}
+
+message UsbDevicePermissionProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ // Name of device set by manufacturer
+ // All devices of the same model have the same name
+ optional string device_name = 1;
+ repeated int32 uids = 2;
+}
+
+message UsbAccessoryPermissionProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ // Description of accessory set by manufacturer
+ // All accessories of the same model have the same description
+ optional string accessory_description = 1;
+ repeated int32 uids = 2;
+}
+
+message UsbDevicePersistentPermissionProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional UsbDeviceFilterProto device_filter = 1;
+ repeated UsbUidPermissionProto permission_values = 2;
+}
+
+message UsbAccessoryPersistentPermissionProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional UsbAccessoryFilterProto accessory_filter = 1;
+ repeated UsbUidPermissionProto permission_values = 2;
+}
+
+message UsbUidPermissionProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional int32 uid = 1;
+ optional bool is_granted = 2;
+}
+
+message UsbDeviceFilterProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ // Mirrors the vendor_id of UsbDeviceProto.
+ optional int32 vendor_id = 1;
+ optional int32 product_id = 2;
+ optional int32 class = 3;
+ optional int32 subclass = 4;
+ optional int32 protocol = 5;
+ optional string manufacturer_name = 6;
+ optional string product_name = 7;
+ optional string serial_number = 8 [ (android.privacy).dest = DEST_EXPLICIT ];
+}
+
+message UserPackageProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional int32 user_id = 1;
+ optional string package_name =2;
+}
+
+message UsbSettingsAccessoryPreferenceProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional UsbAccessoryFilterProto filter = 1;
+ optional UserPackageProto user_package = 2;
+}
+
+message UsbAccessoryFilterProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional string manufacturer = 1;
+ optional string model = 2;
+ optional string version = 3;
+}
+
+message UsbDeviceAttachedActivities {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional android.content.ComponentNameProto activity = 1;
+ repeated UsbDeviceFilterProto filters = 2;
+}
+
+message UsbAccessoryAttachedActivities {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional android.content.ComponentNameProto activity = 1;
+ repeated UsbAccessoryFilterProto filters = 2;
+}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 2f352e9..f65d7a7 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -5123,9 +5123,16 @@
<permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG"
android:protectionLevel="signature|privileged" />
<!-- Allows an app to override compat change config.
+ This permission only allows to override config on debuggable builds or test-apks and is
+ therefore a less powerful version of OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD.
@hide <p>Not for use by third-party applications.</p> -->
<permission android:name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG"
android:protectionLevel="signature|privileged" />
+ <!-- @SystemApi Allows an app to override compat change config on release builds.
+ Only ChangeIds that are annotated as @Overridable can be overridden on release builds.
+ @hide -->
+ <permission android:name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD"
+ android:protectionLevel="signature|privileged" />
<!-- Allows input events to be monitored. Very dangerous! @hide -->
<permission android:name="android.permission.MONITOR_INPUT"
@@ -5172,6 +5179,10 @@
<permission android:name="android.permission.INPUT_CONSUMER"
android:protectionLevel="signature" />
+ <!-- @hide @SystemApi Allows an application to manage app hibernation state. -->
+ <permission android:name="android.permission.MANAGE_APP_HIBERNATION"
+ android:protectionLevel="signature|installer" />
+
<!-- Attribution for Country Detector. -->
<attribution android:tag="CountryDetector" android:label="@string/country_detector"/>
<!-- Attribution for Location service. -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 22a79ed..bfe7802 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -327,9 +327,6 @@
<item>"0,1"</item>
</string-array>
- <!-- The maximum duration (in milliseconds) we expect a network transition to take -->
- <integer name="config_networkTransitionTimeout">60000</integer>
-
<!-- Whether/how to notify the user on network switches. See LingerMonitor.java. -->
<integer translatable="false" name="config_networkNotifySwitchType">0</integer>
@@ -342,16 +339,6 @@
Settings.Global.NETWORK_AVOID_BAD_WIFI. This is the default value of that setting. -->
<integer translatable="false" name="config_networkAvoidBadWifi">1</integer>
- <!-- Configuration hook for the URL returned by ConnectivityManager#getCaptivePortalServerUrl.
- If empty, the returned value is controlled by Settings.Global.CAPTIVE_PORTAL_HTTP_URL,
- and if that value is empty, the framework will use a hard-coded default.
- This is *NOT* a URL that will always be used by the system network validation to detect
- captive portals: NetworkMonitor may use different strategies and will not necessarily use
- this URL. NetworkMonitor behaviour should be configured with NetworkStack resource overlays
- instead. -->
- <!--suppress CheckTagEmptyBody -->
- <string translatable="false" name="config_networkCaptivePortalServerUrl"></string>
-
<!-- If the hardware supports specially marking packets that caused a wakeup of the
main CPU, set this value to the mark used. -->
<integer name="config_networkWakeupPacketMark">0</integer>
@@ -459,14 +446,6 @@
apps requested it. -->
<bool name="config_vehicleInternalNetworkAlwaysRequested">false</bool>
- <!-- Configuration of network interfaces that support WakeOnLAN -->
- <string-array translatable="false" name="config_wakeonlan_supported_interfaces">
- <!--
- <item>wlan0</item>
- <item>eth0</item>
- -->
- </string-array>
-
<!-- This setting is deprecated, please use
com.android.networkstack.tethering.R.array.config_mobile_hotspot_provision_app instead. -->
<string-array translatable="false" name="config_mobile_hotspot_provision_app">
@@ -3436,10 +3415,6 @@
<!-- True if assistant app should be pinned via Pinner Service -->
<bool name="config_pinnerAssistantApp">false</bool>
- <!-- List of files pinned by the Pinner Service with the JIT Zygote boot image b/119800099 -->
- <string-array translatable="false" name="config_jitzygoteBootImagePinnerServiceFiles">
- </string-array>
-
<!-- Number of days preloaded file cache should be preserved on a device before it can be
deleted -->
<integer name="config_keepPreloadsMinDays">7</integer>
@@ -4364,6 +4339,11 @@
check after reboot or airplane mode toggling -->
<bool translatable="false" name="reset_geo_fencing_check_after_boot_or_apm">false</bool>
+ <!-- Boolean indicating whether all CB messages should be disabled on this device. This config
+ is intended to be used by OEMs who need to disable CB messages for regulatory requirements,
+ (e.g. the device is a tablet in a country where tablets should not receive CB messages) -->
+ <bool translatable="false" name="config_disable_all_cb_messages">false</bool>
+
<!-- Screen Wake Keys
Determines whether the specified key groups can be used to wake up the device. -->
<bool name="config_wakeOnDpadKeyPress">true</bool>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 8ac00dc..4a06671 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3605,6 +3605,8 @@
<string name="ext_media_checking_notification_title">Checking <xliff:g id="name" example="SD card">%s</xliff:g>\u2026</string>
<!-- Notification body when external media is being checked [CHAR LIMIT=NONE] -->
<string name="ext_media_checking_notification_message">Reviewing current content</string>
+ <!-- TV specific notification body when external media is being checked [CHAR LIMIT=75] -->
+ <string name="ext_media_checking_notification_message" product="tv">Analyzing media storage</string>
<!-- Notification body when new external media is detected [CHAR LIMIT=30] -->
<string name="ext_media_new_notification_title">New <xliff:g id="name" example="SD card">%s</xliff:g></string>
@@ -3612,11 +3614,15 @@
<string name="ext_media_new_notification_title" product="automotive"><xliff:g id="name" example="SD card">%s</xliff:g> isn\u2019t working</string>
<!-- Notification body when new external media is detected [CHAR LIMIT=NONE] -->
<string name="ext_media_new_notification_message">Tap to set up</string>
+ <!-- TV specific notification body when new external media is detected [CHAR LIMIT=75] -->
+ <string name="ext_media_new_notification_message" product="tv">Select to set up</string>
<!-- Automotive specific notification body when new external media is detected. [CHAR LIMIT=NONE] -->
<string name="ext_media_new_notification_message" product="automotive">You may need to reformat the device. Tap to eject.</string>
<!-- Notification body when external media is ready for use [CHAR LIMIT=NONE] -->
<string name="ext_media_ready_notification_message">For transferring photos and media</string>
+ <!-- TV specific notification body when external media is ready for use [CHAR LIMIT=75] -->
+ <string name="ext_media_ready_notification_message" product="tv">Browse media files</string>
<!-- Notification title when external media is unmountable (corrupt) [CHAR LIMIT=30] -->
<string name="ext_media_unmountable_notification_title">Issue with <xliff:g id="name" example="SD card">%s</xliff:g></string>
@@ -3635,8 +3641,8 @@
<string name="ext_media_unsupported_notification_title" product="automotive"><xliff:g id="name" example="SD card">%s</xliff:g> isn\u2019t working</string>
<!-- Notification body when external media is unsupported [CHAR LIMIT=NONE] -->
<string name="ext_media_unsupported_notification_message">This device doesn\u2019t support this <xliff:g id="name" example="SD card">%s</xliff:g>. Tap to set up in a supported format.</string>
- <!-- TV-specific notification body when external media is unsupported [CHAR LIMIT=NONE] -->
- <string name="ext_media_unsupported_notification_message" product="tv">This device doesn\u2019t support this <xliff:g id="name" example="SD card">%s</xliff:g>. Select to set up in a supported format.</string>
+ <!-- TV-specific notification body when external media is unsupported [CHAR LIMIT=75] -->
+ <string name="ext_media_unsupported_notification_message" product="tv">Select to set up <xliff:g id="name" example="SD card">%s</xliff:g> in a supported format.</string>
<!-- Automotive specific notification body when external media is unsupported [CHAR LIMIT=NONE] -->
<string name="ext_media_unsupported_notification_message" product="automotive">You may need to reformat the device</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index fc75463..2901de5 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -685,7 +685,6 @@
<java-symbol type="string" name="not_checked" />
<java-symbol type="array" name="config_ethernet_interfaces" />
<java-symbol type="bool" name="config_vehicleInternalNetworkAlwaysRequested" />
- <java-symbol type="array" name="config_wakeonlan_supported_interfaces" />
<java-symbol type="string" name="config_forceVoiceInteractionServicePackage" />
<java-symbol type="string" name="config_mms_user_agent" />
<java-symbol type="string" name="config_mms_user_agent_profile_url" />
@@ -1951,11 +1950,9 @@
<java-symbol type="integer" name="config_lowBatteryCloseWarningBump" />
<java-symbol type="integer" name="config_lowBatteryWarningLevel" />
<java-symbol type="integer" name="config_networkPolicyDefaultWarning" />
- <java-symbol type="integer" name="config_networkTransitionTimeout" />
<java-symbol type="integer" name="config_networkNotifySwitchType" />
<java-symbol type="array" name="config_networkNotifySwitches" />
<java-symbol type="integer" name="config_networkAvoidBadWifi" />
- <java-symbol type="string" name="config_networkCaptivePortalServerUrl" />
<java-symbol type="integer" name="config_networkWakeupPacketMark" />
<java-symbol type="integer" name="config_networkWakeupPacketMask" />
<java-symbol type="bool" name="config_apfDrop802_3Frames" />
@@ -3065,7 +3062,6 @@
<java-symbol type="bool" name="config_pinnerCameraApp" />
<java-symbol type="bool" name="config_pinnerHomeApp" />
<java-symbol type="bool" name="config_pinnerAssistantApp" />
- <java-symbol type="array" name="config_jitzygoteBootImagePinnerServiceFiles" />
<java-symbol type="string" name="config_doubleTouchGestureEnableFile" />
@@ -3851,6 +3847,7 @@
<java-symbol type="layout" name="chooser_action_button" />
<java-symbol type="dimen" name="chooser_action_button_icon_size" />
<java-symbol type="string" name="config_defaultNearbySharingComponent" />
+ <java-symbol type="bool" name="config_disable_all_cb_messages" />
<java-symbol type="drawable" name="ic_close" />
<java-symbol type="bool" name="config_automotiveHideNavBarForKeyboard" />
diff --git a/core/tests/coretests/src/android/content/OWNERS b/core/tests/coretests/src/android/content/OWNERS
index c61a4b5..0b94589 100644
--- a/core/tests/coretests/src/android/content/OWNERS
+++ b/core/tests/coretests/src/android/content/OWNERS
@@ -2,3 +2,5 @@
per-file ContextTest.java = file:/services/core/java/com/android/server/wm/OWNERS
per-file *Launcher* = file:/core/java/android/content/pm/LAUNCHER_OWNERS
per-file *Shortcut* = file:/core/java/android/content/pm/SHORTCUT_OWNERS
+per-file ComponentCallbacksControllerTest = file:/services/core/java/com/android/server/wm/OWNERS
+per-file ComponentCallbacksControllerTest = charlesccchen@google.com
diff --git a/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java b/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
index 2c1bbf0..aa2eb63 100644
--- a/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
@@ -232,7 +232,7 @@
assertThat(entry3.handlerClassName).isEqualTo(
"com.android.internal.os.LooperStatsTest$TestHandlerSecond");
assertThat(entry3.messageName).startsWith(
- "com.android.internal.os.LooperStatsTest-$$ExternalSyntheticLambda");
+ "com.android.internal.os.LooperStatsTest$$ExternalSyntheticLambda4");
assertThat(entry3.messageCount).isEqualTo(1);
assertThat(entry3.recordedMessageCount).isEqualTo(1);
assertThat(entry3.exceptionCount).isEqualTo(0);
diff --git a/core/tests/utiltests/src/com/android/internal/util/LocationPermissionCheckerTest.java b/core/tests/utiltests/src/com/android/internal/util/LocationPermissionCheckerTest.java
deleted file mode 100644
index 7175f56..0000000
--- a/core/tests/utiltests/src/com/android/internal/util/LocationPermissionCheckerTest.java
+++ /dev/null
@@ -1,296 +0,0 @@
-/*
- * 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.internal.util;
-
-import static android.Manifest.permission.NETWORK_SETTINGS;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.ArgumentMatchers.nullable;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.Manifest;
-import android.app.ActivityManager;
-import android.app.AppOpsManager;
-import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.location.LocationManager;
-import android.os.Binder;
-import android.os.Build;
-import android.os.UserHandle;
-import android.os.UserManager;
-
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
-
-import java.util.HashMap;
-
-/** Unit tests for {@link LocationPermissionChecker}. */
-public class LocationPermissionCheckerTest {
-
- public static final String TAG = "ConnectivityUtilTest";
-
- // Mock objects for testing
- @Mock private Context mMockContext;
- @Mock private PackageManager mMockPkgMgr;
- @Mock private ApplicationInfo mMockApplInfo;
- @Mock private AppOpsManager mMockAppOps;
- @Mock private UserManager mMockUserManager;
- @Mock private LocationManager mLocationManager;
-
- private static final String TEST_PKG_NAME = "com.google.somePackage";
- private static final String TEST_FEATURE_ID = "com.google.someFeature";
- private static final int MANAGED_PROFILE_UID = 1100000;
- private static final int OTHER_USER_UID = 1200000;
-
- private final String mInteractAcrossUsersFullPermission =
- "android.permission.INTERACT_ACROSS_USERS_FULL";
- private final String mManifestStringCoarse =
- Manifest.permission.ACCESS_COARSE_LOCATION;
- private final String mManifestStringFine =
- Manifest.permission.ACCESS_FINE_LOCATION;
-
- // Test variables
- private int mWifiScanAllowApps;
- private int mUid;
- private int mCoarseLocationPermission;
- private int mAllowCoarseLocationApps;
- private int mFineLocationPermission;
- private int mAllowFineLocationApps;
- private int mNetworkSettingsPermission;
- private int mCurrentUser;
- private boolean mIsLocationEnabled;
- private boolean mThrowSecurityException;
- private Answer<Integer> mReturnPermission;
- private HashMap<String, Integer> mPermissionsList = new HashMap<String, Integer>();
- private LocationPermissionChecker mChecker;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- initTestVars();
- }
-
- private void setupMocks() throws Exception {
- when(mMockPkgMgr.getApplicationInfoAsUser(eq(TEST_PKG_NAME), eq(0), any()))
- .thenReturn(mMockApplInfo);
- when(mMockContext.getPackageManager()).thenReturn(mMockPkgMgr);
- when(mMockAppOps.noteOp(AppOpsManager.OPSTR_WIFI_SCAN, mUid, TEST_PKG_NAME,
- TEST_FEATURE_ID, null)).thenReturn(mWifiScanAllowApps);
- when(mMockAppOps.noteOp(eq(AppOpsManager.OPSTR_COARSE_LOCATION), eq(mUid),
- eq(TEST_PKG_NAME), eq(TEST_FEATURE_ID), nullable(String.class)))
- .thenReturn(mAllowCoarseLocationApps);
- when(mMockAppOps.noteOp(eq(AppOpsManager.OPSTR_FINE_LOCATION), eq(mUid),
- eq(TEST_PKG_NAME), eq(TEST_FEATURE_ID), nullable(String.class)))
- .thenReturn(mAllowFineLocationApps);
- if (mThrowSecurityException) {
- doThrow(new SecurityException("Package " + TEST_PKG_NAME + " doesn't belong"
- + " to application bound to user " + mUid))
- .when(mMockAppOps).checkPackage(mUid, TEST_PKG_NAME);
- }
- when(mMockContext.getSystemService(Context.APP_OPS_SERVICE))
- .thenReturn(mMockAppOps);
- when(mMockContext.getSystemService(Context.USER_SERVICE))
- .thenReturn(mMockUserManager);
- when(mMockContext.getSystemService(Context.LOCATION_SERVICE)).thenReturn(mLocationManager);
- }
-
- private void setupTestCase() throws Exception {
- setupMocks();
- setupMockInterface();
- mChecker = new LocationPermissionChecker(mMockContext);
- }
-
- private void initTestVars() {
- mPermissionsList.clear();
- mReturnPermission = createPermissionAnswer();
- mWifiScanAllowApps = AppOpsManager.MODE_ERRORED;
- mUid = OTHER_USER_UID;
- mThrowSecurityException = true;
- mMockApplInfo.targetSdkVersion = Build.VERSION_CODES.M;
- mIsLocationEnabled = false;
- mCurrentUser = ActivityManager.getCurrentUser();
- mCoarseLocationPermission = PackageManager.PERMISSION_DENIED;
- mFineLocationPermission = PackageManager.PERMISSION_DENIED;
- mAllowCoarseLocationApps = AppOpsManager.MODE_ERRORED;
- mAllowFineLocationApps = AppOpsManager.MODE_ERRORED;
- mNetworkSettingsPermission = PackageManager.PERMISSION_DENIED;
- }
-
- private void setupMockInterface() {
- Binder.restoreCallingIdentity((((long) mUid) << 32) | Binder.getCallingPid());
- doAnswer(mReturnPermission).when(mMockContext).checkPermission(
- anyString(), anyInt(), anyInt());
- when(mMockUserManager.isSameProfileGroup(UserHandle.SYSTEM,
- UserHandle.getUserHandleForUid(MANAGED_PROFILE_UID)))
- .thenReturn(true);
- when(mMockContext.checkPermission(mManifestStringCoarse, -1, mUid))
- .thenReturn(mCoarseLocationPermission);
- when(mMockContext.checkPermission(mManifestStringFine, -1, mUid))
- .thenReturn(mFineLocationPermission);
- when(mMockContext.checkPermission(NETWORK_SETTINGS, -1, mUid))
- .thenReturn(mNetworkSettingsPermission);
- when(mLocationManager.isLocationEnabledForUser(any())).thenReturn(mIsLocationEnabled);
- }
-
- private Answer<Integer> createPermissionAnswer() {
- return new Answer<Integer>() {
- @Override
- public Integer answer(InvocationOnMock invocation) {
- int myUid = (int) invocation.getArguments()[1];
- String myPermission = (String) invocation.getArguments()[0];
- mPermissionsList.get(myPermission);
- if (mPermissionsList.containsKey(myPermission)) {
- int uid = mPermissionsList.get(myPermission);
- if (myUid == uid) {
- return PackageManager.PERMISSION_GRANTED;
- }
- }
- return PackageManager.PERMISSION_DENIED;
- }
- };
- }
-
- @Test
- public void testEnforceLocationPermission_HasAllPermissions_BeforeQ() throws Exception {
- mIsLocationEnabled = true;
- mThrowSecurityException = false;
- mCoarseLocationPermission = PackageManager.PERMISSION_GRANTED;
- mAllowCoarseLocationApps = AppOpsManager.MODE_ALLOWED;
- mWifiScanAllowApps = AppOpsManager.MODE_ALLOWED;
- mUid = mCurrentUser;
- setupTestCase();
-
- final int result =
- mChecker.checkLocationPermissionWithDetailInfo(
- TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null);
- assertEquals(LocationPermissionChecker.SUCCEEDED, result);
- }
-
- @Test
- public void testEnforceLocationPermission_HasAllPermissions_AfterQ() throws Exception {
- mMockApplInfo.targetSdkVersion = Build.VERSION_CODES.Q;
- mIsLocationEnabled = true;
- mThrowSecurityException = false;
- mUid = mCurrentUser;
- mFineLocationPermission = PackageManager.PERMISSION_GRANTED;
- mAllowFineLocationApps = AppOpsManager.MODE_ALLOWED;
- mWifiScanAllowApps = AppOpsManager.MODE_ALLOWED;
- setupTestCase();
-
- final int result =
- mChecker.checkLocationPermissionWithDetailInfo(
- TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null);
- assertEquals(LocationPermissionChecker.SUCCEEDED, result);
- }
-
- @Test
- public void testEnforceLocationPermission_PkgNameAndUidMismatch() throws Exception {
- mThrowSecurityException = true;
- mIsLocationEnabled = true;
- mFineLocationPermission = PackageManager.PERMISSION_GRANTED;
- mAllowFineLocationApps = AppOpsManager.MODE_ALLOWED;
- mWifiScanAllowApps = AppOpsManager.MODE_ALLOWED;
- setupTestCase();
-
- assertThrows(SecurityException.class,
- () -> mChecker.checkLocationPermissionWithDetailInfo(
- TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null));
- }
-
- @Test
- public void testenforceCanAccessScanResults_NoCoarseLocationPermission() throws Exception {
- mThrowSecurityException = false;
- mIsLocationEnabled = true;
- setupTestCase();
-
- final int result =
- mChecker.checkLocationPermissionWithDetailInfo(
- TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null);
- assertEquals(LocationPermissionChecker.ERROR_LOCATION_PERMISSION_MISSING, result);
- }
-
- @Test
- public void testenforceCanAccessScanResults_NoFineLocationPermission() throws Exception {
- mThrowSecurityException = false;
- mMockApplInfo.targetSdkVersion = Build.VERSION_CODES.Q;
- mIsLocationEnabled = true;
- mCoarseLocationPermission = PackageManager.PERMISSION_GRANTED;
- mAllowFineLocationApps = AppOpsManager.MODE_ERRORED;
- mUid = MANAGED_PROFILE_UID;
- setupTestCase();
-
- final int result =
- mChecker.checkLocationPermissionWithDetailInfo(
- TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null);
- assertEquals(LocationPermissionChecker.ERROR_LOCATION_PERMISSION_MISSING, result);
- verify(mMockAppOps, never()).noteOp(anyInt(), anyInt(), anyString());
- }
-
- @Test
- public void testenforceCanAccessScanResults_LocationModeDisabled() throws Exception {
- mThrowSecurityException = false;
- mUid = MANAGED_PROFILE_UID;
- mWifiScanAllowApps = AppOpsManager.MODE_ALLOWED;
- mPermissionsList.put(mInteractAcrossUsersFullPermission, mUid);
- mIsLocationEnabled = false;
-
- setupTestCase();
-
- final int result =
- mChecker.checkLocationPermissionWithDetailInfo(
- TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null);
- assertEquals(LocationPermissionChecker.ERROR_LOCATION_MODE_OFF, result);
- }
-
- @Test
- public void testenforceCanAccessScanResults_LocationModeDisabledHasNetworkSettings()
- throws Exception {
- mThrowSecurityException = false;
- mIsLocationEnabled = false;
- mNetworkSettingsPermission = PackageManager.PERMISSION_GRANTED;
- setupTestCase();
-
- final int result =
- mChecker.checkLocationPermissionWithDetailInfo(
- TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null);
- assertEquals(LocationPermissionChecker.SUCCEEDED, result);
- }
-
-
- private static void assertThrows(Class<? extends Exception> exceptionClass, Runnable r) {
- try {
- r.run();
- Assert.fail("Expected " + exceptionClass + " to be thrown.");
- } catch (Exception exception) {
- assertTrue(exceptionClass.isInstance(exception));
- }
- }
-}
diff --git a/core/tests/uwbtests/src/android/uwb/RangingManagerTest.java b/core/tests/uwbtests/src/android/uwb/RangingManagerTest.java
index c01bb75..e41805d 100644
--- a/core/tests/uwbtests/src/android/uwb/RangingManagerTest.java
+++ b/core/tests/uwbtests/src/android/uwb/RangingManagerTest.java
@@ -22,7 +22,6 @@
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
import android.os.PersistableBundle;
import android.os.RemoteException;
@@ -32,6 +31,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import java.util.concurrent.Executor;
@@ -42,51 +42,23 @@
@RunWith(AndroidJUnit4.class)
public class RangingManagerTest {
- private static final IUwbAdapter ADAPTER = mock(IUwbAdapter.class);
private static final Executor EXECUTOR = UwbTestUtils.getExecutor();
private static final PersistableBundle PARAMS = new PersistableBundle();
private static final @RangingChangeReason int REASON = RangingChangeReason.UNKNOWN;
@Test
public void testOpenSession_OpenRangingInvoked() throws RemoteException {
- RangingManager rangingManager = new RangingManager(ADAPTER);
+ IUwbAdapter adapter = mock(IUwbAdapter.class);
+ RangingManager rangingManager = new RangingManager(adapter);
RangingSession.Callback callback = mock(RangingSession.Callback.class);
rangingManager.openSession(PARAMS, EXECUTOR, callback);
- verify(ADAPTER, times(1)).openRanging(eq(rangingManager), eq(PARAMS));
- }
-
- @Test
- public void testOpenSession_ErrorIfSameSessionHandleReturned() throws RemoteException {
- RangingManager rangingManager = new RangingManager(ADAPTER);
- RangingSession.Callback callback = mock(RangingSession.Callback.class);
- SessionHandle handle = new SessionHandle(1);
- when(ADAPTER.openRanging(any(), any())).thenReturn(handle);
-
- rangingManager.openSession(PARAMS, EXECUTOR, callback);
-
- // Calling openSession will cause the same session handle to be returned. The onClosed
- // callback should be invoked
- RangingSession.Callback callback2 = mock(RangingSession.Callback.class);
- rangingManager.openSession(PARAMS, EXECUTOR, callback2);
- verify(callback, times(0)).onClosed(anyInt(), any());
- verify(callback2, times(1)).onClosed(anyInt(), any());
- }
-
- @Test
- public void testOnRangingOpened_ValidSessionHandle() throws RemoteException {
- RangingManager rangingManager = new RangingManager(ADAPTER);
- RangingSession.Callback callback = mock(RangingSession.Callback.class);
- SessionHandle handle = new SessionHandle(1);
- when(ADAPTER.openRanging(any(), any())).thenReturn(handle);
-
- rangingManager.openSession(PARAMS, EXECUTOR, callback);
- rangingManager.onRangingOpened(handle);
- verify(callback, times(1)).onOpened(any());
+ verify(adapter, times(1)).openRanging(any(), eq(rangingManager), eq(PARAMS));
}
@Test
public void testOnRangingOpened_InvalidSessionHandle() throws RemoteException {
- RangingManager rangingManager = new RangingManager(ADAPTER);
+ IUwbAdapter adapter = mock(IUwbAdapter.class);
+ RangingManager rangingManager = new RangingManager(adapter);
RangingSession.Callback callback = mock(RangingSession.Callback.class);
rangingManager.onRangingOpened(new SessionHandle(2));
@@ -95,18 +67,20 @@
@Test
public void testOnRangingOpened_MultipleSessionsRegistered() throws RemoteException {
- SessionHandle sessionHandle1 = new SessionHandle(1);
- SessionHandle sessionHandle2 = new SessionHandle(2);
+ IUwbAdapter adapter = mock(IUwbAdapter.class);
RangingSession.Callback callback1 = mock(RangingSession.Callback.class);
RangingSession.Callback callback2 = mock(RangingSession.Callback.class);
+ ArgumentCaptor<SessionHandle> sessionHandleCaptor =
+ ArgumentCaptor.forClass(SessionHandle.class);
- when(ADAPTER.openRanging(any(), any()))
- .thenReturn(sessionHandle1)
- .thenReturn(sessionHandle2);
-
- RangingManager rangingManager = new RangingManager(ADAPTER);
+ RangingManager rangingManager = new RangingManager(adapter);
rangingManager.openSession(PARAMS, EXECUTOR, callback1);
+ verify(adapter, times(1)).openRanging(sessionHandleCaptor.capture(), any(), any());
+ SessionHandle sessionHandle1 = sessionHandleCaptor.getValue();
+
rangingManager.openSession(PARAMS, EXECUTOR, callback2);
+ verify(adapter, times(2)).openRanging(sessionHandleCaptor.capture(), any(), any());
+ SessionHandle sessionHandle2 = sessionHandleCaptor.getValue();
rangingManager.onRangingOpened(sessionHandle1);
verify(callback1, times(1)).onOpened(any());
@@ -119,12 +93,17 @@
@Test
public void testCorrectCallbackInvoked() throws RemoteException {
- RangingManager rangingManager = new RangingManager(ADAPTER);
+ IUwbAdapter adapter = mock(IUwbAdapter.class);
+ RangingManager rangingManager = new RangingManager(adapter);
RangingSession.Callback callback = mock(RangingSession.Callback.class);
- SessionHandle handle = new SessionHandle(1);
- when(ADAPTER.openRanging(any(), any())).thenReturn(handle);
+
+ ArgumentCaptor<SessionHandle> sessionHandleCaptor =
+ ArgumentCaptor.forClass(SessionHandle.class);
rangingManager.openSession(PARAMS, EXECUTOR, callback);
+ verify(adapter, times(1)).openRanging(sessionHandleCaptor.capture(), any(), any());
+ SessionHandle handle = sessionHandleCaptor.getValue();
+
rangingManager.onRangingOpened(handle);
verify(callback, times(1)).onOpened(any());
@@ -156,20 +135,23 @@
@Test
public void testOnRangingClosed_MultipleSessionsRegistered() throws RemoteException {
+ IUwbAdapter adapter = mock(IUwbAdapter.class);
// Verify that if multiple sessions are registered, only the session that is
// requested to close receives the associated callbacks
- SessionHandle sessionHandle1 = new SessionHandle(1);
- SessionHandle sessionHandle2 = new SessionHandle(2);
RangingSession.Callback callback1 = mock(RangingSession.Callback.class);
RangingSession.Callback callback2 = mock(RangingSession.Callback.class);
- when(ADAPTER.openRanging(any(), any()))
- .thenReturn(sessionHandle1)
- .thenReturn(sessionHandle2);
+ RangingManager rangingManager = new RangingManager(adapter);
+ ArgumentCaptor<SessionHandle> sessionHandleCaptor =
+ ArgumentCaptor.forClass(SessionHandle.class);
- RangingManager rangingManager = new RangingManager(ADAPTER);
rangingManager.openSession(PARAMS, EXECUTOR, callback1);
+ verify(adapter, times(1)).openRanging(sessionHandleCaptor.capture(), any(), any());
+ SessionHandle sessionHandle1 = sessionHandleCaptor.getValue();
+
rangingManager.openSession(PARAMS, EXECUTOR, callback2);
+ verify(adapter, times(2)).openRanging(sessionHandleCaptor.capture(), any(), any());
+ SessionHandle sessionHandle2 = sessionHandleCaptor.getValue();
rangingManager.onRangingClosed(sessionHandle1, REASON, PARAMS);
verify(callback1, times(1)).onClosed(anyInt(), any());
@@ -182,19 +164,22 @@
@Test
public void testOnRangingReport_MultipleSessionsRegistered() throws RemoteException {
- SessionHandle sessionHandle1 = new SessionHandle(1);
- SessionHandle sessionHandle2 = new SessionHandle(2);
+ IUwbAdapter adapter = mock(IUwbAdapter.class);
RangingSession.Callback callback1 = mock(RangingSession.Callback.class);
RangingSession.Callback callback2 = mock(RangingSession.Callback.class);
- when(ADAPTER.openRanging(any(), any()))
- .thenReturn(sessionHandle1)
- .thenReturn(sessionHandle2);
+ ArgumentCaptor<SessionHandle> sessionHandleCaptor =
+ ArgumentCaptor.forClass(SessionHandle.class);
- RangingManager rangingManager = new RangingManager(ADAPTER);
+ RangingManager rangingManager = new RangingManager(adapter);
rangingManager.openSession(PARAMS, EXECUTOR, callback1);
+ verify(adapter, times(1)).openRanging(sessionHandleCaptor.capture(), any(), any());
+ SessionHandle sessionHandle1 = sessionHandleCaptor.getValue();
+
rangingManager.onRangingStarted(sessionHandle1, PARAMS);
rangingManager.openSession(PARAMS, EXECUTOR, callback2);
+ verify(adapter, times(2)).openRanging(sessionHandleCaptor.capture(), any(), any());
+ SessionHandle sessionHandle2 = sessionHandleCaptor.getValue();
rangingManager.onRangingStarted(sessionHandle2, PARAMS);
rangingManager.onRangingResult(sessionHandle1, UwbTestUtils.getRangingReports(1));
@@ -232,17 +217,24 @@
private void runReason(@RangingChangeReason int reasonIn,
@RangingSession.Callback.Reason int reasonOut) throws RemoteException {
- RangingManager rangingManager = new RangingManager(ADAPTER);
+ IUwbAdapter adapter = mock(IUwbAdapter.class);
+ RangingManager rangingManager = new RangingManager(adapter);
RangingSession.Callback callback = mock(RangingSession.Callback.class);
- SessionHandle handle = new SessionHandle(1);
- when(ADAPTER.openRanging(any(), any())).thenReturn(handle);
+
+ ArgumentCaptor<SessionHandle> sessionHandleCaptor =
+ ArgumentCaptor.forClass(SessionHandle.class);
+
rangingManager.openSession(PARAMS, EXECUTOR, callback);
+ verify(adapter, times(1)).openRanging(sessionHandleCaptor.capture(), any(), any());
+ SessionHandle handle = sessionHandleCaptor.getValue();
rangingManager.onRangingOpenFailed(handle, reasonIn, PARAMS);
verify(callback, times(1)).onOpenFailed(eq(reasonOut), eq(PARAMS));
// Open a new session
rangingManager.openSession(PARAMS, EXECUTOR, callback);
+ verify(adapter, times(2)).openRanging(sessionHandleCaptor.capture(), any(), any());
+ handle = sessionHandleCaptor.getValue();
rangingManager.onRangingOpened(handle);
rangingManager.onRangingStartFailed(handle, reasonIn, PARAMS);
diff --git a/core/tests/uwbtests/src/android/uwb/UwbTestUtils.java b/core/tests/uwbtests/src/android/uwb/UwbTestUtils.java
index 8e7f7c56..75c6924 100644
--- a/core/tests/uwbtests/src/android/uwb/UwbTestUtils.java
+++ b/core/tests/uwbtests/src/android/uwb/UwbTestUtils.java
@@ -16,34 +16,23 @@
package android.uwb;
-import android.content.Context;
-import android.content.pm.PackageManager;
import android.os.SystemClock;
-import java.util.ArrayList;
-import java.util.List;
import java.util.concurrent.Executor;
public class UwbTestUtils {
private UwbTestUtils() {}
- public static boolean isUwbSupported(Context context) {
- PackageManager packageManager = context.getPackageManager();
- return packageManager.hasSystemFeature(PackageManager.FEATURE_UWB);
- }
-
public static AngleMeasurement getAngleMeasurement() {
- return new AngleMeasurement.Builder()
- .setRadians(getDoubleInRange(-Math.PI, Math.PI))
- .setErrorRadians(getDoubleInRange(0, Math.PI))
- .setConfidenceLevel(getDoubleInRange(0, 1))
- .build();
+ return new AngleMeasurement(
+ getDoubleInRange(-Math.PI, Math.PI),
+ getDoubleInRange(0, Math.PI),
+ getDoubleInRange(0, 1));
}
public static AngleOfArrivalMeasurement getAngleOfArrivalMeasurement() {
- return new AngleOfArrivalMeasurement.Builder()
+ return new AngleOfArrivalMeasurement.Builder(getAngleMeasurement())
.setAltitude(getAngleMeasurement())
- .setAzimuth(getAngleMeasurement())
.build();
}
@@ -69,14 +58,6 @@
.build();
}
- public static List<RangingMeasurement> getRangingMeasurements(int num) {
- List<RangingMeasurement> result = new ArrayList<>();
- for (int i = 0; i < num; i++) {
- result.add(getRangingMeasurement());
- }
- return result;
- }
-
public static RangingReport getRangingReports(int numMeasurements) {
RangingReport.Builder builder = new RangingReport.Builder();
for (int i = 0; i < numMeasurements; i++) {
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 354d83c..653e690 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -451,6 +451,7 @@
<permission name="android.permission.MANAGE_SOUND_TRIGGER" />
<permission name="android.permission.CAPTURE_AUDIO_HOTWORD" />
<permission name="android.permission.MODIFY_QUIET_MODE" />
+ <permission name="android.permission.MANAGE_APP_HIBERNATION"/>
</privapp-permissions>
<privapp-permissions package="com.android.statementservice">
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index fe5c1be..d048efc 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -1196,13 +1196,11 @@
/** @hide */
public boolean isSupportedAxes(int axis) {
- if (mSupportedAxes == null) {
- synchronized (this) {
+ synchronized (this) {
+ if (mSupportedAxes == null) {
+ mSupportedAxes = nativeGetSupportedAxes(native_instance);
if (mSupportedAxes == null) {
- mSupportedAxes = nativeGetSupportedAxes(native_instance);
- if (mSupportedAxes == null) {
- mSupportedAxes = EMPTY_AXES;
- }
+ mSupportedAxes = EMPTY_AXES;
}
}
}
diff --git a/keystore/java/android/security/AndroidKeyStoreMaintenance.java b/keystore/java/android/security/AndroidKeyStoreMaintenance.java
index ed789f0..72cea0c 100644
--- a/keystore/java/android/security/AndroidKeyStoreMaintenance.java
+++ b/keystore/java/android/security/AndroidKeyStoreMaintenance.java
@@ -20,7 +20,7 @@
import android.annotation.Nullable;
import android.os.ServiceManager;
import android.os.ServiceSpecificException;
-import android.security.usermanager.IKeystoreUserManager;
+import android.security.maintenance.IKeystoreMaintenance;
import android.system.keystore2.Domain;
import android.system.keystore2.ResponseCode;
import android.util.Log;
@@ -34,9 +34,9 @@
public static final int SYSTEM_ERROR = ResponseCode.SYSTEM_ERROR;
- private static IKeystoreUserManager getService() {
- return IKeystoreUserManager.Stub.asInterface(
- ServiceManager.checkService("android.security.usermanager"));
+ private static IKeystoreMaintenance getService() {
+ return IKeystoreMaintenance.Stub.asInterface(
+ ServiceManager.checkService("android.security.maintenance"));
}
/**
@@ -121,4 +121,36 @@
return SYSTEM_ERROR;
}
}
+
+ /**
+ * Queries user state from Keystore 2.0.
+ *
+ * @param userId - Android user id of the user.
+ * @return UserState enum variant as integer if successful or an error
+ */
+ public static int getState(int userId) {
+ try {
+ return getService().getState(userId);
+ } catch (ServiceSpecificException e) {
+ Log.e(TAG, "getState failed", e);
+ return e.errorCode;
+ } catch (Exception e) {
+ Log.e(TAG, "Can not connect to keystore", e);
+ return SYSTEM_ERROR;
+ }
+ }
+
+ /**
+ * Informs Keystore 2.0 that an off body event was detected.
+ */
+ public static void onDeviceOffBody() {
+ if (!android.security.keystore2.AndroidKeyStoreProvider.isInstalled()) return;
+ try {
+ getService().onDeviceOffBody();
+ } catch (Exception e) {
+ // TODO This fails open. This is not a regression with respect to keystore1 but it
+ // should get fixed.
+ Log.e(TAG, "Error while reporting device off body event.", e);
+ }
+ }
}
diff --git a/keystore/java/android/security/GenerateRkpKey.java b/keystore/java/android/security/GenerateRkpKey.java
new file mode 100644
index 0000000..a1a7aa8
--- /dev/null
+++ b/keystore/java/android/security/GenerateRkpKey.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+import android.os.RemoteException;
+
+/**
+ * GenerateKey is a helper class to handle interactions between Keystore and the RemoteProvisioner
+ * app. There are two cases where Keystore should use this class.
+ *
+ * (1) : An app generates a new attested key pair, so Keystore calls notifyKeyGenerated to let the
+ * RemoteProvisioner app check if the state of the attestation key pool is getting low enough
+ * to warrant provisioning more attestation certificates early.
+ *
+ * (2) : An app attempts to generate a new key pair, but the keystore service discovers it is out of
+ * attestation key pairs and cannot provide one for the given application. Keystore can then
+ * make a blocking call on notifyEmpty to allow the RemoteProvisioner app to get another
+ * attestation certificate chain provisioned.
+ *
+ * In most cases, the proper usage of (1) should preclude the need for (2).
+ *
+ * @hide
+ */
+public class GenerateRkpKey {
+
+ private IGenerateRkpKeyService mBinder;
+ private Context mContext;
+
+ private ServiceConnection mConnection = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ mBinder = IGenerateRkpKeyService.Stub.asInterface(service);
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName className) {
+ mBinder = null;
+ }
+ };
+
+ /**
+ * Constructor which takes a Context object.
+ */
+ public GenerateRkpKey(Context context) {
+ mContext = context;
+ }
+
+ /**
+ * Fulfills the use case of (2) described in the class documentation. Blocks until the
+ * RemoteProvisioner application can get new attestation keys signed by the server.
+ */
+ public void notifyEmpty(int securityLevel) throws RemoteException {
+ Intent intent = new Intent(IGenerateRkpKeyService.class.getName());
+ ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
+ intent.setComponent(comp);
+ if (comp == null || !mContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE)) {
+ throw new RemoteException("Failed to bind to GenerateKeyService");
+ }
+ if (mBinder != null) {
+ mBinder.generateKey(securityLevel);
+ }
+ mContext.unbindService(mConnection);
+ }
+
+ /**
+ * FUlfills the use case of (1) described in the class documentation. Non blocking call.
+ */
+ public void notifyKeyGenerated(int securityLevel) throws RemoteException {
+ Intent intent = new Intent(IGenerateRkpKeyService.class.getName());
+ ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
+ intent.setComponent(comp);
+ if (comp == null || !mContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE)) {
+ throw new RemoteException("Failed to bind to GenerateKeyService");
+ }
+ if (mBinder != null) {
+ mBinder.notifyKeyGenerated(securityLevel);
+ }
+ mContext.unbindService(mConnection);
+ }
+}
diff --git a/packages/Connectivity/framework/src/android/net/IOnSetOemNetworkPreferenceListener.aidl b/keystore/java/android/security/GenerateRkpKeyException.java
similarity index 61%
copy from packages/Connectivity/framework/src/android/net/IOnSetOemNetworkPreferenceListener.aidl
copy to keystore/java/android/security/GenerateRkpKeyException.java
index 7979afc..a2d65e4 100644
--- a/packages/Connectivity/framework/src/android/net/IOnSetOemNetworkPreferenceListener.aidl
+++ b/keystore/java/android/security/GenerateRkpKeyException.java
@@ -1,12 +1,11 @@
-/**
- *
+/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * 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,
@@ -15,9 +14,18 @@
* limitations under the License.
*/
-package android.net;
+package android.security;
-/** @hide */
-oneway interface IOnSetOemNetworkPreferenceListener {
- void onComplete();
+/**
+ * Thrown on problems in attempting to attest to a key using a remotely provisioned key.
+ *
+ * @hide
+ */
+public class GenerateRkpKeyException extends Exception {
+
+ /**
+ * Constructs a new {@code GenerateRkpKeyException}.
+ */
+ public GenerateRkpKeyException() {
+ }
}
diff --git a/keystore/java/android/security/IGenerateRkpKeyService.aidl b/keystore/java/android/security/IGenerateRkpKeyService.aidl
new file mode 100644
index 0000000..5f1d669
--- /dev/null
+++ b/keystore/java/android/security/IGenerateRkpKeyService.aidl
@@ -0,0 +1,36 @@
+/**
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security;
+
+/**
+ * Interface to allow the framework to notify the RemoteProvisioner app when keys are empty. This
+ * will be used if Keystore replies with an error code NO_KEYS_AVAILABLE in response to an
+ * attestation request. The framework can then synchronously call generateKey() to get more
+ * attestation keys generated and signed. Upon return, the caller can be certain an attestation key
+ * is available.
+ *
+ * @hide
+ */
+interface IGenerateRkpKeyService {
+ /**
+ * Ping the provisioner service to let it know an app generated a key. This may or may not have
+ * consumed a remotely provisioned attestation key, so the RemoteProvisioner app should check.
+ */
+ oneway void notifyKeyGenerated(in int securityLevel);
+ /** Ping the provisioner service to indicate there are no remaining attestation keys left. */
+ void generateKey(in int securityLevel);
+}
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index 93658e6..b05149e 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -43,6 +43,7 @@
import android.security.keystore.KeyProperties;
import android.security.keystore.KeystoreResponse;
import android.security.keystore.UserNotAuthenticatedException;
+import android.security.maintenance.UserState;
import android.system.keystore2.Domain;
import android.util.Log;
@@ -196,6 +197,19 @@
public State state(int userId) {
final int ret;
try {
+ if (android.security.keystore2.AndroidKeyStoreProvider.isInstalled()) {
+ int userState = AndroidKeyStoreMaintenance.getState(userId);
+ switch (userState) {
+ case UserState.UNINITIALIZED:
+ return KeyStore.State.UNINITIALIZED;
+ case UserState.LSKF_UNLOCKED:
+ return KeyStore.State.UNLOCKED;
+ case UserState.LSKF_LOCKED:
+ return KeyStore.State.LOCKED;
+ default:
+ throw new AssertionError(userState);
+ }
+ }
ret = mBinder.getState(userId);
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
@@ -1190,6 +1204,7 @@
* Notify keystore that the device went off-body.
*/
public void onDeviceOffBody() {
+ AndroidKeyStoreMaintenance.onDeviceOffBody();
try {
mBinder.onDeviceOffBody();
} catch (RemoteException e) {
diff --git a/keystore/java/android/security/KeyStore2.java b/keystore/java/android/security/KeyStore2.java
index 6ac3821..75e248e 100644
--- a/keystore/java/android/security/KeyStore2.java
+++ b/keystore/java/android/security/KeyStore2.java
@@ -18,8 +18,7 @@
import android.annotation.NonNull;
import android.compat.annotation.ChangeId;
-import android.compat.annotation.EnabledAfter;
-import android.os.Build;
+import android.compat.annotation.Disabled;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceSpecificException;
@@ -86,7 +85,7 @@
* successfully conclude an operation.
*/
@ChangeId
- @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R)
+ @Disabled // See b/180133780
static final long KEYSTORE_OPERATION_CREATION_MAY_FAIL = 169897160L;
// Never use mBinder directly, use KeyStore2.getService() instead or better yet
diff --git a/keystore/java/android/security/keystore/AttestationUtils.java b/keystore/java/android/security/keystore/AttestationUtils.java
index f1eea82..1eb8541 100644
--- a/keystore/java/android/security/keystore/AttestationUtils.java
+++ b/keystore/java/android/security/keystore/AttestationUtils.java
@@ -23,7 +23,6 @@
import android.content.Context;
import android.content.res.Resources;
import android.os.Build;
-import android.security.KeyStore;
import android.security.keymaster.KeymasterArguments;
import android.security.keymaster.KeymasterCertificateChain;
import android.security.keymaster.KeymasterDefs;
@@ -34,9 +33,14 @@
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.nio.charset.StandardCharsets;
+import java.security.KeyPairGenerator;
+import java.security.KeyStore;
+import java.security.SecureRandom;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
+import java.security.spec.ECGenParameterSpec;
import java.util.Collection;
+import java.util.Random;
import java.util.Set;
/**
@@ -256,24 +260,51 @@
@NonNull public static X509Certificate[] attestDeviceIds(Context context,
@NonNull int[] idTypes, @NonNull byte[] attestationChallenge) throws
DeviceIdAttestationException {
- final KeymasterArguments attestArgs = prepareAttestationArgumentsForDeviceId(
- context, idTypes, attestationChallenge);
+ String keystoreAlias = generateRandomAlias();
+ KeyGenParameterSpec.Builder builder =
+ new KeyGenParameterSpec.Builder(keystoreAlias, KeyProperties.PURPOSE_SIGN)
+ .setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1"))
+ .setDigests(KeyProperties.DIGEST_SHA256)
+ .setAttestationChallenge(attestationChallenge);
- // Perform attestation.
- final KeymasterCertificateChain outChain = new KeymasterCertificateChain();
- final int errorCode = KeyStore.getInstance().attestDeviceIds(attestArgs, outChain);
- if (errorCode != KeyStore.NO_ERROR) {
- throw new DeviceIdAttestationException("Unable to perform attestation",
- KeyStore.getKeyStoreException(errorCode));
+ if (idTypes != null) {
+ builder.setAttestationIds(idTypes);
+ builder.setDevicePropertiesAttestationIncluded(true);
}
try {
- return parseCertificateChain(outChain);
- } catch (KeyAttestationException e) {
- throw new DeviceIdAttestationException(e.getMessage(), e);
+ KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(
+ KeyProperties.KEY_ALGORITHM_EC, "AndroidKeyStore");
+ keyPairGenerator.initialize(builder.build());
+ keyPairGenerator.generateKeyPair();
+
+ KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
+ keyStore.load(null);
+
+ X509Certificate[] certificateChain =
+ (X509Certificate[]) keyStore.getCertificateChain(keystoreAlias);
+
+ keyStore.deleteEntry(keystoreAlias);
+
+ return certificateChain;
+ } catch (SecurityException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new DeviceIdAttestationException("Unable to perform attestation", e);
}
}
+ private static String generateRandomAlias() {
+ Random random = new SecureRandom();
+ StringBuilder builder = new StringBuilder();
+ // Pick random uppercase letters, A-Z. 20 of them gives us ~94 bits of entropy, which
+ // should prevent any conflicts with app-selected aliases, even for very unlucky users.
+ for (int i = 0; i < 20; ++i) {
+ builder.append(random.nextInt(26) + 'A');
+ }
+ return builder.toString();
+ }
+
/**
* Returns true if the attestation chain provided is a valid key attestation chain.
* @hide
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
index 72735a7..9ca551b 100644
--- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
@@ -288,7 +288,7 @@
private static final Date DEFAULT_CERT_NOT_AFTER = new Date(2461449600000L); // Jan 1 2048
private final String mKeystoreAlias;
- private final int mNamespace;
+ private final @KeyProperties.Namespace int mNamespace;
private final int mKeySize;
private final AlgorithmParameterSpec mSpec;
private final X500Principal mCertificateSubject;
@@ -331,7 +331,7 @@
*/
public KeyGenParameterSpec(
String keyStoreAlias,
- int namespace,
+ @KeyProperties.Namespace int namespace,
int keySize,
AlgorithmParameterSpec spec,
X500Principal certificateSubject,
@@ -467,12 +467,12 @@
*
* @return The numeric namespace as configured in the keystore2_key_contexts files of Android's
* SEPolicy.
- * TODO b/171806779 link to public Keystore 2.0 documentation.
- * See bug for more details for now.
+ * See <a href="https://source.android.com/security/keystore#access-control">
+ * Keystore 2.0 access control</a>
* @hide
*/
@SystemApi
- public int getNamespace() {
+ public @KeyProperties.Namespace int getNamespace() {
return mNamespace;
}
@@ -896,7 +896,7 @@
private final String mKeystoreAlias;
private @KeyProperties.PurposeEnum int mPurposes;
- private int mNamespace = KeyProperties.NAMESPACE_APPLICATION;
+ private @KeyProperties.Namespace int mNamespace = KeyProperties.NAMESPACE_APPLICATION;
private int mKeySize = -1;
private AlgorithmParameterSpec mSpec;
private X500Principal mCertificateSubject;
@@ -1042,16 +1042,16 @@
* keys between system and vendor components, e.g., WIFI settings and WPA supplicant.
*
* @param namespace Numeric SELinux namespace as configured in keystore2_key_contexts
- * of Android's SEPolicy.
- * TODO b/171806779 link to public Keystore 2.0 documentation.
- * See bug for more details for now.
+ * of Android's SEPolicy.
+ * See <a href="https://source.android.com/security/keystore#access-control">
+ * Keystore 2.0 access control</a>
* @return this Builder object.
*
* @hide
*/
@SystemApi
@NonNull
- public Builder setNamespace(int namespace) {
+ public Builder setNamespace(@KeyProperties.Namespace int namespace) {
mNamespace = namespace;
return this;
}
diff --git a/keystore/java/android/security/keystore/KeyProperties.java b/keystore/java/android/security/keystore/KeyProperties.java
index 7b0fa91..682d12a 100644
--- a/keystore/java/android/security/keystore/KeyProperties.java
+++ b/keystore/java/android/security/keystore/KeyProperties.java
@@ -892,6 +892,22 @@
}
/**
+ * Namespaces provide system developers and vendors with a way to use keystore without
+ * requiring an applications uid. Namespaces can be configured using SEPolicy.
+ * See <a href="https://source.android.com/security/keystore#access-control">
+ * Keystore 2.0 access-control</a>
+ * {@See KeyGenParameterSpec.Builder#setNamespace}
+ * {@See android.security.keystore2.AndroidKeyStoreLoadStoreParameter}
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = { "NAMESPACE_" }, value = {
+ NAMESPACE_APPLICATION,
+ NAMESPACE_WIFI,
+ })
+ public @interface Namespace {}
+
+ /**
* This value indicates the implicit keystore namespace of the calling application.
* It is used by default. Only select system components can choose a different namespace
* which it must be configured in SEPolicy.
@@ -912,14 +928,12 @@
* For legacy support, translate namespaces into known UIDs.
* @hide
*/
- public static int namespaceToLegacyUid(int namespace) {
+ public static int namespaceToLegacyUid(@Namespace int namespace) {
switch (namespace) {
case NAMESPACE_APPLICATION:
return KeyStore.UID_SELF;
case NAMESPACE_WIFI:
return Process.WIFI_UID;
- // TODO Translate WIFI and VPN UIDs once the namespaces are defined.
- // b/171305388 and b/171305607
default:
throw new IllegalArgumentException("No UID corresponding to namespace "
+ namespace);
@@ -930,14 +944,12 @@
* For legacy support, translate namespaces into known UIDs.
* @hide
*/
- public static int legacyUidToNamespace(int uid) {
+ public static @Namespace int legacyUidToNamespace(int uid) {
switch (uid) {
case KeyStore.UID_SELF:
return NAMESPACE_APPLICATION;
case Process.WIFI_UID:
return NAMESPACE_WIFI;
- // TODO Translate WIFI and VPN UIDs once the namespaces are defined.
- // b/171305388 and b/171305607
default:
throw new IllegalArgumentException("No namespace corresponding to uid "
+ uid);
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreCipherSpiBase.java b/keystore/java/android/security/keystore2/AndroidKeyStoreCipherSpiBase.java
index 2ee952c..9d8a5ef 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreCipherSpiBase.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreCipherSpiBase.java
@@ -123,8 +123,9 @@
throws InvalidKeyException {
resetAll();
- if (!(key instanceof AndroidKeyStorePrivateKey
- || key instanceof AndroidKeyStoreSecretKey)) {
+ // Public key operations get diverted to the default provider.
+ if (!(key instanceof AndroidKeyStorePrivateKey)
+ && (key instanceof PrivateKey || key instanceof PublicKey)) {
try {
mCipher = Cipher.getInstance(getTransform());
String transform = getTransform();
@@ -184,8 +185,9 @@
SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException {
resetAll();
- if (!(key instanceof AndroidKeyStorePrivateKey
- || key instanceof AndroidKeyStoreSecretKey)) {
+ // Public key operations get diverted to the default provider.
+ if (!(key instanceof AndroidKeyStorePrivateKey)
+ && (key instanceof PrivateKey || key instanceof PublicKey)) {
try {
mCipher = Cipher.getInstance(getTransform());
mCipher.init(opmode, key, params, random);
@@ -213,8 +215,9 @@
SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException {
resetAll();
- if (!(key instanceof AndroidKeyStorePrivateKey
- || key instanceof AndroidKeyStoreSecretKey)) {
+ // Public key operations get diverted to the default provider.
+ if (!(key instanceof AndroidKeyStorePrivateKey)
+ && (key instanceof PrivateKey || key instanceof PublicKey)) {
try {
mCipher = Cipher.getInstance(getTransform());
mCipher.init(opmode, key, params, random);
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
index e401add..2d8901a 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -24,6 +24,9 @@
import android.hardware.security.keymint.SecurityLevel;
import android.hardware.security.keymint.Tag;
import android.os.Build;
+import android.os.RemoteException;
+import android.security.GenerateRkpKey;
+import android.security.GenerateRkpKeyException;
import android.security.KeyPairGeneratorSpec;
import android.security.KeyStore;
import android.security.KeyStore2;
@@ -520,6 +523,18 @@
@Override
public KeyPair generateKeyPair() {
+ try {
+ return generateKeyPairHelper();
+ } catch (GenerateRkpKeyException e) {
+ try {
+ return generateKeyPairHelper();
+ } catch (GenerateRkpKeyException f) {
+ throw new ProviderException("Failed to provision new attestation keys.");
+ }
+ }
+ }
+
+ private KeyPair generateKeyPairHelper() throws GenerateRkpKeyException {
if (mKeyStore == null || mSpec == null) {
throw new IllegalStateException("Not initialized");
}
@@ -557,13 +572,30 @@
AndroidKeyStorePublicKey publicKey =
AndroidKeyStoreProvider.makeAndroidKeyStorePublicKeyFromKeyEntryResponse(
descriptor, metadata, iSecurityLevel, mKeymasterAlgorithm);
-
+ GenerateRkpKey keyGen = new GenerateRkpKey(KeyStore.getApplicationContext());
+ try {
+ if (mSpec.getAttestationChallenge() != null) {
+ keyGen.notifyKeyGenerated(securityLevel);
+ }
+ } catch (RemoteException e) {
+ // This is not really an error state, and necessarily does not apply to non RKP
+ // systems or hybrid systems where RKP is not currently turned on.
+ Log.d(TAG, "Couldn't connect to the RemoteProvisioner backend.");
+ }
success = true;
return new KeyPair(publicKey, publicKey.getPrivateKey());
} catch (android.security.KeyStoreException e) {
switch(e.getErrorCode()) {
case KeymasterDefs.KM_ERROR_HARDWARE_TYPE_UNAVAILABLE:
throw new StrongBoxUnavailableException("Failed to generated key pair.", e);
+ case ResponseCode.OUT_OF_KEYS:
+ GenerateRkpKey keyGen = new GenerateRkpKey(KeyStore.getApplicationContext());
+ try {
+ keyGen.notifyEmpty(securityLevel);
+ } catch (RemoteException f) {
+ throw new ProviderException("Failed to talk to RemoteProvisioner", f);
+ }
+ throw new GenerateRkpKeyException();
default:
ProviderException p = new ProviderException("Failed to generate key pair.", e);
if ((mSpec.getPurposes() & KeyProperties.PURPOSE_WRAP_KEY) != 0) {
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreLoadStoreParameter.java b/keystore/java/android/security/keystore2/AndroidKeyStoreLoadStoreParameter.java
index 0c6744f..25b1c86 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreLoadStoreParameter.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreLoadStoreParameter.java
@@ -16,6 +16,8 @@
package android.security.keystore2;
+import android.security.keystore.KeyProperties;
+
import java.security.KeyStore;
import java.security.KeyStore.ProtectionParameter;
@@ -24,9 +26,9 @@
*/
public class AndroidKeyStoreLoadStoreParameter implements KeyStore.LoadStoreParameter {
- private final int mNamespace;
+ private final @KeyProperties.Namespace int mNamespace;
- public AndroidKeyStoreLoadStoreParameter(int namespace) {
+ public AndroidKeyStoreLoadStoreParameter(@KeyProperties.Namespace int namespace) {
mNamespace = namespace;
}
@@ -35,7 +37,7 @@
return null;
}
- int getNamespace() {
+ @KeyProperties.Namespace int getNamespace() {
return mNamespace;
}
}
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
index d36695b..ba6d22f 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
@@ -145,23 +145,15 @@
sInstalled = true;
Security.addProvider(new AndroidKeyStoreProvider());
- Security.addProvider(
- new android.security.keystore.AndroidKeyStoreProvider(
- "AndroidKeyStoreLegacy"));
Provider workaroundProvider = new AndroidKeyStoreBCWorkaroundProvider();
- Provider legacyWorkaroundProvider =
- new android.security.keystore.AndroidKeyStoreBCWorkaroundProvider(
- "AndroidKeyStoreBCWorkaroundLegacy");
if (bcProviderIndex != -1) {
// Bouncy Castle provider found -- install the workaround provider above it.
// insertProviderAt uses 1-based positions.
- Security.insertProviderAt(legacyWorkaroundProvider, bcProviderIndex + 1);
Security.insertProviderAt(workaroundProvider, bcProviderIndex + 1);
} else {
// Bouncy Castle provider not found -- install the workaround provider at lowest
// priority.
Security.addProvider(workaroundProvider);
- Security.addProvider(legacyWorkaroundProvider);
}
}
@@ -340,11 +332,11 @@
* @param keyStore The keystore2 backend.
* @param alias The alias of the key in the Keystore database.
* @param namespace The a Keystore namespace. This is used by system api only to request
- * Android system specific keystore namespace, which can be configured
- * in the device's SEPolicy. Third party apps and most system components
- * set this parameter to -1 to indicate their application specific namespace.
- * TODO b/171806779 link to public Keystore 2.0 documentation.
- * See bug for more details for now.
+ * Android system specific keystore namespace, which can be configured
+ * in the device's SEPolicy. Third party apps and most system components
+ * set this parameter to -1 to indicate their application specific namespace.
+ * See <a href="https://source.android.com/security/keystore#access-control">
+ * Keystore 2.0 access control</a>
* @hide
**/
@NonNull
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
index 39607ae..32f98a2 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
@@ -100,7 +100,7 @@
public static final String NAME = "AndroidKeyStore";
private KeyStore2 mKeyStore;
- private int mNamespace = KeyProperties.NAMESPACE_APPLICATION;
+ private @KeyProperties.Namespace int mNamespace = KeyProperties.NAMESPACE_APPLICATION;
@Override
public Key engineGetKey(String alias, char[] password) throws NoSuchAlgorithmException,
@@ -1125,7 +1125,7 @@
@Override
public void engineLoad(LoadStoreParameter param) throws IOException,
NoSuchAlgorithmException, CertificateException {
- int namespace = KeyProperties.NAMESPACE_APPLICATION;
+ @KeyProperties.Namespace int namespace = KeyProperties.NAMESPACE_APPLICATION;
if (param != null) {
if (param instanceof AndroidKeyStoreLoadStoreParameter) {
namespace = ((AndroidKeyStoreLoadStoreParameter) param).getNamespace();
diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp
index 446e81e..c6ab119 100644
--- a/libs/hwui/Properties.cpp
+++ b/libs/hwui/Properties.cpp
@@ -124,7 +124,7 @@
SkAndroidFrameworkTraceUtil::setEnableTracing(
base::GetBoolProperty(PROPERTY_SKIA_ATRACE_ENABLED, false));
- runningInEmulator = base::GetBoolProperty(PROPERTY_QEMU_KERNEL, false);
+ runningInEmulator = base::GetBoolProperty(PROPERTY_IS_EMULATOR, false);
defaultRenderAhead = std::max(-1, std::min(2, base::GetIntProperty(PROPERTY_RENDERAHEAD,
render_ahead().value_or(0))));
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index d3ecb54d..6ea208e 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -160,7 +160,7 @@
/**
* Property for whether this is running in the emulator.
*/
-#define PROPERTY_QEMU_KERNEL "ro.kernel.qemu"
+#define PROPERTY_IS_EMULATOR "ro.boot.qemu"
#define PROPERTY_RENDERAHEAD "debug.hwui.render_ahead"
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 1b05c3b..b265ebf 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -2077,6 +2077,65 @@
}
/**
+ * Sets the streaming start threshold for an <code>AudioTrack</code>.
+ * <p> The streaming start threshold is the buffer level that the written audio
+ * data must reach for audio streaming to start after {@link #play()} is called.
+ * <p> For compressed streams, the size of a frame is considered to be exactly one byte.
+ *
+ * @param startThresholdInFrames the desired start threshold.
+ * @return the actual start threshold in frames value. This is
+ * an integer between 1 to the buffer capacity
+ * (see {@link #getBufferCapacityInFrames()}),
+ * and might change if the output sink changes after track creation.
+ * @throws IllegalStateException if the track is not initialized or the
+ * track transfer mode is not {@link #MODE_STREAM}.
+ * @throws IllegalArgumentException if startThresholdInFrames is not positive.
+ * @see #getStartThresholdInFrames()
+ */
+ public @IntRange(from = 1) int setStartThresholdInFrames(
+ @IntRange (from = 1) int startThresholdInFrames) {
+ if (mState != STATE_INITIALIZED) {
+ throw new IllegalStateException("AudioTrack is not initialized");
+ }
+ if (mDataLoadMode != MODE_STREAM) {
+ throw new IllegalStateException("AudioTrack must be a streaming track");
+ }
+ if (startThresholdInFrames < 1) {
+ throw new IllegalArgumentException("startThresholdInFrames "
+ + startThresholdInFrames + " must be positive");
+ }
+ return native_setStartThresholdInFrames(startThresholdInFrames);
+ }
+
+ /**
+ * Returns the streaming start threshold of the <code>AudioTrack</code>.
+ * <p> The streaming start threshold is the buffer level that the written audio
+ * data must reach for audio streaming to start after {@link #play()} is called.
+ * When an <code>AudioTrack</code> is created, the streaming start threshold
+ * is the buffer capacity in frames. If the buffer size in frames is reduced
+ * by {@link #setBufferSizeInFrames(int)} to a value smaller than the start threshold
+ * then that value will be used instead for the streaming start threshold.
+ * <p> For compressed streams, the size of a frame is considered to be exactly one byte.
+ *
+ * @return the current start threshold in frames value. This is
+ * an integer between 1 to the buffer capacity
+ * (see {@link #getBufferCapacityInFrames()}),
+ * and might change if the output sink changes after track creation.
+ * @throws IllegalStateException if the track is not initialized or the
+ * track is not {@link #MODE_STREAM}.
+ * @see #setStartThresholdInFrames(int)
+ */
+ public @IntRange (from = 1) int getStartThresholdInFrames() {
+ if (mState != STATE_INITIALIZED) {
+ throw new IllegalStateException("AudioTrack is not initialized");
+ }
+ if (mDataLoadMode != MODE_STREAM) {
+ throw new IllegalStateException("AudioTrack must be a streaming track");
+ }
+ return native_getStartThresholdInFrames();
+ }
+
+ /**
* Returns the frame count of the native <code>AudioTrack</code> buffer.
* @return current size in frames of the <code>AudioTrack</code> buffer.
* @throws IllegalStateException
@@ -4179,6 +4238,8 @@
private native int native_get_audio_description_mix_level_db(float[] level);
private native int native_set_dual_mono_mode(int dualMonoMode);
private native int native_get_dual_mono_mode(int[] dualMonoMode);
+ private native int native_setStartThresholdInFrames(int startThresholdInFrames);
+ private native int native_getStartThresholdInFrames();
//---------------------------------------------------------
// Utility methods
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 0780c68..7062f83 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -45,6 +45,7 @@
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
@@ -4554,6 +4555,128 @@
private native void native_enableOnFrameRenderedListener(boolean enable);
+ /**
+ * Returns a list of vendor parameter names.
+ * <p>
+ * This method can be called in any codec state except for released state.
+ *
+ * @return a list containing supported vendor parameters; an empty
+ * list if no vendor parameters are supported. The order of the
+ * parameters is arbitrary.
+ * @throws IllegalStateException if in the Released state.
+ */
+ @NonNull
+ public List<String> getSupportedVendorParameters() {
+ return native_getSupportedVendorParameters();
+ }
+
+ @NonNull
+ private native List<String> native_getSupportedVendorParameters();
+
+ /**
+ * Contains description of a parameter.
+ */
+ public static class ParameterDescriptor {
+ private ParameterDescriptor() {}
+
+ /**
+ * Returns the name of the parameter.
+ */
+ @NonNull
+ public String getName() {
+ return mName;
+ }
+
+ /**
+ * Returns the type of the parameter.
+ * {@link MediaFormat#TYPE_NULL} is never returned.
+ */
+ @MediaFormat.Type
+ public int getType() {
+ return mType;
+ }
+
+ private String mName;
+ private @MediaFormat.Type int mType;
+ }
+
+ /**
+ * Describe a parameter with the name.
+ * <p>
+ * This method can be called in any codec state except for released state.
+ *
+ * @param name name of the parameter to describe, typically one from
+ * {@link #getSupportedVendorParameters}.
+ * @return {@link ParameterDescriptor} object that describes the parameter.
+ * {@code null} if unrecognized / not able to describe.
+ * @throws IllegalStateException if in the Released state.
+ */
+ @Nullable
+ public ParameterDescriptor getParameterDescriptor(@NonNull String name) {
+ return native_getParameterDescriptor(name);
+ }
+
+ @Nullable
+ private native ParameterDescriptor native_getParameterDescriptor(@NonNull String name);
+
+ /**
+ * Subscribe to vendor parameters, so that changes to these parameters generate
+ * output format change event.
+ * <p>
+ * Unrecognized parameter names or standard (non-vendor) parameter names will be ignored.
+ * {@link #reset} also resets the list of subscribed parameters.
+ * If a parameter in {@code names} is already subscribed, it will remain subscribed.
+ * <p>
+ * This method can be called in any codec state except for released state. When called in
+ * running state with newly subscribed parameters, it takes effect no later than the
+ * processing of the subsequently queued buffer. For the new parameters, the codec will generate
+ * output format change event.
+ * <p>
+ * Note that any vendor parameters set in a {@link #configure} or
+ * {@link #setParameters} call are automatically subscribed.
+ * <p>
+ * See also {@link #INFO_OUTPUT_FORMAT_CHANGED} or {@link Callback#onOutputFormatChanged}
+ * for output format change events.
+ *
+ * @param names names of the vendor parameters to subscribe. This may be an empty list,
+ * and in that case this method will not change the list of subscribed parameters.
+ * @throws IllegalStateException if in the Released state.
+ */
+ public void subscribeToVendorParameters(@NonNull List<String> names) {
+ native_subscribeToVendorParameters(names);
+ }
+
+ private native void native_subscribeToVendorParameters(@NonNull List<String> names);
+
+ /**
+ * Unsubscribe from vendor parameters, so that changes to these parameters
+ * no longer generate output format change event.
+ * <p>
+ * Unrecognized parameter names, standard (non-vendor) parameter names will be ignored.
+ * {@link #reset} also resets the list of subscribed parameters.
+ * If a parameter in {@code names} is already unsubscribed, it will remain unsubscribed.
+ * <p>
+ * This method can be called in any codec state except for released state. When called in
+ * running state with newly unsubscribed parameters, it takes effect no later than the
+ * processing of the subsequently queued buffer.
+ * <p>
+ * Note that any vendor parameters set in a {@link #configure} or
+ * {@link #setParameters} call are automatically subscribed, and with this method
+ * they can be unsubscribed.
+ * <p>
+ * See also {@link #INFO_OUTPUT_FORMAT_CHANGED} or {@link Callback#onOutputFormatChanged}
+ * for output format change events.
+ *
+ * @param names names of the vendor parameters to unsubscribe. This may be an empty list,
+ * and in that case this method will not change the list of subscribed parameters.
+ * @throws IllegalStateException if in the Released state.
+ */
+ public void unsubscribeFromVendorParameters(@NonNull List<String> names) {
+ native_unsubscribeFromVendorParameters(names);
+ }
+
+ private native void native_unsubscribeFromVendorParameters(@NonNull List<String> names);
+
private EventHandler getEventHandlerOn(
@Nullable Handler handler, @NonNull EventHandler lastHandler) {
if (handler == null) {
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index f65dfdd..517e192 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -19,6 +19,7 @@
name: "libmedia_jni",
defaults: ["libcodec2-internal-defaults"],
+ min_sdk_version: "",
srcs: [
"android_media_ImageWriter.cpp",
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 0b0e162..b3eb8ba 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -53,6 +53,7 @@
#include <media/MediaCodecBuffer.h>
#include <media/hardware/VideoAPI.h>
+#include <media/stagefright/CodecBase.h>
#include <media/stagefright/MediaCodec.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
@@ -82,6 +83,16 @@
EVENT_FRAME_RENDERED = 3,
};
+// From MediaFormat.java
+enum {
+ TYPE_NULL = 0,
+ TYPE_INTEGER = 1,
+ TYPE_LONG = 2,
+ TYPE_FLOAT = 3,
+ TYPE_STRING = 4,
+ TYPE_BYTE_BUFFER = 5,
+};
+
static struct CryptoErrorCodes {
jint cryptoErrorNoKey;
jint cryptoErrorKeyExpired;
@@ -138,6 +149,8 @@
} gByteBufferInfo;
static struct {
+ jclass clazz;
+ jmethodID ctorId;
jmethodID sizeId;
jmethodID getId;
jmethodID addId;
@@ -152,6 +165,13 @@
jfieldID lockId;
} gLinearBlockInfo;
+static struct {
+ jclass clazz;
+ jmethodID ctorId;
+ jfieldID nameId;
+ jfieldID typeId;
+} gDescriptorInfo;
+
struct fields_t {
jmethodID postEventFromNativeID;
jmethodID lockAndGetContextID;
@@ -922,6 +942,74 @@
(void)mCodec->setParameters(msg);
}
+status_t JMediaCodec::querySupportedVendorParameters(JNIEnv *env, jobject *namesObj) {
+ std::vector<std::string> names;
+ status_t status = mCodec->querySupportedVendorParameters(&names);
+ if (status != OK) {
+ return status;
+ }
+ *namesObj = env->NewObject(gArrayListInfo.clazz, gArrayListInfo.ctorId);
+ for (const std::string &name : names) {
+ ScopedLocalRef<jstring> nameStr{env, env->NewStringUTF(name.c_str())};
+ (void)env->CallBooleanMethod(*namesObj, gArrayListInfo.addId, nameStr.get());
+ }
+ return OK;
+}
+
+status_t JMediaCodec::describeParameter(JNIEnv *env, jstring name, jobject *descObj) {
+ const char *tmp = env->GetStringUTFChars(name, nullptr);
+ CodecParameterDescriptor desc;
+ status_t status = mCodec->describeParameter(tmp, &desc);
+ env->ReleaseStringUTFChars(name, tmp);
+ if (status != OK) {
+ return status;
+ }
+ jint type = TYPE_NULL;
+ switch (desc.type) {
+ case AMessage::kTypeInt32: type = TYPE_INTEGER; break;
+ case AMessage::kTypeSize:
+ case AMessage::kTypeInt64: type = TYPE_LONG; break;
+ case AMessage::kTypeFloat: type = TYPE_FLOAT; break;
+ case AMessage::kTypeString: type = TYPE_STRING; break;
+ case AMessage::kTypeBuffer: type = TYPE_BYTE_BUFFER; break;
+ default: type = TYPE_NULL; break;
+ }
+ if (type == TYPE_NULL) {
+ return BAD_VALUE;
+ }
+ *descObj = env->NewObject(gDescriptorInfo.clazz, gDescriptorInfo.ctorId);
+ env->SetObjectField(*descObj, gDescriptorInfo.nameId, name);
+ env->SetIntField(*descObj, gDescriptorInfo.typeId, type);
+ return OK;
+}
+
+static void BuildVectorFromList(JNIEnv *env, jobject list, std::vector<std::string> *vec) {
+ ScopedLocalRef<jclass> listClazz{env, env->FindClass("java/util/List")};
+ ScopedLocalRef<jclass> iterClazz{env, env->FindClass("java/util/Iterator")};
+ jmethodID hasNextID = env->GetMethodID(iterClazz.get(), "hasNext", "()Z");
+ jmethodID nextID = env->GetMethodID(iterClazz.get(), "next", "()Ljava/lang/Object;");
+ jobject it = env->CallObjectMethod(
+ list, env->GetMethodID(listClazz.get(), "iterator", "()Ljava/util/Iterator;"));
+ while (env->CallBooleanMethod(it, hasNextID)) {
+ jstring name = (jstring)env->CallObjectMethod(it, nextID);
+ const char *tmp = env->GetStringUTFChars(name, nullptr);
+ vec->push_back(tmp);
+ env->ReleaseStringUTFChars(name, tmp);
+ }
+}
+
+status_t JMediaCodec::subscribeToVendorParameters(JNIEnv *env, jobject namesObj) {
+ std::vector<std::string> names;
+ BuildVectorFromList(env, namesObj, &names);
+ return mCodec->subscribeToVendorParameters(names);
+}
+
+status_t JMediaCodec::unsubscribeFromVendorParameters(JNIEnv *env, jobject namesObj) {
+ std::vector<std::string> names;
+ BuildVectorFromList(env, namesObj, &names);
+ return mCodec->unsubscribeFromVendorParameters(names);
+}
+
static jthrowable createCodecException(
JNIEnv *env, status_t err, int32_t actionCode, const char *msg = NULL) {
ScopedLocalRef<jclass> clazz(
@@ -2602,6 +2690,73 @@
codec->selectAudioPresentation((int32_t)presentationId, (int32_t)programId);
}
+static jobject android_media_MediaCodec_getSupportedVendorParameters(
+ JNIEnv *env, jobject thiz) {
+ sp<JMediaCodec> codec = getMediaCodec(env, thiz);
+
+ if (codec == NULL || codec->initCheck() != OK) {
+ throwExceptionAsNecessary(env, INVALID_OPERATION);
+ return NULL;
+ }
+
+ jobject ret = NULL;
+ status_t status = codec->querySupportedVendorParameters(env, &ret);
+ if (status != OK) {
+ throwExceptionAsNecessary(env, status);
+ }
+
+ return ret;
+}
+
+static jobject android_media_MediaCodec_getParameterDescriptor(
+ JNIEnv *env, jobject thiz, jstring name) {
+ sp<JMediaCodec> codec = getMediaCodec(env, thiz);
+
+ if (codec == NULL || codec->initCheck() != OK) {
+ throwExceptionAsNecessary(env, INVALID_OPERATION);
+ return NULL;
+ }
+
+ jobject ret = NULL;
+ status_t status = codec->describeParameter(env, name, &ret);
+ if (status != OK) {
+ ret = NULL;
+ }
+ return ret;
+}
+
+static void android_media_MediaCodec_subscribeToVendorParameters(
+ JNIEnv *env, jobject thiz, jobject names) {
+ sp<JMediaCodec> codec = getMediaCodec(env, thiz);
+
+ if (codec == NULL || codec->initCheck() != OK) {
+ throwExceptionAsNecessary(env, INVALID_OPERATION);
+ return;
+ }
+
+ status_t status = codec->subscribeToVendorParameters(env, names);
+ if (status != OK) {
+ throwExceptionAsNecessary(env, status);
+ }
+ return;
+}
+
+static void android_media_MediaCodec_unsubscribeFromVendorParameters(
+ JNIEnv *env, jobject thiz, jobject names) {
+ sp<JMediaCodec> codec = getMediaCodec(env, thiz);
+
+ if (codec == NULL || codec->initCheck() != OK) {
+ throwExceptionAsNecessary(env, INVALID_OPERATION);
+ return;
+ }
+
+ status_t status = codec->unsubscribeFromVendorParameters(env, names);
+ if (status != OK) {
+ throwExceptionAsNecessary(env, status);
+ }
+ return;
+}
+
static void android_media_MediaCodec_native_init(JNIEnv *env, jclass) {
ScopedLocalRef<jclass> clazz(
env, env->FindClass("android/media/MediaCodec"));
@@ -2861,6 +3016,10 @@
clazz.reset(env->FindClass("java/util/ArrayList"));
CHECK(clazz.get() != NULL);
+ gArrayListInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
+
+ gArrayListInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
+ CHECK(gArrayListInfo.ctorId != NULL);
gArrayListInfo.sizeId = env->GetMethodID(clazz.get(), "size", "()I");
CHECK(gArrayListInfo.sizeId != NULL);
@@ -2891,6 +3050,19 @@
gLinearBlockInfo.lockId = env->GetFieldID(clazz.get(), "mLock", "Ljava/lang/Object;");
CHECK(gLinearBlockInfo.lockId != NULL);
+
+ clazz.reset(env->FindClass("android/media/MediaCodec$ParameterDescriptor"));
+ CHECK(clazz.get() != NULL);
+ gDescriptorInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
+
+ gDescriptorInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
+ CHECK(gDescriptorInfo.ctorId != NULL);
+
+ gDescriptorInfo.nameId = env->GetFieldID(clazz.get(), "mName", "Ljava/lang/String;");
+ CHECK(gDescriptorInfo.nameId != NULL);
+
+ gDescriptorInfo.typeId = env->GetFieldID(clazz.get(), "mType", "I");
+ CHECK(gDescriptorInfo.typeId != NULL);
}
static void android_media_MediaCodec_native_setup(
@@ -3217,6 +3389,21 @@
{ "native_setAudioPresentation", "(II)V",
(void *)android_media_MediaCodec_setAudioPresentation },
+ { "native_getSupportedVendorParameters", "()Ljava/util/List;",
+ (void *)android_media_MediaCodec_getSupportedVendorParameters },
+
+ { "native_getParameterDescriptor",
+ "(Ljava/lang/String;)Landroid/media/MediaCodec$ParameterDescriptor;",
+ (void *)android_media_MediaCodec_getParameterDescriptor },
+
+ { "native_subscribeToVendorParameters",
+ "(Ljava/util/List;)V",
+ (void *)android_media_MediaCodec_subscribeToVendorParameters},
+
+ { "native_unsubscribeFromVendorParameters",
+ "(Ljava/util/List;)V",
+ (void *)android_media_MediaCodec_unsubscribeFromVendorParameters},
+
{ "native_init", "()V", (void *)android_media_MediaCodec_native_init },
{ "native_setup", "(Ljava/lang/String;ZZ)V",
diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h
index a58f9a7..33f481d 100644
--- a/media/jni/android_media_MediaCodec.h
+++ b/media/jni/android_media_MediaCodec.h
@@ -162,6 +162,14 @@
void selectAudioPresentation(const int32_t presentationId, const int32_t programId);
+ status_t querySupportedVendorParameters(JNIEnv *env, jobject *names);
+
+ status_t describeParameter(JNIEnv *env, jstring name, jobject *desc);
+
+ status_t subscribeToVendorParameters(JNIEnv *env, jobject names);
+
+ status_t unsubscribeFromVendorParameters(JNIEnv *env, jobject names);
+
bool hasCryptoOrDescrambler() { return mHasCryptoOrDescrambler; }
protected:
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index 694b939..3976086e 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -287,7 +287,10 @@
jint Dvr::close() {
Result r = mDvrSp->close();
if (r == Result::SUCCESS) {
- EventFlag::deleteEventFlag(&mDvrMQEventFlag);
+ if (mDvrMQEventFlag != nullptr) {
+ EventFlag::deleteEventFlag(&mDvrMQEventFlag);
+ }
+ mDvrMQ = nullptr;
}
return (jint) r;
}
@@ -723,13 +726,15 @@
env->DeleteWeakGlobalRef(mFilterObj);
mFilterObj = NULL;
- EventFlag::deleteEventFlag(&mFilterMQEventFlag);
}
int Filter::close() {
Result r = mFilterSp->close();
if (r == Result::SUCCESS) {
- EventFlag::deleteEventFlag(&mFilterMQEventFlag);
+ if (mFilterMQEventFlag != nullptr) {
+ EventFlag::deleteEventFlag(&mFilterMQEventFlag);
+ }
+ mFilterMQ = nullptr;
}
return (int)r;
}
@@ -3050,6 +3055,9 @@
filterSp->mFilterMQ = std::make_unique<MQ>(filterMQDesc, true);
EventFlag::createEventFlag(
filterSp->mFilterMQ->getEventFlagWord(), &(filterSp->mFilterMQEventFlag));
+ } else {
+ filterSp->mFilterMQ = nullptr;
+ filterSp->mFilterMQEventFlag = nullptr;
}
}
return (jint) getQueueDescResult;
@@ -3137,13 +3145,12 @@
}
static jint android_media_tv_Tuner_close_filter(JNIEnv *env, jobject filter) {
- sp<IFilter> iFilterSp = getFilter(env, filter)->getIFilter();
- if (iFilterSp == NULL) {
+ sp<Filter> filterSp = getFilter(env, filter);
+ if (filterSp == NULL) {
ALOGD("Failed to close filter: filter not found");
return (jint) Result::NOT_INITIALIZED;
}
- Result r = iFilterSp->close();
- return (jint) r;
+ return filterSp->close();
}
static sp<TimeFilter> getTimeFilter(JNIEnv *env, jobject filter) {
diff --git a/media/jni/soundpool/Sound.cpp b/media/jni/soundpool/Sound.cpp
index f8b4bdb..50e0d33 100644
--- a/media/jni/soundpool/Sound.cpp
+++ b/media/jni/soundpool/Sound.cpp
@@ -99,8 +99,8 @@
__func__);
break;
}
- int sampleSize = AMediaExtractor_readSampleData(ex.get(), buf, bufsize);
- ALOGV("%s: read %d", __func__, sampleSize);
+ ssize_t sampleSize = AMediaExtractor_readSampleData(ex.get(), buf, bufsize);
+ ALOGV("%s: read %zd", __func__, sampleSize);
if (sampleSize < 0) {
sampleSize = 0;
sawInputEOS = true;
@@ -124,8 +124,8 @@
}
AMediaCodecBufferInfo info;
- const int status = AMediaCodec_dequeueOutputBuffer(codec.get(), &info, 1);
- ALOGV("%s: dequeueoutput returned: %d", __func__, status);
+ const ssize_t status = AMediaCodec_dequeueOutputBuffer(codec.get(), &info, 1);
+ ALOGV("%s: dequeueoutput returned: %zd", __func__, status);
if (status >= 0) {
if (info.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) {
ALOGV("%s: output EOS", __func__);
@@ -167,10 +167,10 @@
} else if (status == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
ALOGV("%s: no output buffer right now", __func__);
} else if (status <= AMEDIA_ERROR_BASE) {
- ALOGE("%s: decode error: %d", __func__, status);
+ ALOGE("%s: decode error: %zd", __func__, status);
break;
} else {
- ALOGV("%s: unexpected info code: %d", __func__, status);
+ ALOGV("%s: unexpected info code: %zd", __func__, status);
}
}
diff --git a/media/jni/soundpool/Stream.cpp b/media/jni/soundpool/Stream.cpp
index 73e319a..f261bab 100644
--- a/media/jni/soundpool/Stream.cpp
+++ b/media/jni/soundpool/Stream.cpp
@@ -317,7 +317,8 @@
// audio track while the new one is being started and avoids processing them with
// wrong audio audio buffer size (mAudioBufferSize)
auto toggle = mToggle ^ 1;
- void* userData = (void*)((uintptr_t)this | toggle);
+ // NOLINTNEXTLINE(performance-no-int-to-ptr)
+ void* userData = reinterpret_cast<void*>((uintptr_t)this | toggle);
audio_channel_mask_t soundChannelMask = sound->getChannelMask();
// When sound contains a valid channel mask, use it as is.
// Otherwise, use stream count to calculate channel mask.
@@ -386,6 +387,7 @@
void Stream::staticCallback(int event, void* user, void* info)
{
const auto userAsInt = (uintptr_t)user;
+ // NOLINTNEXTLINE(performance-no-int-to-ptr)
auto stream = reinterpret_cast<Stream*>(userAsInt & ~1);
stream->callback(event, info, int(userAsInt & 1), 0 /* tries */);
}
diff --git a/media/jni/soundpool/StreamManager.cpp b/media/jni/soundpool/StreamManager.cpp
index 502ee00..309d71c 100644
--- a/media/jni/soundpool/StreamManager.cpp
+++ b/media/jni/soundpool/StreamManager.cpp
@@ -43,6 +43,14 @@
// Amount of time for a StreamManager thread to wait before closing.
static constexpr int64_t kWaitTimeBeforeCloseNs = 9 * NANOS_PER_SECOND;
+// Debug flag:
+// kForceLockStreamManagerStop is set to true to force lock the StreamManager
+// worker thread during stop. This limits concurrency of Stream processing.
+// Normally we lock the StreamManager worker thread during stop ONLY
+// for SoundPools configured with a single Stream.
+//
+static constexpr bool kForceLockStreamManagerStop = false;
+
////////////
StreamMap::StreamMap(int32_t streams) {
@@ -103,6 +111,7 @@
: StreamMap(streams)
, mAttributes(*attributes)
, mOpPackageName(std::move(opPackageName))
+ , mLockStreamManagerStop(streams == 1 || kForceLockStreamManagerStop)
{
ALOGV("%s(%d, %zu, ...)", __func__, streams, threads);
forEach([this](Stream *stream) {
@@ -113,7 +122,8 @@
});
mThreadPool = std::make_unique<ThreadPool>(
- std::min(threads, (size_t)std::thread::hardware_concurrency()),
+ std::min((size_t)streams, // do not make more threads than streams to play
+ std::min(threads, (size_t)std::thread::hardware_concurrency())),
"SoundPool_");
}
@@ -330,7 +340,7 @@
// streams on mProcessingStreams are undergoing processing by the StreamManager thread
// and do not participate in normal stream migration.
- return found;
+ return (ssize_t)found;
}
void StreamManager::addToRestartQueue_l(Stream *stream) {
@@ -348,14 +358,14 @@
void StreamManager::run(int32_t id)
{
ALOGV("%s(%d) entering", __func__, id);
- int64_t waitTimeNs = kWaitTimeBeforeCloseNs;
+ int64_t waitTimeNs = 0; // on thread start, mRestartStreams can be non-empty.
std::unique_lock lock(mStreamManagerLock);
while (!mQuit) {
- if (mRestartStreams.empty()) { // on thread start, mRestartStreams can be non-empty.
+ if (waitTimeNs > 0) {
mStreamManagerCondition.wait_for(
lock, std::chrono::duration<int64_t, std::nano>(waitTimeNs));
}
- ALOGV("%s(%d) awake", __func__, id);
+ ALOGV("%s(%d) awake lock waitTimeNs:%lld", __func__, id, (long long)waitTimeNs);
sanityCheckQueue_l();
@@ -375,12 +385,12 @@
}
mRestartStreams.erase(it);
mProcessingStreams.emplace(stream);
- lock.unlock();
+ if (!mLockStreamManagerStop) lock.unlock();
stream->stop();
ALOGV("%s(%d) stopping streamID:%d", __func__, id, stream->getStreamID());
if (Stream* nextStream = stream->playPairStream()) {
ALOGV("%s(%d) starting streamID:%d", __func__, id, nextStream->getStreamID());
- lock.lock();
+ if (!mLockStreamManagerStop) lock.lock();
if (nextStream->getStopTimeNs() > 0) {
// the next stream was stopped before we can move it to the active queue.
ALOGV("%s(%d) stopping started streamID:%d",
@@ -390,7 +400,7 @@
addToActiveQueue_l(nextStream);
}
} else {
- lock.lock();
+ if (!mLockStreamManagerStop) lock.lock();
mAvailableStreams.insert(stream);
}
mProcessingStreams.erase(stream);
diff --git a/media/jni/soundpool/StreamManager.h b/media/jni/soundpool/StreamManager.h
index 81ac69e..85b468c 100644
--- a/media/jni/soundpool/StreamManager.h
+++ b/media/jni/soundpool/StreamManager.h
@@ -437,6 +437,14 @@
void sanityCheckQueue_l() const REQUIRES(mStreamManagerLock);
const audio_attributes_t mAttributes;
+ const std::string mOpPackageName;
+
+ // For legacy compatibility, we lock the stream manager on stop when
+ // there is only one stream. This allows a play to be called immediately
+ // after stopping, otherwise it is possible that the play might be discarded
+ // (returns 0) because that stream may be in the worker thread call to stop.
+ const bool mLockStreamManagerStop;
+
std::unique_ptr<ThreadPool> mThreadPool; // locked internally
// mStreamManagerLock is used to lock access for transitions between the
@@ -477,8 +485,6 @@
// The paired stream may be active or restarting.
// No particular order.
std::unordered_set<Stream*> mProcessingStreams GUARDED_BY(mStreamManagerLock);
-
- const std::string mOpPackageName;
};
} // namespace android::soundpool
diff --git a/media/jni/soundpool/android_media_SoundPool.cpp b/media/jni/soundpool/android_media_SoundPool.cpp
index 357cc63..a66d99f 100644
--- a/media/jni/soundpool/android_media_SoundPool.cpp
+++ b/media/jni/soundpool/android_media_SoundPool.cpp
@@ -34,7 +34,8 @@
jclass mSoundPoolClass;
} fields;
static inline SoundPool* MusterSoundPool(JNIEnv *env, jobject thiz) {
- return (SoundPool*)env->GetLongField(thiz, fields.mNativeContext);
+ // NOLINTNEXTLINE(performance-no-int-to-ptr)
+ return reinterpret_cast<SoundPool*>(env->GetLongField(thiz, fields.mNativeContext));
}
static const char* const kAudioAttributesClassPathName = "android/media/AudioAttributes";
struct audio_attributes_fields_t {
diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java
index 6fab9e4..550e324 100644
--- a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java
+++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java
@@ -86,7 +86,7 @@
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- mCm = ConnectivityManager.from(this);
+ mCm = getSystemService(ConnectivityManager.class);
mUrl = getUrlForCaptivePortal();
if (mUrl == null) {
done(false);
@@ -161,7 +161,6 @@
if (network != null) {
network = network.getPrivateDnsBypassingCopy();
mCm.bindProcessToNetwork(network);
- mCm.setProcessDefaultNetworkForHostResolution(network);
}
mNetwork = network;
}
diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/ProvisionObserver.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/ProvisionObserver.java
index 78a02d7..43ca739 100644
--- a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/ProvisionObserver.java
+++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/ProvisionObserver.java
@@ -49,7 +49,7 @@
case PROVISION_OBSERVER_REEVALUATION_JOB_ID:
if (isProvisioned(this)) {
Log.d(TAG, "device provisioned, force network re-evaluation");
- final ConnectivityManager connMgr = ConnectivityManager.from(this);
+ final ConnectivityManager connMgr = getSystemService(ConnectivityManager.class);
Network[] info = connMgr.getAllNetworks();
for (Network nw : info) {
final NetworkCapabilities nc = connMgr.getNetworkCapabilities(nw);
diff --git a/packages/Connectivity/TEST_MAPPING b/packages/Connectivity/TEST_MAPPING
new file mode 100644
index 0000000..94f9232
--- /dev/null
+++ b/packages/Connectivity/TEST_MAPPING
@@ -0,0 +1,19 @@
+{
+ "imports": [
+ {
+ "path": "frameworks/base/core/java/android/net"
+ },
+ {
+ "path": "packages/modules/NetworkStack"
+ },
+ {
+ "path": "packages/modules/CaptivePortalLogin"
+ },
+ {
+ "path": "packages/modules/Connectivity"
+ },
+ {
+ "path": "packages/modules/Connectivity/Tethering"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/packages/Connectivity/framework/Android.bp b/packages/Connectivity/framework/Android.bp
index 9da27d2..017ff51 100644
--- a/packages/Connectivity/framework/Android.bp
+++ b/packages/Connectivity/framework/Android.bp
@@ -23,7 +23,25 @@
default_applicable_licenses: ["frameworks_base_license"],
}
-// TODO: use a java_library in the bootclasspath instead
+java_library {
+ name: "framework-connectivity-protos",
+ proto: {
+ type: "nano",
+ },
+ srcs: [
+ // TODO: consider moving relevant .proto files directly to the module directory
+ ":framework-javastream-protos",
+ ],
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.tethering",
+ ],
+ jarjar_rules: "jarjar-rules-proto.txt",
+ visibility: [
+ "//visibility:private",
+ ],
+}
+
filegroup {
name: "framework-connectivity-internal-sources",
srcs: [
@@ -84,3 +102,39 @@
],
permitted_packages: ["android.net", "com.android.connectivity.aidl"],
}
+
+java_library {
+ name: "framework-connectivity.impl",
+ // Instead of building against private API (framework.jar),
+ // build against core_platform + framework-minus-apex + module
+ // stub libs. This allows framework.jar to depend on this library,
+ // so it can be part of the private API until all clients have been migrated.
+ // TODO: just build against module_api, and remove this jar from
+ // the private API.
+ sdk_version: "core_platform",
+ srcs: [
+ ":framework-connectivity-sources",
+ ],
+ aidl: {
+ include_dirs: [
+ "frameworks/base/core/java", // For framework parcelables
+ "frameworks/native/aidl/binder", // For PersistableBundle.aidl
+ ],
+ },
+ libs: [
+ "framework-minus-apex",
+ // TODO: just framework-tethering, framework-wifi when building against module_api
+ "framework-tethering.stubs.module_lib",
+ "framework-wifi.stubs.module_lib",
+ "unsupportedappusage",
+ "ServiceConnectivityResources",
+ ],
+ static_libs: [
+ "framework-connectivity-protos",
+ "net-utils-device-common",
+ ],
+ jarjar_rules: "jarjar-rules.txt",
+ apex_available: ["com.android.tethering"],
+ installable: true,
+ permitted_packages: ["android.net", "com.android.connectivity.aidl"],
+}
diff --git a/packages/Connectivity/framework/src/android/net/IOnSetOemNetworkPreferenceListener.aidl b/packages/Connectivity/framework/aidl-export/android/net/NetworkScore.aidl
similarity index 79%
copy from packages/Connectivity/framework/src/android/net/IOnSetOemNetworkPreferenceListener.aidl
copy to packages/Connectivity/framework/aidl-export/android/net/NetworkScore.aidl
index 7979afc..af12dcf 100644
--- a/packages/Connectivity/framework/src/android/net/IOnSetOemNetworkPreferenceListener.aidl
+++ b/packages/Connectivity/framework/aidl-export/android/net/NetworkScore.aidl
@@ -1,6 +1,5 @@
/**
- *
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (c) 2021, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,7 +16,5 @@
package android.net;
-/** @hide */
-oneway interface IOnSetOemNetworkPreferenceListener {
- void onComplete();
-}
+parcelable NetworkScore;
+
diff --git a/packages/Connectivity/framework/api/current.txt b/packages/Connectivity/framework/api/current.txt
index a8f1a4d..ad44b27 100644
--- a/packages/Connectivity/framework/api/current.txt
+++ b/packages/Connectivity/framework/api/current.txt
@@ -87,6 +87,7 @@
method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public boolean isActiveNetworkMetered();
method public boolean isDefaultNetworkActive();
method @Deprecated public static boolean isNetworkTypeValid(int);
+ method public void registerBestMatchingNetworkCallback(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerDefaultNetworkCallback(@NonNull android.net.ConnectivityManager.NetworkCallback);
method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerDefaultNetworkCallback(@NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerNetworkCallback(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback);
@@ -143,6 +144,7 @@
public static class ConnectivityManager.NetworkCallback {
ctor public ConnectivityManager.NetworkCallback();
+ ctor public ConnectivityManager.NetworkCallback(int);
method public void onAvailable(@NonNull android.net.Network);
method public void onBlockedStatusChanged(@NonNull android.net.Network, boolean);
method public void onCapabilitiesChanged(@NonNull android.net.Network, @NonNull android.net.NetworkCapabilities);
@@ -150,6 +152,7 @@
method public void onLosing(@NonNull android.net.Network, int);
method public void onLost(@NonNull android.net.Network);
method public void onUnavailable();
+ field public static final int FLAG_INCLUDE_LOCATION_INFO = 1; // 0x1
}
public static interface ConnectivityManager.OnNetworkActiveListener {
@@ -288,11 +291,13 @@
ctor public NetworkCapabilities();
ctor public NetworkCapabilities(android.net.NetworkCapabilities);
method public int describeContents();
+ method @NonNull public int[] getCapabilities();
method public int getLinkDownstreamBandwidthKbps();
method public int getLinkUpstreamBandwidthKbps();
method @Nullable public android.net.NetworkSpecifier getNetworkSpecifier();
method public int getOwnerUid();
method public int getSignalStrength();
+ method @NonNull public java.util.Set<java.lang.Integer> getSubIds();
method @Nullable public android.net.TransportInfo getTransportInfo();
method public boolean hasCapability(int);
method public boolean hasTransport(int);
@@ -391,6 +396,7 @@
public static class NetworkRequest.Builder {
ctor public NetworkRequest.Builder();
+ ctor public NetworkRequest.Builder(@NonNull android.net.NetworkRequest);
method public android.net.NetworkRequest.Builder addCapability(int);
method public android.net.NetworkRequest.Builder addTransportType(int);
method public android.net.NetworkRequest build();
@@ -399,6 +405,11 @@
method public android.net.NetworkRequest.Builder removeTransportType(int);
method @Deprecated public android.net.NetworkRequest.Builder setNetworkSpecifier(String);
method public android.net.NetworkRequest.Builder setNetworkSpecifier(android.net.NetworkSpecifier);
+ method @NonNull public android.net.NetworkRequest.Builder setSubIds(@NonNull java.util.Set<java.lang.Integer>);
+ }
+
+ public class ParseException extends java.lang.RuntimeException {
+ field public String response;
}
public class ProxyInfo implements android.os.Parcelable {
diff --git a/packages/Connectivity/framework/api/module-lib-current.txt b/packages/Connectivity/framework/api/module-lib-current.txt
index d2ed73e..35e45ec 100644
--- a/packages/Connectivity/framework/api/module-lib-current.txt
+++ b/packages/Connectivity/framework/api/module-lib-current.txt
@@ -6,24 +6,134 @@
}
public class ConnectivityManager {
+ method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void factoryReset();
method @NonNull @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public java.util.List<android.net.NetworkStateSnapshot> getAllNetworkStateSnapshot();
+ method @Nullable public android.net.ProxyInfo getGlobalProxy();
+ method @NonNull public static android.util.Range<java.lang.Integer> getIpSecNetIdRange();
+ method @NonNull public static String getPrivateDnsMode(@NonNull android.content.Context);
+ method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void registerDefaultNetworkCallbackAsUid(int, @NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void registerSystemDefaultNetworkCallback(@NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
- method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void requestBackgroundNetwork(@NonNull android.net.NetworkRequest, @Nullable android.os.Handler, @NonNull android.net.ConnectivityManager.NetworkCallback);
+ method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void requestBackgroundNetwork(@NonNull android.net.NetworkRequest, @NonNull android.os.Handler, @NonNull android.net.ConnectivityManager.NetworkCallback);
+ method @Deprecated public boolean requestRouteToHostAddress(int, java.net.InetAddress);
+ method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void setAcceptPartialConnectivity(@NonNull android.net.Network, boolean, boolean);
+ method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void setAcceptUnvalidated(@NonNull android.net.Network, boolean, boolean);
+ method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void setAvoidUnvalidated(@NonNull android.net.Network);
+ method @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void setGlobalProxy(@Nullable android.net.ProxyInfo);
+ method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void setLegacyLockdownVpnEnabled(boolean);
+ method public static void setPrivateDnsMode(@NonNull android.content.Context, @NonNull String);
+ method @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void setProfileNetworkPreference(@NonNull android.os.UserHandle, int, @Nullable java.util.concurrent.Executor, @Nullable Runnable);
+ method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void setRequireVpnForUids(boolean, @NonNull java.util.Collection<android.util.Range<java.lang.Integer>>);
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_TEST_NETWORKS, android.Manifest.permission.NETWORK_STACK}) public void simulateDataStall(int, long, @NonNull android.net.Network, @NonNull android.os.PersistableBundle);
+ method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void startCaptivePortalApp(@NonNull android.net.Network);
+ method public void systemReady();
+ field public static final int BLOCKED_METERED_REASON_ADMIN_DISABLED = 262144; // 0x40000
+ field public static final int BLOCKED_METERED_REASON_DATA_SAVER = 65536; // 0x10000
+ field public static final int BLOCKED_METERED_REASON_MASK = -65536; // 0xffff0000
+ field public static final int BLOCKED_METERED_REASON_USER_RESTRICTED = 131072; // 0x20000
+ field public static final int BLOCKED_REASON_APP_STANDBY = 4; // 0x4
+ field public static final int BLOCKED_REASON_BATTERY_SAVER = 1; // 0x1
+ field public static final int BLOCKED_REASON_DOZE = 2; // 0x2
+ field public static final int BLOCKED_REASON_LOCKDOWN_VPN = 16; // 0x10
+ field public static final int BLOCKED_REASON_NONE = 0; // 0x0
+ field public static final int BLOCKED_REASON_RESTRICTED_MODE = 8; // 0x8
+ field public static final String PRIVATE_DNS_MODE_OFF = "off";
+ field public static final String PRIVATE_DNS_MODE_OPPORTUNISTIC = "opportunistic";
+ field public static final String PRIVATE_DNS_MODE_PROVIDER_HOSTNAME = "hostname";
+ field public static final int PROFILE_NETWORK_PREFERENCE_DEFAULT = 0; // 0x0
+ field public static final int PROFILE_NETWORK_PREFERENCE_ENTERPRISE = 1; // 0x1
+ }
+
+ public static class ConnectivityManager.NetworkCallback {
+ method public void onBlockedStatusChanged(@NonNull android.net.Network, int);
+ }
+
+ public class ConnectivitySettingsManager {
+ method public static void clearGlobalProxy(@NonNull android.content.Context);
+ method @Nullable public static String getCaptivePortalHttpUrl(@NonNull android.content.Context);
+ method public static int getCaptivePortalMode(@NonNull android.content.Context, int);
+ method @NonNull public static java.time.Duration getConnectivityKeepPendingIntentDuration(@NonNull android.content.Context, @NonNull java.time.Duration);
+ method @NonNull public static android.util.Range<java.lang.Integer> getDnsResolverSampleRanges(@NonNull android.content.Context);
+ method @NonNull public static java.time.Duration getDnsResolverSampleValidityDuration(@NonNull android.content.Context, @NonNull java.time.Duration);
+ method public static int getDnsResolverSuccessThresholdPercent(@NonNull android.content.Context, int);
+ method @Nullable public static android.net.ProxyInfo getGlobalProxy(@NonNull android.content.Context);
+ method @NonNull public static java.time.Duration getMobileDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration);
+ method public static boolean getMobileDataAlwaysOn(@NonNull android.content.Context, boolean);
+ method @Nullable public static String getMobileDataPreferredApps(@NonNull android.content.Context);
+ method public static int getNetworkAvoidBadWifi(@NonNull android.content.Context);
+ method @Nullable public static String getNetworkMeteredMultipathPreference(@NonNull android.content.Context);
+ method public static int getNetworkSwitchNotificationMaximumDailyCount(@NonNull android.content.Context, int);
+ method @NonNull public static java.time.Duration getNetworkSwitchNotificationRateDuration(@NonNull android.content.Context, @NonNull java.time.Duration);
+ method @NonNull public static String getPrivateDnsDefaultMode(@NonNull android.content.Context);
+ method @Nullable public static String getPrivateDnsHostname(@NonNull android.content.Context);
+ method public static boolean getWifiAlwaysRequested(@NonNull android.content.Context, boolean);
+ method @NonNull public static java.time.Duration getWifiDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration);
+ method public static void setCaptivePortalHttpUrl(@NonNull android.content.Context, @Nullable String);
+ method public static void setCaptivePortalMode(@NonNull android.content.Context, int);
+ method public static void setConnectivityKeepPendingIntentDuration(@NonNull android.content.Context, @NonNull java.time.Duration);
+ method public static void setDnsResolverSampleRanges(@NonNull android.content.Context, @NonNull android.util.Range<java.lang.Integer>);
+ method public static void setDnsResolverSampleValidityDuration(@NonNull android.content.Context, @NonNull java.time.Duration);
+ method public static void setDnsResolverSuccessThresholdPercent(@NonNull android.content.Context, @IntRange(from=0, to=100) int);
+ method public static void setGlobalProxy(@NonNull android.content.Context, @NonNull android.net.ProxyInfo);
+ method public static void setMobileDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration);
+ method public static void setMobileDataAlwaysOn(@NonNull android.content.Context, boolean);
+ method public static void setMobileDataPreferredApps(@NonNull android.content.Context, @Nullable String);
+ method public static void setNetworkAvoidBadWifi(@NonNull android.content.Context, int);
+ method public static void setNetworkMeteredMultipathPreference(@NonNull android.content.Context, @NonNull String);
+ method public static void setNetworkSwitchNotificationMaximumDailyCount(@NonNull android.content.Context, @IntRange(from=0) int);
+ method public static void setNetworkSwitchNotificationRateDuration(@NonNull android.content.Context, @NonNull java.time.Duration);
+ method public static void setPrivateDnsDefaultMode(@NonNull android.content.Context, @NonNull String);
+ method public static void setPrivateDnsHostname(@NonNull android.content.Context, @Nullable String);
+ method public static void setWifiAlwaysRequested(@NonNull android.content.Context, boolean);
+ method public static void setWifiDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration);
+ field public static final int CAPTIVE_PORTAL_MODE_AVOID = 2; // 0x2
+ field public static final int CAPTIVE_PORTAL_MODE_IGNORE = 0; // 0x0
+ field public static final int CAPTIVE_PORTAL_MODE_PROMPT = 1; // 0x1
+ field public static final int NETWORK_AVOID_BAD_WIFI_AVOID = 2; // 0x2
+ field public static final int NETWORK_AVOID_BAD_WIFI_IGNORE = 0; // 0x0
+ field public static final int NETWORK_AVOID_BAD_WIFI_PROMPT = 1; // 0x1
}
public final class NetworkAgentConfig implements android.os.Parcelable {
method @Nullable public String getSubscriberId();
+ method public boolean isBypassableVpn();
}
public static final class NetworkAgentConfig.Builder {
+ method @NonNull public android.net.NetworkAgentConfig.Builder setBypassableVpn(boolean);
method @NonNull public android.net.NetworkAgentConfig.Builder setSubscriberId(@Nullable String);
}
public final class NetworkCapabilities implements android.os.Parcelable {
+ ctor public NetworkCapabilities(@Nullable android.net.NetworkCapabilities, long);
+ method @Nullable public java.util.Set<android.util.Range<java.lang.Integer>> getUids();
+ method public boolean hasUnwantedCapability(int);
+ field public static final long REDACT_ALL = -1L; // 0xffffffffffffffffL
+ field public static final long REDACT_FOR_ACCESS_FINE_LOCATION = 1L; // 0x1L
+ field public static final long REDACT_FOR_LOCAL_MAC_ADDRESS = 2L; // 0x2L
+ field public static final long REDACT_FOR_NETWORK_SETTINGS = 4L; // 0x4L
+ field public static final long REDACT_NONE = 0L; // 0x0L
field public static final int TRANSPORT_TEST = 7; // 0x7
}
+ public static final class NetworkCapabilities.Builder {
+ method @NonNull public android.net.NetworkCapabilities.Builder setUids(@Nullable java.util.Set<android.util.Range<java.lang.Integer>>);
+ }
+
+ public class NetworkRequest implements android.os.Parcelable {
+ method public boolean hasUnwantedCapability(int);
+ }
+
+ public static class NetworkRequest.Builder {
+ method @NonNull public android.net.NetworkRequest.Builder addUnwantedCapability(int);
+ method @NonNull public android.net.NetworkRequest.Builder removeUnwantedCapability(int);
+ method @NonNull public android.net.NetworkRequest.Builder setUids(@Nullable java.util.Set<android.util.Range<java.lang.Integer>>);
+ }
+
+ public class ParseException extends java.lang.RuntimeException {
+ ctor public ParseException(@NonNull String);
+ ctor public ParseException(@NonNull String, @NonNull Throwable);
+ }
+
public final class TcpRepairWindow {
ctor public TcpRepairWindow(int, int, int, int, int, int);
field public final int maxWindow;
@@ -51,6 +161,19 @@
field public static final String TEST_TAP_PREFIX = "testtap";
}
+ public final class TestNetworkSpecifier extends android.net.NetworkSpecifier implements android.os.Parcelable {
+ ctor public TestNetworkSpecifier(@NonNull String);
+ method public int describeContents();
+ method @Nullable public String getInterfaceName();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.TestNetworkSpecifier> CREATOR;
+ }
+
+ public interface TransportInfo {
+ method public default long getApplicableRedactions();
+ method @NonNull public default android.net.TransportInfo makeCopy(long);
+ }
+
public final class VpnTransportInfo implements android.os.Parcelable android.net.TransportInfo {
ctor public VpnTransportInfo(int);
method public int describeContents();
diff --git a/packages/Connectivity/framework/api/system-current.txt b/packages/Connectivity/framework/api/system-current.txt
index a732430..6f832c6 100644
--- a/packages/Connectivity/framework/api/system-current.txt
+++ b/packages/Connectivity/framework/api/system-current.txt
@@ -18,7 +18,7 @@
method public long getRefreshTimeMillis();
method @Nullable public android.net.Uri getUserPortalUrl();
method public int getUserPortalUrlSource();
- method @Nullable public String getVenueFriendlyName();
+ method @Nullable public CharSequence getVenueFriendlyName();
method @Nullable public android.net.Uri getVenueInfoUrl();
method public int getVenueInfoUrlSource();
method public boolean isCaptive();
@@ -40,7 +40,7 @@
method @NonNull public android.net.CaptivePortalData.Builder setSessionExtendable(boolean);
method @NonNull public android.net.CaptivePortalData.Builder setUserPortalUrl(@Nullable android.net.Uri);
method @NonNull public android.net.CaptivePortalData.Builder setUserPortalUrl(@Nullable android.net.Uri, int);
- method @NonNull public android.net.CaptivePortalData.Builder setVenueFriendlyName(@Nullable String);
+ method @NonNull public android.net.CaptivePortalData.Builder setVenueFriendlyName(@Nullable CharSequence);
method @NonNull public android.net.CaptivePortalData.Builder setVenueInfoUrl(@Nullable android.net.Uri);
method @NonNull public android.net.CaptivePortalData.Builder setVenueInfoUrl(@Nullable android.net.Uri, int);
}
@@ -52,11 +52,11 @@
method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void getLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEntitlementResultListener);
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public boolean isTetheringSupported();
method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_FACTORY}) public int registerNetworkProvider(@NonNull android.net.NetworkProvider);
- method public void registerQosCallback(@NonNull android.net.QosSocketInfo, @NonNull android.net.QosCallback, @NonNull java.util.concurrent.Executor);
+ method public void registerQosCallback(@NonNull android.net.QosSocketInfo, @NonNull java.util.concurrent.Executor, @NonNull android.net.QosCallback);
method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEventCallback);
method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public void requestNetwork(@NonNull android.net.NetworkRequest, int, int, @NonNull android.os.Handler, @NonNull android.net.ConnectivityManager.NetworkCallback);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_AIRPLANE_MODE, android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void setAirplaneMode(boolean);
- method @RequiresPermission(android.Manifest.permission.CONTROL_OEM_PAID_NETWORK_PREFERENCE) public void setOemNetworkPreference(@NonNull android.net.OemNetworkPreferences, @Nullable java.util.concurrent.Executor, @Nullable android.net.ConnectivityManager.OnSetOemNetworkPreferenceListener);
+ method @RequiresPermission(android.Manifest.permission.CONTROL_OEM_PAID_NETWORK_PREFERENCE) public void setOemNetworkPreference(@NonNull android.net.OemNetworkPreferences, @Nullable java.util.concurrent.Executor, @Nullable Runnable);
method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public boolean shouldAvoidBadWifi();
method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public void startCaptivePortalApp(@NonNull android.net.Network, @NonNull android.os.Bundle);
method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback);
@@ -78,10 +78,6 @@
field @Deprecated public static final int TYPE_WIFI_P2P = 13; // 0xd
}
- public static interface ConnectivityManager.OnSetOemNetworkPreferenceListener {
- method public void onComplete();
- }
-
@Deprecated public abstract static class ConnectivityManager.OnStartTetheringCallback {
ctor @Deprecated public ConnectivityManager.OnStartTetheringCallback();
method @Deprecated public void onTetheringFailed();
@@ -216,10 +212,13 @@
public abstract class NetworkAgent {
ctor public NetworkAgent(@NonNull android.content.Context, @NonNull android.os.Looper, @NonNull String, @NonNull android.net.NetworkCapabilities, @NonNull android.net.LinkProperties, int, @NonNull android.net.NetworkAgentConfig, @Nullable android.net.NetworkProvider);
+ ctor public NetworkAgent(@NonNull android.content.Context, @NonNull android.os.Looper, @NonNull String, @NonNull android.net.NetworkCapabilities, @NonNull android.net.LinkProperties, @NonNull android.net.NetworkScore, @NonNull android.net.NetworkAgentConfig, @Nullable android.net.NetworkProvider);
method @Nullable public android.net.Network getNetwork();
method public void markConnected();
method public void onAddKeepalivePacketFilter(int, @NonNull android.net.KeepalivePacketData);
method public void onAutomaticReconnectDisabled();
+ method public void onNetworkCreated();
+ method public void onNetworkDisconnected();
method public void onNetworkUnwanted();
method public void onQosCallbackRegistered(int, @NonNull android.net.QosFilter);
method public void onQosCallbackUnregistered(int);
@@ -234,8 +233,8 @@
method public final void sendNetworkCapabilities(@NonNull android.net.NetworkCapabilities);
method public final void sendNetworkScore(@IntRange(from=0, to=99) int);
method public final void sendQosCallbackError(int, int);
- method public final void sendQosSessionAvailable(int, int, @NonNull android.telephony.data.EpsBearerQosSessionAttributes);
- method public final void sendQosSessionLost(int, int);
+ method public final void sendQosSessionAvailable(int, int, @NonNull android.net.QosSessionAttributes);
+ method public final void sendQosSessionLost(int, int, int);
method public final void sendSocketKeepaliveEvent(int, int);
method public final void setUnderlyingNetworks(@Nullable java.util.List<android.net.Network>);
method public void unregister();
@@ -265,7 +264,6 @@
}
public final class NetworkCapabilities implements android.os.Parcelable {
- ctor public NetworkCapabilities(@Nullable android.net.NetworkCapabilities, boolean);
method @NonNull public int[] getAdministratorUids();
method @Nullable public String getSsid();
method @NonNull public int[] getTransportTypes();
@@ -296,6 +294,7 @@
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 setSubIds(@NonNull java.util.Set<java.lang.Integer>);
method @NonNull public android.net.NetworkCapabilities.Builder setTransportInfo(@Nullable android.net.TransportInfo);
}
@@ -320,6 +319,19 @@
method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP) public android.net.NetworkRequest.Builder setSignalStrength(int);
}
+ public final class NetworkScore implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getLegacyInt();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkScore> CREATOR;
+ }
+
+ public static final class NetworkScore.Builder {
+ ctor public NetworkScore.Builder();
+ method @NonNull public android.net.NetworkScore build();
+ method @NonNull public android.net.NetworkScore.Builder setLegacyInt(int);
+ }
+
public final class OemNetworkPreferences implements android.os.Parcelable {
method public int describeContents();
method @NonNull public java.util.Map<java.lang.String,java.lang.Integer> getNetworkPreferences();
@@ -367,6 +379,7 @@
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.net.QosSession> CREATOR;
field public static final int TYPE_EPS_BEARER = 1; // 0x1
+ field public static final int TYPE_NR_BEARER = 2; // 0x2
}
public interface QosSessionAttributes {
@@ -438,11 +451,6 @@
field public final int tcpWindowScale;
}
- public interface TransportInfo {
- method public default boolean hasLocationSensitiveFields();
- method @NonNull public default android.net.TransportInfo makeCopy(boolean);
- }
-
}
package android.net.apf {
diff --git a/packages/Connectivity/framework/jarjar-rules-proto.txt b/packages/Connectivity/framework/jarjar-rules-proto.txt
new file mode 100644
index 0000000..37b4dec1
--- /dev/null
+++ b/packages/Connectivity/framework/jarjar-rules-proto.txt
@@ -0,0 +1,3 @@
+keep android.net.NetworkCapabilitiesProto
+keep android.net.NetworkProto
+keep android.net.NetworkRequestProto
diff --git a/packages/Connectivity/framework/jarjar-rules.txt b/packages/Connectivity/framework/jarjar-rules.txt
new file mode 100644
index 0000000..0959840
--- /dev/null
+++ b/packages/Connectivity/framework/jarjar-rules.txt
@@ -0,0 +1,10 @@
+rule com.android.net.module.util.** android.net.connectivity.framework.util.@1
+
+# TODO (b/149403767): remove the annotations from net-utils-device-common instead of here
+zap android.annotation.**
+zap com.android.net.module.annotation.**
+zap com.android.internal.annotations.**
+
+rule android.net.NetworkCapabilitiesProto* android.net.connectivity.proto.NetworkCapabilitiesProto@1
+rule android.net.NetworkProto* android.net.connectivity.proto.NetworkProto@1
+rule android.net.NetworkRequestProto* android.net.connectivity.proto.NetworkRequestProto@1
diff --git a/packages/Connectivity/framework/src/android/net/CaptivePortalData.java b/packages/Connectivity/framework/src/android/net/CaptivePortalData.java
index eafda4d..82dbd0f 100644
--- a/packages/Connectivity/framework/src/android/net/CaptivePortalData.java
+++ b/packages/Connectivity/framework/src/android/net/CaptivePortalData.java
@@ -42,7 +42,7 @@
private final long mByteLimit;
private final long mExpiryTimeMillis;
private final boolean mCaptive;
- private final String mVenueFriendlyName;
+ private final CharSequence mVenueFriendlyName;
private final int mVenueInfoUrlSource;
private final int mUserPortalUrlSource;
@@ -65,7 +65,7 @@
private CaptivePortalData(long refreshTimeMillis, Uri userPortalUrl, Uri venueInfoUrl,
boolean isSessionExtendable, long byteLimit, long expiryTimeMillis, boolean captive,
- String venueFriendlyName, int venueInfoUrlSource, int userPortalUrlSource) {
+ CharSequence venueFriendlyName, int venueInfoUrlSource, int userPortalUrlSource) {
mRefreshTimeMillis = refreshTimeMillis;
mUserPortalUrl = userPortalUrl;
mVenueInfoUrl = venueInfoUrl;
@@ -80,7 +80,7 @@
private CaptivePortalData(Parcel p) {
this(p.readLong(), p.readParcelable(null), p.readParcelable(null), p.readBoolean(),
- p.readLong(), p.readLong(), p.readBoolean(), p.readString(), p.readInt(),
+ p.readLong(), p.readLong(), p.readBoolean(), p.readCharSequence(), p.readInt(),
p.readInt());
}
@@ -98,7 +98,7 @@
dest.writeLong(mByteLimit);
dest.writeLong(mExpiryTimeMillis);
dest.writeBoolean(mCaptive);
- dest.writeString(mVenueFriendlyName);
+ dest.writeCharSequence(mVenueFriendlyName);
dest.writeInt(mVenueInfoUrlSource);
dest.writeInt(mUserPortalUrlSource);
}
@@ -114,7 +114,7 @@
private long mBytesRemaining = -1;
private long mExpiryTime = -1;
private boolean mCaptive;
- private String mVenueFriendlyName;
+ private CharSequence mVenueFriendlyName;
private @CaptivePortalDataSource int mVenueInfoUrlSource = CAPTIVE_PORTAL_DATA_SOURCE_OTHER;
private @CaptivePortalDataSource int mUserPortalUrlSource =
CAPTIVE_PORTAL_DATA_SOURCE_OTHER;
@@ -228,7 +228,7 @@
* Set the venue friendly name.
*/
@NonNull
- public Builder setVenueFriendlyName(@Nullable String venueFriendlyName) {
+ public Builder setVenueFriendlyName(@Nullable CharSequence venueFriendlyName) {
mVenueFriendlyName = venueFriendlyName;
return this;
}
@@ -321,7 +321,7 @@
* Get the venue friendly name
*/
@Nullable
- public String getVenueFriendlyName() {
+ public CharSequence getVenueFriendlyName() {
return mVenueFriendlyName;
}
diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityDiagnosticsManager.java b/packages/Connectivity/framework/src/android/net/ConnectivityDiagnosticsManager.java
index 5234494..3598ebc 100644
--- a/packages/Connectivity/framework/src/android/net/ConnectivityDiagnosticsManager.java
+++ b/packages/Connectivity/framework/src/android/net/ConnectivityDiagnosticsManager.java
@@ -28,7 +28,6 @@
import android.os.RemoteException;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.Preconditions;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -70,8 +69,8 @@
/** @hide */
public ConnectivityDiagnosticsManager(Context context, IConnectivityManager service) {
- mContext = Preconditions.checkNotNull(context, "missing context");
- mService = Preconditions.checkNotNull(service, "missing IConnectivityManager");
+ mContext = Objects.requireNonNull(context, "missing context");
+ mService = Objects.requireNonNull(service, "missing IConnectivityManager");
}
/** @hide */
diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
index 45ed317..d196c1a 100644
--- a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
+++ b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
@@ -16,9 +16,11 @@
package android.net;
import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
-import static android.net.IpSecManager.INVALID_RESOURCE_ID;
+import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_DEFAULT_MODE;
+import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE;
import static android.net.NetworkRequest.Type.BACKGROUND_REQUEST;
import static android.net.NetworkRequest.Type.LISTEN;
+import static android.net.NetworkRequest.Type.LISTEN_FOR_BEST;
import static android.net.NetworkRequest.Type.REQUEST;
import static android.net.NetworkRequest.Type.TRACK_DEFAULT;
import static android.net.NetworkRequest.Type.TRACK_SYSTEM_DEFAULT;
@@ -31,11 +33,15 @@
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.StringDef;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.app.PendingIntent;
+import android.app.admin.DevicePolicyManager;
import android.compat.annotation.UnsupportedAppUsage;
+import android.content.ComponentName;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.net.IpSecManager.UdpEncapsulationSocket;
@@ -43,6 +49,7 @@
import android.net.TetheringManager.StartTetheringCallback;
import android.net.TetheringManager.TetheringEventCallback;
import android.net.TetheringManager.TetheringRequest;
+import android.net.wifi.WifiNetworkSuggestion;
import android.os.Binder;
import android.os.Build;
import android.os.Build.VERSION_CODES;
@@ -57,20 +64,18 @@
import android.os.Process;
import android.os.RemoteException;
import android.os.ResultReceiver;
-import android.os.ServiceManager;
import android.os.ServiceSpecificException;
+import android.os.UserHandle;
import android.provider.Settings;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
+import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Range;
import android.util.SparseIntArray;
-import com.android.connectivity.aidl.INetworkAgent;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.Preconditions;
-import com.android.internal.util.Protocol;
import libcore.net.event.NetworkEventDispatcher;
@@ -801,24 +806,134 @@
/**
* @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
public static final String PRIVATE_DNS_MODE_OFF = "off";
/**
* @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
public static final String PRIVATE_DNS_MODE_OPPORTUNISTIC = "opportunistic";
/**
* @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
public static final String PRIVATE_DNS_MODE_PROVIDER_HOSTNAME = "hostname";
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @StringDef(value = {
+ PRIVATE_DNS_MODE_OFF,
+ PRIVATE_DNS_MODE_OPPORTUNISTIC,
+ PRIVATE_DNS_MODE_PROVIDER_HOSTNAME,
+ })
+ public @interface PrivateDnsMode {}
+
/**
- * The default Private DNS mode.
- *
- * This may change from release to release or may become dependent upon
- * the capabilities of the underlying platform.
+ * Flag to indicate that an app is not subject to any restrictions that could result in its
+ * network access blocked.
*
* @hide
*/
- public static final String PRIVATE_DNS_DEFAULT_MODE_FALLBACK = PRIVATE_DNS_MODE_OPPORTUNISTIC;
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final int BLOCKED_REASON_NONE = 0;
+
+ /**
+ * Flag to indicate that an app is subject to Battery saver restrictions that would
+ * result in its network access being blocked.
+ *
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final int BLOCKED_REASON_BATTERY_SAVER = 1 << 0;
+
+ /**
+ * Flag to indicate that an app is subject to Doze restrictions that would
+ * result in its network access being blocked.
+ *
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final int BLOCKED_REASON_DOZE = 1 << 1;
+
+ /**
+ * Flag to indicate that an app is subject to App Standby restrictions that would
+ * result in its network access being blocked.
+ *
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final int BLOCKED_REASON_APP_STANDBY = 1 << 2;
+
+ /**
+ * Flag to indicate that an app is subject to Restricted mode restrictions that would
+ * result in its network access being blocked.
+ *
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final int BLOCKED_REASON_RESTRICTED_MODE = 1 << 3;
+
+ /**
+ * Flag to indicate that an app is blocked because it is subject to an always-on VPN but the VPN
+ * is not currently connected.
+ *
+ * @see DevicePolicyManager#setAlwaysOnVpnPackage(ComponentName, String, boolean)
+ *
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final int BLOCKED_REASON_LOCKDOWN_VPN = 1 << 4;
+
+ /**
+ * Flag to indicate that an app is subject to Data saver restrictions that would
+ * result in its metered network access being blocked.
+ *
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final int BLOCKED_METERED_REASON_DATA_SAVER = 1 << 16;
+
+ /**
+ * Flag to indicate that an app is subject to user restrictions that would
+ * result in its metered network access being blocked.
+ *
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final int BLOCKED_METERED_REASON_USER_RESTRICTED = 1 << 17;
+
+ /**
+ * Flag to indicate that an app is subject to Device admin restrictions that would
+ * result in its metered network access being blocked.
+ *
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final int BLOCKED_METERED_REASON_ADMIN_DISABLED = 1 << 18;
+
+ /**
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, prefix = {"BLOCKED_"}, value = {
+ BLOCKED_REASON_NONE,
+ BLOCKED_REASON_BATTERY_SAVER,
+ BLOCKED_REASON_DOZE,
+ BLOCKED_REASON_APP_STANDBY,
+ BLOCKED_REASON_RESTRICTED_MODE,
+ BLOCKED_METERED_REASON_DATA_SAVER,
+ BLOCKED_METERED_REASON_USER_RESTRICTED,
+ BLOCKED_METERED_REASON_ADMIN_DISABLED,
+ })
+ public @interface BlockedReason {}
+
+ /**
+ * Set of blocked reasons that are only applicable on metered networks.
+ *
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final int BLOCKED_METERED_REASON_MASK = 0xffff0000;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562)
private final IConnectivityManager mService;
@@ -833,7 +948,6 @@
private final Context mContext;
- private INetworkPolicyManager mNPManager;
private final TetheringManager mTetheringManager;
/**
@@ -906,8 +1020,8 @@
/**
* @hide
- * TODO: Expose for SystemServer when becomes a module.
*/
+ @SystemApi(client = MODULE_LIBRARIES)
public void systemReady() {
try {
mService.systemReady();
@@ -962,6 +1076,33 @@
}
/**
+ * Preference for {@link #setNetworkPreferenceForUser(UserHandle, int, Executor, Runnable)}.
+ * Specify that the traffic for this user should by follow the default rules.
+ * @hide
+ */
+ @SystemApi(client = MODULE_LIBRARIES)
+ public static final int PROFILE_NETWORK_PREFERENCE_DEFAULT = 0;
+
+ /**
+ * Preference for {@link #setNetworkPreferenceForUser(UserHandle, int, Executor, Runnable)}.
+ * Specify that the traffic for this user should by default go on a network with
+ * {@link NetworkCapabilities#NET_CAPABILITY_ENTERPRISE}, and on the system default network
+ * if no such network is available.
+ * @hide
+ */
+ @SystemApi(client = MODULE_LIBRARIES)
+ public static final int PROFILE_NETWORK_PREFERENCE_ENTERPRISE = 1;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(value = {
+ PROFILE_NETWORK_PREFERENCE_DEFAULT,
+ PROFILE_NETWORK_PREFERENCE_ENTERPRISE
+ })
+ public @interface ProfileNetworkPreference {
+ }
+
+ /**
* Specifies the preferred network type. When the device has more
* than one type available the preferred network type will be used.
*
@@ -1090,12 +1231,13 @@
* @param ranges the UID ranges to restrict
* @param requireVpn whether the specified UID ranges must use a VPN
*
- * TODO: expose as @SystemApi.
* @hide
*/
@RequiresPermission(anyOf = {
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
- android.Manifest.permission.NETWORK_STACK})
+ android.Manifest.permission.NETWORK_STACK,
+ android.Manifest.permission.NETWORK_SETTINGS})
+ @SystemApi(client = MODULE_LIBRARIES)
public void setRequireVpnForUids(boolean requireVpn,
@NonNull Collection<Range<Integer>> ranges) {
Objects.requireNonNull(ranges);
@@ -1139,13 +1281,13 @@
*
* @param enabled whether legacy lockdown VPN is enabled or disabled
*
- * TODO: @SystemApi(client = MODULE_LIBRARIES)
- *
* @hide
*/
@RequiresPermission(anyOf = {
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
+ android.Manifest.permission.NETWORK_STACK,
android.Manifest.permission.NETWORK_SETTINGS})
+ @SystemApi(client = MODULE_LIBRARIES)
public void setLegacyLockdownVpnEnabled(boolean enabled) {
try {
mService.setLegacyLockdownVpnEnabled(enabled);
@@ -1314,7 +1456,7 @@
}
/**
- * Returns an array of {@link android.net.NetworkCapabilities} objects, representing
+ * Returns an array of {@link NetworkCapabilities} objects, representing
* the Networks that applications run by the given user will use by default.
* @hide
*/
@@ -1394,11 +1536,19 @@
}
/**
- * Get the {@link android.net.NetworkCapabilities} for the given {@link Network}. This
+ * Get the {@link NetworkCapabilities} for the given {@link Network}. This
* will return {@code null} if the network is unknown.
*
+ * This will remove any location sensitive data in {@link TransportInfo} embedded in
+ * {@link NetworkCapabilities#getTransportInfo()}. Some transport info instances like
+ * {@link android.net.wifi.WifiInfo} contain location sensitive information. Retrieving
+ * this location sensitive information (subject to app's location permissions) will be
+ * noted by system. To include any location sensitive data in {@link TransportInfo},
+ * use a {@link NetworkCallback} with
+ * {@link NetworkCallback#FLAG_INCLUDE_LOCATION_INFO} flag.
+ *
* @param network The {@link Network} object identifying the network in question.
- * @return The {@link android.net.NetworkCapabilities} for the network, or {@code null}.
+ * @return The {@link NetworkCapabilities} for the network, or {@code null}.
*/
@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
@Nullable
@@ -1733,7 +1883,9 @@
// Map from type to transports.
final int NOT_FOUND = -1;
final int transport = sLegacyTypeToTransport.get(type, NOT_FOUND);
- Preconditions.checkArgument(transport != NOT_FOUND, "unknown legacy type: " + type);
+ if (transport == NOT_FOUND) {
+ throw new IllegalArgumentException("unknown legacy type: " + type);
+ }
nc.addTransportType(transport);
// Map from type to capabilities.
@@ -1838,8 +1990,8 @@
}
private PacketKeepalive(Network network, PacketKeepaliveCallback callback) {
- Preconditions.checkNotNull(network, "network cannot be null");
- Preconditions.checkNotNull(callback, "callback cannot be null");
+ Objects.requireNonNull(network, "network cannot be null");
+ Objects.requireNonNull(callback, "callback cannot be null");
mNetwork = network;
mExecutor = Executors.newSingleThreadExecutor();
mCallback = new ISocketKeepaliveCallback.Stub() {
@@ -1996,7 +2148,7 @@
dup = createInvalidFd();
}
return new NattSocketKeepalive(mService, network, dup,
- INVALID_RESOURCE_ID /* Unused */, source, destination, executor, callback);
+ -1 /* Unused */, source, destination, executor, callback);
}
/**
@@ -2082,6 +2234,7 @@
*/
@Deprecated
@UnsupportedAppUsage
+ @SystemApi(client = MODULE_LIBRARIES)
public boolean requestRouteToHostAddress(int networkType, InetAddress hostAddress) {
checkLegacyRoutingApiAccess();
try {
@@ -2214,7 +2367,9 @@
*/
public void removeDefaultNetworkActiveListener(@NonNull OnNetworkActiveListener l) {
INetworkActivityListener rl = mNetworkActivityListeners.get(l);
- Preconditions.checkArgument(rl != null, "Listener was not registered.");
+ if (rl == null) {
+ throw new IllegalArgumentException("Listener was not registered.");
+ }
try {
mService.registerNetworkActivityListener(rl);
} catch (RemoteException e) {
@@ -2242,8 +2397,8 @@
* {@hide}
*/
public ConnectivityManager(Context context, IConnectivityManager service) {
- mContext = Preconditions.checkNotNull(context, "missing context");
- mService = Preconditions.checkNotNull(service, "missing IConnectivityManager");
+ mContext = Objects.requireNonNull(context, "missing context");
+ mService = Objects.requireNonNull(service, "missing IConnectivityManager");
mTetheringManager = (TetheringManager) mContext.getSystemService(Context.TETHERING_SERVICE);
sInstance = this;
}
@@ -2510,7 +2665,7 @@
@RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
public void startTethering(int type, boolean showProvisioningUi,
final OnStartTetheringCallback callback, Handler handler) {
- Preconditions.checkNotNull(callback, "OnStartTetheringCallback cannot be null.");
+ Objects.requireNonNull(callback, "OnStartTetheringCallback cannot be null.");
final Executor executor = new Executor() {
@Override
@@ -2603,7 +2758,7 @@
public void registerTetheringEventCallback(
@NonNull @CallbackExecutor Executor executor,
@NonNull final OnTetheringEventCallback callback) {
- Preconditions.checkNotNull(callback, "OnTetheringEventCallback cannot be null.");
+ Objects.requireNonNull(callback, "OnTetheringEventCallback cannot be null.");
final TetheringEventCallback tetherCallback =
new TetheringEventCallback() {
@@ -2901,7 +3056,7 @@
public void getLatestTetheringEntitlementResult(int type, boolean showEntitlementUi,
@NonNull @CallbackExecutor Executor executor,
@NonNull final OnTetheringEntitlementResultListener listener) {
- Preconditions.checkNotNull(listener, "TetheringEntitlementResultListener cannot be null.");
+ Objects.requireNonNull(listener, "TetheringEntitlementResultListener cannot be null.");
ResultReceiver wrappedListener = new ResultReceiver(null) {
@Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
@@ -2994,8 +3149,9 @@
* HTTP proxy. A {@code null} value will clear the global HTTP proxy.
* @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
@RequiresPermission(android.Manifest.permission.NETWORK_STACK)
- public void setGlobalProxy(ProxyInfo p) {
+ public void setGlobalProxy(@Nullable ProxyInfo p) {
try {
mService.setGlobalProxy(p);
} catch (RemoteException e) {
@@ -3010,6 +3166,8 @@
* if no global HTTP proxy is set.
* @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
+ @Nullable
public ProxyInfo getGlobalProxy() {
try {
return mService.getGlobalProxy();
@@ -3196,10 +3354,6 @@
}
}
- // TODO : remove this method. It is a stopgap measure to help sheperding a number
- // of dependent changes that would conflict throughout the automerger graph. Having this
- // temporarily helps with the process of going through with all these dependent changes across
- // the entire tree.
/**
* @hide
* Register a NetworkAgent with ConnectivityService.
@@ -3209,20 +3363,8 @@
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
android.Manifest.permission.NETWORK_FACTORY})
public Network registerNetworkAgent(INetworkAgent na, NetworkInfo ni, LinkProperties lp,
- NetworkCapabilities nc, int score, NetworkAgentConfig config) {
- return registerNetworkAgent(na, ni, lp, nc, score, config, NetworkProvider.ID_NONE);
- }
-
- /**
- * @hide
- * Register a NetworkAgent with ConnectivityService.
- * @return Network corresponding to NetworkAgent.
- */
- @RequiresPermission(anyOf = {
- NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
- android.Manifest.permission.NETWORK_FACTORY})
- public Network registerNetworkAgent(INetworkAgent na, NetworkInfo ni, LinkProperties lp,
- NetworkCapabilities nc, int score, NetworkAgentConfig config, int providerId) {
+ NetworkCapabilities nc, @NonNull NetworkScore score, NetworkAgentConfig config,
+ int providerId) {
try {
return mService.registerNetworkAgent(na, ni, lp, nc, score, config, providerId);
} catch (RemoteException e) {
@@ -3244,6 +3386,56 @@
*/
public static class NetworkCallback {
/**
+ * No flags associated with this callback.
+ * @hide
+ */
+ public static final int FLAG_NONE = 0;
+ /**
+ * Use this flag to include any location sensitive data in {@link NetworkCapabilities} sent
+ * via {@link #onCapabilitiesChanged(Network, NetworkCapabilities)}.
+ * <p>
+ * These include:
+ * <li> Some transport info instances (retrieved via
+ * {@link NetworkCapabilities#getTransportInfo()}) like {@link android.net.wifi.WifiInfo}
+ * contain location sensitive information.
+ * <li> OwnerUid (retrieved via {@link NetworkCapabilities#getOwnerUid()} is location
+ * sensitive for wifi suggestor apps (i.e using {@link WifiNetworkSuggestion}).</li>
+ * </p>
+ * <p>
+ * Note:
+ * <li> Retrieving this location sensitive information (subject to app's location
+ * permissions) will be noted by system. </li>
+ * <li> Without this flag any {@link NetworkCapabilities} provided via the callback does
+ * not include location sensitive info.
+ * </p>
+ */
+ public static final int FLAG_INCLUDE_LOCATION_INFO = 1 << 0;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, prefix = "FLAG_", value = {
+ FLAG_NONE,
+ FLAG_INCLUDE_LOCATION_INFO
+ })
+ public @interface Flag { }
+
+ /**
+ * All the valid flags for error checking.
+ */
+ private static final int VALID_FLAGS = FLAG_INCLUDE_LOCATION_INFO;
+
+ public NetworkCallback() {
+ this(FLAG_NONE);
+ }
+
+ public NetworkCallback(@Flag int flags) {
+ if ((flags & VALID_FLAGS) != flags) {
+ throw new IllegalArgumentException("Invalid flags");
+ }
+ mFlags = flags;
+ }
+
+ /**
* Called when the framework connects to a new network to evaluate whether it satisfies this
* request. If evaluation succeeds, this callback may be followed by an {@link #onAvailable}
* callback. There is no guarantee that this new network will satisfy any requests, or that
@@ -3271,12 +3463,30 @@
* @param blocked Whether access to the {@link Network} is blocked due to system policy.
* @hide
*/
- public void onAvailable(@NonNull Network network,
+ public final void onAvailable(@NonNull Network network,
@NonNull NetworkCapabilities networkCapabilities,
- @NonNull LinkProperties linkProperties, boolean blocked) {
+ @NonNull LinkProperties linkProperties, @BlockedReason int blocked) {
// Internally only this method is called when a new network is available, and
// it calls the callback in the same way and order that older versions used
// to call so as not to change the behavior.
+ onAvailable(network, networkCapabilities, linkProperties, blocked != 0);
+ onBlockedStatusChanged(network, blocked);
+ }
+
+ /**
+ * Legacy variant of onAvailable that takes a boolean blocked reason.
+ *
+ * This method has never been public API, but it's not final, so there may be apps that
+ * implemented it and rely on it being called. Do our best not to break them.
+ * Note: such apps will also get a second call to onBlockedStatusChanged immediately after
+ * this method is called. There does not seem to be a way to avoid this.
+ * TODO: add a compat check to move apps off this method, and eventually stop calling it.
+ *
+ * @hide
+ */
+ public void onAvailable(@NonNull Network network,
+ @NonNull NetworkCapabilities networkCapabilities,
+ @NonNull LinkProperties linkProperties, boolean blocked) {
onAvailable(network);
if (!networkCapabilities.hasCapability(
NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED)) {
@@ -3284,7 +3494,7 @@
}
onCapabilitiesChanged(network, networkCapabilities);
onLinkPropertiesChanged(network, linkProperties);
- onBlockedStatusChanged(network, blocked);
+ // No call to onBlockedStatusChanged here. That is done by the caller.
}
/**
@@ -3380,7 +3590,7 @@
* calling these methods while in a callback may return an outdated or even a null object.
*
* @param network The {@link Network} whose capabilities have changed.
- * @param networkCapabilities The new {@link android.net.NetworkCapabilities} for this
+ * @param networkCapabilities The new {@link NetworkCapabilities} for this
* network.
*/
public void onCapabilitiesChanged(@NonNull Network network,
@@ -3448,7 +3658,28 @@
*/
public void onBlockedStatusChanged(@NonNull Network network, boolean blocked) {}
+ /**
+ * Called when access to the specified network is blocked or unblocked.
+ *
+ * If a NetworkCallback object implements this method,
+ * {@link #onBlockedStatusChanged(Network, boolean)} will not be called.
+ *
+ * <p>Do NOT call {@link #getNetworkCapabilities(Network)} or
+ * {@link #getLinkProperties(Network)} or other synchronous ConnectivityManager methods in
+ * this callback as this is prone to race conditions : calling these methods while in a
+ * callback may return an outdated or even a null object.
+ *
+ * @param network The {@link Network} whose blocked status has changed.
+ * @param blocked The blocked status of this {@link Network}.
+ * @hide
+ */
+ @SystemApi(client = MODULE_LIBRARIES)
+ public void onBlockedStatusChanged(@NonNull Network network, @BlockedReason int blocked) {
+ onBlockedStatusChanged(network, blocked != 0);
+ }
+
private NetworkRequest networkRequest;
+ private final int mFlags;
}
/**
@@ -3473,29 +3704,28 @@
}
}
- private static final int BASE = Protocol.BASE_CONNECTIVITY_MANAGER;
/** @hide */
- public static final int CALLBACK_PRECHECK = BASE + 1;
+ public static final int CALLBACK_PRECHECK = 1;
/** @hide */
- public static final int CALLBACK_AVAILABLE = BASE + 2;
+ public static final int CALLBACK_AVAILABLE = 2;
/** @hide arg1 = TTL */
- public static final int CALLBACK_LOSING = BASE + 3;
+ public static final int CALLBACK_LOSING = 3;
/** @hide */
- public static final int CALLBACK_LOST = BASE + 4;
+ public static final int CALLBACK_LOST = 4;
/** @hide */
- public static final int CALLBACK_UNAVAIL = BASE + 5;
+ public static final int CALLBACK_UNAVAIL = 5;
/** @hide */
- public static final int CALLBACK_CAP_CHANGED = BASE + 6;
+ public static final int CALLBACK_CAP_CHANGED = 6;
/** @hide */
- public static final int CALLBACK_IP_CHANGED = BASE + 7;
+ public static final int CALLBACK_IP_CHANGED = 7;
/** @hide obj = NetworkCapabilities, arg1 = seq number */
- private static final int EXPIRE_LEGACY_REQUEST = BASE + 8;
+ private static final int EXPIRE_LEGACY_REQUEST = 8;
/** @hide */
- public static final int CALLBACK_SUSPENDED = BASE + 9;
+ public static final int CALLBACK_SUSPENDED = 9;
/** @hide */
- public static final int CALLBACK_RESUMED = BASE + 10;
+ public static final int CALLBACK_RESUMED = 10;
/** @hide */
- public static final int CALLBACK_BLK_CHANGED = BASE + 11;
+ public static final int CALLBACK_BLK_CHANGED = 11;
/** @hide */
public static String getCallbackName(int whichCallback) {
@@ -3525,7 +3755,7 @@
}
CallbackHandler(Handler handler) {
- this(Preconditions.checkNotNull(handler, "Handler cannot be null.").getLooper());
+ this(Objects.requireNonNull(handler, "Handler cannot be null.").getLooper());
}
@Override
@@ -3562,7 +3792,7 @@
case CALLBACK_AVAILABLE: {
NetworkCapabilities cap = getObject(message, NetworkCapabilities.class);
LinkProperties lp = getObject(message, LinkProperties.class);
- callback.onAvailable(network, cap, lp, message.arg1 != 0);
+ callback.onAvailable(network, cap, lp, message.arg1);
break;
}
case CALLBACK_LOSING: {
@@ -3596,8 +3826,7 @@
break;
}
case CALLBACK_BLK_CHANGED: {
- boolean blocked = message.arg1 != 0;
- callback.onBlockedStatusChanged(network, blocked);
+ callback.onBlockedStatusChanged(network, message.arg1);
}
}
}
@@ -3619,13 +3848,14 @@
private static final HashMap<NetworkRequest, NetworkCallback> sCallbacks = new HashMap<>();
private static CallbackHandler sCallbackHandler;
- private NetworkRequest sendRequestForNetwork(NetworkCapabilities need, NetworkCallback callback,
- int timeoutMs, NetworkRequest.Type reqType, int legacyType, CallbackHandler handler) {
+ private NetworkRequest sendRequestForNetwork(int asUid, NetworkCapabilities need,
+ NetworkCallback callback, int timeoutMs, NetworkRequest.Type reqType, int legacyType,
+ CallbackHandler handler) {
printStackTrace();
checkCallbackNotNull(callback);
- Preconditions.checkArgument(
- reqType == TRACK_DEFAULT || reqType == TRACK_SYSTEM_DEFAULT || need != null,
- "null NetworkCapabilities");
+ if (reqType != TRACK_DEFAULT && reqType != TRACK_SYSTEM_DEFAULT && need == null) {
+ throw new IllegalArgumentException("null NetworkCapabilities");
+ }
final NetworkRequest request;
final String callingPackageName = mContext.getOpPackageName();
try {
@@ -3638,14 +3868,15 @@
}
Messenger messenger = new Messenger(handler);
Binder binder = new Binder();
+ final int callbackFlags = callback.mFlags;
if (reqType == LISTEN) {
request = mService.listenForNetwork(
- need, messenger, binder, callingPackageName,
+ need, messenger, binder, callbackFlags, callingPackageName,
getAttributionTag());
} else {
request = mService.requestNetwork(
- need, reqType.ordinal(), messenger, timeoutMs, binder, legacyType,
- callingPackageName, getAttributionTag());
+ asUid, need, reqType.ordinal(), messenger, timeoutMs, binder,
+ legacyType, callbackFlags, callingPackageName, getAttributionTag());
}
if (request != null) {
sCallbacks.put(request, callback);
@@ -3660,6 +3891,12 @@
return request;
}
+ private NetworkRequest sendRequestForNetwork(NetworkCapabilities need, NetworkCallback callback,
+ int timeoutMs, NetworkRequest.Type reqType, int legacyType, CallbackHandler handler) {
+ return sendRequestForNetwork(Process.INVALID_UID, need, callback, timeoutMs, reqType,
+ legacyType, handler);
+ }
+
/**
* Helper function to request a network with a particular legacy type.
*
@@ -3692,7 +3929,7 @@
}
/**
- * Request a network to satisfy a set of {@link android.net.NetworkCapabilities}.
+ * Request a network to satisfy a set of {@link NetworkCapabilities}.
*
* <p>This method will attempt to find the best network that matches the passed
* {@link NetworkRequest}, and to bring up one that does if none currently satisfies the
@@ -3776,7 +4013,7 @@
}
/**
- * Request a network to satisfy a set of {@link android.net.NetworkCapabilities}.
+ * Request a network to satisfy a set of {@link NetworkCapabilities}.
*
* This method behaves identically to {@link #requestNetwork(NetworkRequest, NetworkCallback)}
* but runs all the callbacks on the passed Handler.
@@ -3798,7 +4035,7 @@
}
/**
- * Request a network to satisfy a set of {@link android.net.NetworkCapabilities}, limited
+ * Request a network to satisfy a set of {@link NetworkCapabilities}, limited
* by a timeout.
*
* This function behaves identically to the non-timed-out version
@@ -3833,7 +4070,7 @@
}
/**
- * Request a network to satisfy a set of {@link android.net.NetworkCapabilities}, limited
+ * Request a network to satisfy a set of {@link NetworkCapabilities}, limited
* by a timeout.
*
* This method behaves identically to
@@ -3878,7 +4115,7 @@
/**
- * Request a network to satisfy a set of {@link android.net.NetworkCapabilities}.
+ * Request a network to satisfy a set of {@link NetworkCapabilities}.
*
* This function behaves identically to the version that takes a NetworkCallback, but instead
* of {@link NetworkCallback} a {@link PendingIntent} is used. This means
@@ -3971,15 +4208,17 @@
}
private static void checkPendingIntentNotNull(PendingIntent intent) {
- Preconditions.checkNotNull(intent, "PendingIntent cannot be null.");
+ Objects.requireNonNull(intent, "PendingIntent cannot be null.");
}
private static void checkCallbackNotNull(NetworkCallback callback) {
- Preconditions.checkNotNull(callback, "null NetworkCallback");
+ Objects.requireNonNull(callback, "null NetworkCallback");
}
private static void checkTimeout(int timeoutMs) {
- Preconditions.checkArgumentPositive(timeoutMs, "timeoutMs must be strictly positive.");
+ if (timeoutMs <= 0) {
+ throw new IllegalArgumentException("timeoutMs must be strictly positive.");
+ }
}
/**
@@ -4143,8 +4382,40 @@
@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
public void registerDefaultNetworkCallback(@NonNull NetworkCallback networkCallback,
@NonNull Handler handler) {
+ registerDefaultNetworkCallbackAsUid(Process.INVALID_UID, networkCallback, handler);
+ }
+
+ /**
+ * Registers to receive notifications about changes in the default network for the specified
+ * UID. This may be a physical network or a virtual network, such as a VPN that applies to the
+ * UID. The callbacks will continue to be called until either the application exits or
+ * {@link #unregisterNetworkCallback(NetworkCallback)} is called.
+ *
+ * <p>To avoid performance issues due to apps leaking callbacks, the system will limit the
+ * number of outstanding requests to 100 per app (identified by their UID), shared with
+ * all variants of this method, of {@link #requestNetwork} as well as
+ * {@link ConnectivityDiagnosticsManager#registerConnectivityDiagnosticsCallback}.
+ * Requesting a network with this method will count toward this limit. If this limit is
+ * exceeded, an exception will be thrown. To avoid hitting this issue and to conserve resources,
+ * make sure to unregister the callbacks with
+ * {@link #unregisterNetworkCallback(NetworkCallback)}.
+ *
+ * @param uid the UID for which to track default network changes.
+ * @param networkCallback The {@link NetworkCallback} that the system will call as the
+ * UID's default network changes.
+ * @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
+ * @throws RuntimeException if the app already has too many callbacks registered.
+ * @hide
+ */
+ @SystemApi(client = MODULE_LIBRARIES)
+ @SuppressLint({"ExecutorRegistration", "PairedRegistration"})
+ @RequiresPermission(anyOf = {
+ NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
+ android.Manifest.permission.NETWORK_SETTINGS})
+ public void registerDefaultNetworkCallbackAsUid(int uid,
+ @NonNull NetworkCallback networkCallback, @NonNull Handler handler) {
CallbackHandler cbHandler = new CallbackHandler(handler);
- sendRequestForNetwork(null /* NetworkCapabilities need */, networkCallback, 0,
+ sendRequestForNetwork(uid, null /* need */, networkCallback, 0 /* timeoutMs */,
TRACK_DEFAULT, TYPE_NONE, cbHandler);
}
@@ -4190,6 +4461,36 @@
}
/**
+ * Registers to receive notifications about the best matching network which satisfy the given
+ * {@link NetworkRequest}. The callbacks will continue to be called until
+ * either the application exits or {@link #unregisterNetworkCallback(NetworkCallback)} is
+ * called.
+ *
+ * <p>To avoid performance issues due to apps leaking callbacks, the system will limit the
+ * number of outstanding requests to 100 per app (identified by their UID), shared with
+ * {@link #registerNetworkCallback} and its variants and {@link #requestNetwork} as well as
+ * {@link ConnectivityDiagnosticsManager#registerConnectivityDiagnosticsCallback}.
+ * Requesting a network with this method will count toward this limit. If this limit is
+ * exceeded, an exception will be thrown. To avoid hitting this issue and to conserve resources,
+ * make sure to unregister the callbacks with
+ * {@link #unregisterNetworkCallback(NetworkCallback)}.
+ *
+ *
+ * @param request {@link NetworkRequest} describing this request.
+ * @param networkCallback The {@link NetworkCallback} that the system will call as suitable
+ * networks change state.
+ * @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
+ * @throws RuntimeException if the app already has too many callbacks registered.
+ */
+ @SuppressLint("ExecutorRegistration")
+ public void registerBestMatchingNetworkCallback(@NonNull NetworkRequest request,
+ @NonNull NetworkCallback networkCallback, @NonNull Handler handler) {
+ final NetworkCapabilities nc = request.networkCapabilities;
+ final CallbackHandler cbHandler = new CallbackHandler(handler);
+ sendRequestForNetwork(nc, networkCallback, 0, LISTEN_FOR_BEST, TYPE_NONE, cbHandler);
+ }
+
+ /**
* Requests bandwidth update for a given {@link Network} and returns whether the update request
* is accepted by ConnectivityService. Once accepted, ConnectivityService will poll underlying
* network connection for updated bandwidth information. The caller will be notified via
@@ -4229,8 +4530,9 @@
// Find all requests associated to this callback and stop callback triggers immediately.
// Callback is reusable immediately. http://b/20701525, http://b/35921499.
synchronized (sCallbacks) {
- Preconditions.checkArgument(networkCallback.networkRequest != null,
- "NetworkCallback was not registered");
+ if (networkCallback.networkRequest == null) {
+ throw new IllegalArgumentException("NetworkCallback was not registered");
+ }
if (networkCallback.networkRequest == ALREADY_UNREGISTERED) {
Log.d(TAG, "NetworkCallback was already unregistered");
return;
@@ -4281,8 +4583,13 @@
*
* @hide
*/
- @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
- public void setAcceptUnvalidated(Network network, boolean accept, boolean always) {
+ @SystemApi(client = MODULE_LIBRARIES)
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.NETWORK_SETTINGS,
+ android.Manifest.permission.NETWORK_SETUP_WIZARD,
+ android.Manifest.permission.NETWORK_STACK,
+ NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK})
+ public void setAcceptUnvalidated(@NonNull Network network, boolean accept, boolean always) {
try {
mService.setAcceptUnvalidated(network, accept, always);
} catch (RemoteException e) {
@@ -4304,8 +4611,14 @@
*
* @hide
*/
- @RequiresPermission(android.Manifest.permission.NETWORK_STACK)
- public void setAcceptPartialConnectivity(Network network, boolean accept, boolean always) {
+ @SystemApi(client = MODULE_LIBRARIES)
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.NETWORK_SETTINGS,
+ android.Manifest.permission.NETWORK_SETUP_WIZARD,
+ android.Manifest.permission.NETWORK_STACK,
+ NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK})
+ public void setAcceptPartialConnectivity(@NonNull Network network, boolean accept,
+ boolean always) {
try {
mService.setAcceptPartialConnectivity(network, accept, always);
} catch (RemoteException e) {
@@ -4323,8 +4636,13 @@
*
* @hide
*/
- @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
- public void setAvoidUnvalidated(Network network) {
+ @SystemApi(client = MODULE_LIBRARIES)
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.NETWORK_SETTINGS,
+ android.Manifest.permission.NETWORK_SETUP_WIZARD,
+ android.Manifest.permission.NETWORK_STACK,
+ NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK})
+ public void setAvoidUnvalidated(@NonNull Network network) {
try {
mService.setAvoidUnvalidated(network);
} catch (RemoteException e) {
@@ -4335,12 +4653,20 @@
/**
* Requests that the system open the captive portal app on the specified network.
*
+ * <p>This is to be used on networks where a captive portal was detected, as per
+ * {@link NetworkCapabilities#NET_CAPABILITY_CAPTIVE_PORTAL}.
+ *
* @param network The network to log into.
*
* @hide
*/
- @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
- public void startCaptivePortalApp(Network network) {
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.NETWORK_SETTINGS,
+ android.Manifest.permission.NETWORK_STACK,
+ NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
+ })
+ public void startCaptivePortalApp(@NonNull Network network) {
try {
mService.startCaptivePortalApp(network);
} catch (RemoteException e) {
@@ -4454,7 +4780,10 @@
* Resets all connectivity manager settings back to factory defaults.
* @hide
*/
- @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+ @SystemApi(client = MODULE_LIBRARIES)
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.NETWORK_SETTINGS,
+ NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK})
public void factoryReset() {
try {
mService.factoryReset();
@@ -4532,7 +4861,7 @@
Log.e(TAG, "Can't set proxy properties", e);
}
// Must flush DNS cache as new network may have different DNS resolutions.
- InetAddress.clearDnsCache();
+ InetAddressCompat.clearDnsCache();
// Must flush socket pool as idle sockets will be bound to previous network and may
// cause subsequent fetches to be performed on old network.
NetworkEventDispatcher.getInstance().onNetworkConfigurationChanged();
@@ -4657,17 +4986,6 @@
public @interface RestrictBackgroundStatus {
}
- private INetworkPolicyManager getNetworkPolicyManager() {
- synchronized (this) {
- if (mNPManager != null) {
- return mNPManager;
- }
- mNPManager = INetworkPolicyManager.Stub.asInterface(ServiceManager
- .getService(Context.NETWORK_POLICY_SERVICE));
- return mNPManager;
- }
- }
-
/**
* Determines if the calling application is subject to metered network restrictions while
* running on background.
@@ -4678,7 +4996,7 @@
*/
public @RestrictBackgroundStatus int getRestrictBackgroundStatus() {
try {
- return getNetworkPolicyManager().getRestrictBackgroundByCaller();
+ return mService.getRestrictBackgroundStatusByCaller();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -4808,20 +5126,20 @@
* {@link QosCallback#onError(QosCallbackException)}. see: {@link QosCallbackException}.
*
* @param socketInfo the socket information used to match QoS events
- * @param callback receives qos events that satisfy socketInfo
* @param executor The executor on which the callback will be invoked. The provided
* {@link Executor} must run callback sequentially, otherwise the order of
- * callbacks cannot be guaranteed.
+ * callbacks cannot be guaranteed.onQosCallbackRegistered
+ * @param callback receives qos events that satisfy socketInfo
*
* @hide
*/
@SystemApi
public void registerQosCallback(@NonNull final QosSocketInfo socketInfo,
- @NonNull final QosCallback callback,
- @CallbackExecutor @NonNull final Executor executor) {
+ @CallbackExecutor @NonNull final Executor executor,
+ @NonNull final QosCallback callback) {
Objects.requireNonNull(socketInfo, "socketInfo must be non-null");
- Objects.requireNonNull(callback, "callback must be non-null");
Objects.requireNonNull(executor, "executor must be non-null");
+ Objects.requireNonNull(callback, "callback must be non-null");
try {
synchronized (mQosCallbackConnections) {
@@ -4898,7 +5216,7 @@
}
/**
- * Request a network to satisfy a set of {@link android.net.NetworkCapabilities}, but
+ * Request a network to satisfy a set of {@link NetworkCapabilities}, but
* does not cause any networks to retain the NET_CAPABILITY_FOREGROUND capability. This can
* be used to request that the system provide a network without causing the network to be
* in the foreground.
@@ -4979,23 +5297,10 @@
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
})
public void requestBackgroundNetwork(@NonNull NetworkRequest request,
- @Nullable Handler handler, @NonNull NetworkCallback networkCallback) {
+ @NonNull Handler handler, @NonNull NetworkCallback networkCallback) {
final NetworkCapabilities nc = request.networkCapabilities;
sendRequestForNetwork(nc, networkCallback, 0, BACKGROUND_REQUEST,
- TYPE_NONE, handler == null ? getDefaultHandler() : new CallbackHandler(handler));
- }
-
- /**
- * Listener for {@link #setOemNetworkPreference(OemNetworkPreferences, Executor,
- * OnSetOemNetworkPreferenceListener)}.
- * @hide
- */
- @SystemApi
- public interface OnSetOemNetworkPreferenceListener {
- /**
- * Called when setOemNetworkPreference() successfully completes.
- */
- void onComplete();
+ TYPE_NONE, new CallbackHandler(handler));
}
/**
@@ -5020,16 +5325,16 @@
@RequiresPermission(android.Manifest.permission.CONTROL_OEM_PAID_NETWORK_PREFERENCE)
public void setOemNetworkPreference(@NonNull final OemNetworkPreferences preference,
@Nullable @CallbackExecutor final Executor executor,
- @Nullable final OnSetOemNetworkPreferenceListener listener) {
+ @Nullable final Runnable listener) {
Objects.requireNonNull(preference, "OemNetworkPreferences must be non-null");
if (null != listener) {
Objects.requireNonNull(executor, "Executor must be non-null");
}
- final IOnSetOemNetworkPreferenceListener listenerInternal = listener == null ? null :
- new IOnSetOemNetworkPreferenceListener.Stub() {
+ final IOnCompleteListener listenerInternal = listener == null ? null :
+ new IOnCompleteListener.Stub() {
@Override
public void onComplete() {
- executor.execute(listener::onComplete);
+ executor.execute(listener::run);
}
};
@@ -5040,4 +5345,107 @@
throw e.rethrowFromSystemServer();
}
}
+
+ /**
+ * Request that a user profile is put by default on a network matching a given preference.
+ *
+ * See the documentation for the individual preferences for a description of the supported
+ * behaviors.
+ *
+ * @param profile the profile concerned.
+ * @param preference the preference for this profile.
+ * @param executor an executor to execute the listener on. Optional if listener is null.
+ * @param listener an optional listener to listen for completion of the operation.
+ * @throws IllegalArgumentException if {@code profile} is not a valid user profile.
+ * @throws SecurityException if missing the appropriate permissions.
+ * @hide
+ */
+ // This function is for establishing per-profile default networking and can only be called by
+ // the device policy manager, running as the system server. It would make no sense to call it
+ // on a context for a user because it does not establish a setting on behalf of a user, rather
+ // it establishes a setting for a user on behalf of the DPM.
+ @SuppressLint({"UserHandle"})
+ @SystemApi(client = MODULE_LIBRARIES)
+ @RequiresPermission(android.Manifest.permission.NETWORK_STACK)
+ public void setProfileNetworkPreference(@NonNull final UserHandle profile,
+ @ProfileNetworkPreference final int preference,
+ @Nullable @CallbackExecutor final Executor executor,
+ @Nullable final Runnable listener) {
+ if (null != listener) {
+ Objects.requireNonNull(executor, "Pass a non-null executor, or a null listener");
+ }
+ final IOnCompleteListener proxy;
+ if (null == listener) {
+ proxy = null;
+ } else {
+ proxy = new IOnCompleteListener.Stub() {
+ @Override
+ public void onComplete() {
+ executor.execute(listener::run);
+ }
+ };
+ }
+ try {
+ mService.setProfileNetworkPreference(profile, preference, proxy);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ // The first network ID of IPSec tunnel interface.
+ private static final int TUN_INTF_NETID_START = 0xFC00; // 0xFC00 = 64512
+ // The network ID range of IPSec tunnel interface.
+ private static final int TUN_INTF_NETID_RANGE = 0x0400; // 0x0400 = 1024
+
+ /**
+ * Get the network ID range reserved for IPSec tunnel interfaces.
+ *
+ * @return A Range which indicates the network ID range of IPSec tunnel interface.
+ * @hide
+ */
+ @SystemApi(client = MODULE_LIBRARIES)
+ @NonNull
+ public static Range<Integer> getIpSecNetIdRange() {
+ return new Range(TUN_INTF_NETID_START, TUN_INTF_NETID_START + TUN_INTF_NETID_RANGE - 1);
+ }
+
+ /**
+ * Get private DNS mode from settings.
+ *
+ * @param context The Context to query the private DNS mode from settings.
+ * @return A string of private DNS mode as one of the PRIVATE_DNS_MODE_* constants.
+ *
+ * @hide
+ */
+ @SystemApi(client = MODULE_LIBRARIES)
+ @NonNull
+ @PrivateDnsMode
+ public static String getPrivateDnsMode(@NonNull Context context) {
+ final ContentResolver cr = context.getContentResolver();
+ String mode = Settings.Global.getString(cr, PRIVATE_DNS_MODE);
+ if (TextUtils.isEmpty(mode)) mode = Settings.Global.getString(cr, PRIVATE_DNS_DEFAULT_MODE);
+ // If both PRIVATE_DNS_MODE and PRIVATE_DNS_DEFAULT_MODE are not set, choose
+ // PRIVATE_DNS_MODE_OPPORTUNISTIC as default mode.
+ if (TextUtils.isEmpty(mode)) mode = PRIVATE_DNS_MODE_OPPORTUNISTIC;
+ return mode;
+ }
+
+ /**
+ * Set private DNS mode to settings.
+ *
+ * @param context The {@link Context} to set the private DNS mode.
+ * @param mode The private dns mode. This should be one of the PRIVATE_DNS_MODE_* constants.
+ *
+ * @hide
+ */
+ @SystemApi(client = MODULE_LIBRARIES)
+ public static void setPrivateDnsMode(@NonNull Context context,
+ @NonNull @PrivateDnsMode String mode) {
+ if (!(mode == PRIVATE_DNS_MODE_OFF
+ || mode == PRIVATE_DNS_MODE_OPPORTUNISTIC
+ || mode == PRIVATE_DNS_MODE_PROVIDER_HOSTNAME)) {
+ throw new IllegalArgumentException("Invalid private dns mode");
+ }
+ Settings.Global.putString(context.getContentResolver(), PRIVATE_DNS_MODE, mode);
+ }
}
diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityResources.java b/packages/Connectivity/framework/src/android/net/ConnectivityResources.java
new file mode 100644
index 0000000..18f0de0
--- /dev/null
+++ b/packages/Connectivity/framework/src/android/net/ConnectivityResources.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.List;
+
+/**
+ * Utility to obtain the {@link com.android.server.ConnectivityService} {@link Resources}, in the
+ * ServiceConnectivityResources APK.
+ * @hide
+ */
+public class ConnectivityResources {
+ private static final String RESOURCES_APK_INTENT =
+ "com.android.server.connectivity.intent.action.SERVICE_CONNECTIVITY_RESOURCES_APK";
+ private static final String RES_PKG_DIR = "/apex/com.android.tethering/";
+
+ @NonNull
+ private final Context mContext;
+
+ @Nullable
+ private Context mResourcesContext = null;
+
+ @Nullable
+ private static Context sTestResourcesContext = null;
+
+ public ConnectivityResources(Context context) {
+ mContext = context;
+ }
+
+ /**
+ * Convenience method to mock all resources for the duration of a test.
+ *
+ * Call with a null context to reset after the test.
+ */
+ @VisibleForTesting
+ public static void setResourcesContextForTest(@Nullable Context testContext) {
+ sTestResourcesContext = testContext;
+ }
+
+ /**
+ * Get the {@link Context} of the resources package.
+ */
+ public synchronized Context getResourcesContext() {
+ if (sTestResourcesContext != null) {
+ return sTestResourcesContext;
+ }
+
+ if (mResourcesContext != null) {
+ return mResourcesContext;
+ }
+
+ final List<ResolveInfo> pkgs = mContext.getPackageManager()
+ .queryIntentActivities(new Intent(RESOURCES_APK_INTENT), MATCH_SYSTEM_ONLY);
+ pkgs.removeIf(pkg -> !pkg.activityInfo.applicationInfo.sourceDir.startsWith(RES_PKG_DIR));
+ if (pkgs.size() > 1) {
+ Log.wtf(ConnectivityResources.class.getSimpleName(),
+ "More than one package found: " + pkgs);
+ }
+ if (pkgs.isEmpty()) {
+ throw new IllegalStateException("No connectivity resource package found");
+ }
+
+ final Context pkgContext;
+ try {
+ pkgContext = mContext.createPackageContext(
+ pkgs.get(0).activityInfo.applicationInfo.packageName, 0 /* flags */);
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new IllegalStateException("Resolved package not found", e);
+ }
+
+ mResourcesContext = pkgContext;
+ return pkgContext;
+ }
+
+ /**
+ * Get the {@link Resources} of the ServiceConnectivityResources APK.
+ */
+ public Resources get() {
+ return getResourcesContext().getResources();
+ }
+}
diff --git a/packages/Connectivity/framework/src/android/net/ConnectivitySettingsManager.java b/packages/Connectivity/framework/src/android/net/ConnectivitySettingsManager.java
new file mode 100644
index 0000000..9a00055
--- /dev/null
+++ b/packages/Connectivity/framework/src/android/net/ConnectivitySettingsManager.java
@@ -0,0 +1,929 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import static android.net.ConnectivityManager.MULTIPATH_PREFERENCE_HANDOVER;
+import static android.net.ConnectivityManager.MULTIPATH_PREFERENCE_PERFORMANCE;
+import static android.net.ConnectivityManager.MULTIPATH_PREFERENCE_RELIABILITY;
+import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF;
+import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
+import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
+
+import android.annotation.IntDef;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.content.Context;
+import android.net.ConnectivityManager.MultipathPreference;
+import android.net.ConnectivityManager.PrivateDnsMode;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.Range;
+
+import com.android.net.module.util.ProxyUtils;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.time.Duration;
+import java.util.List;
+
+/**
+ * A manager class for connectivity module settings.
+ *
+ * @hide
+ */
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+public class ConnectivitySettingsManager {
+
+ private ConnectivitySettingsManager() {}
+
+ /** Data activity timeout settings */
+
+ /**
+ * Inactivity timeout to track mobile data activity.
+ *
+ * If set to a positive integer, it indicates the inactivity timeout value in seconds to
+ * infer the data activity of mobile network. After a period of no activity on mobile
+ * networks with length specified by the timeout, an {@code ACTION_DATA_ACTIVITY_CHANGE}
+ * intent is fired to indicate a transition of network status from "active" to "idle". Any
+ * subsequent activity on mobile networks triggers the firing of {@code
+ * ACTION_DATA_ACTIVITY_CHANGE} intent indicating transition from "idle" to "active".
+ *
+ * Network activity refers to transmitting or receiving data on the network interfaces.
+ *
+ * Tracking is disabled if set to zero or negative value.
+ *
+ * @hide
+ */
+ public static final String DATA_ACTIVITY_TIMEOUT_MOBILE = "data_activity_timeout_mobile";
+
+ /**
+ * Timeout to tracking Wifi data activity. Same as {@code DATA_ACTIVITY_TIMEOUT_MOBILE}
+ * but for Wifi network.
+ *
+ * @hide
+ */
+ public static final String DATA_ACTIVITY_TIMEOUT_WIFI = "data_activity_timeout_wifi";
+
+ /** Dns resolver settings */
+
+ /**
+ * Sample validity in seconds to configure for the system DNS resolver.
+ *
+ * @hide
+ */
+ public static final String DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS =
+ "dns_resolver_sample_validity_seconds";
+
+ /**
+ * Success threshold in percent for use with the system DNS resolver.
+ *
+ * @hide
+ */
+ public static final String DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT =
+ "dns_resolver_success_threshold_percent";
+
+ /**
+ * Minimum number of samples needed for statistics to be considered meaningful in the
+ * system DNS resolver.
+ *
+ * @hide
+ */
+ public static final String DNS_RESOLVER_MIN_SAMPLES = "dns_resolver_min_samples";
+
+ /**
+ * Maximum number taken into account for statistics purposes in the system DNS resolver.
+ *
+ * @hide
+ */
+ public static final String DNS_RESOLVER_MAX_SAMPLES = "dns_resolver_max_samples";
+
+ private static final int DNS_RESOLVER_DEFAULT_MIN_SAMPLES = 8;
+ private static final int DNS_RESOLVER_DEFAULT_MAX_SAMPLES = 64;
+
+ /** Network switch notification settings */
+
+ /**
+ * The maximum number of notifications shown in 24 hours when switching networks.
+ *
+ * @hide
+ */
+ public static final String NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT =
+ "network_switch_notification_daily_limit";
+
+ /**
+ * The minimum time in milliseconds between notifications when switching networks.
+ *
+ * @hide
+ */
+ public static final String NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS =
+ "network_switch_notification_rate_limit_millis";
+
+ /** Captive portal settings */
+
+ /**
+ * The URL used for HTTP captive portal detection upon a new connection.
+ * A 204 response code from the server is used for validation.
+ *
+ * @hide
+ */
+ public static final String CAPTIVE_PORTAL_HTTP_URL = "captive_portal_http_url";
+
+ /**
+ * What to do when connecting a network that presents a captive portal.
+ * Must be one of the CAPTIVE_PORTAL_MODE_* constants below.
+ *
+ * The default for this setting is CAPTIVE_PORTAL_MODE_PROMPT.
+ *
+ * @hide
+ */
+ public static final String CAPTIVE_PORTAL_MODE = "captive_portal_mode";
+
+ /**
+ * Don't attempt to detect captive portals.
+ */
+ public static final int CAPTIVE_PORTAL_MODE_IGNORE = 0;
+
+ /**
+ * When detecting a captive portal, display a notification that
+ * prompts the user to sign in.
+ */
+ public static final int CAPTIVE_PORTAL_MODE_PROMPT = 1;
+
+ /**
+ * When detecting a captive portal, immediately disconnect from the
+ * network and do not reconnect to that network in the future.
+ */
+ public static final int CAPTIVE_PORTAL_MODE_AVOID = 2;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(value = {
+ CAPTIVE_PORTAL_MODE_IGNORE,
+ CAPTIVE_PORTAL_MODE_PROMPT,
+ CAPTIVE_PORTAL_MODE_AVOID,
+ })
+ public @interface CaptivePortalMode {}
+
+ /** Global http proxy settings */
+
+ /**
+ * Host name for global http proxy. Set via ConnectivityManager.
+ *
+ * @hide
+ */
+ public static final String GLOBAL_HTTP_PROXY_HOST = "global_http_proxy_host";
+
+ /**
+ * Integer host port for global http proxy. Set via ConnectivityManager.
+ *
+ * @hide
+ */
+ public static final String GLOBAL_HTTP_PROXY_PORT = "global_http_proxy_port";
+
+ /**
+ * Exclusion list for global proxy. This string contains a list of
+ * comma-separated domains where the global proxy does not apply.
+ * Domains should be listed in a comma- separated list. Example of
+ * acceptable formats: ".domain1.com,my.domain2.com" Use
+ * ConnectivityManager to set/get.
+ *
+ * @hide
+ */
+ public static final String GLOBAL_HTTP_PROXY_EXCLUSION_LIST =
+ "global_http_proxy_exclusion_list";
+
+ /**
+ * The location PAC File for the proxy.
+ *
+ * @hide
+ */
+ public static final String GLOBAL_HTTP_PROXY_PAC = "global_proxy_pac_url";
+
+ /** Private dns settings */
+
+ /**
+ * The requested Private DNS mode (string), and an accompanying specifier (string).
+ *
+ * Currently, the specifier holds the chosen provider name when the mode requests
+ * a specific provider. It may be used to store the provider name even when the
+ * mode changes so that temporarily disabling and re-enabling the specific
+ * provider mode does not necessitate retyping the provider hostname.
+ *
+ * @hide
+ */
+ public static final String PRIVATE_DNS_MODE = "private_dns_mode";
+
+ /**
+ * The specific Private DNS provider name.
+ *
+ * @hide
+ */
+ public static final String PRIVATE_DNS_SPECIFIER = "private_dns_specifier";
+
+ /**
+ * Forced override of the default mode (hardcoded as "automatic", nee "opportunistic").
+ * This allows changing the default mode without effectively disabling other modes,
+ * all of which require explicit user action to enable/configure. See also b/79719289.
+ *
+ * Value is a string, suitable for assignment to PRIVATE_DNS_MODE above.
+ *
+ * @hide
+ */
+ public static final String PRIVATE_DNS_DEFAULT_MODE = "private_dns_default_mode";
+
+ /** Other settings */
+
+ /**
+ * The number of milliseconds to hold on to a PendingIntent based request. This delay gives
+ * the receivers of the PendingIntent an opportunity to make a new network request before
+ * the Network satisfying the request is potentially removed.
+ *
+ * @hide
+ */
+ public static final String CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS =
+ "connectivity_release_pending_intent_delay_ms";
+
+ /**
+ * Whether the mobile data connection should remain active even when higher
+ * priority networks like WiFi are active, to help make network switching faster.
+ *
+ * See ConnectivityService for more info.
+ *
+ * (0 = disabled, 1 = enabled)
+ *
+ * @hide
+ */
+ public static final String MOBILE_DATA_ALWAYS_ON = "mobile_data_always_on";
+
+ /**
+ * Whether the wifi data connection should remain active even when higher
+ * priority networks like Ethernet are active, to keep both networks.
+ * In the case where higher priority networks are connected, wifi will be
+ * unused unless an application explicitly requests to use it.
+ *
+ * See ConnectivityService for more info.
+ *
+ * (0 = disabled, 1 = enabled)
+ *
+ * @hide
+ */
+ public static final String WIFI_ALWAYS_REQUESTED = "wifi_always_requested";
+
+ /**
+ * Whether to automatically switch away from wifi networks that lose Internet access.
+ * Only meaningful if config_networkAvoidBadWifi is set to 0, otherwise the system always
+ * avoids such networks. Valid values are:
+ *
+ * 0: Don't avoid bad wifi, don't prompt the user. Get stuck on bad wifi like it's 2013.
+ * null: Ask the user whether to switch away from bad wifi.
+ * 1: Avoid bad wifi.
+ *
+ * @hide
+ */
+ public static final String NETWORK_AVOID_BAD_WIFI = "network_avoid_bad_wifi";
+
+ /**
+ * Don't avoid bad wifi, don't prompt the user. Get stuck on bad wifi like it's 2013.
+ */
+ public static final int NETWORK_AVOID_BAD_WIFI_IGNORE = 0;
+
+ /**
+ * Ask the user whether to switch away from bad wifi.
+ */
+ public static final int NETWORK_AVOID_BAD_WIFI_PROMPT = 1;
+
+ /**
+ * Avoid bad wifi.
+ */
+ public static final int NETWORK_AVOID_BAD_WIFI_AVOID = 2;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(value = {
+ NETWORK_AVOID_BAD_WIFI_IGNORE,
+ NETWORK_AVOID_BAD_WIFI_PROMPT,
+ NETWORK_AVOID_BAD_WIFI_AVOID,
+ })
+ public @interface NetworkAvoidBadWifi {}
+
+ /**
+ * User setting for ConnectivityManager.getMeteredMultipathPreference(). This value may be
+ * overridden by the system based on device or application state. If null, the value
+ * specified by config_networkMeteredMultipathPreference is used.
+ *
+ * @hide
+ */
+ public static final String NETWORK_METERED_MULTIPATH_PREFERENCE =
+ "network_metered_multipath_preference";
+
+ /**
+ * A list of apps that should go on cellular networks in preference even when higher-priority
+ * networks are connected.
+ *
+ * @hide
+ */
+ public static final String MOBILE_DATA_PREFERRED_APPS = "mobile_data_preferred_apps";
+
+ /**
+ * Get mobile data activity timeout from {@link Settings}.
+ *
+ * @param context The {@link Context} to query the setting.
+ * @param def The default timeout if no setting value.
+ * @return The {@link Duration} of timeout to track mobile data activity.
+ */
+ @NonNull
+ public static Duration getMobileDataActivityTimeout(@NonNull Context context,
+ @NonNull Duration def) {
+ final int timeout = Settings.Global.getInt(
+ context.getContentResolver(), DATA_ACTIVITY_TIMEOUT_MOBILE, (int) def.getSeconds());
+ return Duration.ofSeconds(timeout);
+ }
+
+ /**
+ * Set mobile data activity timeout to {@link Settings}.
+ * Tracking is disabled if set to zero or negative value.
+ *
+ * Note: Only use the number of seconds in this duration, lower second(nanoseconds) will be
+ * ignored.
+ *
+ * @param context The {@link Context} to set the setting.
+ * @param timeout The mobile data activity timeout.
+ */
+ public static void setMobileDataActivityTimeout(@NonNull Context context,
+ @NonNull Duration timeout) {
+ Settings.Global.putInt(context.getContentResolver(), DATA_ACTIVITY_TIMEOUT_MOBILE,
+ (int) timeout.getSeconds());
+ }
+
+ /**
+ * Get wifi data activity timeout from {@link Settings}.
+ *
+ * @param context The {@link Context} to query the setting.
+ * @param def The default timeout if no setting value.
+ * @return The {@link Duration} of timeout to track wifi data activity.
+ */
+ @NonNull
+ public static Duration getWifiDataActivityTimeout(@NonNull Context context,
+ @NonNull Duration def) {
+ final int timeout = Settings.Global.getInt(
+ context.getContentResolver(), DATA_ACTIVITY_TIMEOUT_WIFI, (int) def.getSeconds());
+ return Duration.ofSeconds(timeout);
+ }
+
+ /**
+ * Set wifi data activity timeout to {@link Settings}.
+ * Tracking is disabled if set to zero or negative value.
+ *
+ * Note: Only use the number of seconds in this duration, lower second(nanoseconds) will be
+ * ignored.
+ *
+ * @param context The {@link Context} to set the setting.
+ * @param timeout The wifi data activity timeout.
+ */
+ public static void setWifiDataActivityTimeout(@NonNull Context context,
+ @NonNull Duration timeout) {
+ Settings.Global.putInt(context.getContentResolver(), DATA_ACTIVITY_TIMEOUT_WIFI,
+ (int) timeout.getSeconds());
+ }
+
+ /**
+ * Get dns resolver sample validity duration from {@link Settings}.
+ *
+ * @param context The {@link Context} to query the setting.
+ * @param def The default duration if no setting value.
+ * @return The {@link Duration} of sample validity duration to configure for the system DNS
+ * resolver.
+ */
+ @NonNull
+ public static Duration getDnsResolverSampleValidityDuration(@NonNull Context context,
+ @NonNull Duration def) {
+ final int duration = Settings.Global.getInt(context.getContentResolver(),
+ DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS, (int) def.getSeconds());
+ return Duration.ofSeconds(duration);
+ }
+
+ /**
+ * Set dns resolver sample validity duration to {@link Settings}. The duration must be a
+ * positive number of seconds.
+ *
+ * @param context The {@link Context} to set the setting.
+ * @param duration The sample validity duration.
+ */
+ public static void setDnsResolverSampleValidityDuration(@NonNull Context context,
+ @NonNull Duration duration) {
+ final int time = (int) duration.getSeconds();
+ if (time <= 0) {
+ throw new IllegalArgumentException("Invalid duration");
+ }
+ Settings.Global.putInt(
+ context.getContentResolver(), DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS, time);
+ }
+
+ /**
+ * Get dns resolver success threshold percent from {@link Settings}.
+ *
+ * @param context The {@link Context} to query the setting.
+ * @param def The default value if no setting value.
+ * @return The success threshold in percent for use with the system DNS resolver.
+ */
+ public static int getDnsResolverSuccessThresholdPercent(@NonNull Context context, int def) {
+ return Settings.Global.getInt(
+ context.getContentResolver(), DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT, def);
+ }
+
+ /**
+ * Set dns resolver success threshold percent to {@link Settings}. The threshold percent must
+ * be 0~100.
+ *
+ * @param context The {@link Context} to set the setting.
+ * @param percent The success threshold percent.
+ */
+ public static void setDnsResolverSuccessThresholdPercent(@NonNull Context context,
+ @IntRange(from = 0, to = 100) int percent) {
+ if (percent < 0 || percent > 100) {
+ throw new IllegalArgumentException("Percent must be 0~100");
+ }
+ Settings.Global.putInt(
+ context.getContentResolver(), DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT, percent);
+ }
+
+ /**
+ * Get dns resolver samples range from {@link Settings}.
+ *
+ * @param context The {@link Context} to query the setting.
+ * @return The {@link Range<Integer>} of samples needed for statistics to be considered
+ * meaningful in the system DNS resolver.
+ */
+ @NonNull
+ public static Range<Integer> getDnsResolverSampleRanges(@NonNull Context context) {
+ final int minSamples = Settings.Global.getInt(context.getContentResolver(),
+ DNS_RESOLVER_MIN_SAMPLES, DNS_RESOLVER_DEFAULT_MIN_SAMPLES);
+ final int maxSamples = Settings.Global.getInt(context.getContentResolver(),
+ DNS_RESOLVER_MAX_SAMPLES, DNS_RESOLVER_DEFAULT_MAX_SAMPLES);
+ return new Range<>(minSamples, maxSamples);
+ }
+
+ /**
+ * Set dns resolver samples range to {@link Settings}.
+ *
+ * @param context The {@link Context} to set the setting.
+ * @param range The samples range. The minimum number should be more than 0 and the maximum
+ * number should be less that 64.
+ */
+ public static void setDnsResolverSampleRanges(@NonNull Context context,
+ @NonNull Range<Integer> range) {
+ if (range.getLower() < 0 || range.getUpper() > 64) {
+ throw new IllegalArgumentException("Argument must be 0~64");
+ }
+ Settings.Global.putInt(
+ context.getContentResolver(), DNS_RESOLVER_MIN_SAMPLES, range.getLower());
+ Settings.Global.putInt(
+ context.getContentResolver(), DNS_RESOLVER_MAX_SAMPLES, range.getUpper());
+ }
+
+ /**
+ * Get maximum count (from {@link Settings}) of switching network notifications shown in 24
+ * hours.
+ *
+ * @param context The {@link Context} to query the setting.
+ * @param def The default value if no setting value.
+ * @return The maximum count of notifications shown in 24 hours when switching networks.
+ */
+ public static int getNetworkSwitchNotificationMaximumDailyCount(@NonNull Context context,
+ int def) {
+ return Settings.Global.getInt(
+ context.getContentResolver(), NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT, def);
+ }
+
+ /**
+ * Set maximum count (to {@link Settings}) of switching network notifications shown in 24 hours.
+ * The count must be at least 0.
+ *
+ * @param context The {@link Context} to set the setting.
+ * @param count The maximum count of switching network notifications shown in 24 hours.
+ */
+ public static void setNetworkSwitchNotificationMaximumDailyCount(@NonNull Context context,
+ @IntRange(from = 0) int count) {
+ if (count < 0) {
+ throw new IllegalArgumentException("Count must be 0~10.");
+ }
+ Settings.Global.putInt(
+ context.getContentResolver(), NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT, count);
+ }
+
+ /**
+ * Get minimum duration (from {@link Settings}) between each switching network notifications.
+ *
+ * @param context The {@link Context} to query the setting.
+ * @param def The default time if no setting value.
+ * @return The minimum duration between notifications when switching networks.
+ */
+ @NonNull
+ public static Duration getNetworkSwitchNotificationRateDuration(@NonNull Context context,
+ @NonNull Duration def) {
+ final int duration = Settings.Global.getInt(context.getContentResolver(),
+ NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS, (int) def.toMillis());
+ return Duration.ofMillis(duration);
+ }
+
+ /**
+ * Set minimum duration (to {@link Settings}) between each switching network notifications.
+ *
+ * @param context The {@link Context} to set the setting.
+ * @param duration The minimum duration between notifications when switching networks.
+ */
+ public static void setNetworkSwitchNotificationRateDuration(@NonNull Context context,
+ @NonNull Duration duration) {
+ final int time = (int) duration.toMillis();
+ if (time < 0) {
+ throw new IllegalArgumentException("Invalid duration.");
+ }
+ Settings.Global.putInt(context.getContentResolver(),
+ NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS, time);
+ }
+
+ /**
+ * Get URL (from {@link Settings}) used for HTTP captive portal detection upon a new connection.
+ *
+ * @param context The {@link Context} to query the setting.
+ * @return The URL used for HTTP captive portal detection upon a new connection.
+ */
+ @Nullable
+ public static String getCaptivePortalHttpUrl(@NonNull Context context) {
+ return Settings.Global.getString(context.getContentResolver(), CAPTIVE_PORTAL_HTTP_URL);
+ }
+
+ /**
+ * Set URL (to {@link Settings}) used for HTTP captive portal detection upon a new connection.
+ * This URL should respond with a 204 response to a GET request to indicate no captive portal is
+ * present. And this URL must be HTTP as redirect responses are used to find captive portal
+ * sign-in pages. If the URL set to null or be incorrect, it will result in captive portal
+ * detection failed and lost the connection.
+ *
+ * @param context The {@link Context} to set the setting.
+ * @param url The URL used for HTTP captive portal detection upon a new connection.
+ */
+ public static void setCaptivePortalHttpUrl(@NonNull Context context, @Nullable String url) {
+ Settings.Global.putString(context.getContentResolver(), CAPTIVE_PORTAL_HTTP_URL, url);
+ }
+
+ /**
+ * Get mode (from {@link Settings}) when connecting a network that presents a captive portal.
+ *
+ * @param context The {@link Context} to query the setting.
+ * @param def The default mode if no setting value.
+ * @return The mode when connecting a network that presents a captive portal.
+ */
+ @CaptivePortalMode
+ public static int getCaptivePortalMode(@NonNull Context context,
+ @CaptivePortalMode int def) {
+ return Settings.Global.getInt(context.getContentResolver(), CAPTIVE_PORTAL_MODE, def);
+ }
+
+ /**
+ * Set mode (to {@link Settings}) when connecting a network that presents a captive portal.
+ *
+ * @param context The {@link Context} to set the setting.
+ * @param mode The mode when connecting a network that presents a captive portal.
+ */
+ public static void setCaptivePortalMode(@NonNull Context context, @CaptivePortalMode int mode) {
+ if (!(mode == CAPTIVE_PORTAL_MODE_IGNORE
+ || mode == CAPTIVE_PORTAL_MODE_PROMPT
+ || mode == CAPTIVE_PORTAL_MODE_AVOID)) {
+ throw new IllegalArgumentException("Invalid captive portal mode");
+ }
+ Settings.Global.putInt(context.getContentResolver(), CAPTIVE_PORTAL_MODE, mode);
+ }
+
+ /**
+ * Get the global HTTP proxy applied to the device, or null if none.
+ *
+ * @param context The {@link Context} to query the setting.
+ * @return The {@link ProxyInfo} which build from global http proxy settings.
+ */
+ @Nullable
+ public static ProxyInfo getGlobalProxy(@NonNull Context context) {
+ final String host = Settings.Global.getString(
+ context.getContentResolver(), GLOBAL_HTTP_PROXY_HOST);
+ final int port = Settings.Global.getInt(
+ context.getContentResolver(), GLOBAL_HTTP_PROXY_PORT, 0 /* def */);
+ final String exclusionList = Settings.Global.getString(
+ context.getContentResolver(), GLOBAL_HTTP_PROXY_EXCLUSION_LIST);
+ final String pacFileUrl = Settings.Global.getString(
+ context.getContentResolver(), GLOBAL_HTTP_PROXY_PAC);
+
+ if (TextUtils.isEmpty(host) && TextUtils.isEmpty(pacFileUrl)) {
+ return null; // No global proxy.
+ }
+
+ if (TextUtils.isEmpty(pacFileUrl)) {
+ return ProxyInfo.buildDirectProxy(
+ host, port, ProxyUtils.exclusionStringAsList(exclusionList));
+ } else {
+ return ProxyInfo.buildPacProxy(Uri.parse(pacFileUrl));
+ }
+ }
+
+ /**
+ * Set global http proxy settings from given {@link ProxyInfo}.
+ *
+ * @param context The {@link Context} to set the setting.
+ * @param proxyInfo The {@link ProxyInfo} for global http proxy settings which build from
+ * {@link ProxyInfo#buildPacProxy(Uri)} or
+ * {@link ProxyInfo#buildDirectProxy(String, int, List)}
+ */
+ public static void setGlobalProxy(@NonNull Context context, @NonNull ProxyInfo proxyInfo) {
+ final String host = proxyInfo.getHost();
+ final int port = proxyInfo.getPort();
+ final String exclusionList = proxyInfo.getExclusionListAsString();
+ final String pacFileUrl = proxyInfo.getPacFileUrl().toString();
+
+ if (TextUtils.isEmpty(pacFileUrl)) {
+ Settings.Global.putString(context.getContentResolver(), GLOBAL_HTTP_PROXY_HOST, host);
+ Settings.Global.putInt(context.getContentResolver(), GLOBAL_HTTP_PROXY_PORT, port);
+ Settings.Global.putString(
+ context.getContentResolver(), GLOBAL_HTTP_PROXY_EXCLUSION_LIST, exclusionList);
+ Settings.Global.putString(
+ context.getContentResolver(), GLOBAL_HTTP_PROXY_PAC, "" /* value */);
+ } else {
+ Settings.Global.putString(
+ context.getContentResolver(), GLOBAL_HTTP_PROXY_PAC, pacFileUrl);
+ Settings.Global.putString(
+ context.getContentResolver(), GLOBAL_HTTP_PROXY_HOST, "" /* value */);
+ Settings.Global.putInt(
+ context.getContentResolver(), GLOBAL_HTTP_PROXY_PORT, 0 /* value */);
+ Settings.Global.putString(
+ context.getContentResolver(), GLOBAL_HTTP_PROXY_EXCLUSION_LIST, "" /* value */);
+ }
+ }
+
+ /**
+ * Clear all global http proxy settings.
+ *
+ * @param context The {@link Context} to set the setting.
+ */
+ public static void clearGlobalProxy(@NonNull Context context) {
+ Settings.Global.putString(
+ context.getContentResolver(), GLOBAL_HTTP_PROXY_HOST, "" /* value */);
+ Settings.Global.putInt(
+ context.getContentResolver(), GLOBAL_HTTP_PROXY_PORT, 0 /* value */);
+ Settings.Global.putString(
+ context.getContentResolver(), GLOBAL_HTTP_PROXY_EXCLUSION_LIST, "" /* value */);
+ Settings.Global.putString(
+ context.getContentResolver(), GLOBAL_HTTP_PROXY_PAC, "" /* value */);
+ }
+
+ /**
+ * Get specific private dns provider name from {@link Settings}.
+ *
+ * @param context The {@link Context} to query the setting.
+ * @return The specific private dns provider name, or null if no setting value.
+ */
+ @Nullable
+ public static String getPrivateDnsHostname(@NonNull Context context) {
+ return Settings.Global.getString(context.getContentResolver(), PRIVATE_DNS_SPECIFIER);
+ }
+
+ /**
+ * Set specific private dns provider name to {@link Settings}.
+ *
+ * @param context The {@link Context} to set the setting.
+ * @param specifier The specific private dns provider name.
+ */
+ public static void setPrivateDnsHostname(@NonNull Context context,
+ @Nullable String specifier) {
+ Settings.Global.putString(context.getContentResolver(), PRIVATE_DNS_SPECIFIER, specifier);
+ }
+
+ /**
+ * Get default private dns mode from {@link Settings}.
+ *
+ * @param context The {@link Context} to query the setting.
+ * @return The default private dns mode.
+ */
+ @PrivateDnsMode
+ @NonNull
+ public static String getPrivateDnsDefaultMode(@NonNull Context context) {
+ return Settings.Global.getString(context.getContentResolver(), PRIVATE_DNS_DEFAULT_MODE);
+ }
+
+ /**
+ * Set default private dns mode to {@link Settings}.
+ *
+ * @param context The {@link Context} to set the setting.
+ * @param mode The default private dns mode. This should be one of the PRIVATE_DNS_MODE_*
+ * constants.
+ */
+ public static void setPrivateDnsDefaultMode(@NonNull Context context,
+ @NonNull @PrivateDnsMode String mode) {
+ if (!(mode == PRIVATE_DNS_MODE_OFF
+ || mode == PRIVATE_DNS_MODE_OPPORTUNISTIC
+ || mode == PRIVATE_DNS_MODE_PROVIDER_HOSTNAME)) {
+ throw new IllegalArgumentException("Invalid private dns mode");
+ }
+ Settings.Global.putString(context.getContentResolver(), PRIVATE_DNS_DEFAULT_MODE, mode);
+ }
+
+ /**
+ * Get duration (from {@link Settings}) to keep a PendingIntent-based request.
+ *
+ * @param context The {@link Context} to query the setting.
+ * @param def The default duration if no setting value.
+ * @return The duration to keep a PendingIntent-based request.
+ */
+ @NonNull
+ public static Duration getConnectivityKeepPendingIntentDuration(@NonNull Context context,
+ @NonNull Duration def) {
+ final int duration = Settings.Secure.getInt(context.getContentResolver(),
+ CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS, (int) def.toMillis());
+ return Duration.ofMillis(duration);
+ }
+
+ /**
+ * Set duration (to {@link Settings}) to keep a PendingIntent-based request.
+ *
+ * @param context The {@link Context} to set the setting.
+ * @param duration The duration to keep a PendingIntent-based request.
+ */
+ public static void setConnectivityKeepPendingIntentDuration(@NonNull Context context,
+ @NonNull Duration duration) {
+ final int time = (int) duration.toMillis();
+ if (time < 0) {
+ throw new IllegalArgumentException("Invalid duration.");
+ }
+ Settings.Secure.putInt(
+ context.getContentResolver(), CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS, time);
+ }
+
+ /**
+ * Read from {@link Settings} whether the mobile data connection should remain active
+ * even when higher priority networks are active.
+ *
+ * @param context The {@link Context} to query the setting.
+ * @param def The default value if no setting value.
+ * @return Whether the mobile data connection should remain active even when higher
+ * priority networks are active.
+ */
+ public static boolean getMobileDataAlwaysOn(@NonNull Context context, boolean def) {
+ final int enable = Settings.Global.getInt(
+ context.getContentResolver(), MOBILE_DATA_ALWAYS_ON, (def ? 1 : 0));
+ return (enable != 0) ? true : false;
+ }
+
+ /**
+ * Write into {@link Settings} whether the mobile data connection should remain active
+ * even when higher priority networks are active.
+ *
+ * @param context The {@link Context} to set the setting.
+ * @param enable Whether the mobile data connection should remain active even when higher
+ * priority networks are active.
+ */
+ public static void setMobileDataAlwaysOn(@NonNull Context context, boolean enable) {
+ Settings.Global.putInt(
+ context.getContentResolver(), MOBILE_DATA_ALWAYS_ON, (enable ? 1 : 0));
+ }
+
+ /**
+ * Read from {@link Settings} whether the wifi data connection should remain active
+ * even when higher priority networks are active.
+ *
+ * @param context The {@link Context} to query the setting.
+ * @param def The default value if no setting value.
+ * @return Whether the wifi data connection should remain active even when higher
+ * priority networks are active.
+ */
+ public static boolean getWifiAlwaysRequested(@NonNull Context context, boolean def) {
+ final int enable = Settings.Global.getInt(
+ context.getContentResolver(), WIFI_ALWAYS_REQUESTED, (def ? 1 : 0));
+ return (enable != 0) ? true : false;
+ }
+
+ /**
+ * Write into {@link Settings} whether the wifi data connection should remain active
+ * even when higher priority networks are active.
+ *
+ * @param context The {@link Context} to set the setting.
+ * @param enable Whether the wifi data connection should remain active even when higher
+ * priority networks are active
+ */
+ public static void setWifiAlwaysRequested(@NonNull Context context, boolean enable) {
+ Settings.Global.putInt(
+ context.getContentResolver(), WIFI_ALWAYS_REQUESTED, (enable ? 1 : 0));
+ }
+
+ /**
+ * Get avoid bad wifi setting from {@link Settings}.
+ *
+ * @param context The {@link Context} to query the setting.
+ * @return The setting whether to automatically switch away from wifi networks that lose
+ * internet access.
+ */
+ @NetworkAvoidBadWifi
+ public static int getNetworkAvoidBadWifi(@NonNull Context context) {
+ final String setting =
+ Settings.Global.getString(context.getContentResolver(), NETWORK_AVOID_BAD_WIFI);
+ if ("0".equals(setting)) {
+ return NETWORK_AVOID_BAD_WIFI_IGNORE;
+ } else if ("1".equals(setting)) {
+ return NETWORK_AVOID_BAD_WIFI_AVOID;
+ } else {
+ return NETWORK_AVOID_BAD_WIFI_PROMPT;
+ }
+ }
+
+ /**
+ * Set avoid bad wifi setting to {@link Settings}.
+ *
+ * @param context The {@link Context} to set the setting.
+ * @param value Whether to automatically switch away from wifi networks that lose internet
+ * access.
+ */
+ public static void setNetworkAvoidBadWifi(@NonNull Context context,
+ @NetworkAvoidBadWifi int value) {
+ final String setting;
+ if (value == NETWORK_AVOID_BAD_WIFI_IGNORE) {
+ setting = "0";
+ } else if (value == NETWORK_AVOID_BAD_WIFI_AVOID) {
+ setting = "1";
+ } else if (value == NETWORK_AVOID_BAD_WIFI_PROMPT) {
+ setting = null;
+ } else {
+ throw new IllegalArgumentException("Invalid avoid bad wifi setting");
+ }
+ Settings.Global.putString(context.getContentResolver(), NETWORK_AVOID_BAD_WIFI, setting);
+ }
+
+ /**
+ * Get network metered multipath preference from {@link Settings}.
+ *
+ * @param context The {@link Context} to query the setting.
+ * @return The network metered multipath preference which should be one of
+ * ConnectivityManager#MULTIPATH_PREFERENCE_* value or null if the value specified
+ * by config_networkMeteredMultipathPreference is used.
+ */
+ @Nullable
+ public static String getNetworkMeteredMultipathPreference(@NonNull Context context) {
+ return Settings.Global.getString(
+ context.getContentResolver(), NETWORK_METERED_MULTIPATH_PREFERENCE);
+ }
+
+ /**
+ * Set network metered multipath preference to {@link Settings}.
+ *
+ * @param context The {@link Context} to set the setting.
+ * @param preference The network metered multipath preference which should be one of
+ * ConnectivityManager#MULTIPATH_PREFERENCE_* value or null if the value
+ * specified by config_networkMeteredMultipathPreference is used.
+ */
+ public static void setNetworkMeteredMultipathPreference(@NonNull Context context,
+ @NonNull @MultipathPreference String preference) {
+ if (!(Integer.valueOf(preference) == MULTIPATH_PREFERENCE_HANDOVER
+ || Integer.valueOf(preference) == MULTIPATH_PREFERENCE_RELIABILITY
+ || Integer.valueOf(preference) == MULTIPATH_PREFERENCE_PERFORMANCE)) {
+ throw new IllegalArgumentException("Invalid private dns mode");
+ }
+ Settings.Global.putString(
+ context.getContentResolver(), NETWORK_METERED_MULTIPATH_PREFERENCE, preference);
+ }
+
+ /**
+ * Get the list of apps(from {@link Settings}) that should go on cellular networks in preference
+ * even when higher-priority networks are connected.
+ *
+ * @param context The {@link Context} to query the setting.
+ * @return A list of apps that should go on cellular networks in preference even when
+ * higher-priority networks are connected or null if no setting value.
+ */
+ @Nullable
+ public static String getMobileDataPreferredApps(@NonNull Context context) {
+ return Settings.Secure.getString(context.getContentResolver(), MOBILE_DATA_PREFERRED_APPS);
+ }
+
+ /**
+ * Set the list of apps(to {@link Settings}) that should go on cellular networks in preference
+ * even when higher-priority networks are connected.
+ *
+ * @param context The {@link Context} to set the setting.
+ * @param list A list of apps that should go on cellular networks in preference even when
+ * higher-priority networks are connected.
+ */
+ public static void setMobileDataPreferredApps(@NonNull Context context, @Nullable String list) {
+ Settings.Secure.putString(context.getContentResolver(), MOBILE_DATA_PREFERRED_APPS, list);
+ }
+}
diff --git a/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl b/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl
index cd49258..0826922 100644
--- a/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl
+++ b/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl
@@ -20,7 +20,8 @@
import android.net.ConnectionInfo;
import android.net.ConnectivityDiagnosticsManager;
import android.net.IConnectivityDiagnosticsCallback;
-import android.net.IOnSetOemNetworkPreferenceListener;
+import android.net.INetworkAgent;
+import android.net.IOnCompleteListener;
import android.net.INetworkActivityListener;
import android.net.IQosCallback;
import android.net.ISocketKeepaliveCallback;
@@ -30,6 +31,7 @@
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.NetworkRequest;
+import android.net.NetworkScore;
import android.net.NetworkState;
import android.net.NetworkStateSnapshot;
import android.net.OemNetworkPreferences;
@@ -42,8 +44,7 @@
import android.os.ParcelFileDescriptor;
import android.os.PersistableBundle;
import android.os.ResultReceiver;
-
-import com.android.connectivity.aidl.INetworkAgent;
+import android.os.UserHandle;
/**
* Interface that answers queries about, and allows changing, the
@@ -138,12 +139,12 @@
void declareNetworkRequestUnfulfillable(in NetworkRequest request);
Network registerNetworkAgent(in INetworkAgent na, in NetworkInfo ni, in LinkProperties lp,
- in NetworkCapabilities nc, int score, in NetworkAgentConfig config,
+ in NetworkCapabilities nc, in NetworkScore score, in NetworkAgentConfig config,
in int factorySerialNumber);
- NetworkRequest requestNetwork(in NetworkCapabilities networkCapabilities, int reqType,
+ NetworkRequest requestNetwork(int uid, in NetworkCapabilities networkCapabilities, int reqType,
in Messenger messenger, int timeoutSec, in IBinder binder, int legacy,
- String callingPackageName, String callingAttributionTag);
+ int callbackFlags, String callingPackageName, String callingAttributionTag);
NetworkRequest pendingRequestForNetwork(in NetworkCapabilities networkCapabilities,
in PendingIntent operation, String callingPackageName, String callingAttributionTag);
@@ -151,7 +152,7 @@
void releasePendingNetworkRequest(in PendingIntent operation);
NetworkRequest listenForNetwork(in NetworkCapabilities networkCapabilities,
- in Messenger messenger, in IBinder binder, String callingPackageName,
+ in Messenger messenger, in IBinder binder, int callbackFlags, String callingPackageName,
String callingAttributionTag);
void pendingListenForNetwork(in NetworkCapabilities networkCapabilities,
@@ -214,5 +215,10 @@
void unregisterQosCallback(in IQosCallback callback);
void setOemNetworkPreference(in OemNetworkPreferences preference,
- in IOnSetOemNetworkPreferenceListener listener);
+ in IOnCompleteListener listener);
+
+ void setProfileNetworkPreference(in UserHandle profile, int preference,
+ in IOnCompleteListener listener);
+
+ int getRestrictBackgroundStatusByCaller();
}
diff --git a/packages/Connectivity/framework/src/com/android/connectivity/aidl/INetworkAgent.aidl b/packages/Connectivity/framework/src/android/net/INetworkAgent.aidl
similarity index 93%
rename from packages/Connectivity/framework/src/com/android/connectivity/aidl/INetworkAgent.aidl
rename to packages/Connectivity/framework/src/android/net/INetworkAgent.aidl
index 64b5567..f9d3994 100644
--- a/packages/Connectivity/framework/src/com/android/connectivity/aidl/INetworkAgent.aidl
+++ b/packages/Connectivity/framework/src/android/net/INetworkAgent.aidl
@@ -13,13 +13,13 @@
* See the License for the specific language governing perNmissions and
* limitations under the License.
*/
-package com.android.connectivity.aidl;
+package android.net;
import android.net.NattKeepalivePacketData;
import android.net.QosFilterParcelable;
import android.net.TcpKeepalivePacketData;
-import com.android.connectivity.aidl.INetworkAgentRegistry;
+import android.net.INetworkAgentRegistry;
/**
* Interface to notify NetworkAgent of connectivity events.
@@ -46,4 +46,6 @@
void onRemoveKeepalivePacketFilter(int slot);
void onQosFilterCallbackRegistered(int qosCallbackId, in QosFilterParcelable filterParcel);
void onQosCallbackUnregistered(int qosCallbackId);
+ void onNetworkCreated();
+ void onNetworkDisconnected();
}
diff --git a/packages/Connectivity/framework/src/com/android/connectivity/aidl/INetworkAgentRegistry.aidl b/packages/Connectivity/framework/src/android/net/INetworkAgentRegistry.aidl
similarity index 83%
rename from packages/Connectivity/framework/src/com/android/connectivity/aidl/INetworkAgentRegistry.aidl
rename to packages/Connectivity/framework/src/android/net/INetworkAgentRegistry.aidl
index f0193db..cbd6193 100644
--- a/packages/Connectivity/framework/src/com/android/connectivity/aidl/INetworkAgentRegistry.aidl
+++ b/packages/Connectivity/framework/src/android/net/INetworkAgentRegistry.aidl
@@ -13,17 +13,19 @@
* See the License for the specific language governing perNmissions and
* limitations under the License.
*/
-package com.android.connectivity.aidl;
+package android.net;
import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
+import android.net.NetworkScore;
import android.net.QosSession;
import android.telephony.data.EpsBearerQosSessionAttributes;
+import android.telephony.data.NrQosSessionAttributes;
/**
- * Interface for NetworkAgents to send network network properties.
+ * Interface for NetworkAgents to send network properties.
* @hide
*/
oneway interface INetworkAgentRegistry {
@@ -31,11 +33,12 @@
void sendLinkProperties(in LinkProperties lp);
// TODO: consider replacing this by "markConnected()" and removing
void sendNetworkInfo(in NetworkInfo info);
- void sendScore(int score);
+ void sendScore(in NetworkScore score);
void sendExplicitlySelected(boolean explicitlySelected, boolean acceptPartial);
void sendSocketKeepaliveEvent(int slot, int reason);
void sendUnderlyingNetworks(in @nullable List<Network> networks);
void sendEpsQosSessionAvailable(int callbackId, in QosSession session, in EpsBearerQosSessionAttributes attributes);
+ void sendNrQosSessionAvailable(int callbackId, in QosSession session, in NrQosSessionAttributes attributes);
void sendQosSessionLost(int qosCallbackId, in QosSession session);
void sendQosCallbackError(int qosCallbackId, int exceptionType);
}
diff --git a/packages/Connectivity/framework/src/android/net/IOnSetOemNetworkPreferenceListener.aidl b/packages/Connectivity/framework/src/android/net/IOnCompleteListener.aidl
similarity index 92%
rename from packages/Connectivity/framework/src/android/net/IOnSetOemNetworkPreferenceListener.aidl
rename to packages/Connectivity/framework/src/android/net/IOnCompleteListener.aidl
index 7979afc..4bb89f6c 100644
--- a/packages/Connectivity/framework/src/android/net/IOnSetOemNetworkPreferenceListener.aidl
+++ b/packages/Connectivity/framework/src/android/net/IOnCompleteListener.aidl
@@ -18,6 +18,6 @@
package android.net;
/** @hide */
-oneway interface IOnSetOemNetworkPreferenceListener {
+oneway interface IOnCompleteListener {
void onComplete();
}
diff --git a/packages/Connectivity/framework/src/android/net/IQosCallback.aidl b/packages/Connectivity/framework/src/android/net/IQosCallback.aidl
index 91c7575..c973541 100644
--- a/packages/Connectivity/framework/src/android/net/IQosCallback.aidl
+++ b/packages/Connectivity/framework/src/android/net/IQosCallback.aidl
@@ -19,6 +19,7 @@
import android.os.Bundle;
import android.net.QosSession;
import android.telephony.data.EpsBearerQosSessionAttributes;
+import android.telephony.data.NrQosSessionAttributes;
/**
* AIDL interface for QosCallback
@@ -29,6 +30,8 @@
{
void onQosEpsBearerSessionAvailable(in QosSession session,
in EpsBearerQosSessionAttributes attributes);
+ void onNrQosSessionAvailable(in QosSession session,
+ in NrQosSessionAttributes attributes);
void onQosSessionLost(in QosSession session);
void onError(in int type);
}
diff --git a/packages/Connectivity/framework/src/android/net/InetAddressCompat.java b/packages/Connectivity/framework/src/android/net/InetAddressCompat.java
new file mode 100644
index 0000000..6b7e75c
--- /dev/null
+++ b/packages/Connectivity/framework/src/android/net/InetAddressCompat.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.util.Log;
+
+import java.lang.reflect.InvocationTargetException;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+/**
+ * Compatibility utility for InetAddress core platform APIs.
+ *
+ * Connectivity has access to such APIs, but they are not part of the module_current stubs yet
+ * (only core_current). Most stable core platform APIs are included manually in the connectivity
+ * build rules, but because InetAddress is also part of the base java SDK that is earlier on the
+ * classpath, the extra core platform APIs are not seen.
+ *
+ * TODO (b/183097033): remove this utility as soon as core_current is part of module_current
+ * @hide
+ */
+public class InetAddressCompat {
+
+ /**
+ * @see InetAddress#clearDnsCache()
+ */
+ public static void clearDnsCache() {
+ try {
+ InetAddress.class.getMethod("clearDnsCache").invoke(null);
+ } catch (InvocationTargetException e) {
+ if (e.getCause() instanceof RuntimeException) {
+ throw (RuntimeException) e.getCause();
+ }
+ throw new IllegalStateException("Unknown InvocationTargetException", e.getCause());
+ } catch (IllegalAccessException | NoSuchMethodException e) {
+ Log.wtf(InetAddressCompat.class.getSimpleName(), "Error clearing DNS cache", e);
+ }
+ }
+
+ /**
+ * @see InetAddress#getAllByNameOnNet(String, int)
+ */
+ public static InetAddress[] getAllByNameOnNet(String host, int netId) throws
+ UnknownHostException {
+ return (InetAddress[]) callGetByNameMethod("getAllByNameOnNet", host, netId);
+ }
+
+ /**
+ * @see InetAddress#getByNameOnNet(String, int)
+ */
+ public static InetAddress getByNameOnNet(String host, int netId) throws
+ UnknownHostException {
+ return (InetAddress) callGetByNameMethod("getByNameOnNet", host, netId);
+ }
+
+ private static Object callGetByNameMethod(String method, String host, int netId)
+ throws UnknownHostException {
+ try {
+ return InetAddress.class.getMethod(method, String.class, int.class)
+ .invoke(null, host, netId);
+ } catch (InvocationTargetException e) {
+ if (e.getCause() instanceof UnknownHostException) {
+ throw (UnknownHostException) e.getCause();
+ }
+ if (e.getCause() instanceof RuntimeException) {
+ throw (RuntimeException) e.getCause();
+ }
+ throw new IllegalStateException("Unknown InvocationTargetException", e.getCause());
+ } catch (IllegalAccessException | NoSuchMethodException e) {
+ Log.wtf(InetAddressCompat.class.getSimpleName(), "Error calling " + method, e);
+ throw new IllegalStateException("Error querying via " + method, e);
+ }
+ }
+}
diff --git a/packages/Connectivity/framework/src/android/net/IpPrefix.java b/packages/Connectivity/framework/src/android/net/IpPrefix.java
index d2ee7d1..bf4481a 100644
--- a/packages/Connectivity/framework/src/android/net/IpPrefix.java
+++ b/packages/Connectivity/framework/src/android/net/IpPrefix.java
@@ -113,7 +113,7 @@
// first statement in constructor". We could factor out setting the member variables to an
// init() method, but if we did, then we'd have to make the members non-final, or "error:
// cannot assign a value to final variable address". So we just duplicate the code here.
- Pair<InetAddress, Integer> ipAndMask = NetworkUtils.parseIpAndMask(prefix);
+ Pair<InetAddress, Integer> ipAndMask = NetworkUtils.legacyParseIpAndMask(prefix);
this.address = ipAndMask.first.getAddress();
this.prefixLength = ipAndMask.second;
checkAndMaskAddressAndPrefixLength();
diff --git a/packages/Connectivity/framework/src/android/net/LinkAddress.java b/packages/Connectivity/framework/src/android/net/LinkAddress.java
index d1bdaa0..d48b8c7 100644
--- a/packages/Connectivity/framework/src/android/net/LinkAddress.java
+++ b/packages/Connectivity/framework/src/android/net/LinkAddress.java
@@ -325,7 +325,7 @@
public LinkAddress(@NonNull String address, int flags, int scope) {
// This may throw an IllegalArgumentException; catching it is the caller's responsibility.
// TODO: consider rejecting mapped IPv4 addresses such as "::ffff:192.0.2.5/24".
- Pair<InetAddress, Integer> ipAndMask = NetworkUtils.parseIpAndMask(address);
+ Pair<InetAddress, Integer> ipAndMask = NetworkUtils.legacyParseIpAndMask(address);
init(ipAndMask.first, ipAndMask.second, flags, scope, LIFETIME_UNKNOWN, LIFETIME_UNKNOWN);
}
diff --git a/packages/Connectivity/framework/src/android/net/MacAddress.java b/packages/Connectivity/framework/src/android/net/MacAddress.java
index c83c23a..26a504a 100644
--- a/packages/Connectivity/framework/src/android/net/MacAddress.java
+++ b/packages/Connectivity/framework/src/android/net/MacAddress.java
@@ -25,7 +25,6 @@
import android.os.Parcel;
import android.os.Parcelable;
-import com.android.internal.util.Preconditions;
import com.android.net.module.util.MacAddressUtils;
import java.lang.annotation.Retention;
@@ -34,6 +33,7 @@
import java.net.UnknownHostException;
import java.security.SecureRandom;
import java.util.Arrays;
+import java.util.Objects;
/**
* Representation of a MAC address.
@@ -229,7 +229,7 @@
* @hide
*/
public static @NonNull byte[] byteAddrFromStringAddr(String addr) {
- Preconditions.checkNotNull(addr);
+ Objects.requireNonNull(addr);
String[] parts = addr.split(":");
if (parts.length != ETHER_ADDR_LEN) {
throw new IllegalArgumentException(addr + " was not a valid MAC address");
@@ -275,7 +275,7 @@
// Internal conversion function equivalent to longAddrFromByteAddr(byteAddrFromStringAddr(addr))
// that avoids the allocation of an intermediary byte[].
private static long longAddrFromStringAddr(String addr) {
- Preconditions.checkNotNull(addr);
+ Objects.requireNonNull(addr);
String[] parts = addr.split(":");
if (parts.length != ETHER_ADDR_LEN) {
throw new IllegalArgumentException(addr + " was not a valid MAC address");
@@ -364,8 +364,8 @@
*
*/
public boolean matches(@NonNull MacAddress baseAddress, @NonNull MacAddress mask) {
- Preconditions.checkNotNull(baseAddress);
- Preconditions.checkNotNull(mask);
+ Objects.requireNonNull(baseAddress);
+ Objects.requireNonNull(mask);
return (mAddr & mask.mAddr) == (baseAddress.mAddr & mask.mAddr);
}
diff --git a/packages/Connectivity/framework/src/android/net/Network.java b/packages/Connectivity/framework/src/android/net/Network.java
index 46141e0..0741414 100644
--- a/packages/Connectivity/framework/src/android/net/Network.java
+++ b/packages/Connectivity/framework/src/android/net/Network.java
@@ -30,10 +30,10 @@
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
-import com.android.okhttp.internalandroidapi.Dns;
-import com.android.okhttp.internalandroidapi.HttpURLConnectionFactory;
import libcore.io.IoUtils;
+import libcore.net.http.Dns;
+import libcore.net.http.HttpURLConnectionFactory;
import java.io.FileDescriptor;
import java.io.IOException;
@@ -142,7 +142,7 @@
* @throws UnknownHostException if the address lookup fails.
*/
public InetAddress[] getAllByName(String host) throws UnknownHostException {
- return InetAddress.getAllByNameOnNet(host, getNetIdForResolv());
+ return InetAddressCompat.getAllByNameOnNet(host, getNetIdForResolv());
}
/**
@@ -155,7 +155,7 @@
* if the address lookup fails.
*/
public InetAddress getByName(String host) throws UnknownHostException {
- return InetAddress.getByNameOnNet(host, getNetIdForResolv());
+ return InetAddressCompat.getByNameOnNet(host, getNetIdForResolv());
}
/**
@@ -299,7 +299,7 @@
// Set configuration on the HttpURLConnectionFactory that will be good for all
// connections created by this Network. Configuration that might vary is left
// until openConnection() and passed as arguments.
- HttpURLConnectionFactory urlConnectionFactory = new HttpURLConnectionFactory();
+ HttpURLConnectionFactory urlConnectionFactory = HttpURLConnectionFactory.createInstance();
urlConnectionFactory.setDns(dnsLookup); // Let traffic go via dnsLookup
// A private connection pool just for this Network.
urlConnectionFactory.setNewConnectionPool(httpMaxConnections,
diff --git a/packages/Connectivity/framework/src/android/net/NetworkAgent.java b/packages/Connectivity/framework/src/android/net/NetworkAgent.java
index 27aa15d..01b88aa 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkAgent.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkAgent.java
@@ -32,12 +32,10 @@
import android.os.Message;
import android.os.RemoteException;
import android.telephony.data.EpsBearerQosSessionAttributes;
+import android.telephony.data.NrQosSessionAttributes;
import android.util.Log;
-import com.android.connectivity.aidl.INetworkAgent;
-import com.android.connectivity.aidl.INetworkAgentRegistry;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.Protocol;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -125,7 +123,10 @@
*/
public final int providerId;
- private static final int BASE = Protocol.BASE_NETWORK_AGENT;
+ // ConnectivityService parses message constants from itself and NetworkAgent with MessageUtils
+ // for debugging purposes, and crashes if some messages have the same values.
+ // TODO: have ConnectivityService store message names in different maps and remove this base
+ private static final int BASE = 200;
/**
* Sent by ConnectivityService to the NetworkAgent to inform it of
@@ -361,6 +362,22 @@
*/
public static final int CMD_UNREGISTER_QOS_CALLBACK = BASE + 21;
+ /**
+ * Sent by ConnectivityService to {@link NetworkAgent} to inform the agent that its native
+ * network was created and the Network object is now valid.
+ *
+ * @hide
+ */
+ public static final int CMD_NETWORK_CREATED = BASE + 22;
+
+ /**
+ * Sent by ConnectivityService to {@link NetworkAgent} to inform the agent that its native
+ * network was destroyed.
+ *
+ * @hide
+ */
+ public static final int CMD_NETWORK_DISCONNECTED = BASE + 23;
+
private static NetworkInfo getLegacyNetworkInfo(final NetworkAgentConfig config) {
// The subtype can be changed with (TODO) setLegacySubtype, but it starts
// with 0 (TelephonyManager.NETWORK_TYPE_UNKNOWN) and an empty description.
@@ -371,6 +388,14 @@
return ni;
}
+ // Temporary backward compatibility constructor
+ public NetworkAgent(@NonNull Context context, @NonNull Looper looper, @NonNull String logTag,
+ @NonNull NetworkCapabilities nc, @NonNull LinkProperties lp, int score,
+ @NonNull NetworkAgentConfig config, @Nullable NetworkProvider provider) {
+ this(context, looper, logTag, nc, lp,
+ new NetworkScore.Builder().setLegacyInt(score).build(), config, provider);
+ }
+
/**
* Create a new network agent.
* @param context a {@link Context} to get system services from.
@@ -384,8 +409,9 @@
* @param provider the {@link NetworkProvider} managing this agent.
*/
public NetworkAgent(@NonNull Context context, @NonNull Looper looper, @NonNull String logTag,
- @NonNull NetworkCapabilities nc, @NonNull LinkProperties lp, int score,
- @NonNull NetworkAgentConfig config, @Nullable NetworkProvider provider) {
+ @NonNull NetworkCapabilities nc, @NonNull LinkProperties lp,
+ @NonNull NetworkScore score, @NonNull NetworkAgentConfig config,
+ @Nullable NetworkProvider provider) {
this(looper, context, logTag, nc, lp, score, config,
provider == null ? NetworkProvider.ID_NONE : provider.getProviderId(),
getLegacyNetworkInfo(config));
@@ -395,12 +421,12 @@
public final Context context;
public final NetworkCapabilities capabilities;
public final LinkProperties properties;
- public final int score;
+ public final NetworkScore score;
public final NetworkAgentConfig config;
public final NetworkInfo info;
InitialConfiguration(@NonNull Context context, @NonNull NetworkCapabilities capabilities,
- @NonNull LinkProperties properties, int score, @NonNull NetworkAgentConfig config,
- @NonNull NetworkInfo info) {
+ @NonNull LinkProperties properties, @NonNull NetworkScore score,
+ @NonNull NetworkAgentConfig config, @NonNull NetworkInfo info) {
this.context = context;
this.capabilities = capabilities;
this.properties = properties;
@@ -412,8 +438,9 @@
private volatile InitialConfiguration mInitialConfiguration;
private NetworkAgent(@NonNull Looper looper, @NonNull Context context, @NonNull String logTag,
- @NonNull NetworkCapabilities nc, @NonNull LinkProperties lp, int score,
- @NonNull NetworkAgentConfig config, int providerId, @NonNull NetworkInfo ni) {
+ @NonNull NetworkCapabilities nc, @NonNull LinkProperties lp,
+ @NonNull NetworkScore score, @NonNull NetworkAgentConfig config, int providerId,
+ @NonNull NetworkInfo ni) {
mHandler = new NetworkAgentHandler(looper);
LOG_TAG = logTag;
mNetworkInfo = new NetworkInfo(ni);
@@ -423,7 +450,7 @@
}
mInitialConfiguration = new InitialConfiguration(context,
- new NetworkCapabilities(nc, /* parcelLocationSensitiveFields */ true),
+ new NetworkCapabilities(nc, NetworkCapabilities.REDACT_NONE),
new LinkProperties(lp), score, config, ni);
}
@@ -551,6 +578,14 @@
msg.arg1 /* QoS callback id */);
break;
}
+ case CMD_NETWORK_CREATED: {
+ onNetworkCreated();
+ break;
+ }
+ case CMD_NETWORK_DISCONNECTED: {
+ onNetworkDisconnected();
+ break;
+ }
}
}
}
@@ -691,6 +726,16 @@
mHandler.sendMessage(mHandler.obtainMessage(
CMD_UNREGISTER_QOS_CALLBACK, qosCallbackId, 0, null));
}
+
+ @Override
+ public void onNetworkCreated() {
+ mHandler.sendMessage(mHandler.obtainMessage(CMD_NETWORK_CREATED));
+ }
+
+ @Override
+ public void onNetworkDisconnected() {
+ mHandler.sendMessage(mHandler.obtainMessage(CMD_NETWORK_DISCONNECTED));
+ }
}
/**
@@ -867,21 +912,29 @@
mBandwidthUpdatePending.set(false);
mLastBwRefreshTime = System.currentTimeMillis();
final NetworkCapabilities nc =
- new NetworkCapabilities(networkCapabilities,
- /* parcelLocationSensitiveFields */ true);
+ new NetworkCapabilities(networkCapabilities, NetworkCapabilities.REDACT_NONE);
queueOrSendMessage(reg -> reg.sendNetworkCapabilities(nc));
}
/**
* Must be called by the agent to update the score of this network.
*
+ * @param score the new score.
+ * @hide TODO : unhide when impl is complete
+ */
+ public final void sendNetworkScore(@NonNull NetworkScore score) {
+ Objects.requireNonNull(score);
+ queueOrSendMessage(reg -> reg.sendScore(score));
+ }
+
+ /**
+ * Must be called by the agent to update the score of this network.
+ *
* @param score the new score, between 0 and 99.
+ * deprecated use sendNetworkScore(NetworkScore) TODO : remove in S.
*/
public final void sendNetworkScore(@IntRange(from = 0, to = 99) int score) {
- if (score < 0) {
- throw new IllegalArgumentException("Score must be >= 0");
- }
- queueOrSendMessage(reg -> reg.sendScore(score));
+ sendNetworkScore(new NetworkScore.Builder().setLegacyInt(score).build());
}
/**
@@ -991,6 +1044,17 @@
}
/**
+ * Called when ConnectivityService has successfully created this NetworkAgent's native network.
+ */
+ public void onNetworkCreated() {}
+
+
+ /**
+ * Called when ConnectivityService has successfully destroy this NetworkAgent's native network.
+ */
+ public void onNetworkDisconnected() {}
+
+ /**
* Requests that the network hardware send the specified packet at the specified interval.
*
* @param slot the hardware slot on which to start the keepalive.
@@ -1141,29 +1205,37 @@
/**
- * Sends the attributes of Eps Bearer Qos Session back to the Application
+ * Sends the attributes of Qos Session back to the Application
*
* @param qosCallbackId the callback id that the session belongs to
- * @param sessionId the unique session id across all Eps Bearer Qos Sessions
- * @param attributes the attributes of the Eps Qos Session
+ * @param sessionId the unique session id across all Qos Sessions
+ * @param attributes the attributes of the Qos Session
*/
public final void sendQosSessionAvailable(final int qosCallbackId, final int sessionId,
- @NonNull final EpsBearerQosSessionAttributes attributes) {
+ @NonNull final QosSessionAttributes attributes) {
Objects.requireNonNull(attributes, "The attributes must be non-null");
- queueOrSendMessage(ra -> ra.sendEpsQosSessionAvailable(qosCallbackId,
- new QosSession(sessionId, QosSession.TYPE_EPS_BEARER),
- attributes));
+ if (attributes instanceof EpsBearerQosSessionAttributes) {
+ queueOrSendMessage(ra -> ra.sendEpsQosSessionAvailable(qosCallbackId,
+ new QosSession(sessionId, QosSession.TYPE_EPS_BEARER),
+ (EpsBearerQosSessionAttributes)attributes));
+ } else if (attributes instanceof NrQosSessionAttributes) {
+ queueOrSendMessage(ra -> ra.sendNrQosSessionAvailable(qosCallbackId,
+ new QosSession(sessionId, QosSession.TYPE_NR_BEARER),
+ (NrQosSessionAttributes)attributes));
+ }
}
/**
- * Sends event that the Eps Qos Session was lost.
+ * Sends event that the Qos Session was lost.
*
* @param qosCallbackId the callback id that the session belongs to
- * @param sessionId the unique session id across all Eps Bearer Qos Sessions
+ * @param sessionId the unique session id across all Qos Sessions
+ * @param qosSessionType the session type {@code QosSesson#QosSessionType}
*/
- public final void sendQosSessionLost(final int qosCallbackId, final int sessionId) {
+ public final void sendQosSessionLost(final int qosCallbackId,
+ final int sessionId, final int qosSessionType) {
queueOrSendMessage(ra -> ra.sendQosSessionLost(qosCallbackId,
- new QosSession(sessionId, QosSession.TYPE_EPS_BEARER)));
+ new QosSession(sessionId, qosSessionType)));
}
/**
diff --git a/packages/Connectivity/framework/src/android/net/NetworkAgentConfig.java b/packages/Connectivity/framework/src/android/net/NetworkAgentConfig.java
index 664c265..0bd2371 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkAgentConfig.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkAgentConfig.java
@@ -50,7 +50,8 @@
* ap in the wifi settings to trigger a connection is explicit. A 3rd party app asking to
* connect to a particular access point is also explicit, though this may change in the future
* as we want apps to use the multinetwork apis.
- *
+ * TODO : this is a bad name, because it sounds like the user just tapped on the network.
+ * It's not necessarily the case ; auto-reconnection to WiFi has this true for example.
* @hide
*/
public boolean explicitlySelected;
@@ -63,6 +64,16 @@
}
/**
+ * @return whether this VPN connection can be bypassed by the apps.
+ *
+ * @hide
+ */
+ @SystemApi(client = MODULE_LIBRARIES)
+ public boolean isBypassableVpn() {
+ return allowBypass;
+ }
+
+ /**
* Set if the user desires to use this network even if it is unvalidated. This field has meaning
* only if {@link explicitlySelected} is true. If it is, this field must also be set to the
* appropriate value based on previous user choice.
@@ -346,6 +357,19 @@
}
/**
+ * Sets whether the apps can bypass the VPN connection.
+ *
+ * @return this builder, to facilitate chaining.
+ * @hide
+ */
+ @NonNull
+ @SystemApi(client = MODULE_LIBRARIES)
+ public Builder setBypassableVpn(boolean allowBypass) {
+ mConfig.allowBypass = allowBypass;
+ return this;
+ }
+
+ /**
* Returns the constructed {@link NetworkAgentConfig} object.
*/
@NonNull
diff --git a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
index c82cd3b..881fa8c 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
@@ -19,22 +19,25 @@
import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE;
import android.annotation.IntDef;
+import android.annotation.LongDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.net.ConnectivityManager.NetworkCallback;
+import android.net.wifi.WifiNetworkSuggestion;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.Process;
import android.text.TextUtils;
import android.util.ArraySet;
+import android.util.Range;
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.Preconditions;
import com.android.net.module.util.CollectionUtils;
import com.android.net.module.util.NetworkCapabilitiesUtils;
@@ -62,6 +65,68 @@
public final class NetworkCapabilities implements Parcelable {
private static final String TAG = "NetworkCapabilities";
+ /**
+ * Mechanism to support redaction of fields in NetworkCapabilities that are guarded by specific
+ * app permissions.
+ **/
+ /**
+ * Don't redact any fields since the receiving app holds all the necessary permissions.
+ *
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final long REDACT_NONE = 0;
+
+ /**
+ * Redact any fields that need {@link android.Manifest.permission#ACCESS_FINE_LOCATION}
+ * permission since the receiving app does not hold this permission or the location toggle
+ * is off.
+ *
+ * @see android.Manifest.permission#ACCESS_FINE_LOCATION
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final long REDACT_FOR_ACCESS_FINE_LOCATION = 1 << 0;
+
+ /**
+ * Redact any fields that need {@link android.Manifest.permission#LOCAL_MAC_ADDRESS}
+ * permission since the receiving app does not hold this permission.
+ *
+ * @see android.Manifest.permission#LOCAL_MAC_ADDRESS
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final long REDACT_FOR_LOCAL_MAC_ADDRESS = 1 << 1;
+
+ /**
+ *
+ * Redact any fields that need {@link android.Manifest.permission#NETWORK_SETTINGS}
+ * permission since the receiving app does not hold this permission.
+ *
+ * @see android.Manifest.permission#NETWORK_SETTINGS
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final long REDACT_FOR_NETWORK_SETTINGS = 1 << 2;
+
+ /**
+ * Redact all fields in this object that require any relevant permission.
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final long REDACT_ALL = -1L;
+
+ /** @hide */
+ @LongDef(flag = true, prefix = { "REDACT_" }, value = {
+ REDACT_NONE,
+ REDACT_FOR_ACCESS_FINE_LOCATION,
+ REDACT_FOR_LOCAL_MAC_ADDRESS,
+ REDACT_FOR_NETWORK_SETTINGS,
+ REDACT_ALL
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface RedactionType {}
+
// Set to true when private DNS is broken.
private boolean mPrivateDnsBroken;
@@ -76,32 +141,31 @@
private String mRequestorPackageName;
/**
- * Indicates whether parceling should preserve fields that are set based on permissions of
- * the process receiving the {@link NetworkCapabilities}.
+ * Indicates what fields should be redacted from this instance.
*/
- private final boolean mParcelLocationSensitiveFields;
+ private final @RedactionType long mRedactions;
public NetworkCapabilities() {
- mParcelLocationSensitiveFields = false;
+ mRedactions = REDACT_ALL;
clearAll();
mNetworkCapabilities = DEFAULT_CAPABILITIES;
}
public NetworkCapabilities(NetworkCapabilities nc) {
- this(nc, false /* parcelLocationSensitiveFields */);
+ this(nc, REDACT_ALL);
}
/**
* Make a copy of NetworkCapabilities.
*
* @param nc Original NetworkCapabilities
- * @param parcelLocationSensitiveFields Whether to parcel location sensitive data or not.
+ * @param redactions bitmask of redactions that needs to be performed on this new instance of
+ * {@link NetworkCapabilities}.
* @hide
*/
- @SystemApi
- public NetworkCapabilities(
- @Nullable NetworkCapabilities nc, boolean parcelLocationSensitiveFields) {
- mParcelLocationSensitiveFields = parcelLocationSensitiveFields;
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public NetworkCapabilities(@Nullable NetworkCapabilities nc, @RedactionType long redactions) {
+ mRedactions = redactions;
if (nc != null) {
set(nc);
}
@@ -113,11 +177,13 @@
* @hide
*/
public void clearAll() {
- // Ensures that the internal copies maintained by the connectivity stack does not set
- // this bit.
- if (mParcelLocationSensitiveFields) {
+ // Ensures that the internal copies maintained by the connectivity stack does not set it to
+ // anything other than |REDACT_ALL|.
+ if (mRedactions != REDACT_ALL) {
+ // This is needed because the current redaction mechanism relies on redaction while
+ // parceling.
throw new UnsupportedOperationException(
- "Cannot clear NetworkCapabilities when parcelLocationSensitiveFields is set");
+ "Cannot clear NetworkCapabilities when mRedactions is set");
}
mNetworkCapabilities = mTransportTypes = mUnwantedNetworkCapabilities = 0;
mLinkUpBandwidthKbps = mLinkDownBandwidthKbps = LINK_BANDWIDTH_UNSPECIFIED;
@@ -131,6 +197,7 @@
mPrivateDnsBroken = false;
mRequestorUid = Process.INVALID_UID;
mRequestorPackageName = null;
+ mSubIds = new ArraySet<>();
}
/**
@@ -146,12 +213,12 @@
mLinkDownBandwidthKbps = nc.mLinkDownBandwidthKbps;
mNetworkSpecifier = nc.mNetworkSpecifier;
if (nc.getTransportInfo() != null) {
- setTransportInfo(nc.getTransportInfo().makeCopy(mParcelLocationSensitiveFields));
+ setTransportInfo(nc.getTransportInfo().makeCopy(mRedactions));
} else {
setTransportInfo(null);
}
mSignalStrength = nc.mSignalStrength;
- setUids(nc.mUids); // Will make the defensive copy
+ mUids = (nc.mUids == null) ? null : new ArraySet<>(nc.mUids);
setAdministratorUids(nc.getAdministratorUids());
mOwnerUid = nc.mOwnerUid;
mUnwantedNetworkCapabilities = nc.mUnwantedNetworkCapabilities;
@@ -159,6 +226,7 @@
mPrivateDnsBroken = nc.mPrivateDnsBroken;
mRequestorUid = nc.mRequestorUid;
mRequestorPackageName = nc.mRequestorPackageName;
+ mSubIds = new ArraySet<>(nc.mSubIds);
}
/**
@@ -571,19 +639,31 @@
}
/**
- * Removes (if found) the given capability from this {@code NetworkCapability} instance.
+ * Removes (if found) the given capability from this {@code NetworkCapability}
+ * instance that were added via addCapability(int) or setCapabilities(int[], int[]).
*
* @param capability the capability to be removed.
* @return This NetworkCapabilities instance, to facilitate chaining.
* @hide
*/
public @NonNull NetworkCapabilities removeCapability(@NetCapability int capability) {
- // Note that this method removes capabilities that were added via addCapability(int),
- // addUnwantedCapability(int) or setCapabilities(int[], int[]).
checkValidCapability(capability);
final long mask = ~(1 << capability);
mNetworkCapabilities &= mask;
- mUnwantedNetworkCapabilities &= mask;
+ return this;
+ }
+
+ /**
+ * Removes (if found) the given unwanted capability from this {@code NetworkCapability}
+ * instance that were added via addUnwantedCapability(int) or setCapabilities(int[], int[]).
+ *
+ * @param capability the capability to be removed.
+ * @return This NetworkCapabilities instance, to facilitate chaining.
+ * @hide
+ */
+ public @NonNull NetworkCapabilities removeUnwantedCapability(@NetCapability int capability) {
+ checkValidCapability(capability);
+ mUnwantedNetworkCapabilities &= ~(1 << capability);
return this;
}
@@ -606,10 +686,8 @@
* Gets all the capabilities set on this {@code NetworkCapability} instance.
*
* @return an array of capability values for this instance.
- * @hide
*/
- @UnsupportedAppUsage
- public @NetCapability int[] getCapabilities() {
+ public @NonNull @NetCapability int[] getCapabilities() {
return NetworkCapabilitiesUtils.unpackBits(mNetworkCapabilities);
}
@@ -657,6 +735,7 @@
}
/** @hide */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public boolean hasUnwantedCapability(@NetCapability int capability) {
return isValidCapability(capability)
&& ((mUnwantedNetworkCapabilities & (1 << capability)) != 0);
@@ -670,10 +749,16 @@
return ((mNetworkCapabilities & CONNECTIVITY_MANAGED_CAPABILITIES) != 0);
}
- /** Note this method may result in having the same capability in wanted and unwanted lists. */
private void combineNetCapabilities(@NonNull NetworkCapabilities nc) {
- this.mNetworkCapabilities |= nc.mNetworkCapabilities;
- this.mUnwantedNetworkCapabilities |= nc.mUnwantedNetworkCapabilities;
+ final long wantedCaps = this.mNetworkCapabilities | nc.mNetworkCapabilities;
+ final long unwantedCaps =
+ this.mUnwantedNetworkCapabilities | nc.mUnwantedNetworkCapabilities;
+ if ((wantedCaps & unwantedCaps) != 0) {
+ throw new IllegalArgumentException(
+ "Cannot have the same capability in wanted and unwanted lists.");
+ }
+ this.mNetworkCapabilities = wantedCaps;
+ this.mUnwantedNetworkCapabilities = unwantedCaps;
}
/**
@@ -1048,6 +1133,16 @@
*
* Instances of NetworkCapabilities sent to apps without the appropriate permissions will have
* this field cleared out.
+ *
+ * <p>
+ * This field will only be populated for VPN and wifi network suggestor apps (i.e using
+ * {@link WifiNetworkSuggestion}), and only for the network they own.
+ * In the case of wifi network suggestors apps, this field is also location sensitive, so the
+ * app needs to hold {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permission. If the
+ * app targets SDK version greater than or equal to {@link Build.VERSION_CODES#S}, then they
+ * also need to use {@link NetworkCallback#FLAG_INCLUDE_LOCATION_INFO} to get the info in their
+ * callback. The app will be blamed for location access if this field is included.
+ * </p>
*/
public int getOwnerUid() {
return mOwnerUid;
@@ -1445,9 +1540,8 @@
* @hide
*/
public @NonNull NetworkCapabilities setSingleUid(int uid) {
- final ArraySet<UidRange> identity = new ArraySet<>(1);
- identity.add(new UidRange(uid, uid));
- setUids(identity);
+ mUids = new ArraySet<>(1);
+ mUids.add(new UidRange(uid, uid));
return this;
}
@@ -1456,22 +1550,34 @@
* This makes a copy of the set so that callers can't modify it after the call.
* @hide
*/
- public @NonNull NetworkCapabilities setUids(Set<UidRange> uids) {
- if (null == uids) {
- mUids = null;
- } else {
- mUids = new ArraySet<>(uids);
- }
+ public @NonNull NetworkCapabilities setUids(@Nullable Set<Range<Integer>> uids) {
+ mUids = UidRange.fromIntRanges(uids);
return this;
}
/**
* Get the list of UIDs this network applies to.
* This returns a copy of the set so that callers can't modify the original object.
+ *
+ * @return the list of UIDs this network applies to. If {@code null}, then the network applies
+ * to all UIDs.
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @SuppressLint("NullableCollection")
+ public @Nullable Set<Range<Integer>> getUids() {
+ return UidRange.toIntRanges(mUids);
+ }
+
+ /**
+ * Get the list of UIDs this network applies to.
+ * This returns a copy of the set so that callers can't modify the original object.
* @hide
*/
- public @Nullable Set<UidRange> getUids() {
- return null == mUids ? null : new ArraySet<>(mUids);
+ public @Nullable Set<UidRange> getUidRanges() {
+ if (mUids == null) return null;
+
+ return new ArraySet<>(mUids);
}
/**
@@ -1655,6 +1761,7 @@
combineSSIDs(nc);
combineRequestor(nc);
combineAdministratorUids(nc);
+ combineSubIds(nc);
}
/**
@@ -1674,8 +1781,9 @@
&& satisfiedBySpecifier(nc)
&& (onlyImmutable || satisfiedBySignalStrength(nc))
&& (onlyImmutable || satisfiedByUids(nc))
- && (onlyImmutable || satisfiedBySSID(nc)))
- && (onlyImmutable || satisfiedByRequestor(nc));
+ && (onlyImmutable || satisfiedBySSID(nc))
+ && (onlyImmutable || satisfiedByRequestor(nc))
+ && (onlyImmutable || satisfiedBySubIds(nc)));
}
/**
@@ -1771,7 +1879,8 @@
&& equalsOwnerUid(that)
&& equalsPrivateDnsBroken(that)
&& equalsRequestor(that)
- && equalsAdministratorUids(that);
+ && equalsAdministratorUids(that)
+ && equalsSubIds(that);
}
@Override
@@ -1793,7 +1902,8 @@
+ Objects.hashCode(mPrivateDnsBroken) * 47
+ Objects.hashCode(mRequestorUid) * 53
+ Objects.hashCode(mRequestorPackageName) * 59
- + Arrays.hashCode(mAdministratorUids) * 61;
+ + Arrays.hashCode(mAdministratorUids) * 61
+ + Objects.hashCode(mSubIds) * 67;
}
@Override
@@ -1827,6 +1937,7 @@
dest.writeInt(mOwnerUid);
dest.writeInt(mRequestorUid);
dest.writeString(mRequestorPackageName);
+ dest.writeIntArray(CollectionUtils.toIntArray(mSubIds));
}
public static final @android.annotation.NonNull Creator<NetworkCapabilities> CREATOR =
@@ -1850,6 +1961,11 @@
netCap.mOwnerUid = in.readInt();
netCap.mRequestorUid = in.readInt();
netCap.mRequestorPackageName = in.readString();
+ netCap.mSubIds = new ArraySet<>();
+ final int[] subIdInts = Objects.requireNonNull(in.createIntArray());
+ for (int i = 0; i < subIdInts.length; i++) {
+ netCap.mSubIds.add(subIdInts[i]);
+ }
return netCap;
}
@Override
@@ -1933,11 +2049,14 @@
sb.append(" SSID: ").append(mSSID);
}
-
if (mPrivateDnsBroken) {
sb.append(" PrivateDnsBroken");
}
+ if (!mSubIds.isEmpty()) {
+ sb.append(" SubscriptionIds: ").append(mSubIds);
+ }
+
sb.append("]");
return sb.toString();
}
@@ -2073,8 +2192,9 @@
}
private static void checkValidTransportType(@Transport int transport) {
- Preconditions.checkArgument(
- isValidTransport(transport), "Invalid TransportType " + transport);
+ if (!isValidTransport(transport)) {
+ throw new IllegalArgumentException("Invalid TransportType " + transport);
+ }
}
private static boolean isValidCapability(@NetworkCapabilities.NetCapability int capability) {
@@ -2082,8 +2202,9 @@
}
private static void checkValidCapability(@NetworkCapabilities.NetCapability int capability) {
- Preconditions.checkArgument(isValidCapability(capability),
- "NetworkCapability " + capability + "out of range");
+ if (!isValidCapability(capability)) {
+ throw new IllegalArgumentException("NetworkCapability " + capability + "out of range");
+ }
}
/**
@@ -2251,6 +2372,84 @@
}
/**
+ * Set of the subscription IDs that identifies the network or request, empty if none.
+ */
+ @NonNull
+ private ArraySet<Integer> mSubIds = new ArraySet<>();
+
+ /**
+ * Sets the subscription ID set that associated to this network or request.
+ *
+ * @hide
+ */
+ @NonNull
+ public NetworkCapabilities setSubIds(@NonNull Set<Integer> subIds) {
+ mSubIds = new ArraySet(Objects.requireNonNull(subIds));
+ return this;
+ }
+
+ /**
+ * Gets the subscription ID set that associated to this network or request.
+ * @return
+ */
+ @NonNull
+ public Set<Integer> getSubIds() {
+ return new ArraySet<>(mSubIds);
+ }
+
+ /**
+ * Tests if the subscription ID set of this network is the same as that of the passed one.
+ */
+ private boolean equalsSubIds(@NonNull NetworkCapabilities nc) {
+ return Objects.equals(mSubIds, nc.mSubIds);
+ }
+
+ /**
+ * Check if the subscription ID set requirements of this object are matched by the passed one.
+ * If specified in the request, the passed one need to have at least one subId and at least
+ * one of them needs to be in the request set.
+ */
+ private boolean satisfiedBySubIds(@NonNull NetworkCapabilities nc) {
+ if (mSubIds.isEmpty()) return true;
+ if (nc.mSubIds.isEmpty()) return false;
+ for (final Integer subId : nc.mSubIds) {
+ if (mSubIds.contains(subId)) return true;
+ }
+ return false;
+ }
+
+ /**
+ * Combine subscription ID set of the capabilities.
+ *
+ * <p>This is only legal if the subscription Ids are equal.
+ *
+ * <p>If both subscription IDs are not equal, they belong to different subscription
+ * (or no subscription). In this case, it would not make sense to add them together.
+ */
+ private void combineSubIds(@NonNull NetworkCapabilities nc) {
+ if (!Objects.equals(mSubIds, nc.mSubIds)) {
+ throw new IllegalStateException("Can't combine two subscription ID sets");
+ }
+ }
+
+ /**
+ * Returns a bitmask of all the applicable redactions (based on the permissions held by the
+ * receiving app) to be performed on this object.
+ *
+ * @return bitmask of redactions applicable on this instance.
+ * @hide
+ */
+ public @RedactionType long getApplicableRedactions() {
+ // Currently, there are no fields redacted in NetworkCapabilities itself, so we just
+ // passthrough the redactions required by the embedded TransportInfo. If this changes
+ // in the future, modify this method.
+ if (mTransportInfo == null) {
+ return NetworkCapabilities.REDACT_NONE;
+ }
+ return mTransportInfo.getApplicableRedactions();
+ }
+
+ /**
* Builder class for NetworkCapabilities.
*
* This class is mainly for for {@link NetworkAgent} instances to use. Many fields in
@@ -2556,6 +2755,33 @@
}
/**
+ * Set the subscription ID set.
+ *
+ * @param subIds a set that represent the subscription IDs. Empty if clean up.
+ * @return this builder.
+ */
+ @NonNull
+ public Builder setSubIds(@NonNull final Set<Integer> subIds) {
+ mCaps.setSubIds(subIds);
+ return this;
+ }
+
+ /**
+ * Set the list of UIDs this network applies to.
+ *
+ * @param uids the list of UIDs this network applies to, or {@code null} if this network
+ * applies to all UIDs.
+ * @return this builder
+ * @hide
+ */
+ @NonNull
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public Builder setUids(@Nullable Set<Range<Integer>> uids) {
+ mCaps.setUids(uids);
+ return this;
+ }
+
+ /**
* Builds the instance of the capabilities.
*
* @return the built instance of NetworkCapabilities.
diff --git a/packages/Connectivity/framework/src/android/net/NetworkInfo.java b/packages/Connectivity/framework/src/android/net/NetworkInfo.java
index d752901..bb23494 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkInfo.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkInfo.java
@@ -21,7 +21,6 @@
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Parcel;
import android.os.Parcelable;
-import android.telephony.Annotation.NetworkType;
import android.text.TextUtils;
import com.android.internal.annotations.VisibleForTesting;
@@ -164,7 +163,7 @@
* @param typeName a human-readable string for the network type, or an empty string or null.
* @param subtypeName a human-readable string for the subtype, or an empty string or null.
*/
- public NetworkInfo(int type, @NetworkType int subtype,
+ public NetworkInfo(int type, int subtype,
@Nullable String typeName, @Nullable String subtypeName) {
if (!ConnectivityManager.isNetworkTypeValid(type)
&& type != ConnectivityManager.TYPE_NONE) {
diff --git a/packages/Connectivity/framework/src/android/net/NetworkRequest.java b/packages/Connectivity/framework/src/android/net/NetworkRequest.java
index b4a651c..bcbc04f7 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkRequest.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkRequest.java
@@ -31,10 +31,12 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
+import static android.net.NetworkCapabilities.TRANSPORT_TEST;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.net.NetworkCapabilities.NetCapability;
@@ -44,6 +46,7 @@
import android.os.Parcelable;
import android.os.Process;
import android.text.TextUtils;
+import android.util.Range;
import android.util.proto.ProtoOutputStream;
import java.util.Arrays;
@@ -113,6 +116,10 @@
* for the network (if any) that satisfies the default Internet
* request.
*
+ * - TRACK_BEST, which causes the framework to send callbacks about
+ * the single, highest scoring current network (if any) that matches
+ * the specified NetworkCapabilities.
+ *
* - BACKGROUND_REQUEST, like REQUEST but does not cause any networks
* to retain the NET_CAPABILITY_FOREGROUND capability. A network with
* no foreground requests is in the background. A network that has
@@ -135,6 +142,7 @@
REQUEST,
BACKGROUND_REQUEST,
TRACK_SYSTEM_DEFAULT,
+ LISTEN_FOR_BEST,
};
/**
@@ -208,6 +216,14 @@
}
/**
+ * Creates a new Builder of NetworkRequest from an existing instance.
+ */
+ public Builder(@NonNull final NetworkRequest request) {
+ Objects.requireNonNull(request);
+ mNetworkCapabilities = request.networkCapabilities;
+ }
+
+ /**
* Build {@link NetworkRequest} give the current set of capabilities.
*/
public NetworkRequest build() {
@@ -271,11 +287,14 @@
* Set the watched UIDs for this request. This will be reset and wiped out unless
* the calling app holds the CHANGE_NETWORK_STATE permission.
*
- * @param uids The watched UIDs as a set of UidRanges, or null for everything.
+ * @param uids The watched UIDs as a set of {@code Range<Integer>}, or null for everything.
* @return The builder to facilitate chaining.
* @hide
*/
- public Builder setUids(Set<UidRange> uids) {
+ @NonNull
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @SuppressLint("MissingGetterMatchingBuilder")
+ public Builder setUids(@Nullable Set<Range<Integer>> uids) {
mNetworkCapabilities.setUids(uids);
return this;
}
@@ -294,12 +313,31 @@
*
* @hide
*/
+ @NonNull
+ @SuppressLint("MissingGetterMatchingBuilder")
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public Builder addUnwantedCapability(@NetworkCapabilities.NetCapability int capability) {
mNetworkCapabilities.addUnwantedCapability(capability);
return this;
}
/**
+ * Removes (if found) the given unwanted capability from this builder instance.
+ *
+ * @param capability The unwanted capability to remove.
+ * @return The builder to facilitate chaining.
+ *
+ * @hide
+ */
+ @NonNull
+ @SuppressLint("BuilderSetStyle")
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public Builder removeUnwantedCapability(@NetworkCapabilities.NetCapability int capability) {
+ mNetworkCapabilities.removeUnwantedCapability(capability);
+ return this;
+ }
+
+ /**
* Completely clears all the {@code NetworkCapabilities} from this builder instance,
* removing even the capabilities that are set by default when the object is constructed.
*
@@ -382,11 +420,17 @@
return setNetworkSpecifier(new TelephonyNetworkSpecifier.Builder()
.setSubscriptionId(subId).build());
} catch (NumberFormatException nfe) {
- // A StringNetworkSpecifier does not accept null or empty ("") strings. When network
- // specifiers were strings a null string and an empty string were considered
- // equivalent. Hence no meaning is attached to a null or empty ("") string.
- return setNetworkSpecifier(TextUtils.isEmpty(networkSpecifier) ? null
- : new StringNetworkSpecifier(networkSpecifier));
+ // An EthernetNetworkSpecifier or TestNetworkSpecifier does not accept null or empty
+ // ("") strings. When network specifiers were strings a null string and an empty
+ // string were considered equivalent. Hence no meaning is attached to a null or
+ // empty ("") string.
+ if (TextUtils.isEmpty(networkSpecifier)) {
+ return setNetworkSpecifier((NetworkSpecifier) null);
+ } else if (mNetworkCapabilities.hasTransport(TRANSPORT_TEST)) {
+ return setNetworkSpecifier(new TestNetworkSpecifier(networkSpecifier));
+ } else {
+ return setNetworkSpecifier(new EthernetNetworkSpecifier(networkSpecifier));
+ }
}
}
@@ -449,6 +493,21 @@
}
nc.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
}
+
+ /**
+ * Sets the optional subscription ID set.
+ * <p>
+ * This specify the subscription IDs requirement.
+ * A network will satisfy this request only if it matches one of the subIds in this set.
+ * An empty set matches all networks, including those without a subId.
+ *
+ * @param subIds A {@code Set} that represents subscription IDs.
+ */
+ @NonNull
+ public Builder setSubIds(@NonNull Set<Integer> subIds) {
+ mNetworkCapabilities.setSubIds(subIds);
+ return this;
+ }
}
// implement the Parcelable interface
@@ -487,6 +546,15 @@
}
/**
+ * Returns true iff. this NetworkRequest is of type LISTEN_FOR_BEST.
+ *
+ * @hide
+ */
+ public boolean isListenForBest() {
+ return type == Type.LISTEN_FOR_BEST;
+ }
+
+ /**
* Returns true iff. the contained NetworkRequest is one that:
*
* - should be associated with at most one satisfying network
@@ -526,6 +594,7 @@
*
* @hide
*/
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public boolean hasUnwantedCapability(@NetCapability int capability) {
return networkCapabilities.hasUnwantedCapability(capability);
}
diff --git a/packages/Connectivity/framework/src/android/net/NetworkScore.java b/packages/Connectivity/framework/src/android/net/NetworkScore.java
new file mode 100644
index 0000000..6584993
--- /dev/null
+++ b/packages/Connectivity/framework/src/android/net/NetworkScore.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * Object representing the quality of a network as perceived by the user.
+ *
+ * A NetworkScore object represents the characteristics of a network that affects how good the
+ * network is considered for a particular use.
+ * @hide
+ */
+@SystemApi
+public final class NetworkScore implements Parcelable {
+ // This will be removed soon. Do *NOT* depend on it for any new code that is not part of
+ // a migration.
+ private final int mLegacyInt;
+
+ // Agent-managed policies
+ // TODO : add them here, starting from 1
+ /** @hide */
+ public static final int MIN_AGENT_MANAGED_POLICY = 0;
+ /** @hide */
+ public static final int MAX_AGENT_MANAGED_POLICY = -1;
+
+ // Bitmask of all the policies applied to this score.
+ private final long mPolicies;
+
+ /** @hide */
+ NetworkScore(final int legacyInt, final long policies) {
+ mLegacyInt = legacyInt;
+ mPolicies = policies;
+ }
+
+ private NetworkScore(@NonNull final Parcel in) {
+ mLegacyInt = in.readInt();
+ mPolicies = in.readLong();
+ }
+
+ public int getLegacyInt() {
+ return mLegacyInt;
+ }
+
+ /**
+ * @return whether this score has a particular policy.
+ *
+ * @hide
+ */
+ @VisibleForTesting
+ public boolean hasPolicy(final int policy) {
+ return 0 != (mPolicies & (1L << policy));
+ }
+
+ @Override
+ public String toString() {
+ return "Score(" + mLegacyInt + ")";
+ }
+
+ @Override
+ public void writeToParcel(@NonNull final Parcel dest, final int flags) {
+ dest.writeInt(mLegacyInt);
+ dest.writeLong(mPolicies);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @NonNull public static final Creator<NetworkScore> CREATOR = new Creator<>() {
+ @Override
+ @NonNull
+ public NetworkScore createFromParcel(@NonNull final Parcel in) {
+ return new NetworkScore(in);
+ }
+
+ @Override
+ @NonNull
+ public NetworkScore[] newArray(int size) {
+ return new NetworkScore[size];
+ }
+ };
+
+ /**
+ * A builder for NetworkScore.
+ */
+ public static final class Builder {
+ private static final long POLICY_NONE = 0L;
+ private static final int INVALID_LEGACY_INT = Integer.MIN_VALUE;
+ private int mLegacyInt = INVALID_LEGACY_INT;
+
+ /**
+ * Sets the legacy int for this score.
+ *
+ * Do not rely on this. It will be gone by the time S is released.
+ *
+ * @param score the legacy int
+ * @return this
+ */
+ @NonNull
+ public Builder setLegacyInt(final int score) {
+ mLegacyInt = score;
+ return this;
+ }
+
+ /**
+ * Builds this NetworkScore.
+ * @return The built NetworkScore object.
+ */
+ @NonNull
+ public NetworkScore build() {
+ return new NetworkScore(mLegacyInt, POLICY_NONE);
+ }
+ }
+}
diff --git a/packages/Connectivity/framework/src/android/net/NetworkState.java b/packages/Connectivity/framework/src/android/net/NetworkState.java
index d010265..9b69674 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkState.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkState.java
@@ -22,7 +22,7 @@
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
-import android.util.Slog;
+import android.util.Log;
/**
* Snapshot of network state.
@@ -83,7 +83,7 @@
if (VALIDATE_ROAMING_STATE && networkInfo != null && networkCapabilities != null) {
if (networkInfo.isRoaming() == networkCapabilities
.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING)) {
- Slog.wtf("NetworkState", "Roaming state disagreement between " + networkInfo
+ Log.wtf("NetworkState", "Roaming state disagreement between " + networkInfo
+ " and " + networkCapabilities);
}
}
diff --git a/packages/Connectivity/framework/src/android/net/NetworkUtils.java b/packages/Connectivity/framework/src/android/net/NetworkUtils.java
index 9e42bbe..a92fda1 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkUtils.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkUtils.java
@@ -27,8 +27,10 @@
import java.io.FileDescriptor;
import java.math.BigInteger;
import java.net.Inet4Address;
+import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.SocketException;
+import java.net.UnknownHostException;
import java.util.Locale;
import java.util.TreeSet;
@@ -90,7 +92,10 @@
* Determine if {@code uid} can access network designated by {@code netId}.
* @return {@code true} if {@code uid} can access network, {@code false} otherwise.
*/
- public native static boolean queryUserAccess(int uid, int netId);
+ public static boolean queryUserAccess(int uid, int netId) {
+ // TODO (b/183485986): remove this method
+ return false;
+ }
/**
* DNS resolver series jni method.
@@ -212,7 +217,7 @@
@Deprecated
public static InetAddress numericToInetAddress(String addrString)
throws IllegalArgumentException {
- return InetAddress.parseNumericAddress(addrString);
+ return InetAddresses.parseNumericAddress(addrString);
}
/**
@@ -234,7 +239,7 @@
try {
String[] pieces = ipAndMaskString.split("/", 2);
prefixLength = Integer.parseInt(pieces[1]);
- address = InetAddress.parseNumericAddress(pieces[0]);
+ address = InetAddresses.parseNumericAddress(pieces[0]);
} catch (NullPointerException e) { // Null string.
} catch (ArrayIndexOutOfBoundsException e) { // No prefix length.
} catch (NumberFormatException e) { // Non-numeric prefix.
@@ -249,6 +254,47 @@
}
/**
+ * Utility method to parse strings such as "192.0.2.5/24" or "2001:db8::cafe:d00d/64".
+ * @hide
+ *
+ * @deprecated This method is used only for IpPrefix and LinkAddress. Since Android S, use
+ * {@link #parseIpAndMask(String)}, if possible.
+ */
+ @Deprecated
+ public static Pair<InetAddress, Integer> legacyParseIpAndMask(String ipAndMaskString) {
+ InetAddress address = null;
+ int prefixLength = -1;
+ try {
+ String[] pieces = ipAndMaskString.split("/", 2);
+ prefixLength = Integer.parseInt(pieces[1]);
+ if (pieces[0] == null || pieces[0].isEmpty()) {
+ final byte[] bytes = new byte[16];
+ bytes[15] = 1;
+ return new Pair<InetAddress, Integer>(Inet6Address.getByAddress(
+ "ip6-localhost"/* host */, bytes, 0 /* scope_id */), prefixLength);
+ }
+
+ if (pieces[0].startsWith("[")
+ && pieces[0].endsWith("]")
+ && pieces[0].indexOf(':') != -1) {
+ pieces[0] = pieces[0].substring(1, pieces[0].length() - 1);
+ }
+ address = InetAddresses.parseNumericAddress(pieces[0]);
+ } catch (NullPointerException e) { // Null string.
+ } catch (ArrayIndexOutOfBoundsException e) { // No prefix length.
+ } catch (NumberFormatException e) { // Non-numeric prefix.
+ } catch (IllegalArgumentException e) { // Invalid IP address.
+ } catch (UnknownHostException e) { // IP address length is illegal
+ }
+
+ if (address == null || prefixLength == -1) {
+ throw new IllegalArgumentException("Invalid IP address and mask " + ipAndMaskString);
+ }
+
+ return new Pair<InetAddress, Integer>(address, prefixLength);
+ }
+
+ /**
* Convert a 32 char hex string into a Inet6Address.
* throws a runtime exception if the string isn't 32 chars, isn't hex or can't be
* made into an Inet6Address
@@ -280,22 +326,7 @@
*/
@UnsupportedAppUsage
public static String trimV4AddrZeros(String addr) {
- if (addr == null) return null;
- String[] octets = addr.split("\\.");
- if (octets.length != 4) return addr;
- StringBuilder builder = new StringBuilder(16);
- String result = null;
- for (int i = 0; i < 4; i++) {
- try {
- if (octets[i].length() > 3) return addr;
- builder.append(Integer.parseInt(octets[i]));
- } catch (NumberFormatException e) {
- return addr;
- }
- if (i < 3) builder.append('.');
- }
- result = builder.toString();
- return result;
+ return Inet4AddressUtils.trimAddressZeros(addr);
}
/**
diff --git a/packages/Connectivity/framework/src/android/net/OemNetworkPreferences.java b/packages/Connectivity/framework/src/android/net/OemNetworkPreferences.java
index 48bd297..5a76cd6 100644
--- a/packages/Connectivity/framework/src/android/net/OemNetworkPreferences.java
+++ b/packages/Connectivity/framework/src/android/net/OemNetworkPreferences.java
@@ -73,6 +73,14 @@
private final Bundle mNetworkMappings;
/**
+ * Return whether this object is empty.
+ * @hide
+ */
+ public boolean isEmpty() {
+ return mNetworkMappings.keySet().size() == 0;
+ }
+
+ /**
* Return the currently built application package name to {@link OemNetworkPreference} mappings.
* @return the current network preferences map.
*/
diff --git a/core/java/android/net/ParseException.java b/packages/Connectivity/framework/src/android/net/ParseException.java
similarity index 75%
rename from core/java/android/net/ParseException.java
rename to packages/Connectivity/framework/src/android/net/ParseException.java
index bcfdd7e..ca6d012 100644
--- a/core/java/android/net/ParseException.java
+++ b/packages/Connectivity/framework/src/android/net/ParseException.java
@@ -17,6 +17,7 @@
package android.net;
import android.annotation.NonNull;
+import android.annotation.SystemApi;
/**
* Thrown when parsing failed.
@@ -25,12 +26,16 @@
public class ParseException extends RuntimeException {
public String response;
- ParseException(@NonNull String response) {
+ /** @hide */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public ParseException(@NonNull String response) {
super(response);
this.response = response;
}
- ParseException(@NonNull String response, @NonNull Throwable cause) {
+ /** @hide */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public ParseException(@NonNull String response, @NonNull Throwable cause) {
super(response, cause);
this.response = response;
}
diff --git a/packages/Connectivity/framework/src/android/net/ProxyInfo.java b/packages/Connectivity/framework/src/android/net/ProxyInfo.java
index 229db0d..745e20f 100644
--- a/packages/Connectivity/framework/src/android/net/ProxyInfo.java
+++ b/packages/Connectivity/framework/src/android/net/ProxyInfo.java
@@ -129,7 +129,7 @@
}
/**
- * Only used in PacProxyInstaller after Local Proxy is bound.
+ * Only used in PacProxyService after Local Proxy is bound.
* @hide
*/
public ProxyInfo(@NonNull Uri pacFileUrl, int localProxyPort) {
diff --git a/packages/Connectivity/framework/src/android/net/QosCallbackConnection.java b/packages/Connectivity/framework/src/android/net/QosCallbackConnection.java
index bdb4ad6..de0fc24 100644
--- a/packages/Connectivity/framework/src/android/net/QosCallbackConnection.java
+++ b/packages/Connectivity/framework/src/android/net/QosCallbackConnection.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.telephony.data.EpsBearerQosSessionAttributes;
+import android.telephony.data.NrQosSessionAttributes;
import com.android.internal.annotations.VisibleForTesting;
@@ -84,6 +85,25 @@
}
/**
+ * Called when either the {@link NrQosSessionAttributes} has changed or on the first time
+ * the attributes have become available.
+ *
+ * @param session the session that is now available
+ * @param attributes the corresponding attributes of session
+ */
+ @Override
+ public void onNrQosSessionAvailable(@NonNull final QosSession session,
+ @NonNull final NrQosSessionAttributes attributes) {
+
+ mExecutor.execute(() -> {
+ final QosCallback callback = mCallback;
+ if (callback != null) {
+ callback.onQosSessionAvailable(session, attributes);
+ }
+ });
+ }
+
+ /**
* Called when the session is lost.
*
* @param session the session that was lost
diff --git a/packages/Connectivity/framework/src/android/net/QosSession.java b/packages/Connectivity/framework/src/android/net/QosSession.java
index 4f3bb77..93f2ff2 100644
--- a/packages/Connectivity/framework/src/android/net/QosSession.java
+++ b/packages/Connectivity/framework/src/android/net/QosSession.java
@@ -36,6 +36,11 @@
*/
public static final int TYPE_EPS_BEARER = 1;
+ /**
+ * The {@link QosSession} is a NR Session.
+ */
+ public static final int TYPE_NR_BEARER = 2;
+
private final int mSessionId;
private final int mSessionType;
@@ -100,6 +105,7 @@
*/
@IntDef(value = {
TYPE_EPS_BEARER,
+ TYPE_NR_BEARER,
})
@interface QosSessionType {}
diff --git a/packages/Connectivity/framework/src/android/net/QosSocketInfo.java b/packages/Connectivity/framework/src/android/net/QosSocketInfo.java
index d37c469..53d9669 100644
--- a/packages/Connectivity/framework/src/android/net/QosSocketInfo.java
+++ b/packages/Connectivity/framework/src/android/net/QosSocketInfo.java
@@ -92,7 +92,7 @@
Objects.requireNonNull(socket, "socket cannot be null");
mNetwork = Objects.requireNonNull(network, "network cannot be null");
- mParcelFileDescriptor = ParcelFileDescriptor.dup(socket.getFileDescriptor$());
+ mParcelFileDescriptor = ParcelFileDescriptor.fromSocket(socket);
mLocalSocketAddress =
new InetSocketAddress(socket.getLocalAddress(), socket.getLocalPort());
}
@@ -114,10 +114,10 @@
try {
return new InetSocketAddress(InetAddress.getByAddress(address), port);
} catch (final UnknownHostException e) {
- /* The catch block was purposely left empty. UnknownHostException will never be thrown
+ /* This can never happen. UnknownHostException will never be thrown
since the address provided is numeric and non-null. */
+ throw new RuntimeException("UnknownHostException on numeric address", e);
}
- return new InetSocketAddress();
}
@Override
diff --git a/packages/Connectivity/framework/src/android/net/StaticIpConfiguration.java b/packages/Connectivity/framework/src/android/net/StaticIpConfiguration.java
index ce54597..7904f7a 100644
--- a/packages/Connectivity/framework/src/android/net/StaticIpConfiguration.java
+++ b/packages/Connectivity/framework/src/android/net/StaticIpConfiguration.java
@@ -24,7 +24,6 @@
import android.os.Parcel;
import android.os.Parcelable;
-import com.android.internal.util.Preconditions;
import com.android.net.module.util.InetAddressUtils;
import java.net.InetAddress;
@@ -153,7 +152,7 @@
* @return The {@link Builder} for chaining.
*/
public @NonNull Builder setDnsServers(@NonNull Iterable<InetAddress> dnsServers) {
- Preconditions.checkNotNull(dnsServers);
+ Objects.requireNonNull(dnsServers);
mDnsServers = dnsServers;
return this;
}
diff --git a/packages/Connectivity/framework/src/android/net/TestNetworkManager.java b/packages/Connectivity/framework/src/android/net/TestNetworkManager.java
index a174a7b..a7a6235 100644
--- a/packages/Connectivity/framework/src/android/net/TestNetworkManager.java
+++ b/packages/Connectivity/framework/src/android/net/TestNetworkManager.java
@@ -21,10 +21,9 @@
import android.os.IBinder;
import android.os.RemoteException;
-import com.android.internal.util.Preconditions;
-
import java.util.Arrays;
import java.util.Collection;
+import java.util.Objects;
/**
* Class that allows creation and management of per-app, test-only networks
@@ -50,7 +49,7 @@
/** @hide */
public TestNetworkManager(@NonNull ITestNetworkManager service) {
- mService = Preconditions.checkNotNull(service, "missing ITestNetworkManager");
+ mService = Objects.requireNonNull(service, "missing ITestNetworkManager");
}
/**
@@ -93,7 +92,7 @@
*/
public void setupTestNetwork(
@NonNull LinkProperties lp, boolean isMetered, @NonNull IBinder binder) {
- Preconditions.checkNotNull(lp, "Invalid LinkProperties");
+ Objects.requireNonNull(lp, "Invalid LinkProperties");
setupTestNetwork(lp.getInterfaceName(), lp, isMetered, new int[0], binder);
}
diff --git a/packages/Connectivity/framework/src/android/net/TestNetworkSpecifier.java b/packages/Connectivity/framework/src/android/net/TestNetworkSpecifier.java
new file mode 100644
index 0000000..117457d
--- /dev/null
+++ b/packages/Connectivity/framework/src/android/net/TestNetworkSpecifier.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+
+import java.util.Objects;
+
+/**
+ * A {@link NetworkSpecifier} used to identify test interfaces.
+ *
+ * @see TestNetworkManager
+ * @hide
+ */
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+public final class TestNetworkSpecifier extends NetworkSpecifier implements Parcelable {
+
+ /**
+ * Name of the network interface.
+ */
+ @NonNull
+ private final String mInterfaceName;
+
+ public TestNetworkSpecifier(@NonNull String interfaceName) {
+ if (TextUtils.isEmpty(interfaceName)) {
+ throw new IllegalArgumentException("Empty interfaceName");
+ }
+ mInterfaceName = interfaceName;
+ }
+
+ // This may be null in the future to support specifiers based on data other than the interface
+ // name.
+ @Nullable
+ public String getInterfaceName() {
+ return mInterfaceName;
+ }
+
+ @Override
+ public boolean canBeSatisfiedBy(@Nullable NetworkSpecifier other) {
+ return equals(other);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof TestNetworkSpecifier)) return false;
+ return TextUtils.equals(mInterfaceName, ((TestNetworkSpecifier) o).mInterfaceName);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(mInterfaceName);
+ }
+
+ @Override
+ public String toString() {
+ return "TestNetworkSpecifier (" + mInterfaceName + ")";
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeString(mInterfaceName);
+ }
+
+ public static final @NonNull Creator<TestNetworkSpecifier> CREATOR =
+ new Creator<TestNetworkSpecifier>() {
+ public TestNetworkSpecifier createFromParcel(Parcel in) {
+ return new TestNetworkSpecifier(in.readString());
+ }
+ public TestNetworkSpecifier[] newArray(int size) {
+ return new TestNetworkSpecifier[size];
+ }
+ };
+}
diff --git a/packages/Connectivity/framework/src/android/net/TransportInfo.java b/packages/Connectivity/framework/src/android/net/TransportInfo.java
index aa4bbb0..fa889ea 100644
--- a/packages/Connectivity/framework/src/android/net/TransportInfo.java
+++ b/packages/Connectivity/framework/src/android/net/TransportInfo.java
@@ -29,35 +29,47 @@
public interface TransportInfo {
/**
- * Create a copy of a {@link TransportInfo} that will preserve location sensitive fields that
- * were set based on the permissions of the process that originally received it.
+ * Create a copy of a {@link TransportInfo} with some fields redacted based on the permissions
+ * held by the receiving app.
*
- * <p>By default {@link TransportInfo} does not preserve such fields during parceling, as
- * they should not be shared outside of the process that receives them without appropriate
- * checks.
+ * <p>
+ * Usage by connectivity stack:
+ * <ul>
+ * <li> Connectivity stack will invoke {@link #getApplicableRedactions()} to find the list
+ * of redactions that are required by this {@link TransportInfo} instance.</li>
+ * <li> Connectivity stack then loops through each bit in the bitmask returned and checks if the
+ * receiving app holds the corresponding permission.
+ * <ul>
+ * <li> If the app holds the corresponding permission, the bit is cleared from the
+ * |redactions| bitmask. </li>
+ * <li> If the app does not hold the corresponding permission, the bit is retained in the
+ * |redactions| bitmask. </li>
+ * </ul>
+ * <li> Connectivity stack then invokes {@link #makeCopy(long)} with the necessary |redactions|
+ * to create a copy to send to the corresponding app. </li>
+ * </ul>
+ * </p>
*
- * @param parcelLocationSensitiveFields Whether the location sensitive fields should be kept
- * when parceling
- * @return Copy of this instance.
+ * @param redactions bitmask of redactions that needs to be performed on this instance.
+ * @return Copy of this instance with the necessary redactions.
* @hide
*/
- @SystemApi
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
@NonNull
- default TransportInfo makeCopy(boolean parcelLocationSensitiveFields) {
+ default TransportInfo makeCopy(@NetworkCapabilities.RedactionType long redactions) {
return this;
}
/**
- * Returns whether this TransportInfo type has location sensitive fields or not (helps
- * to determine whether to perform a location permission check or not before sending to
- * apps).
+ * Returns a bitmask of all the applicable redactions (based on the permissions held by the
+ * receiving app) to be performed on this TransportInfo.
*
- * @return {@code true} if this instance contains location sensitive info, {@code false}
- * otherwise.
+ * @return bitmask of redactions applicable on this instance.
+ * @see #makeCopy(long)
* @hide
*/
- @SystemApi
- default boolean hasLocationSensitiveFields() {
- return false;
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ default @NetworkCapabilities.RedactionType long getApplicableRedactions() {
+ return NetworkCapabilities.REDACT_NONE;
}
}
diff --git a/packages/Connectivity/framework/src/android/net/UidRange.java b/packages/Connectivity/framework/src/android/net/UidRange.java
index 26518d3..bc67c74 100644
--- a/packages/Connectivity/framework/src/android/net/UidRange.java
+++ b/packages/Connectivity/framework/src/android/net/UidRange.java
@@ -20,8 +20,11 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.os.UserHandle;
+import android.util.ArraySet;
+import android.util.Range;
import java.util.Collection;
+import java.util.Set;
/**
* An inclusive range of UIDs.
@@ -149,4 +152,32 @@
}
return false;
}
+
+ /**
+ * Convert a set of {@code Range<Integer>} to a set of {@link UidRange}.
+ */
+ @Nullable
+ public static ArraySet<UidRange> fromIntRanges(@Nullable Set<Range<Integer>> ranges) {
+ if (null == ranges) return null;
+
+ final ArraySet<UidRange> uids = new ArraySet<>();
+ for (Range<Integer> range : ranges) {
+ uids.add(new UidRange(range.getLower(), range.getUpper()));
+ }
+ return uids;
+ }
+
+ /**
+ * Convert a set of {@link UidRange} to a set of {@code Range<Integer>}.
+ */
+ @Nullable
+ public static ArraySet<Range<Integer>> toIntRanges(@Nullable Set<UidRange> ranges) {
+ if (null == ranges) return null;
+
+ final ArraySet<Range<Integer>> uids = new ArraySet<>();
+ for (UidRange range : ranges) {
+ uids.add(new Range<Integer>(range.start, range.stop));
+ }
+ return uids;
+ }
}
diff --git a/packages/Connectivity/framework/src/android/net/VpnTransportInfo.java b/packages/Connectivity/framework/src/android/net/VpnTransportInfo.java
index 340141b..cd8f4c0 100644
--- a/packages/Connectivity/framework/src/android/net/VpnTransportInfo.java
+++ b/packages/Connectivity/framework/src/android/net/VpnTransportInfo.java
@@ -22,9 +22,6 @@
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
-import android.util.SparseArray;
-
-import com.android.internal.util.MessageUtils;
import java.util.Objects;
@@ -38,13 +35,10 @@
*/
@SystemApi(client = MODULE_LIBRARIES)
public final class VpnTransportInfo implements TransportInfo, Parcelable {
- private static final SparseArray<String> sTypeToString =
- MessageUtils.findMessageNames(new Class[]{VpnManager.class}, new String[]{"TYPE_VPN_"});
-
/** Type of this VPN. */
- @VpnManager.VpnType public final int type;
+ public final int type;
- public VpnTransportInfo(@VpnManager.VpnType int type) {
+ public VpnTransportInfo(int type) {
this.type = type;
}
@@ -63,8 +57,7 @@
@Override
public String toString() {
- final String typeString = sTypeToString.get(type, "VPN_TYPE_???");
- return String.format("VpnTransportInfo{%s}", typeString);
+ return String.format("VpnTransportInfo{type=%d}", type);
}
@Override
diff --git a/packages/Connectivity/framework/src/android/net/apf/ApfCapabilities.java b/packages/Connectivity/framework/src/android/net/apf/ApfCapabilities.java
index bf5b26e..85b24713 100644
--- a/packages/Connectivity/framework/src/android/net/apf/ApfCapabilities.java
+++ b/packages/Connectivity/framework/src/android/net/apf/ApfCapabilities.java
@@ -19,12 +19,12 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.content.Context;
import android.content.res.Resources;
+import android.net.ConnectivityResources;
import android.os.Parcel;
import android.os.Parcelable;
-import com.android.internal.R;
-
/**
* APF program support capabilities. APF stands for Android Packet Filtering and it is a flexible
* way to drop unwanted network packets to save power.
@@ -36,6 +36,8 @@
*/
@SystemApi
public final class ApfCapabilities implements Parcelable {
+ private static ConnectivityResources sResources;
+
/**
* Version of APF instruction set supported for packet filtering. 0 indicates no support for
* packet filtering using APF programs.
@@ -65,6 +67,14 @@
apfPacketFormat = in.readInt();
}
+ @NonNull
+ private static synchronized ConnectivityResources getResources(@NonNull Context ctx) {
+ if (sResources == null) {
+ sResources = new ConnectivityResources(ctx);
+ }
+ return sResources;
+ }
+
@Override
public int describeContents() {
@@ -121,13 +131,43 @@
* @return Whether the APF Filter in the device should filter out IEEE 802.3 Frames.
*/
public static boolean getApfDrop8023Frames() {
- return Resources.getSystem().getBoolean(R.bool.config_apfDrop802_3Frames);
+ // TODO(b/183076074): remove reading resources from system resources
+ final Resources systemRes = Resources.getSystem();
+ final int id = systemRes.getIdentifier("config_apfDrop802_3Frames", "bool", "android");
+ return systemRes.getBoolean(id);
+ }
+
+ /**
+ * @return Whether the APF Filter in the device should filter out IEEE 802.3 Frames.
+ * @hide
+ */
+ public static boolean getApfDrop8023Frames(@NonNull Context context) {
+ final ConnectivityResources res = getResources(context);
+ // TODO(b/183076074): use R.bool.config_apfDrop802_3Frames directly
+ final int id = res.get().getIdentifier("config_apfDrop802_3Frames", "bool",
+ res.getResourcesContext().getPackageName());
+ return res.get().getBoolean(id);
}
/**
* @return An array of denylisted EtherType, packets with EtherTypes within it will be dropped.
*/
public static @NonNull int[] getApfEtherTypeBlackList() {
- return Resources.getSystem().getIntArray(R.array.config_apfEthTypeBlackList);
+ // TODO(b/183076074): remove reading resources from system resources
+ final Resources systemRes = Resources.getSystem();
+ final int id = systemRes.getIdentifier("config_apfEthTypeBlackList", "array", "android");
+ return systemRes.getIntArray(id);
+ }
+
+ /**
+ * @return An array of denylisted EtherType, packets with EtherTypes within it will be dropped.
+ * @hide
+ */
+ public static @NonNull int[] getApfEtherTypeDenyList(@NonNull Context context) {
+ final ConnectivityResources res = getResources(context);
+ // TODO(b/183076074): use R.array.config_apfEthTypeDenyList directly
+ final int id = res.get().getIdentifier("config_apfEthTypeDenyList", "array",
+ res.getResourcesContext().getPackageName());
+ return res.get().getIntArray(id);
}
}
diff --git a/packages/Connectivity/framework/src/android/net/util/KeepaliveUtils.java b/packages/Connectivity/framework/src/android/net/util/KeepaliveUtils.java
index bfc4563..8d7a0b3 100644
--- a/packages/Connectivity/framework/src/android/net/util/KeepaliveUtils.java
+++ b/packages/Connectivity/framework/src/android/net/util/KeepaliveUtils.java
@@ -19,12 +19,11 @@
import android.annotation.NonNull;
import android.content.Context;
import android.content.res.Resources;
+import android.net.ConnectivityResources;
import android.net.NetworkCapabilities;
import android.text.TextUtils;
import android.util.AndroidRuntimeException;
-import com.android.internal.R;
-
/**
* Collection of utilities for socket keepalive offload.
*
@@ -52,8 +51,11 @@
public static int[] getSupportedKeepalives(@NonNull Context context) {
String[] res = null;
try {
- res = context.getResources().getStringArray(
- R.array.config_networkSupportedKeepaliveCount);
+ final ConnectivityResources connRes = new ConnectivityResources(context);
+ // TODO: use R.id.config_networkSupportedKeepaliveCount directly
+ final int id = connRes.get().getIdentifier("config_networkSupportedKeepaliveCount",
+ "array", connRes.getResourcesContext().getPackageName());
+ res = new ConnectivityResources(context).get().getStringArray(id);
} catch (Resources.NotFoundException unused) {
}
if (res == null) throw new KeepaliveDeviceConfigurationException("invalid resource");
diff --git a/packages/Connectivity/framework/src/android/net/util/MultinetworkPolicyTracker.java b/packages/Connectivity/framework/src/android/net/util/MultinetworkPolicyTracker.java
index 739ddad..0b42a00 100644
--- a/packages/Connectivity/framework/src/android/net/util/MultinetworkPolicyTracker.java
+++ b/packages/Connectivity/framework/src/android/net/util/MultinetworkPolicyTracker.java
@@ -16,8 +16,8 @@
package android.net.util;
-import static android.provider.Settings.Global.NETWORK_AVOID_BAD_WIFI;
-import static android.provider.Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE;
+import static android.net.ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI;
+import static android.net.ConnectivitySettingsManager.NETWORK_METERED_MULTIPATH_PREFERENCE;
import android.annotation.NonNull;
import android.content.BroadcastReceiver;
@@ -27,6 +27,7 @@
import android.content.IntentFilter;
import android.content.res.Resources;
import android.database.ContentObserver;
+import android.net.ConnectivityResources;
import android.net.Uri;
import android.os.Handler;
import android.provider.Settings;
@@ -35,7 +36,6 @@
import android.telephony.TelephonyManager;
import android.util.Log;
-import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import java.util.Arrays;
@@ -64,6 +64,7 @@
private static String TAG = MultinetworkPolicyTracker.class.getSimpleName();
private final Context mContext;
+ private final ConnectivityResources mResources;
private final Handler mHandler;
private final Runnable mAvoidBadWifiCallback;
private final List<Uri> mSettingsUris;
@@ -107,11 +108,12 @@
public MultinetworkPolicyTracker(Context ctx, Handler handler, Runnable avoidBadWifiCallback) {
mContext = ctx;
+ mResources = new ConnectivityResources(ctx);
mHandler = handler;
mAvoidBadWifiCallback = avoidBadWifiCallback;
mSettingsUris = Arrays.asList(
- Settings.Global.getUriFor(NETWORK_AVOID_BAD_WIFI),
- Settings.Global.getUriFor(NETWORK_METERED_MULTIPATH_PREFERENCE));
+ Settings.Global.getUriFor(NETWORK_AVOID_BAD_WIFI),
+ Settings.Global.getUriFor(NETWORK_METERED_MULTIPATH_PREFERENCE));
mResolver = mContext.getContentResolver();
mSettingObserver = new SettingObserver();
mBroadcastReceiver = new BroadcastReceiver() {
@@ -160,12 +162,16 @@
* Whether the device or carrier configuration disables avoiding bad wifi by default.
*/
public boolean configRestrictsAvoidBadWifi() {
- return (getResourcesForActiveSubId().getInteger(R.integer.config_networkAvoidBadWifi) == 0);
+ // TODO: use R.integer.config_networkAvoidBadWifi directly
+ final int id = mResources.get().getIdentifier("config_networkAvoidBadWifi",
+ "integer", mResources.getResourcesContext().getPackageName());
+ return (getResourcesForActiveSubId().getInteger(id) == 0);
}
@NonNull
private Resources getResourcesForActiveSubId() {
- return SubscriptionManager.getResourcesForSubId(mContext, mActiveSubId);
+ return SubscriptionManager.getResourcesForSubId(
+ mResources.getResourcesContext(), mActiveSubId);
}
/**
@@ -205,8 +211,10 @@
* The default (device and carrier-dependent) value for metered multipath preference.
*/
public int configMeteredMultipathPreference() {
- return mContext.getResources().getInteger(
- R.integer.config_networkMeteredMultipathPreference);
+ // TODO: use R.integer.config_networkMeteredMultipathPreference directly
+ final int id = mResources.get().getIdentifier("config_networkMeteredMultipathPreference",
+ "integer", mResources.getResourcesContext().getPackageName());
+ return mResources.get().getInteger(id);
}
public void updateMeteredMultipathPreference() {
diff --git a/packages/Connectivity/service/Android.bp b/packages/Connectivity/service/Android.bp
index e65b7b4..1330e71 100644
--- a/packages/Connectivity/service/Android.bp
+++ b/packages/Connectivity/service/Android.bp
@@ -50,26 +50,56 @@
}
java_library {
- name: "service-connectivity",
+ name: "service-connectivity-pre-jarjar",
srcs: [
+ ":framework-connectivity-shared-srcs",
":connectivity-service-srcs",
],
- installable: true,
- jarjar_rules: "jarjar-rules.txt",
libs: [
"android.net.ipsec.ike",
"services.core",
"services.net",
"unsupportedappusage",
+ "ServiceConnectivityResources",
],
static_libs: [
"modules-utils-os",
"net-utils-device-common",
"net-utils-framework-common",
"netd-client",
+ "PlatformProperties",
+ "service-connectivity-protos",
],
apex_available: [
"//apex_available:platform",
"com.android.tethering",
],
}
+
+java_library {
+ name: "service-connectivity-protos",
+ proto: {
+ type: "nano",
+ },
+ srcs: [
+ ":system-messages-proto-src",
+ ],
+ libs: ["libprotobuf-java-nano"],
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.tethering",
+ ],
+}
+
+java_library {
+ name: "service-connectivity",
+ installable: true,
+ static_libs: [
+ "service-connectivity-pre-jarjar",
+ ],
+ jarjar_rules: "jarjar-rules.txt",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.tethering",
+ ],
+}
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/Android.bp b/packages/Connectivity/service/ServiceConnectivityResources/Android.bp
new file mode 100644
index 0000000..fa4501a
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/Android.bp
@@ -0,0 +1,35 @@
+//
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// APK to hold all the wifi overlayable resources.
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_app {
+ name: "ServiceConnectivityResources",
+ sdk_version: "module_current",
+ resource_dirs: [
+ "res",
+ ],
+ privileged: true,
+ export_package_resources: true,
+ apex_available: [
+ "com.android.tethering",
+ ],
+ // TODO: use a dedicated cert once generated
+ certificate: "platform",
+}
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/AndroidManifest.xml b/packages/Connectivity/service/ServiceConnectivityResources/AndroidManifest.xml
new file mode 100644
index 0000000..2c30302
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/AndroidManifest.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<!-- Manifest for connectivity resources APK -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.connectivity.resources"
+ coreApp="true"
+ android:versionCode="1"
+ android:versionName="S-initial">
+ <application
+ android:label="@string/connectivityResourcesAppLabel"
+ android:defaultToDeviceProtectedStorage="true"
+ android:directBootAware="true">
+ <!-- This is only used to identify this app by resolving the action.
+ The activity is never actually triggered. -->
+ <activity android:name="android.app.Activity" android:exported="true" android:enabled="true">
+ <intent-filter>
+ <action android:name="com.android.server.connectivity.intent.action.SERVICE_CONNECTIVITY_RESOURCES_APK" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/drawable-hdpi/stat_notify_rssi_in_range.png b/packages/Connectivity/service/ServiceConnectivityResources/res/drawable-hdpi/stat_notify_rssi_in_range.png
new file mode 100644
index 0000000..74977e6
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/drawable-hdpi/stat_notify_rssi_in_range.png
Binary files differ
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/drawable-mdpi/stat_notify_rssi_in_range.png b/packages/Connectivity/service/ServiceConnectivityResources/res/drawable-mdpi/stat_notify_rssi_in_range.png
new file mode 100644
index 0000000..62e4fe9
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/drawable-mdpi/stat_notify_rssi_in_range.png
Binary files differ
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/drawable-xhdpi/stat_notify_rssi_in_range.png b/packages/Connectivity/service/ServiceConnectivityResources/res/drawable-xhdpi/stat_notify_rssi_in_range.png
new file mode 100644
index 0000000..c0586d8
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/drawable-xhdpi/stat_notify_rssi_in_range.png
Binary files differ
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/drawable-xxhdpi/stat_notify_rssi_in_range.png b/packages/Connectivity/service/ServiceConnectivityResources/res/drawable-xxhdpi/stat_notify_rssi_in_range.png
new file mode 100644
index 0000000..86c34ed
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/drawable-xxhdpi/stat_notify_rssi_in_range.png
Binary files differ
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/drawable/stat_notify_wifi_in_range.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/drawable/stat_notify_wifi_in_range.xml
new file mode 100644
index 0000000..a271ca5
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/drawable/stat_notify_wifi_in_range.xml
@@ -0,0 +1,27 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="26.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="26.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#4DFFFFFF"
+ android:pathData="M19.1,14l-3.4,0l0,-1.5c0,-1.8 0.8,-2.8 1.5,-3.4C18.1,8.3 19.200001,8 20.6,8c1.2,0 2.3,0.3 3.1,0.8l1.9,-2.3C25.1,6.1 20.299999,2.1 13,2.1S0.9,6.1 0.4,6.5L13,22l0,0l0,0l0,0l0,0l6.5,-8.1L19.1,14z"/>
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M19.5,17.799999c0,-0.8 0.1,-1.3 0.2,-1.6c0.2,-0.3 0.5,-0.7 1.1,-1.2c0.4,-0.4 0.7,-0.8 1,-1.1s0.4,-0.8 0.4,-1.2c0,-0.5 -0.1,-0.9 -0.4,-1.2c-0.3,-0.3 -0.7,-0.4 -1.2,-0.4c-0.4,0 -0.8,0.1 -1.1,0.3c-0.3,0.2 -0.4,0.6 -0.4,1.1l-1.9,0c0,-1 0.3,-1.7 1,-2.2c0.6,-0.5 1.5,-0.8 2.5,-0.8c1.1,0 2,0.3 2.6,0.8c0.6,0.5 0.9,1.3 0.9,2.3c0,0.7 -0.2,1.3 -0.6,1.8c-0.4,0.6 -0.9,1.1 -1.5,1.6c-0.3,0.3 -0.5,0.5 -0.6,0.7c-0.1,0.2 -0.1,0.6 -0.1,1L19.5,17.700001zM21.4,21l-1.9,0l0,-1.8l1.9,0L21.4,21z"/>
+</vector>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-af/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-af/strings.xml
new file mode 100644
index 0000000..68720d5
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-af/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Meld aan by Wi-Fi-netwerk"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Meld by netwerk aan"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> het geen internettoegang nie"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Tik vir opsies"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Selnetwerk het nie internettoegang nie"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Netwerk het nie internettoegang nie"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Daar kan nie by private DNS-bediener ingegaan word nie"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> het beperkte konnektiwiteit"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Tik om in elk geval te koppel"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Het oorgeskakel na <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Toestel gebruik <xliff:g id="NEW_NETWORK">%1$s</xliff:g> wanneer <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> geen internettoegang het nie. Heffings kan geld."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Het oorgeskakel van <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"\'n onbekende netwerktipe"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"mobiele data"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-am/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-am/strings.xml
new file mode 100644
index 0000000..78d9283
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-am/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"ወደ Wi-Fi አውታረ መረብ በመለያ ግባ"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"ወደ አውታረ መረብ በመለያ ይግቡ"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ምንም የበይነ መረብ መዳረሻ የለም"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"ለአማራጮች መታ ያድርጉ"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"የተንቀሳቃሽ ስልክ አውታረ መረብ የበይነመረብ መዳረሻ የለውም"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"አውታረ መረብ የበይነመረብ መዳረሻ የለውም"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"የግል ዲኤንኤስ አገልጋይ ሊደረስበት አይችልም"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> የተገደበ ግንኙነት አለው"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"ለማንኛውም ለማገናኘት መታ ያድርጉ"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"ወደ <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ተቀይሯል"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ምንም ዓይነት የበይነመረብ ግንኙነት በማይኖረው ጊዜ መሣሪያዎች <xliff:g id="NEW_NETWORK">%1$s</xliff:g>ን ይጠቀማሉ። ክፍያዎች ተፈጻሚ ሊሆኑ ይችላሉ።"</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"ከ<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ወደ <xliff:g id="NEW_NETWORK">%2$s</xliff:g> ተቀይሯል"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"አንድ ያልታወቀ አውታረ መረብ ዓይነት"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"የተንቀሳቃሽ ስልክ ውሂብ"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"ብሉቱዝ"</item>
+ <item msgid="1616528372438698248">"ኤተርኔት"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-ar/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ar/strings.xml
new file mode 100644
index 0000000..8698a7e
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ar/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"تسجيل الدخول إلى شبكة Wi-Fi"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"تسجيل الدخول إلى الشبكة"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"لا يتوفّر في <xliff:g id="NETWORK_SSID">%1$s</xliff:g> إمكانية الاتصال بالإنترنت."</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"انقر للحصول على الخيارات."</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"شبكة الجوّال هذه غير متصلة بالإنترنت"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"الشبكة غير متصلة بالإنترنت"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"لا يمكن الوصول إلى خادم أسماء نظام نطاقات خاص"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"إمكانية اتصال <xliff:g id="NETWORK_SSID">%1$s</xliff:g> محدودة."</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"يمكنك النقر للاتصال على أي حال."</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"تم التبديل إلى <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"يستخدم الجهاز <xliff:g id="NEW_NETWORK">%1$s</xliff:g> عندما لا يتوفر اتصال بالإنترنت في شبكة <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>، ويمكن أن يتم فرض رسوم مقابل ذلك."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"تم التبديل من <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> إلى <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"نوع شبكة غير معروف"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"بيانات الجوّال"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"بلوتوث"</item>
+ <item msgid="1616528372438698248">"إيثرنت"</item>
+ <item msgid="9177085807664964627">"شبكة افتراضية خاصة (VPN)"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-as/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-as/strings.xml
new file mode 100644
index 0000000..10b234a
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-as/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"ৱাই-ফাই নেটৱৰ্কত ছাইন ইন কৰক"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"নেটৱৰ্কত ছাইন ইন কৰক"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>ৰ ইণ্টাৰনেটৰ এক্সেছ নাই"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"অধিক বিকল্পৰ বাবে টিপক"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"ম’বাইল নেটৱৰ্কৰ কোনো ইণ্টাৰনেটৰ এক্সেছ নাই"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"নেটৱৰ্কৰ কোনো ইণ্টাৰনেটৰ এক্সেছ নাই"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"ব্যক্তিগত DNS ছাৰ্ভাৰ এক্সেছ কৰিব নোৱাৰি"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>ৰ সকলো সেৱাৰ এক্সেছ নাই"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"যিকোনো প্ৰকাৰে সংযোগ কৰিবলৈ টিপক"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>লৈ সলনি কৰা হ’ল"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"যেতিয়া <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>ত ইণ্টাৰনেট নাথাকে, তেতিয়া ডিভাইচে <xliff:g id="NEW_NETWORK">%1$s</xliff:g>ক ব্যৱহাৰ কৰে। মাচুল প্ৰযোজ্য হ\'ব পাৰে।"</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>ৰ পৰা <xliff:g id="NEW_NETWORK">%2$s</xliff:g> লৈ সলনি কৰা হ’ল"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"অজ্ঞাত প্ৰকাৰৰ নেটৱৰ্ক"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"ম’বাইল ডেটা"</item>
+ <item msgid="5520925862115353992">"ৱাই-ফাই"</item>
+ <item msgid="1055487873974272842">"ব্লুটুথ"</item>
+ <item msgid="1616528372438698248">"ইথাৰনেট"</item>
+ <item msgid="9177085807664964627">"ভিপিএন"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-az/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-az/strings.xml
new file mode 100644
index 0000000..d75a204
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-az/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Wi-Fi şəbəkəsinə daxil ol"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Şəbəkəyə daxil olun"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> üçün internet girişi əlçatan deyil"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Seçimlər üçün tıklayın"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Mobil şəbəkənin internetə girişi yoxdur"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Şəbəkənin internetə girişi yoxdur"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Özəl DNS serverinə giriş mümkün deyil"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> bağlantını məhdudlaşdırdı"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"İstənilən halda klikləyin"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> şəbəkə növünə keçirildi"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> şəbəkəsinin internetə girişi olmadıqda, cihaz <xliff:g id="NEW_NETWORK">%1$s</xliff:g> şəbəkəsini istifadə edir. Xidmət haqqı tutula bilər."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> şəbəkəsindən <xliff:g id="NEW_NETWORK">%2$s</xliff:g> şəbəkəsinə keçirildi"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"naməlum şəbəkə növü"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"mobil data"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-b+sr+Latn/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 0000000..11e4957
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-b+sr+Latn/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Prijavljivanje na WiFi mrežu"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Prijavite se na mrežu"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> nema pristup internetu"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Dodirnite za opcije"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Mobilna mreža nema pristup internetu"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Mreža nema pristup internetu"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Pristup privatnom DNS serveru nije uspeo"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ima ograničenu vezu"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Dodirnite da biste se ipak povezali"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Prešli ste na tip mreže <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Uređaj koristi tip mreže <xliff:g id="NEW_NETWORK">%1$s</xliff:g> kada tip mreže <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nema pristup internetu. Možda će se naplaćivati troškovi."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Prešli ste sa tipa mreže <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na tip mreže <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"nepoznat tip mreže"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"mobilni podaci"</item>
+ <item msgid="5520925862115353992">"WiFi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Eternet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-be/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-be/strings.xml
new file mode 100644
index 0000000..6b0b1f1
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-be/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Уваход у сетку Wi-Fi"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Увайдзіце ў сетку"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> не мае доступу ў інтэрнэт"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Дакраніцеся, каб убачыць параметры"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Мабільная сетка не мае доступу ў інтэрнэт"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Сетка не мае доступу ў інтэрнэт"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Не ўдалося атрымаць доступ да прыватнага DNS-сервера"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> мае абмежаваную магчымасць падключэння"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Націсніце, каб падключыцца"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Выкананы пераход да <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Прылада выкарыстоўвае сетку <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, калі ў сетцы <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> няма доступу да інтэрнэту. Можа спаганяцца плата."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Выкананы пераход з <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> да <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"невядомы тып сеткі"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"мабільная перадача даных"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-bg/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-bg/strings.xml
new file mode 100644
index 0000000..6427bd0
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-bg/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Влизане в Wi-Fi мрежа"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Вход в мрежата"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> няма достъп до интернет"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Докоснете за опции"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Мобилната мрежа няма достъп до интернет"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Мрежата няма достъп до интернет"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Не може да се осъществи достъп до частния DNS сървър"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> има ограничена свързаност"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Докоснете, за да се свържете въпреки това"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Превключи се към <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Устройството използва <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, когато <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> няма достъп до интернет. Възможно е да бъдете таксувани."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Превключи се от <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> към <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"неизвестен тип мрежа"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"мобилни данни"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"виртуална частна мрежа (VPN)"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-bn/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-bn/strings.xml
new file mode 100644
index 0000000..74d4cd6
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-bn/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"ওয়াই-ফাই নেটওয়ার্কে সাইন-ইন করুন"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"নেটওয়ার্কে সাইন-ইন করুন"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>-এর ইন্টারনেটে অ্যাক্সেস নেই"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"বিকল্পগুলির জন্য আলতো চাপুন"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"মোবাইল নেটওয়ার্কে কোনও ইন্টারনেট অ্যাক্সেস নেই"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"নেটওয়ার্কে কোনও ইন্টারনেট অ্যাক্সেস নেই"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"ব্যক্তিগত ডিএনএস সার্ভার অ্যাক্সেস করা যাবে না"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>-এর সীমিত কানেক্টিভিটি আছে"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"তবুও কানেক্ট করতে ট্যাপ করুন"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> এ পাল্টানো হয়েছে"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> এ ইন্টারনেট অ্যাক্সেস না থাকলে <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ব্যবহার করা হয়৷ ডেটা চার্জ প্রযোজ্য৷"</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> থেকে <xliff:g id="NEW_NETWORK">%2$s</xliff:g> এ পাল্টানো হয়েছে"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"এই নেটওয়ার্কের প্রকার অজানা"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"মোবাইল ডেটা"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"ব্লুটুথ"</item>
+ <item msgid="1616528372438698248">"ইথারনেট"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-bs/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-bs/strings.xml
new file mode 100644
index 0000000..19f6e1a
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-bs/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Prijavljivanje na WiFi mrežu"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Prijava na mrežu"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"Mreža <xliff:g id="NETWORK_SSID">%1$s</xliff:g> nema pristup internetu"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Dodirnite za opcije"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Mobilna mreža nema pristup internetu"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Mreža nema pristup internetu"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Nije moguće pristupiti privatnom DNS serveru"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"Mreža <xliff:g id="NETWORK_SSID">%1$s</xliff:g> ima ograničenu povezivost"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Dodirnite da se ipak povežete"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Prebačeno na: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Kada <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nema pristup internetu, uređaj koristi mrežu <xliff:g id="NEW_NETWORK">%1$s</xliff:g>. Moguća je naplata usluge."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Prebačeno iz mreže <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> u <xliff:g id="NEW_NETWORK">%2$s</xliff:g> mrežu"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"nepoznata vrsta mreže"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"prijenos podataka na mobilnoj mreži"</item>
+ <item msgid="5520925862115353992">"WiFi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-ca/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ca/strings.xml
new file mode 100644
index 0000000..c55684d
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ca/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Inicia la sessió a la xarxa Wi-Fi"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Inicia la sessió a la xarxa"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> no té accés a Internet"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Toca per veure les opcions"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"La xarxa mòbil no té accés a Internet"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"La xarxa no té accés a Internet"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"No es pot accedir al servidor DNS privat"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> té una connectivitat limitada"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Toca per connectar igualment"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Actualment en ús: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"El dispositiu utilitza <xliff:g id="NEW_NETWORK">%1$s</xliff:g> en cas que <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> no tingui accés a Internet. És possible que s\'hi apliquin càrrecs."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Abans es feia servir la xarxa <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>; ara s\'utilitza <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"una tipus de xarxa desconegut"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"dades mòbils"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-cs/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-cs/strings.xml
new file mode 100644
index 0000000..fa8c411
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-cs/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Přihlásit se k síti Wi-Fi"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Přihlásit se k síti"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"Síť <xliff:g id="NETWORK_SSID">%1$s</xliff:g> nemá přístup k internetu"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Klepnutím zobrazíte možnosti"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Mobilní síť nemá přístup k internetu"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Síť nemá přístup k internetu"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Nelze získat přístup k soukromému serveru DNS"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"Síť <xliff:g id="NETWORK_SSID">%1$s</xliff:g> umožňuje jen omezené připojení"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Klepnutím se i přesto připojíte"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Přechod na síť <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Když síť <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nebude mít přístup k internetu, zařízení použije síť <xliff:g id="NEW_NETWORK">%1$s</xliff:g>. Mohou být účtovány poplatky."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Přechod ze sítě <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na síť <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"neznámý typ sítě"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"mobilní data"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-da/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-da/strings.xml
new file mode 100644
index 0000000..f7be6df
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-da/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Log ind på Wi-Fi-netværk"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Log ind på netværk"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> har ingen internetforbindelse"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Tryk for at se valgmuligheder"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Mobilnetværket har ingen internetadgang"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Netværket har ingen internetadgang"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Der er ikke adgang til den private DNS-server"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> har begrænset forbindelse"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Tryk for at oprette forbindelse alligevel"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Der blev skiftet til <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Enheden benytter <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, når der ikke er internetadgang via <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>. Der opkræves muligvis betaling."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Der blev skiftet fra <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> til <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"en ukendt netværkstype"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"mobildata"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-de/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-de/strings.xml
new file mode 100644
index 0000000..1e7b80c
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-de/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"In WLAN anmelden"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Im Netzwerk anmelden"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> hat keinen Internetzugriff"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Für Optionen tippen"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Mobiles Netzwerk hat keinen Internetzugriff"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Netzwerk hat keinen Internetzugriff"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Auf den privaten DNS-Server kann nicht zugegriffen werden"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"Schlechte Verbindung mit <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Tippen, um die Verbindung trotzdem herzustellen"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Zu <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> gewechselt"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Auf dem Gerät werden <xliff:g id="NEW_NETWORK">%1$s</xliff:g> genutzt, wenn über <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> kein Internet verfügbar ist. Eventuell fallen Gebühren an."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Von \"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>\" zu \"<xliff:g id="NEW_NETWORK">%2$s</xliff:g>\" gewechselt"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"ein unbekannter Netzwerktyp"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"Mobile Daten"</item>
+ <item msgid="5520925862115353992">"WLAN"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-el/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-el/strings.xml
new file mode 100644
index 0000000..89647fdb
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-el/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Συνδεθείτε στο δίκτυο Wi-Fi"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Σύνδεση στο δίκτυο"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"Η εφαρμογή <xliff:g id="NETWORK_SSID">%1$s</xliff:g> δεν έχει πρόσβαση στο διαδίκτυο"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Πατήστε για να δείτε τις επιλογές"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Το δίκτυο κινητής τηλεφωνίας δεν έχει πρόσβαση στο διαδίκτυο."</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Το δίκτυο δεν έχει πρόσβαση στο διαδίκτυο."</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Δεν είναι δυνατή η πρόσβαση στον ιδιωτικό διακομιστή DNS."</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"Το δίκτυο <xliff:g id="NETWORK_SSID">%1$s</xliff:g> έχει περιορισμένη συνδεσιμότητα"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Πατήστε για σύνδεση ούτως ή άλλως"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Μετάβαση σε δίκτυο <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Η συσκευή χρησιμοποιεί το δίκτυο <xliff:g id="NEW_NETWORK">%1$s</xliff:g> όταν το δίκτυο <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> δεν έχει πρόσβαση στο διαδίκτυο. Μπορεί να ισχύουν χρεώσεις."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Μετάβαση από το δίκτυο <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> στο δίκτυο <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"άγνωστος τύπος δικτύου"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"δεδομένα κινητής τηλεφωνίας"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-en-rAU/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-en-rAU/strings.xml
new file mode 100644
index 0000000..d29e2ec
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-en-rAU/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Sign in to a Wi-Fi network"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Sign in to network"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> has no Internet access"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Tap for options"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Mobile network has no Internet access"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Network has no Internet access"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Private DNS server cannot be accessed"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> has limited connectivity"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Tap to connect anyway"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Switched to <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Device uses <xliff:g id="NEW_NETWORK">%1$s</xliff:g> when <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> has no Internet access. Charges may apply."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Switched from <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> to <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"an unknown network type"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"mobile data"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-en-rCA/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-en-rCA/strings.xml
new file mode 100644
index 0000000..d29e2ec
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-en-rCA/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Sign in to a Wi-Fi network"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Sign in to network"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> has no Internet access"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Tap for options"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Mobile network has no Internet access"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Network has no Internet access"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Private DNS server cannot be accessed"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> has limited connectivity"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Tap to connect anyway"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Switched to <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Device uses <xliff:g id="NEW_NETWORK">%1$s</xliff:g> when <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> has no Internet access. Charges may apply."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Switched from <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> to <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"an unknown network type"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"mobile data"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-en-rGB/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-en-rGB/strings.xml
new file mode 100644
index 0000000..d29e2ec
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-en-rGB/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Sign in to a Wi-Fi network"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Sign in to network"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> has no Internet access"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Tap for options"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Mobile network has no Internet access"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Network has no Internet access"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Private DNS server cannot be accessed"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> has limited connectivity"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Tap to connect anyway"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Switched to <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Device uses <xliff:g id="NEW_NETWORK">%1$s</xliff:g> when <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> has no Internet access. Charges may apply."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Switched from <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> to <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"an unknown network type"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"mobile data"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-en-rIN/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-en-rIN/strings.xml
new file mode 100644
index 0000000..d29e2ec
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-en-rIN/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Sign in to a Wi-Fi network"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Sign in to network"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> has no Internet access"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Tap for options"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Mobile network has no Internet access"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Network has no Internet access"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Private DNS server cannot be accessed"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> has limited connectivity"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Tap to connect anyway"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Switched to <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Device uses <xliff:g id="NEW_NETWORK">%1$s</xliff:g> when <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> has no Internet access. Charges may apply."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Switched from <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> to <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"an unknown network type"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"mobile data"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-en-rXC/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-en-rXC/strings.xml
new file mode 100644
index 0000000..cd69133
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-en-rXC/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Sign in to Wi-Fi network"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Sign in to network"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> has no internet access"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Tap for options"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Mobile network has no internet access"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Network has no internet access"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Private DNS server cannot be accessed"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> has limited connectivity"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Tap to connect anyway"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Switched to <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Device uses <xliff:g id="NEW_NETWORK">%1$s</xliff:g> when <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> has no internet access. Charges may apply."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Switched from <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> to <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"an unknown network type"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"mobile data"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-es-rUS/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-es-rUS/strings.xml
new file mode 100644
index 0000000..9102dc0
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-es-rUS/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Accede a una red Wi-Fi."</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Acceder a la red"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>no tiene acceso a Internet"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Presiona para ver opciones"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"La red móvil no tiene acceso a Internet"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"La red no tiene acceso a Internet"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"No se puede acceder al servidor DNS privado"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> tiene conectividad limitada"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Presiona para conectarte de todas formas"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Se cambió a <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"El dispositivo usa <xliff:g id="NEW_NETWORK">%1$s</xliff:g> cuando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> no tiene acceso a Internet. Es posible que se apliquen cargos."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Se cambió de <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> a <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"un tipo de red desconocido"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"Datos móviles"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-es/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-es/strings.xml
new file mode 100644
index 0000000..4c15566
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-es/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Iniciar sesión en red Wi-Fi"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Iniciar sesión en la red"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> no tiene acceso a Internet"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Toca para ver opciones"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"La red móvil no tiene acceso a Internet"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"La red no tiene acceso a Internet"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"No se ha podido acceder al servidor DNS privado"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> tiene una conectividad limitada"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Toca para conectarte de todas formas"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Se ha cambiado a <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"El dispositivo utiliza <xliff:g id="NEW_NETWORK">%1$s</xliff:g> cuando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> no tiene acceso a Internet. Es posible que se apliquen cargos."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Se ha cambiado de <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> a <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"tipo de red desconocido"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"datos móviles"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-et/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-et/strings.xml
new file mode 100644
index 0000000..398223a
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-et/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Logi sisse WiFi-võrku"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Võrku sisselogimine"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"Võrgul <xliff:g id="NETWORK_SSID">%1$s</xliff:g> puudub Interneti-ühendus"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Puudutage valikute nägemiseks"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Mobiilsidevõrgul puudub Interneti-ühendus"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Võrgul puudub Interneti-ühendus"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Privaatsele DNS-serverile ei pääse juurde"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"Võrgu <xliff:g id="NETWORK_SSID">%1$s</xliff:g> ühendus on piiratud"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Puudutage, kui soovite siiski ühenduse luua"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Lülitati võrgule <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Seade kasutab võrku <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, kui võrgul <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> puudub juurdepääs Internetile. Rakenduda võivad tasud."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Lülitati võrgult <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> võrgule <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"tundmatu võrgutüüp"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"mobiilne andmeside"</item>
+ <item msgid="5520925862115353992">"WiFi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-eu/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-eu/strings.xml
new file mode 100644
index 0000000..dd70316
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-eu/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Hasi saioa Wi-Fi sarean"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Hasi saioa sarean"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"Ezin da konektatu Internetera <xliff:g id="NETWORK_SSID">%1$s</xliff:g> sarearen bidez"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Sakatu aukerak ikusteko"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Sare mugikorra ezin da konektatu Internetera"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Sarea ezin da konektatu Internetera"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Ezin da atzitu DNS zerbitzari pribatua"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> sareak konektagarritasun murriztua du"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Sakatu hala ere konektatzeko"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> erabiltzen ari zara orain"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> Internetera konektatzeko gauza ez denean, <xliff:g id="NEW_NETWORK">%1$s</xliff:g> erabiltzen du gailuak. Agian kostuak ordaindu beharko dituzu."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> erabiltzen ari zinen, baina <xliff:g id="NEW_NETWORK">%2$s</xliff:g> erabiltzen ari zara orain"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"sare mota ezezaguna"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"datu-konexioa"</item>
+ <item msgid="5520925862115353992">"Wifia"</item>
+ <item msgid="1055487873974272842">"Bluetooth-a"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-fa/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-fa/strings.xml
new file mode 100644
index 0000000..46a946c
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-fa/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"ورود به شبکه Wi-Fi"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"ورود به سیستم شبکه"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> به اینترنت دسترسی ندارد"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"برای گزینهها ضربه بزنید"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"شبکه تلفن همراه به اینترنت دسترسی ندارد"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"شبکه به اینترنت دسترسی ندارد"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"سرور DNS خصوصی قابل دسترسی نیست"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> اتصال محدودی دارد"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"بههرصورت، برای اتصال ضربه بزنید"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"به <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> تغییر کرد"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"وقتی <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> به اینترنت دسترسی نداشته باشد، دستگاه از <xliff:g id="NEW_NETWORK">%1$s</xliff:g> استفاده میکند. ممکن است هزینههایی اعمال شود."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"از <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> به <xliff:g id="NEW_NETWORK">%2$s</xliff:g> تغییر کرد"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"نوع شبکه نامشخص"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"داده تلفن همراه"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"بلوتوث"</item>
+ <item msgid="1616528372438698248">"اترنت"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-fi/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-fi/strings.xml
new file mode 100644
index 0000000..dd94441
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-fi/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Kirjaudu Wi-Fi-verkkoon"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Kirjaudu verkkoon"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ei ole yhteydessä internetiin"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Näytä vaihtoehdot napauttamalla."</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Mobiiliverkko ei ole yhteydessä internetiin"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Verkko ei ole yhteydessä internetiin"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Ei pääsyä yksityiselle DNS-palvelimelle"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> toimii rajoitetulla yhteydellä"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Yhdistä napauttamalla"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> otettiin käyttöön"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="NEW_NETWORK">%1$s</xliff:g> otetaan käyttöön, kun <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ei voi muodostaa yhteyttä internetiin. Veloitukset ovat mahdollisia."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> poistettiin käytöstä ja <xliff:g id="NEW_NETWORK">%2$s</xliff:g> otettiin käyttöön."</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"tuntematon verkon tyyppi"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"mobiilidata"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-fr-rCA/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-fr-rCA/strings.xml
new file mode 100644
index 0000000..02ef50b
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-fr-rCA/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Connectez-vous au réseau Wi-Fi"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Connectez-vous au réseau"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"Le réseau <xliff:g id="NETWORK_SSID">%1$s</xliff:g> n\'offre aucun accès à Internet"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Touchez pour afficher les options"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Le réseau cellulaire n\'offre aucun accès à Internet"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Le réseau n\'offre aucun accès à Internet"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Impossible d\'accéder au serveur DNS privé"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"Le réseau <xliff:g id="NETWORK_SSID">%1$s</xliff:g> offre une connectivité limitée"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Touchez pour vous connecter quand même"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Passé au réseau <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"L\'appareil utilise <xliff:g id="NEW_NETWORK">%1$s</xliff:g> quand <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> n\'a pas d\'accès à Internet. Des frais peuvent s\'appliquer."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Passé du réseau <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> au <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"un type de réseau inconnu"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"données cellulaires"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"RPV"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-fr/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-fr/strings.xml
new file mode 100644
index 0000000..08c9d81
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-fr/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Connectez-vous au réseau Wi-Fi"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Se connecter au réseau"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"Aucune connexion à Internet pour <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Appuyez ici pour afficher des options."</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Le réseau mobile ne dispose d\'aucun accès à Internet"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Le réseau ne dispose d\'aucun accès à Internet"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Impossible d\'accéder au serveur DNS privé"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"La connectivité de <xliff:g id="NETWORK_SSID">%1$s</xliff:g> est limitée"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Appuyer pour se connecter quand même"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Nouveau réseau : <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"L\'appareil utilise <xliff:g id="NEW_NETWORK">%1$s</xliff:g> lorsque <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> n\'a pas de connexion Internet. Des frais peuvent s\'appliquer."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Ancien réseau : <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>. Nouveau réseau : <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"type de réseau inconnu"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"données mobiles"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-gl/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-gl/strings.xml
new file mode 100644
index 0000000..9f98055
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-gl/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Inicia sesión na rede wifi"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Inicia sesión na rede"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> non ten acceso a Internet"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Toca para ver opcións."</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"A rede de telefonía móbil non ten acceso a Internet"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"A rede non ten acceso a Internet"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Non se puido acceder ao servidor DNS privado"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"A conectividade de <xliff:g id="NETWORK_SSID">%1$s</xliff:g> é limitada"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Toca para conectarte de todas formas"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Cambiouse a: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"O dispositivo utiliza <xliff:g id="NEW_NETWORK">%1$s</xliff:g> cando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> non ten acceso a Internet. Pódense aplicar cargos."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Cambiouse de <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> a <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"un tipo de rede descoñecido"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"datos móbiles"</item>
+ <item msgid="5520925862115353992">"wifi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-gu/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-gu/strings.xml
new file mode 100644
index 0000000..4ae5a2c
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-gu/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"વાઇ-ફાઇ નેટવર્ક પર સાઇન ઇન કરો"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"નેટવર્ક પર સાઇન ઇન કરો"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ઇન્ટરનેટ ઍક્સેસ ધરાવતું નથી"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"વિકલ્પો માટે ટૅપ કરો"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"મોબાઇલ નેટવર્ક કોઈ ઇન્ટરનેટ ઍક્સેસ ધરાવતું નથી"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"નેટવર્ક કોઈ ઇન્ટરનેટ ઍક્સેસ ધરાવતું નથી"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"ખાનગી DNS સર્વર ઍક્સેસ કરી શકાતા નથી"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> મર્યાદિત કનેક્ટિવિટી ધરાવે છે"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"છતાં કનેક્ટ કરવા માટે ટૅપ કરો"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> પર સ્વિચ કર્યું"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"જ્યારે <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> પાસે કોઈ ઇન્ટરનેટ ઍક્સેસ ન હોય ત્યારે ઉપકરણ <xliff:g id="NEW_NETWORK">%1$s</xliff:g>નો ઉપયોગ કરે છે. શુલ્ક લાગુ થઈ શકે છે."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> પરથી <xliff:g id="NEW_NETWORK">%2$s</xliff:g> પર સ્વિચ કર્યું"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"અજાણ્યો નેટવર્ક પ્રકાર"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"મોબાઇલ ડેટા"</item>
+ <item msgid="5520925862115353992">"વાઇ-ફાઇ"</item>
+ <item msgid="1055487873974272842">"બ્લૂટૂથ"</item>
+ <item msgid="1616528372438698248">"ઇથરનેટ"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-hi/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-hi/strings.xml
new file mode 100644
index 0000000..eff1b60
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-hi/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"वाई-फ़ाई नेटवर्क में साइन इन करें"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"नेटवर्क में साइन इन करें"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> का इंटरनेट नहीं चल रहा है"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"विकल्पों के लिए टैप करें"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"मोबाइल नेटवर्क पर इंटरनेट ऐक्सेस नहीं है"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"इस नेटवर्क पर इंटरनेट ऐक्सेस नहीं है"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"निजी डीएनएस सर्वर को ऐक्सेस नहीं किया जा सकता"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> की कनेक्टिविटी सीमित है"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"फिर भी कनेक्ट करने के लिए टैप करें"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> पर ले जाया गया"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> में इंटरनेट की सुविधा नहीं होने पर डिवाइस <xliff:g id="NEW_NETWORK">%1$s</xliff:g> का इस्तेमाल करता है. इसके लिए शुल्क लिया जा सकता है."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> से <xliff:g id="NEW_NETWORK">%2$s</xliff:g> पर ले जाया गया"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"अज्ञात नेटवर्क प्रकार"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"मोबाइल डेटा"</item>
+ <item msgid="5520925862115353992">"वाई-फ़ाई"</item>
+ <item msgid="1055487873974272842">"ब्लूटूथ"</item>
+ <item msgid="1616528372438698248">"ईथरनेट"</item>
+ <item msgid="9177085807664964627">"वीपीएन"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-hr/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-hr/strings.xml
new file mode 100644
index 0000000..52bfb93
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-hr/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Prijava na Wi-Fi mrežu"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Prijava na mrežu"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> nema pristup internetu"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Dodirnite za opcije"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Mobilna mreža nema pristup internetu"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Mreža nema pristup internetu"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Nije moguće pristupiti privatnom DNS poslužitelju"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ima ograničenu povezivost"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Dodirnite da biste se ipak povezali"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Prelazak na drugu mrežu: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Kada <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nema pristup internetu, na uređaju se upotrebljava <xliff:g id="NEW_NETWORK">%1$s</xliff:g>. Moguća je naplata naknade."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Mreža je promijenjena: <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> > <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"nepoznata vrsta mreže"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"mobilni podaci"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-hu/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-hu/strings.xml
new file mode 100644
index 0000000..2ff59b5
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-hu/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Bejelentkezés Wi-Fi hálózatba"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Bejelentkezés a hálózatba"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"A(z) <xliff:g id="NETWORK_SSID">%1$s</xliff:g> hálózaton nincs internet-hozzáférés"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Koppintson a beállítások megjelenítéséhez"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"A mobilhálózaton nincs internet-hozzáférés"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"A hálózaton nincs internet-hozzáférés"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"A privát DNS-kiszolgálóhoz nem lehet hozzáférni"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"A(z) <xliff:g id="NETWORK_SSID">%1$s</xliff:g> hálózat korlátozott kapcsolatot biztosít"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Koppintson, ha mindenképpen csatlakozni szeretne"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Átváltva erre: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="NEW_NETWORK">%1$s</xliff:g> használata, ha nincs internet-hozzáférés <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>-kapcsolaton keresztül. A szolgáltató díjat számíthat fel."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Átváltva <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>-hálózatról erre: <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"ismeretlen hálózati típus"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"mobiladatok"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-hy/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-hy/strings.xml
new file mode 100644
index 0000000..b35d31c
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-hy/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Մուտք գործեք Wi-Fi ցանց"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Մուտք գործեք ցանց"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ցանցը չունի մուտք ինտերնետին"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Հպեք՝ ընտրանքները տեսնելու համար"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Բջջային ցանցը չի ապահովում ինտերնետ կապ"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Ցանցը միացված չէ ինտերնետին"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Մասնավոր DNS սերվերն անհասանելի է"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ցանցի կապը սահմանափակ է"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Հպեք՝ միանալու համար"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Անցել է <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ցանցի"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Երբ <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ցանցում ինտերնետ կապ չի լինում, սարքն անցնում է <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ցանցի: Նման դեպքում կարող են վճարներ գանձվել:"</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ցանցից անցել է <xliff:g id="NEW_NETWORK">%2$s</xliff:g> ցանցի"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"ցանցի անհայտ տեսակ"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"բջջային ինտերնետ"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-in/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-in/strings.xml
new file mode 100644
index 0000000..27d7d89
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-in/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Login ke jaringan Wi-Fi"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Login ke jaringan"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> tidak memiliki akses internet"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Ketuk untuk melihat opsi"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Jaringan seluler tidak memiliki akses internet"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Jaringan tidak memiliki akses internet"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Server DNS pribadi tidak dapat diakses"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> memiliki konektivitas terbatas"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Ketuk untuk tetap menyambungkan"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Dialihkan ke <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Perangkat menggunakan <xliff:g id="NEW_NETWORK">%1$s</xliff:g> jika <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> tidak memiliki akses internet. Tarif mungkin berlaku."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Dialihkan dari <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ke <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"jenis jaringan yang tidak dikenal"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"data seluler"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-is/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-is/strings.xml
new file mode 100644
index 0000000..97f42dc
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-is/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Skrá inn á Wi-Fi net"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Skrá inn á net"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> er ekki með internetaðgang"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Ýttu til að sjá valkosti"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Farsímakerfið er ekki tengt við internetið"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Netkerfið er ekki tengt við internetið"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Ekki næst í DNS-einkaþjón"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"Tengigeta <xliff:g id="NETWORK_SSID">%1$s</xliff:g> er takmörkuð"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Ýttu til að tengjast samt"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Skipt yfir á <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Tækið notar <xliff:g id="NEW_NETWORK">%1$s</xliff:g> þegar <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> er ekki með internetaðgang. Gjöld kunna að eiga við."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Skipt úr <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> yfir í <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"óþekkt tegund netkerfis"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"farsímagögn"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-it/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-it/strings.xml
new file mode 100644
index 0000000..7836101
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-it/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Accedi a rete Wi-Fi"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Accedi alla rete"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> non ha accesso a Internet"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Tocca per le opzioni"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"La rete mobile non ha accesso a Internet"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"La rete non ha accesso a Internet"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Non è possibile accedere al server DNS privato"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ha una connettività limitata"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Tocca per connettere comunque"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Passato a <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Il dispositivo utilizza <xliff:g id="NEW_NETWORK">%1$s</xliff:g> quando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> non ha accesso a Internet. Potrebbero essere applicati costi."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Passato da <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> a <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"tipo di rete sconosciuto"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"dati mobili"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-iw/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-iw/strings.xml
new file mode 100644
index 0000000..f322b99
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-iw/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"היכנס לרשת Wi-Fi"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"היכנס לרשת"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"ל-<xliff:g id="NETWORK_SSID">%1$s</xliff:g> אין גישה לאינטרנט"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"הקש לקבלת אפשרויות"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"לרשת הסלולרית אין גישה לאינטרנט"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"לרשת אין גישה לאינטרנט"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"לא ניתן לגשת לשרת DNS הפרטי"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"הקישוריות של <xliff:g id="NETWORK_SSID">%1$s</xliff:g> מוגבלת"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"כדי להתחבר למרות זאת יש להקיש"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"מעבר אל <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"המכשיר משתמש ברשת <xliff:g id="NEW_NETWORK">%1$s</xliff:g> כשלרשת <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> אין גישה לאינטרנט. עשויים לחול חיובים."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"עבר מרשת <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> לרשת <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"סוג רשת לא מזוהה"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"חבילת גלישה"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-ja/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ja/strings.xml
new file mode 100644
index 0000000..1aa3216
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ja/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Wi-Fiネットワークにログイン"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"ネットワークにログインしてください"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> はインターネットにアクセスできません"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"タップしてその他のオプションを表示"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"モバイル ネットワークがインターネットに接続されていません"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"ネットワークがインターネットに接続されていません"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"プライベート DNS サーバーにアクセスできません"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> の接続が制限されています"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"接続するにはタップしてください"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"「<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>」に切り替えました"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"デバイスで「<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>」によるインターネット接続ができない場合に「<xliff:g id="NEW_NETWORK">%1$s</xliff:g>」を使用します。通信料が発生することがあります。"</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"「<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>」から「<xliff:g id="NEW_NETWORK">%2$s</xliff:g>」に切り替えました"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"不明なネットワーク タイプ"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"モバイルデータ"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"イーサネット"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-ka/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ka/strings.xml
new file mode 100644
index 0000000..61d21b5
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ka/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Wi-Fi ქსელთან დაკავშირება"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"ქსელში შესვლა"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>-ს არ აქვს ინტერნეტზე წვდომა"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"შეეხეთ ვარიანტების სანახავად"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"მობილურ ქსელს არ აქვს ინტერნეტზე წვდომა"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"ქსელს არ აქვს ინტერნეტზე წვდომა"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"პირად DNS სერვერზე წვდომა შეუძლებელია"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>-ის კავშირები შეზღუდულია"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"შეეხეთ, თუ მაინც გსურთ დაკავშირება"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"ახლა გამოიყენება <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"თუ <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ინტერნეტთან კავშირს დაკარგავს, მოწყობილობის მიერ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> იქნება გამოყენებული, რამაც შეიძლება დამატებითი ხარჯები გამოიწვიოს."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"ახლა გამოიყენება <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> (გამოიყენებოდა <xliff:g id="NEW_NETWORK">%2$s</xliff:g>)"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"უცნობი ტიპის ქსელი"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"მობილური ინტერნეტი"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-kk/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-kk/strings.xml
new file mode 100644
index 0000000..969aaef
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-kk/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Wi-Fi желісіне кіру"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Желіге кіру"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> желісінің интернетті пайдалану мүмкіндігі шектеулі."</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Опциялар үшін түртіңіз"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Мобильдік желі интернетке қосылмаған."</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Желі интернетке қосылмаған."</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Жеке DNS серверіне кіру мүмкін емес."</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> желісінің қосылу мүмкіндігі шектеулі."</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Бәрібір жалғау үшін түртіңіз."</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> желісіне ауысты"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Құрылғы <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> желісінде интернетпен байланыс жоғалған жағдайда <xliff:g id="NEW_NETWORK">%1$s</xliff:g> желісін пайдаланады. Деректер ақысы алынуы мүмкін."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> желісінен <xliff:g id="NEW_NETWORK">%2$s</xliff:g> желісіне ауысты"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"желі түрі белгісіз"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"мобильдік деректер"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-km/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-km/strings.xml
new file mode 100644
index 0000000..da3c337
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-km/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"ចូលបណ្ដាញវ៉ាយហ្វាយ"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"ចូលទៅបណ្តាញ"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> មិនមានការតភ្ជាប់អ៊ីនធឺណិតទេ"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"ប៉ះសម្រាប់ជម្រើស"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"បណ្ដាញទូរសព្ទចល័តមិនមានការតភ្ជាប់អ៊ីនធឺណិតទេ"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"បណ្ដាញមិនមានការតភ្ជាប់អ៊ីនធឺណិតទេ"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"មិនអាចចូលប្រើម៉ាស៊ីនមេ DNS ឯកជនបានទេ"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> មានការតភ្ជាប់មានកម្រិត"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"មិនអីទេ ចុចភ្ជាប់ចុះ"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"បានប្តូរទៅ <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"ឧបករណ៍ប្រើ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> នៅពេលដែល <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> មិនមានការតភ្ជាប់អ៊ីនធឺណិត។ អាចគិតថ្លៃលើការប្រើប្រាស់ទិន្នន័យ។"</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"បានប្តូរពី <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ទៅ <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"ប្រភេទបណ្តាញមិនស្គាល់"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"ទិន្នន័យទូរសព្ទចល័ត"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"ប៊្លូធូស"</item>
+ <item msgid="1616528372438698248">"អ៊ីសឺរណិត"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-kn/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-kn/strings.xml
new file mode 100644
index 0000000..3b5e047
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-kn/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"ವೈ-ಫೈ ನೆಟ್ವರ್ಕ್ಗೆ ಸೈನ್ ಇನ್ ಮಾಡಿ"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"ನೆಟ್ವರ್ಕ್ಗೆ ಸೈನ್ ಇನ್ ಮಾಡಿ"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ಯಾವುದೇ ಇಂಟರ್ನೆಟ್ ಸಂಪರ್ಕವನ್ನು ಹೊಂದಿಲ್ಲ"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"ಆಯ್ಕೆಗಳಿಗೆ ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"ಮೊಬೈಲ್ ನೆಟ್ವರ್ಕ್ ಯಾವುದೇ ಇಂಟರ್ನೆಟ್ ಪ್ರವೇಶವನ್ನು ಹೊಂದಿಲ್ಲ"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"ನೆಟ್ವರ್ಕ್ ಇಂಟರ್ನೆಟ್ ಪ್ರವೇಶವನ್ನು ಹೊಂದಿಲ್ಲ"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"ಖಾಸಗಿ DNS ಸರ್ವರ್ ಅನ್ನು ಪ್ರವೇಶಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ಸೀಮಿತ ಸಂಪರ್ಕ ಕಲ್ಪಿಸುವಿಕೆಯನ್ನು ಹೊಂದಿದೆ"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"ಹೇಗಾದರೂ ಸಂಪರ್ಕಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ಗೆ ಬದಲಾಯಿಸಲಾಗಿದೆ"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ಇಂಟರ್ನೆಟ್ ಪ್ರವೇಶ ಹೊಂದಿಲ್ಲದಿರುವಾಗ, ಸಾಧನವು <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ಬಳಸುತ್ತದೆ. ಶುಲ್ಕಗಳು ಅನ್ವಯವಾಗಬಹುದು."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ರಿಂದ <xliff:g id="NEW_NETWORK">%2$s</xliff:g> ಗೆ ಬದಲಾಯಿಸಲಾಗಿದೆ"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"ಅಪರಿಚಿತ ನೆಟ್ವರ್ಕ್ ಪ್ರಕಾರ"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"ಮೊಬೈಲ್ ಡೇಟಾ"</item>
+ <item msgid="5520925862115353992">"ವೈ-ಫೈ"</item>
+ <item msgid="1055487873974272842">"ಬ್ಲೂಟೂತ್"</item>
+ <item msgid="1616528372438698248">"ಇಥರ್ನೆಟ್"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-ko/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ko/strings.xml
new file mode 100644
index 0000000..874bd75
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ko/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Wi-Fi 네트워크에 로그인"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"네트워크에 로그인"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>이(가) 인터넷에 액세스할 수 없습니다."</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"탭하여 옵션 보기"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"모바일 네트워크에 인터넷이 연결되어 있지 않습니다."</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"네트워크에 인터넷이 연결되어 있지 않습니다."</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"비공개 DNS 서버에 액세스할 수 없습니다."</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>에서 연결을 제한했습니다."</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"계속 연결하려면 탭하세요."</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>(으)로 전환"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>(으)로 인터넷에 연결할 수 없는 경우 기기에서 <xliff:g id="NEW_NETWORK">%1$s</xliff:g>이(가) 사용됩니다. 요금이 부과될 수 있습니다."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>에서 <xliff:g id="NEW_NETWORK">%2$s</xliff:g>(으)로 전환"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"알 수 없는 네트워크 유형"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"모바일 데이터"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"블루투스"</item>
+ <item msgid="1616528372438698248">"이더넷"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-ky/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ky/strings.xml
new file mode 100644
index 0000000..1ace4dc
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ky/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Wi-Fi түйүнүнө кирүү"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Тармакка кирүү"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> Интернетке туташуусу жок"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Параметрлерди ачуу үчүн таптап коюңуз"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Мобилдик Интернет жок"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Тармактын Интернет жок"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Жеке DNS сервери жеткиликсиз"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> байланышы чектелген"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Баары бир туташуу үчүн таптаңыз"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> тармагына которуштурулду"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> тармагы Интернетке туташпай турганда, түзмөгүңүз <xliff:g id="NEW_NETWORK">%1$s</xliff:g> тармагын колдонот. Акы алынышы мүмкүн."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> дегенден <xliff:g id="NEW_NETWORK">%2$s</xliff:g> тармагына которуштурулду"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"белгисиз тармак түрү"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"мобилдик трафик"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-lo/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-lo/strings.xml
new file mode 100644
index 0000000..3db497e
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-lo/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"ເຂົ້າສູ່ລະບົບເຄືອຂ່າຍ Wi-Fi"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"ລົງຊື່ເຂົ້າເຄືອຂ່າຍ"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ບໍ່ມີການເຊື່ອມຕໍ່ອິນເຕີເນັດ"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"ແຕະເພື່ອເບິ່ງຕົວເລືອກ"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"ເຄືອຂ່າຍມືຖືບໍ່ສາມາດເຂົ້າເຖິງອິນເຕີເນັດໄດ້"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"ເຄືອຂ່າຍບໍ່ສາມາດເຂົ້າເຖິງອິນເຕີເນັດໄດ້"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"ບໍ່ສາມາດເຂົ້າເຖິງເຊີບເວີ DNS ສ່ວນຕົວໄດ້"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ມີການເຊື່ອມຕໍ່ທີ່ຈຳກັດ"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"ແຕະເພື່ອຢືນຢັນການເຊື່ອມຕໍ່"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"ສະຫຼັບໄປໃຊ້ <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ແລ້ວ"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"ອຸປະກອນຈະໃຊ້ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ເມື່ອ <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ບໍ່ມີການເຊື່ອມຕໍ່ອິນເຕີເນັດ. ອາດມີການຮຽກເກັບຄ່າບໍລິການ."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"ສະຫຼັບຈາກ <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ໄປໃຊ້ <xliff:g id="NEW_NETWORK">%2$s</xliff:g> ແລ້ວ"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"ບໍ່ຮູ້ຈັກປະເພດເຄືອຂ່າຍ"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"ອິນເຕີເນັດມືຖື"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"ອີເທີເນັດ"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-lt/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-lt/strings.xml
new file mode 100644
index 0000000..c639c1f
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-lt/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Prisijungti prie „Wi-Fi“ tinklo"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Prisijungti prie tinklo"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"„<xliff:g id="NETWORK_SSID">%1$s</xliff:g>“ negali pasiekti interneto"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Palieskite, kad būtų rodomos parinktys."</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Mobiliojo ryšio tinkle nėra prieigos prie interneto"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Tinkle nėra prieigos prie interneto"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Privataus DNS serverio negalima pasiekti"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"„<xliff:g id="NETWORK_SSID">%1$s</xliff:g>“ ryšys apribotas"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Palieskite, jei vis tiek norite prisijungti"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Perjungta į tinklą <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Įrenginyje naudojamas kitas tinklas (<xliff:g id="NEW_NETWORK">%1$s</xliff:g>), kai dabartiniame tinkle (<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>) nėra interneto ryšio. Gali būti taikomi mokesčiai."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Perjungta iš tinklo <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> į tinklą <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"nežinomas tinklo tipas"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"mobiliojo ryšio duomenys"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Eternetas"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-lv/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-lv/strings.xml
new file mode 100644
index 0000000..5774603
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-lv/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Pierakstieties Wi-Fi tīklā"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Pierakstīšanās tīklā"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"Tīklā <xliff:g id="NETWORK_SSID">%1$s</xliff:g> nav piekļuves internetam"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Pieskarieties, lai skatītu iespējas."</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Mobilajā tīklā nav piekļuves internetam."</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Tīklā nav piekļuves internetam."</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Nevar piekļūt privātam DNS serverim."</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"Tīklā <xliff:g id="NETWORK_SSID">%1$s</xliff:g> ir ierobežota savienojamība"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Lai tik un tā izveidotu savienojumu, pieskarieties"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Pārslēdzās uz tīklu <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Kad vienā tīklā (<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>) nav piekļuves internetam, ierīcē tiek izmantots cits tīkls (<xliff:g id="NEW_NETWORK">%1$s</xliff:g>). Var tikt piemērota maksa."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Pārslēdzās no tīkla <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> uz tīklu <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"nezināms tīkla veids"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"mobilie dati"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-mcc204-mnc04/config.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-mcc204-mnc04/config.xml
new file mode 100644
index 0000000..7e7025f
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-mcc204-mnc04/config.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<!-- Configuration values for ConnectivityService
+ DO NOT EDIT THIS FILE for specific device configuration; instead, use a Runtime Resources
+ Overlay package following the overlayable.xml configuration in the same directory:
+ https://source.android.com/devices/architecture/rros -->
+<resources>
+ <!-- Whether the device should automatically switch away from Wi-Fi networks that lose
+ Internet access. Actual device behaviour is controlled by
+ Settings.Global.NETWORK_AVOID_BAD_WIFI. This is the default value of that setting. -->
+ <integer translatable="false" name="config_networkAvoidBadWifi">0</integer>
+</resources>
\ No newline at end of file
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-mcc310-mnc004/config.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-mcc310-mnc004/config.xml
new file mode 100644
index 0000000..7e7025f
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-mcc310-mnc004/config.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<!-- Configuration values for ConnectivityService
+ DO NOT EDIT THIS FILE for specific device configuration; instead, use a Runtime Resources
+ Overlay package following the overlayable.xml configuration in the same directory:
+ https://source.android.com/devices/architecture/rros -->
+<resources>
+ <!-- Whether the device should automatically switch away from Wi-Fi networks that lose
+ Internet access. Actual device behaviour is controlled by
+ Settings.Global.NETWORK_AVOID_BAD_WIFI. This is the default value of that setting. -->
+ <integer translatable="false" name="config_networkAvoidBadWifi">0</integer>
+</resources>
\ No newline at end of file
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-mcc311-mnc480/config.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-mcc311-mnc480/config.xml
new file mode 100644
index 0000000..7e7025f
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-mcc311-mnc480/config.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<!-- Configuration values for ConnectivityService
+ DO NOT EDIT THIS FILE for specific device configuration; instead, use a Runtime Resources
+ Overlay package following the overlayable.xml configuration in the same directory:
+ https://source.android.com/devices/architecture/rros -->
+<resources>
+ <!-- Whether the device should automatically switch away from Wi-Fi networks that lose
+ Internet access. Actual device behaviour is controlled by
+ Settings.Global.NETWORK_AVOID_BAD_WIFI. This is the default value of that setting. -->
+ <integer translatable="false" name="config_networkAvoidBadWifi">0</integer>
+</resources>
\ No newline at end of file
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-mk/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-mk/strings.xml
new file mode 100644
index 0000000..053c7cf
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-mk/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Најавете се на мрежа на Wi-Fi"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Најавете се на мрежа"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> нема интернет-пристап"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Допрете за опции"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Мобилната мрежа нема интернет-пристап"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Мрежата нема интернет-пристап"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Не може да се пристапи до приватниот DNS-сервер"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> има ограничена поврзливост"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Допрете за да се поврзете и покрај тоа"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Префрлено на <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Уредот користи <xliff:g id="NEW_NETWORK">%1$s</xliff:g> кога <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> нема пристап до интернет. Може да се наплатат трошоци."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Префрлено од <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> на <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"непознат тип мрежа"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"мобилен интернет"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Етернет"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-ml/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ml/strings.xml
new file mode 100644
index 0000000..3e80cf1
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ml/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"വൈഫൈ നെറ്റ്വർക്കിലേക്ക് സൈൻ ഇൻ ചെയ്യുക"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"നെറ്റ്വർക്കിലേക്ക് സൈൻ ഇൻ ചെയ്യുക"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> എന്നതിന് ഇന്റർനെറ്റ് ആക്സസ് ഇല്ല"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"ഓപ്ഷനുകൾക്ക് ടാപ്പുചെയ്യുക"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"മൊബെെൽ നെറ്റ്വർക്കിന് ഇന്റർനെറ്റ് ആക്സസ് ഇല്ല"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"നെറ്റ്വർക്കിന് ഇന്റർനെറ്റ് ആക്സസ് ഇല്ല"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"സ്വകാര്യ DNS സെർവർ ആക്സസ് ചെയ്യാനാവില്ല"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> എന്നതിന് പരിമിതമായ കണക്റ്റിവിറ്റി ഉണ്ട്"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"ഏതുവിധേനയും കണക്റ്റ് ചെയ്യാൻ ടാപ്പ് ചെയ്യുക"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> എന്നതിലേക്ക് മാറി"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>-ന് ഇന്റർനെറ്റ് ആക്സസ് ഇല്ലാത്തപ്പോൾ ഉപകരണം <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ഉപയോഗിക്കുന്നു. നിരക്കുകൾ ബാധകമായേക്കാം."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> നെറ്റ്വർക്കിൽ നിന്ന് <xliff:g id="NEW_NETWORK">%2$s</xliff:g> നെറ്റ്വർക്കിലേക്ക് മാറി"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"തിരിച്ചറിയാനാകാത്ത ഒരു നെറ്റ്വർക്ക് തരം"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"മൊബൈൽ ഡാറ്റ"</item>
+ <item msgid="5520925862115353992">"വൈഫൈ"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"ഇതര്നെറ്റ്"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-mn/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-mn/strings.xml
new file mode 100644
index 0000000..214fc0c
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-mn/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Wi-Fi сүлжээнд нэвтэрнэ үү"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Сүлжээнд нэвтэрнэ үү"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>-д интернэтийн хандалт алга"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Сонголт хийхийн тулд товшино уу"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Мобайл сүлжээнд интернэт хандалт байхгүй байна"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Сүлжээнд интернэт хандалт байхгүй байна"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Хувийн DNS серверт хандах боломжгүй байна"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> зарим үйлчилгээнд хандах боломжгүй байна"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Ямар ч тохиолдолд холбогдохын тулд товших"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> руу шилжүүлсэн"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> интернет холболтгүй үед төхөөрөмж <xliff:g id="NEW_NETWORK">%1$s</xliff:g>-г ашигладаг. Төлбөр гарч болзошгүй."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>-с <xliff:g id="NEW_NETWORK">%2$s</xliff:g> руу шилжүүлсэн"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"сүлжээний тодорхойгүй төрөл"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"мобайл дата"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Этернэт"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-mr/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-mr/strings.xml
new file mode 100644
index 0000000..c4b1998
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-mr/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"वाय-फाय नेटवर्कमध्ये साइन इन करा"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"नेटवर्कवर साइन इन करा"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ला इंटरनेट अॅक्सेस नाही"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"पर्यायांसाठी टॅप करा"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"मोबाइल नेटवर्कला इंटरनेट ॲक्सेस नाही"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"नेटवर्कला इंटरनेट ॲक्सेस नाही"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"खाजगी DNS सर्व्हर ॲक्सेस करू शकत नाही"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ला मर्यादित कनेक्टिव्हिटी आहे"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"तरीही कनेक्ट करण्यासाठी टॅप करा"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> वर स्विच केले"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> कडे इंटरनेटचा अॅक्सेस नसताना डिव्हाइस <xliff:g id="NEW_NETWORK">%1$s</xliff:g> वापरते. शुल्क लागू शकते."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> वरून <xliff:g id="NEW_NETWORK">%2$s</xliff:g> वर स्विच केले"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"अज्ञात नेटवर्क प्रकार"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"मोबाइल डेटा"</item>
+ <item msgid="5520925862115353992">"वाय-फाय"</item>
+ <item msgid="1055487873974272842">"ब्लूटूथ"</item>
+ <item msgid="1616528372438698248">"इथरनेट"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-ms/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ms/strings.xml
new file mode 100644
index 0000000..529d0bd
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ms/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Log masuk ke rangkaian Wi-Fi"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Log masuk ke rangkaian"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> tiada akses Internet"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Ketik untuk mendapatkan pilihan"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Rangkaian mudah alih tiada akses Internet"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Rangkaian tiada akses Internet"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Pelayan DNS peribadi tidak boleh diakses"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> mempunyai kesambungan terhad"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Ketik untuk menyambung juga"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Beralih kepada <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Peranti menggunakan <xliff:g id="NEW_NETWORK">%1$s</xliff:g> apabila <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> tiada akses Internet. Bayaran mungkin dikenakan."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Beralih daripada <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> kepada <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"jenis rangkaian tidak diketahui"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"data mudah alih"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-my/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-my/strings.xml
new file mode 100644
index 0000000..50590fa
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-my/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"ဝိုင်ဖိုင်ကွန်ရက်သို့ လက်မှတ်ထိုးဝင်ပါ"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"ကွန်ယက်သို့ လက်မှတ်ထိုးဝင်ရန်"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> တွင် အင်တာနက်အသုံးပြုခွင့် မရှိပါ"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"အခြားရွေးချယ်စရာများကိုကြည့်ရန် တို့ပါ"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"မိုဘိုင်းကွန်ရက်တွင် အင်တာနက်ချိတ်ဆက်မှု မရှိပါ"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"ကွန်ရက်တွင် အင်တာနက်အသုံးပြုခွင့် မရှိပါ"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"သီးသန့် ဒီအန်အက်စ် (DNS) ဆာဗာကို သုံး၍မရပါ။"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> တွင် ချိတ်ဆက်မှုကို ကန့်သတ်ထားသည်"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"မည်သို့ပင်ဖြစ်စေ ချိတ်ဆက်ရန် တို့ပါ"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> သို့ ပြောင်းလိုက်ပြီ"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ဖြင့် အင်တာနက် အသုံးမပြုနိုင်သည့်အချိန်တွင် စက်ပစ္စည်းသည် <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ကို သုံးပါသည်။ ဒေတာသုံးစွဲခ ကျသင့်နိုင်ပါသည်။"</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> မှ <xliff:g id="NEW_NETWORK">%2$s</xliff:g> သို့ ပြောင်းလိုက်ပြီ"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"အမည်မသိကွန်ရက်အမျိုးအစား"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"မိုဘိုင်းဒေတာ"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"ဘလူးတုသ်"</item>
+ <item msgid="1616528372438698248">"အီသာနက်"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-nb/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-nb/strings.xml
new file mode 100644
index 0000000..b89d198
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-nb/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Logg på Wi-Fi-nettverket"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Logg på nettverk"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> har ingen internettilkobling"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Trykk for å få alternativer"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Mobilnettverket har ingen internettilgang"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Nettverket har ingen internettilgang"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Den private DNS-tjeneren kan ikke nås"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> har begrenset tilkobling"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Trykk for å koble til likevel"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Byttet til <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Enheten bruker <xliff:g id="NEW_NETWORK">%1$s</xliff:g> når <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ikke har Internett-tilgang. Avgifter kan påløpe."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Byttet fra <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> til <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"en ukjent nettverkstype"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"mobildata"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-ne/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ne/strings.xml
new file mode 100644
index 0000000..bdcfa3b
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ne/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Wi-Fi नेटवर्कमा साइन इन गर्नुहोस्"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"सञ्जालमा साइन इन गर्नुहोस्"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> को इन्टरनेटमाथि पहुँच छैन"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"विकल्पहरूका लागि ट्याप गर्नुहोस्"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"मोबाइल नेटवर्कको इन्टरनेटमाथि पहुँच छैन"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"नेटवर्कको इन्टरनेटमाथि पहुँच छैन"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"निजी DNS सर्भरमाथि पहुँच प्राप्त गर्न सकिँदैन"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> को जडान सीमित छ"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"जसरी भए पनि जडान गर्न ट्याप गर्नुहोस्"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> मा बदल्नुहोस्"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> मार्फत इन्टरनेटमाथि पहुँच राख्न नसकेको अवस्थामा यन्त्रले <xliff:g id="NEW_NETWORK">%1$s</xliff:g> प्रयोग गर्दछ। शुल्क लाग्न सक्छ।"</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> बाट <xliff:g id="NEW_NETWORK">%2$s</xliff:g> मा परिवर्तन गरियो"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"नेटवर्कको कुनै अज्ञात प्रकार"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"मोबाइल डेटा"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"ब्लुटुथ"</item>
+ <item msgid="1616528372438698248">"इथरनेट"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-nl/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-nl/strings.xml
new file mode 100644
index 0000000..8ecff6e
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-nl/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Inloggen bij wifi-netwerk"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Inloggen bij netwerk"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> heeft geen internettoegang"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Tik voor opties"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Mobiel netwerk heeft geen internettoegang"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Netwerk heeft geen internettoegang"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Geen toegang tot privé-DNS-server"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> heeft beperkte connectiviteit"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Tik om toch verbinding te maken"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Overgeschakeld naar <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Apparaat gebruikt <xliff:g id="NEW_NETWORK">%1$s</xliff:g> wanneer <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> geen internetverbinding heeft. Er kunnen kosten in rekening worden gebracht."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Overgeschakeld van <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> naar <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"een onbekend netwerktype"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"mobiele data"</item>
+ <item msgid="5520925862115353992">"Wifi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-or/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-or/strings.xml
new file mode 100644
index 0000000..6ec1f9d
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-or/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"ୱାଇ-ଫାଇ ନେଟୱର୍କରେ ସାଇନ୍-ଇନ୍ କରନ୍ତୁ"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"ନେଟ୍ୱର୍କରେ ସାଇନ୍ ଇନ୍ କରନ୍ତୁ"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>ର ଇଣ୍ଟର୍ନେଟ୍ ଆକ୍ସେସ୍ ନାହିଁ"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"ବିକଳ୍ପ ପାଇଁ ଟାପ୍ କରନ୍ତୁ"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"ମୋବାଇଲ୍ ନେଟ୍ୱାର୍କରେ ଇଣ୍ଟର୍ନେଟ୍ ଆକ୍ସେସ୍ ନାହିଁ"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"ନେଟ୍ୱାର୍କରେ ଇଣ୍ଟର୍ନେଟ୍ ଆକ୍ସେସ୍ ନାହିଁ"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"ବ୍ୟକ୍ତିଗତ DNS ସର୍ଭର୍ ଆକ୍ସେସ୍ କରିହେବ ନାହିଁ"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>ର ସୀମିତ ସଂଯୋଗ ଅଛି"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"ତଥାପି ଯୋଗାଯୋଗ କରିବାକୁ ଟାପ୍ କରନ୍ତୁ"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>କୁ ବଦଳାଗଲା"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>ର ଇଣ୍ଟରନେଟ୍ ଆକ୍ସେସ୍ ନଥିବାବେଳେ ଡିଭାଇସ୍ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ବ୍ୟବହାର କରିଥାଏ। ଶୁଳ୍କ ଲାଗୁ ହୋଇପାରେ।"</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ରୁ <xliff:g id="NEW_NETWORK">%2$s</xliff:g>କୁ ବଦଳାଗଲା"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"ଏକ ଅଜଣା ନେଟ୍ୱର୍କ ପ୍ରକାର"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"ମୋବାଇଲ୍ ଡାଟା"</item>
+ <item msgid="5520925862115353992">"ୱାଇ-ଫାଇ"</item>
+ <item msgid="1055487873974272842">"ବ୍ଲୁଟୁଥ"</item>
+ <item msgid="1616528372438698248">"ଇଥରନେଟ୍"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-pa/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-pa/strings.xml
new file mode 100644
index 0000000..e948193
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-pa/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"ਵਾਈ-ਫਾਈ ਨੈੱਟਵਰਕ \'ਤੇ ਸਾਈਨ-ਇਨ ਕਰੋ"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"ਨੈੱਟਵਰਕ \'ਤੇ ਸਾਈਨ-ਇਨ ਕਰੋ"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ਕੋਲ ਇੰਟਰਨੈੱਟ ਪਹੁੰਚ ਨਹੀਂ ਹੈ"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"ਵਿਕਲਪਾਂ ਲਈ ਟੈਪ ਕਰੋ"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"ਮੋਬਾਈਲ ਨੈੱਟਵਰਕ ਕੋਲ ਇੰਟਰਨੈੱਟ ਤੱਕ ਪਹੁੰਚ ਨਹੀਂ ਹੈ"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"ਨੈੱਟਵਰਕ ਕੋਲ ਇੰਟਰਨੈੱਟ ਤੱਕ ਪਹੁੰਚ ਨਹੀਂ ਹੈ"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"ਨਿੱਜੀ ਡੋਮੇਨ ਨਾਮ ਪ੍ਰਣਾਲੀ (DNS) ਸਰਵਰ \'ਤੇ ਪਹੁੰਚ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕੀ"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ਕੋਲ ਸੀਮਤ ਕਨੈਕਟੀਵਿਟੀ ਹੈ"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"ਫਿਰ ਵੀ ਕਨੈਕਟ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"ਬਦਲਕੇ <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ਲਿਆਂਦਾ ਗਿਆ"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ਦੀ ਇੰਟਰਨੈੱਟ \'ਤੇ ਪਹੁੰਚ ਨਾ ਹੋਣ \'ਤੇ ਡੀਵਾਈਸ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ਦੀ ਵਰਤੋਂ ਕਰਦਾ ਹੈ। ਖਰਚੇ ਲਾਗੂ ਹੋ ਸਕਦੇ ਹਨ।"</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ਤੋਂ ਬਦਲਕੇ <xliff:g id="NEW_NETWORK">%2$s</xliff:g> \'ਤੇ ਕੀਤਾ ਗਿਆ"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"ਇੱਕ ਅਗਿਆਤ ਨੈੱਟਵਰਕ ਕਿਸਮ"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"ਮੋਬਾਈਲ ਡਾਟਾ"</item>
+ <item msgid="5520925862115353992">"ਵਾਈ-ਫਾਈ"</item>
+ <item msgid="1055487873974272842">"ਬਲੂਟੁੱਥ"</item>
+ <item msgid="1616528372438698248">"ਈਥਰਨੈੱਟ"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-pl/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-pl/strings.xml
new file mode 100644
index 0000000..038328f
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-pl/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Zaloguj się w sieci Wi-Fi"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Zaloguj się do sieci"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> nie ma dostępu do internetu"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Kliknij, by wyświetlić opcje"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Sieć komórkowa nie ma dostępu do internetu"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Sieć nie ma dostępu do internetu"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Brak dostępu do prywatnego serwera DNS"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ma ograniczoną łączność"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Kliknij, by mimo to nawiązać połączenie"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Zmieniono na połączenie typu <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Urządzenie korzysta z połączenia typu <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, gdy <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nie dostępu do internetu. Mogą zostać naliczone opłaty."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Przełączono z połączenia typu <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na <xliff:g id="NEW_NETWORK">%2$s</xliff:g>."</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"nieznany typ sieci"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"mobilna transmisja danych"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-pt-rBR/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-pt-rBR/strings.xml
new file mode 100644
index 0000000..fe37405
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-pt-rBR/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Fazer login na rede Wi-Fi"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Fazer login na rede"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> não tem acesso à Internet"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Toque para ver opções"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"A rede móvel não tem acesso à Internet"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"A rede não tem acesso à Internet"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Não é possível acessar o servidor DNS privado"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> tem conectividade limitada"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Toque para conectar mesmo assim"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Alternado para <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"O dispositivo usa <xliff:g id="NEW_NETWORK">%1$s</xliff:g> quando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> não tem acesso à Internet. Esse serviço pode ser cobrado."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Alternado de <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> para <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"um tipo de rede desconhecido"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"dados móveis"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-pt-rPT/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-pt-rPT/strings.xml
new file mode 100644
index 0000000..69060f7
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-pt-rPT/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Iniciar sessão na rede Wi-Fi"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Início de sessão na rede"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> não tem acesso à Internet"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Toque para obter mais opções"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"A rede móvel não tem acesso à Internet"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"A rede não tem acesso à Internet"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Não é possível aceder ao servidor DNS."</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> tem conetividade limitada."</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Toque para ligar mesmo assim."</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Mudou para <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"O dispositivo utiliza <xliff:g id="NEW_NETWORK">%1$s</xliff:g> quando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> não tem acesso à Internet. Podem aplicar-se custos."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Mudou de <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> para <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"um tipo de rede desconhecido"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"dados móveis"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-pt/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-pt/strings.xml
new file mode 100644
index 0000000..fe37405
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-pt/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Fazer login na rede Wi-Fi"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Fazer login na rede"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> não tem acesso à Internet"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Toque para ver opções"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"A rede móvel não tem acesso à Internet"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"A rede não tem acesso à Internet"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Não é possível acessar o servidor DNS privado"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> tem conectividade limitada"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Toque para conectar mesmo assim"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Alternado para <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"O dispositivo usa <xliff:g id="NEW_NETWORK">%1$s</xliff:g> quando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> não tem acesso à Internet. Esse serviço pode ser cobrado."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Alternado de <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> para <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"um tipo de rede desconhecido"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"dados móveis"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-ro/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ro/strings.xml
new file mode 100644
index 0000000..227b7be
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ro/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Conectați-vă la rețeaua Wi-Fi"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Conectați-vă la rețea"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> nu are acces la internet"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Atingeți pentru opțiuni"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Rețeaua mobilă nu are acces la internet"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Rețeaua nu are acces la internet"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Serverul DNS privat nu poate fi accesat"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> are conectivitate limitată"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Atingeți pentru a vă conecta oricum"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"S-a comutat la <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Dispozitivul folosește <xliff:g id="NEW_NETWORK">%1$s</xliff:g> când <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nu are acces la internet. Se pot aplica taxe."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"S-a comutat de la <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> la <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"un tip de rețea necunoscut"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"date mobile"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-ru/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ru/strings.xml
new file mode 100644
index 0000000..18acf81
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ru/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Подключение к Wi-Fi"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Регистрация в сети"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"Сеть \"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>\" не подключена к Интернету"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Нажмите, чтобы показать варианты."</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Мобильная сеть не подключена к Интернету"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Сеть не подключена к Интернету"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Доступа к частному DNS-серверу нет."</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"Подключение к сети \"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>\" ограничено"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Нажмите, чтобы подключиться"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Новое подключение: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Устройство использует <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, если подключение к сети <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> недоступно. Может взиматься плата за передачу данных."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Устройство отключено от сети <xliff:g id="NEW_NETWORK">%2$s</xliff:g> и теперь использует <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"неизвестный тип сети"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"мобильный Интернет"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-si/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-si/strings.xml
new file mode 100644
index 0000000..6307c2b
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-si/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Wi-Fi ජාලයට පුරනය වන්න"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"ජාලයට පුරනය වන්න"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> හට අන්තර්ජාල ප්රවේශය නැත"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"විකල්ප සඳහා තට්ටු කරන්න"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"ජංගම ජාලවලට අන්තර්ජාල ප්රවේශය නැත"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"ජාලයට අන්තර්ජාල ප්රවේශය නැත"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"පුද්ගලික DNS සේවාදායකයට ප්රවේශ වීමට නොහැකිය"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> හට සීමිත සබැඳුම් හැකියාවක් ඇත"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"කෙසේ වෙතත් ඉදිරියට යාමට තට්ටු කරන්න"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> වෙත මාරු විය"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"උපාංගය <xliff:g id="NEW_NETWORK">%1$s</xliff:g> <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> සඳහා අන්තර්ජාල ප්රවේශය නැති විට භාවිත කරයි. ගාස්තු අදාළ විය හැකිය."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> සිට <xliff:g id="NEW_NETWORK">%2$s</xliff:g> වෙත මාරු විය"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"නොදන්නා ජාල වර්ගයකි"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"ජංගම දත්ත"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"බ්ලූටූත්"</item>
+ <item msgid="1616528372438698248">"ඊතර්නෙට්"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-sk/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-sk/strings.xml
new file mode 100644
index 0000000..e894fef
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-sk/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Prihlásiť sa do siete Wi‑Fi"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Prihlásenie do siete"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> nemá prístup k internetu"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Klepnutím získate možnosti"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Mobilná sieť nemá prístup k internetu"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Sieť nemá prístup k internetu"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"K súkromnému serveru DNS sa nepodarilo získať prístup"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> má obmedzené pripojenie"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Ak sa chcete aj napriek tomu pripojiť, klepnite"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Prepnuté na sieť: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Keď <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nemá prístup k internetu, zariadenie používa <xliff:g id="NEW_NETWORK">%1$s</xliff:g>. Môžu sa účtovať poplatky."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Prepnuté zo siete <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na sieť <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"neznámy typ siete"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"mobilné dáta"</item>
+ <item msgid="5520925862115353992">"Wi‑Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-sl/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-sl/strings.xml
new file mode 100644
index 0000000..954b324
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-sl/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Prijavite se v omrežje Wi-Fi"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Prijava v omrežje"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"Omrežje <xliff:g id="NETWORK_SSID">%1$s</xliff:g> nima dostopa do interneta"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Dotaknite se za možnosti"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Mobilno omrežje nima dostopa do interneta"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Omrežje nima dostopa do interneta"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Do zasebnega strežnika DNS ni mogoče dostopati"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"Povezljivost omrežja <xliff:g id="NETWORK_SSID">%1$s</xliff:g> je omejena"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Dotaknite se, da kljub temu vzpostavite povezavo"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Preklopljeno na omrežje vrste <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Naprava uporabi omrežje vrste <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, ko omrežje vrste <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nima dostopa do interneta. Prenos podatkov se lahko zaračuna."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Preklopljeno z omrežja vrste <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na omrežje vrste <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"neznana vrsta omrežja"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"prenos podatkov v mobilnem omrežju"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-sq/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-sq/strings.xml
new file mode 100644
index 0000000..bd5d052
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-sq/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Identifikohu në rrjetin Wi-Fi"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Identifikohu në rrjet"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> nuk ka qasje në internet"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Trokit për opsionet"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Rrjeti celular nuk ka qasje në internet"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Rrjeti nuk ka qasje në internet"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Serveri privat DNS nuk mund të qaset"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ka lidhshmëri të kufizuar"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Trokit për t\'u lidhur gjithsesi"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Kaloi te <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Pajisja përdor <xliff:g id="NEW_NETWORK">%1$s</xliff:g> kur <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nuk ka qasje në internet. Mund të zbatohen tarifa."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Kaloi nga <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> te <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"një lloj rrjeti i panjohur"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"të dhënat celulare"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Eternet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-sr/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-sr/strings.xml
new file mode 100644
index 0000000..8bedbff
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-sr/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Пријављивање на WiFi мрежу"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Пријавите се на мрежу"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> нема приступ интернету"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Додирните за опције"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Мобилна мрежа нема приступ интернету"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Мрежа нема приступ интернету"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Приступ приватном DNS серверу није успео"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> има ограничену везу"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Додирните да бисте се ипак повезали"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Прешли сте на тип мреже <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Уређај користи тип мреже <xliff:g id="NEW_NETWORK">%1$s</xliff:g> када тип мреже <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> нема приступ интернету. Можда ће се наплаћивати трошкови."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Прешли сте са типа мреже <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> на тип мреже <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"непознат тип мреже"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"мобилни подаци"</item>
+ <item msgid="5520925862115353992">"WiFi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Етернет"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-sv/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-sv/strings.xml
new file mode 100644
index 0000000..b3f1763
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-sv/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Logga in på ett Wi-Fi-nätverk"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Logga in på nätverket"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> har ingen internetanslutning"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Tryck för alternativ"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Mobilnätverket har ingen internetanslutning"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Nätverket har ingen internetanslutning"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Det går inte att komma åt den privata DNS-servern."</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> har begränsad anslutning"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Tryck för att ansluta ändå"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Byte av nätverk till <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="NEW_NETWORK">%1$s</xliff:g> används på enheten när det inte finns internetåtkomst via <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>. Avgifter kan tillkomma."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Byte av nätverk från <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> till <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"en okänd nätverkstyp"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"mobildata"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-sw/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-sw/strings.xml
new file mode 100644
index 0000000..9674654
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-sw/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Ingia kwa mtandao wa Wi-Fi"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Ingia katika mtandao"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> haina uwezo wa kufikia intaneti"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Gusa ili upate chaguo"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Mtandao wa simu hauna uwezo wa kufikia intaneti"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Mtandao hauna uwezo wa kufikia intaneti"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Seva ya faragha ya DNS haiwezi kufikiwa"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ina muunganisho unaofikia huduma chache."</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Gusa ili uunganishe tu"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Sasa inatumia <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Kifaa hutumia <xliff:g id="NEW_NETWORK">%1$s</xliff:g> wakati <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> haina intaneti. Huenda ukalipishwa."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Imebadilisha mtandao kutoka <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na sasa inatumia <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"aina ya mtandao isiyojulikana"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"data ya simu"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethaneti"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-ta/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ta/strings.xml
new file mode 100644
index 0000000..12604cb
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ta/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"வைஃபை நெட்வொர்க்கில் உள்நுழையவும்"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"நெட்வொர்க்கில் உள்நுழையவும்"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> நெட்வொர்க்கிற்கு இணைய அணுகல் இல்லை"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"விருப்பங்களுக்கு, தட்டவும்"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"மொபைல் நெட்வொர்க்கிற்கு இணைய அணுகல் இல்லை"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"நெட்வொர்க்கிற்கு இணைய அணுகல் இல்லை"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"தனிப்பட்ட DNS சேவையகத்தை அணுக இயலாது"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> வரம்பிற்கு உட்பட்ட இணைப்புநிலையைக் கொண்டுள்ளது"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"எப்படியேனும் இணைப்பதற்குத் தட்டவும்"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>க்கு மாற்றப்பட்டது"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> நெட்வொர்க்கில் இண்டர்நெட் அணுகல் இல்லாததால், சாதனமானது <xliff:g id="NEW_NETWORK">%1$s</xliff:g> நெட்வொர்க்கைப் பயன்படுத்துகிறது. கட்டணங்கள் விதிக்கப்படலாம்."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> இலிருந்து <xliff:g id="NEW_NETWORK">%2$s</xliff:g>க்கு மாற்றப்பட்டது"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"தெரியாத நெட்வொர்க் வகை"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"மொபைல் டேட்டா"</item>
+ <item msgid="5520925862115353992">"வைஃபை"</item>
+ <item msgid="1055487873974272842">"புளூடூத்"</item>
+ <item msgid="1616528372438698248">"ஈத்தர்நெட்"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-te/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-te/strings.xml
new file mode 100644
index 0000000..84a8640
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-te/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Wi-Fi నెట్వర్క్కి సైన్ ఇన్ చేయండి"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"నెట్వర్క్కి సైన్ ఇన్ చేయండి"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>కి ఇంటర్నెట్ యాక్సెస్ లేదు"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"ఎంపికల కోసం నొక్కండి"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"మొబైల్ నెట్వర్క్కు ఇంటర్నెట్ యాక్సెస్ లేదు"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"నెట్వర్క్కు ఇంటర్నెట్ యాక్సెస్ లేదు"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"ప్రైవేట్ DNS సర్వర్ను యాక్సెస్ చేయడం సాధ్యపడదు"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> పరిమిత కనెక్టివిటీని కలిగి ఉంది"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"ఏదేమైనా కనెక్ట్ చేయడానికి నొక్కండి"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>కి మార్చబడింది"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"పరికరం <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>కి ఇంటర్నెట్ యాక్సెస్ లేనప్పుడు <xliff:g id="NEW_NETWORK">%1$s</xliff:g>ని ఉపయోగిస్తుంది. ఛార్జీలు వర్తించవచ్చు."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> నుండి <xliff:g id="NEW_NETWORK">%2$s</xliff:g>కి మార్చబడింది"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"తెలియని నెట్వర్క్ రకం"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"మొబైల్ డేటా"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"బ్లూటూత్"</item>
+ <item msgid="1616528372438698248">"ఈథర్నెట్"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-th/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-th/strings.xml
new file mode 100644
index 0000000..1616e51
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-th/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"ลงชื่อเข้าใช้เครือข่าย WiFi"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"ลงชื่อเข้าใช้เครือข่าย"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> เข้าถึงอินเทอร์เน็ตไม่ได้"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"แตะเพื่อดูตัวเลือก"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"เครือข่ายมือถือไม่มีการเข้าถึงอินเทอร์เน็ต"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"เครือข่ายไม่มีการเข้าถึงอินเทอร์เน็ต"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"เข้าถึงเซิร์ฟเวอร์ DNS ไม่ได้"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> มีการเชื่อมต่อจำกัด"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"แตะเพื่อเชื่อมต่อ"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"เปลี่ยนเป็น <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"อุปกรณ์จะใช้ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> เมื่อ <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> เข้าถึงอินเทอร์เน็ตไม่ได้ โดยอาจมีค่าบริการ"</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"เปลี่ยนจาก <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> เป็น <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"ประเภทเครือข่ายที่ไม่รู้จัก"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"เน็ตมือถือ"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"บลูทูธ"</item>
+ <item msgid="1616528372438698248">"อีเทอร์เน็ต"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-tl/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-tl/strings.xml
new file mode 100644
index 0000000..3bf1ce4
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-tl/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Mag-sign in sa Wi-Fi network"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Mag-sign in sa network"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"Walang access sa internet ang <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"I-tap para sa mga opsyon"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Walang access sa internet ang mobile network"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Walang access sa internet ang network"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Hindi ma-access ang pribadong DNS server"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"Limitado ang koneksyon ng <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"I-tap para kumonekta pa rin"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Lumipat sa <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Ginagamit ng device ang <xliff:g id="NEW_NETWORK">%1$s</xliff:g> kapag walang access sa internet ang <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>. Maaaring may mga malapat na singilin."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Lumipat sa <xliff:g id="NEW_NETWORK">%2$s</xliff:g> mula sa <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"isang hindi kilalang uri ng network"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"mobile data"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-tr/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-tr/strings.xml
new file mode 100644
index 0000000..5c326e5
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-tr/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Kablosuz ağda oturum açın"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Ağda oturum açın"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ağının internet bağlantısı yok"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Seçenekler için dokunun"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Mobil ağın internet bağlantısı yok"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Ağın internet bağlantısı yok"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Gizli DNS sunucusuna erişilemiyor"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> sınırlı bağlantıya sahip"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Yine de bağlanmak için dokunun"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ağına geçildi"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ağının internet erişimi olmadığında cihaz <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ağını kullanır. Bunun için ödeme alınabilir."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ağından <xliff:g id="NEW_NETWORK">%2$s</xliff:g> ağına geçildi"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"bilinmeyen ağ türü"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"mobil veri"</item>
+ <item msgid="5520925862115353992">"Kablosuz"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-uk/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-uk/strings.xml
new file mode 100644
index 0000000..d1382da
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-uk/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Вхід у мережу Wi-Fi"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Вхід у мережу"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"Мережа <xliff:g id="NETWORK_SSID">%1$s</xliff:g> не має доступу до Інтернету"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Торкніться, щоб відкрити опції"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Мобільна мережа не має доступу до Інтернету"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Мережа не має доступу до Інтернету"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Немає доступу до приватного DNS-сервера"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"Підключення до мережі <xliff:g id="NETWORK_SSID">%1$s</xliff:g> обмежено"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Натисніть, щоб усе одно підключитися"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Пристрій перейшов на мережу <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Коли мережа <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> не має доступу до Інтернету, використовується <xliff:g id="NEW_NETWORK">%1$s</xliff:g>. Може стягуватися плата."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Пристрій перейшов з мережі <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> на мережу <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"невідомий тип мережі"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"мобільне передавання даних"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"Мережа VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-ur/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ur/strings.xml
new file mode 100644
index 0000000..3c031ad
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ur/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Wi-Fi نیٹ ورک میں سائن ان کریں"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"نیٹ ورک میں سائن ان کریں"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> کو انٹرنیٹ تک رسائی حاصل نہیں ہے"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"اختیارات کیلئے تھپتھپائیں"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"موبائل نیٹ ورک کو انٹرنیٹ تک رسائی حاصل نہیں ہے"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"نیٹ ورک کو انٹرنیٹ تک رسائی حاصل نہیں ہے"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"نجی DNS سرور تک رسائی حاصل نہیں کی جا سکی"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> کی کنیکٹوٹی محدود ہے"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"بہر حال منسلک کرنے کے لیے تھپتھپائیں"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> پر سوئچ ہو گیا"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"جب <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> کو انٹرنیٹ تک رسائی نہیں ہوتی ہے تو آلہ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> کا استعمال کرتا ہے۔ چارجز لاگو ہو سکتے ہیں۔"</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> سے <xliff:g id="NEW_NETWORK">%2$s</xliff:g> پر سوئچ ہو گیا"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"نیٹ ورک کی نامعلوم قسم"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"موبائل ڈیٹا"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"بلوٹوتھ"</item>
+ <item msgid="1616528372438698248">"ایتھرنیٹ"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-uz/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-uz/strings.xml
new file mode 100644
index 0000000..7518db3
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-uz/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Wi-Fi tarmoqqa kirish"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Tarmoqqa kirish"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> nomli tarmoqda internetga ruxsati yoʻq"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Variantlarni ko‘rsatish uchun bosing"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Mobil tarmoq internetga ulanmagan"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Tarmoq internetga ulanmagan"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Xususiy DNS server ishlamayapti"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> nomli tarmoqda aloqa cheklangan"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Baribir ulash uchun bosing"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Yangi ulanish: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Agar <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> tarmoqda internet uzilsa, qurilma <xliff:g id="NEW_NETWORK">%1$s</xliff:g>ga ulanadi. Sarflangan trafik uchun haq olinishi mumkin."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> tarmog‘idan <xliff:g id="NEW_NETWORK">%2$s</xliff:g> tarmog‘iga o‘tildi"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"noma’lum tarmoq turi"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"mobil internet"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-vi/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-vi/strings.xml
new file mode 100644
index 0000000..d2284d4
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-vi/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Đăng nhập vào mạng Wi-Fi"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Đăng nhập vào mạng"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> không có quyền truy cập Internet"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Nhấn để biết tùy chọn"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Mạng di động không có quyền truy cập Internet"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Mạng không có quyền truy cập Internet"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Không thể truy cập máy chủ DNS riêng tư"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> có khả năng kết nối giới hạn"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Nhấn để tiếp tục kết nối"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Đã chuyển sang <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Thiết bị sử dụng <xliff:g id="NEW_NETWORK">%1$s</xliff:g> khi <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> không có quyền truy cập Internet. Bạn có thể phải trả phí."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Đã chuyển từ <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> sang <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"loại mạng không xác định"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"dữ liệu di động"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-zh-rCN/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-zh-rCN/strings.xml
new file mode 100644
index 0000000..813482b
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-zh-rCN/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"登录到WLAN网络"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"登录到网络"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> 无法访问互联网"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"点按即可查看相关选项"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"此移动网络无法访问互联网"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"此网络无法访问互联网"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"无法访问私人 DNS 服务器"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> 的连接受限"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"点按即可继续连接"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"已切换至<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"设备会在<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>无法访问互联网时使用<xliff:g id="NEW_NETWORK">%1$s</xliff:g>(可能需要支付相应的费用)。"</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"已从<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>切换至<xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"未知网络类型"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"移动数据"</item>
+ <item msgid="5520925862115353992">"WLAN"</item>
+ <item msgid="1055487873974272842">"蓝牙"</item>
+ <item msgid="1616528372438698248">"以太网"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-zh-rHK/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-zh-rHK/strings.xml
new file mode 100644
index 0000000..676404f
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-zh-rHK/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"登入 Wi-Fi 網絡"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"登入網絡"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>未有連接至互聯網"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"輕按即可查看選項"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"流動網絡並未連接互聯網"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"網絡並未連接互聯網"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"無法存取私人 DNS 伺服器"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>連線受限"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"仍要輕按以連結至此網絡"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"已切換至<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"裝置會在 <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> 無法連線至互聯網時使用<xliff:g id="NEW_NETWORK">%1$s</xliff:g> (可能需要支付相關費用)。"</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"已從<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>切換至<xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"不明網絡類型"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"流動數據"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"藍牙"</item>
+ <item msgid="1616528372438698248">"以太網"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-zh-rTW/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-zh-rTW/strings.xml
new file mode 100644
index 0000000..f355138
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-zh-rTW/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"登入 Wi-Fi 網路"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"登入網路"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> 沒有網際網路連線"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"輕觸即可查看選項"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"這個行動網路沒有網際網路連線"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"這個網路沒有網際網路連線"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"無法存取私人 DNS 伺服器"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> 的連線能力受限"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"輕觸即可繼續連線"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"已切換至<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"裝置會在無法連上「<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>」時切換至「<xliff:g id="NEW_NETWORK">%1$s</xliff:g>」(可能需要支付相關費用)。"</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"已從 <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> 切換至<xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"不明的網路類型"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"行動數據"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"藍牙"</item>
+ <item msgid="1616528372438698248">"乙太網路"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-zu/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-zu/strings.xml
new file mode 100644
index 0000000..55fefb7
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-zu/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Ngena ngemvume kunethiwekhi ye-Wi-Fi"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Ngena ngemvume kunethiwekhi"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"I-<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ayinakho ukufinyelela kwe-inthanethi"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Thepha ukuze uthole izinketho"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Inethiwekhi yeselula ayinakho ukufinyelela kwe-inthanethi"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Inethiwekhi ayinakho ukufinyelela kwenethiwekhi"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Iseva eyimfihlo ye-DNS ayikwazi ukufinyelelwa"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"I-<xliff:g id="NETWORK_SSID">%1$s</xliff:g> inokuxhumeka okukhawulelwe"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Thepha ukuze uxhume noma kunjalo"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Kushintshelwe ku-<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Idivayisi isebenzisa i-<xliff:g id="NEW_NETWORK">%1$s</xliff:g> uma i-<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> inganakho ukufinyelela kwe-inthanethi. Kungasebenza izindleko."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Kushintshelewe kusuka ku-<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> kuya ku-<xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"uhlobo olungaziwa lwenethiwekhi"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"idatha yeselula"</item>
+ <item msgid="5520925862115353992">"I-Wi-Fi"</item>
+ <item msgid="1055487873974272842">"I-Bluetooth"</item>
+ <item msgid="1616528372438698248">"I-Ethernet"</item>
+ <item msgid="9177085807664964627">"I-VPN"</item>
+ </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values/config.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values/config.xml
new file mode 100644
index 0000000..71674e4
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values/config.xml
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<!-- Configuration values for ConnectivityService
+ DO NOT EDIT THIS FILE for specific device configuration; instead, use a Runtime Resources
+ Overlay package following the overlayable.xml configuration in the same directory:
+ https://source.android.com/devices/architecture/rros -->
+<resources>
+
+ <!-- Configuration hook for the URL returned by ConnectivityManager#getCaptivePortalServerUrl.
+ If empty, the returned value is controlled by Settings.Global.CAPTIVE_PORTAL_HTTP_URL,
+ and if that value is empty, the framework will use a hard-coded default.
+ This is *NOT* a URL that will always be used by the system network validation to detect
+ captive portals: NetworkMonitor may use different strategies and will not necessarily use
+ this URL. NetworkMonitor behaviour should be configured with NetworkStack resource overlays
+ instead. -->
+ <!--suppress CheckTagEmptyBody -->
+ <string translatable="false" name="config_networkCaptivePortalServerUrl"></string>
+
+ <!-- The maximum duration (in milliseconds) we expect a network transition to take -->
+ <integer name="config_networkTransitionTimeout">60000</integer>
+
+ <!-- Configuration of network interfaces that support WakeOnLAN -->
+ <string-array translatable="false" name="config_wakeonlan_supported_interfaces">
+ <!--
+ <item>wlan0</item>
+ <item>eth0</item>
+ -->
+ </string-array>
+
+ <string-array translatable="false" name="config_legacy_networktype_restore_timers">
+ <item>2,60000</item><!-- mobile_mms -->
+ <item>3,60000</item><!-- mobile_supl -->
+ <item>4,60000</item><!-- mobile_dun -->
+ <item>5,60000</item><!-- mobile_hipri -->
+ <item>10,60000</item><!-- mobile_fota -->
+ <item>11,60000</item><!-- mobile_ims -->
+ <item>12,60000</item><!-- mobile_cbs -->
+ </string-array>
+
+ <!-- Whether the APF Filter in the device should filter out IEEE 802.3 Frames
+ Those frames are identified by the field Eth-type having values
+ less than 0x600 -->
+ <bool translatable="false" name="config_apfDrop802_3Frames">true</bool>
+
+ <!-- An array of Denylisted EtherType, packets with EtherTypes within this array
+ will be dropped
+ TODO: need to put proper values, these are for testing purposes only -->
+ <integer-array translatable="false" name="config_apfEthTypeDenyList">
+ <item>0x88A2</item>
+ <item>0x88A4</item>
+ <item>0x88B8</item>
+ <item>0x88CD</item>
+ <item>0x88E3</item>
+ </integer-array>
+
+ <!-- Default supported concurrent socket keepalive slots per transport type, used by
+ ConnectivityManager.createSocketKeepalive() for calculating the number of keepalive
+ offload slots that should be reserved for privileged access. This string array should be
+ overridden by the device to present the capability of creating socket keepalives. -->
+ <!-- An Array of "[NetworkCapabilities.TRANSPORT_*],[supported keepalives] -->
+ <string-array translatable="false" name="config_networkSupportedKeepaliveCount">
+ <item>0,1</item>
+ <item>1,3</item>
+ </string-array>
+
+
+ <!-- Default value for ConnectivityManager.getMultipathPreference() on metered networks. Actual
+ device behaviour is controlled by the metered multipath preference in
+ ConnectivitySettingsManager. This is the default value of that setting. -->
+ <integer translatable="false" name="config_networkMeteredMultipathPreference">0</integer>
+
+ <!-- Whether the device should automatically switch away from Wi-Fi networks that lose
+ Internet access. Actual device behaviour is controlled by
+ Settings.Global.NETWORK_AVOID_BAD_WIFI. This is the default value of that setting. -->
+ <integer translatable="false" name="config_networkAvoidBadWifi">1</integer>
+
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values/overlayable.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values/overlayable.xml
new file mode 100644
index 0000000..25e19ce
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values/overlayable.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+ <overlayable name="ServiceConnectivityResourcesConfig">
+ <policy type="product|system|vendor">
+ <!-- Configuration values for ConnectivityService -->
+ <item type="array" name="config_legacy_networktype_restore_timers"/>
+ <item type="string" name="config_networkCaptivePortalServerUrl"/>
+ <item type="integer" name="config_networkTransitionTimeout"/>
+ <item type="array" name="config_wakeonlan_supported_interfaces"/>
+ <item type="bool" name="config_apfDrop802_3Frames"/>
+ <item type="array" name="config_apfEthTypeDenyList"/>
+ <item type="integer" name="config_networkMeteredMultipathPreference"/>
+ <item type="array" name="config_networkSupportedKeepaliveCount"/>
+ <item type="integer" name="config_networkAvoidBadWifi"/>
+
+ </policy>
+ </overlayable>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values/strings.xml
new file mode 100644
index 0000000..b2fa5f5
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values/strings.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- The System Connectivity Resources package is an internal system package that provides
+ configuration values for system networking that were pre-configured in the device. This
+ is the name of the package to display in the list of system apps. [CHAR LIMIT=40] -->
+ <string name="connectivityResourcesAppLabel">System Connectivity Resources</string>
+
+ <!-- A notification is shown when a wifi captive portal network is detected. This is the notification's title. -->
+ <string name="wifi_available_sign_in">Sign in to Wi-Fi network</string>
+
+ <!-- A notification is shown when a captive portal network is detected. This is the notification's title. -->
+ <string name="network_available_sign_in">Sign in to network</string>
+
+ <!-- A notification is shown when a captive portal network is detected. This is the notification's message. -->
+ <string name="network_available_sign_in_detailed"><xliff:g id="network_ssid">%1$s</xliff:g></string>
+
+ <!-- A notification is shown when the user connects to a Wi-Fi network and the system detects that that network has no Internet access. This is the notification's title. -->
+ <string name="wifi_no_internet"><xliff:g id="network_ssid" example="GoogleGuest">%1$s</xliff:g> has no internet access</string>
+
+ <!-- A notification is shown when the user connects to a Wi-Fi network and the system detects that that network has no Internet access. This is the notification's message. -->
+ <string name="wifi_no_internet_detailed">Tap for options</string>
+
+ <!-- A notification is shown when the user connects to a mobile network without internet access. This is the notification's title. -->
+ <string name="mobile_no_internet">Mobile network has no internet access</string>
+
+ <!-- A notification is shown when the user connects to a non-mobile and non-wifi network without internet access. This is the notification's title. -->
+ <string name="other_networks_no_internet">Network has no internet access</string>
+
+ <!-- A notification is shown when connected network without internet due to private dns validation failed. This is the notification's message. [CHAR LIMIT=NONE] -->
+ <string name="private_dns_broken_detailed">Private DNS server cannot be accessed</string>
+
+ <!-- A notification is shown when the user connects to a network that doesn't have access to some services (e.g. Push notifications may not work). This is the notification's title. [CHAR LIMIT=50] -->
+ <string name="network_partial_connectivity"><xliff:g id="network_ssid" example="GoogleGuest">%1$s</xliff:g> has limited connectivity</string>
+
+ <!-- A notification is shown when the user connects to a network that doesn't have access to some services (e.g. Push notifications may not work). This is the notification's message. [CHAR LIMIT=50] -->
+ <string name="network_partial_connectivity_detailed">Tap to connect anyway</string>
+
+ <!-- A notification might be shown if the device switches to another network type (e.g., mobile data) because it detects that the network it was using (e.g., Wi-Fi) has lost Internet connectivity. This is the notification's title. %1$s is the network type that the device switched to, e.g., cellular data. It is one of the strings in the network_switch_type_name array. -->
+ <string name="network_switch_metered">Switched to <xliff:g id="network_type">%1$s</xliff:g></string>
+
+ <!-- A notification might be shown if the device switches to another network type (e.g., mobile data) because it detects that the network it was using (e.g., Wi-Fi) has lost Internet connectivity. This is the notification's message. %1$s is the network that the device switched to, e.g., cellular data. %2$s is the network type the device switched from, e.g., Wi-Fi. Both are strings in the network_switch_type_name array. -->
+ <string name="network_switch_metered_detail">Device uses <xliff:g id="new_network">%1$s</xliff:g> when <xliff:g id="previous_network">%2$s</xliff:g> has no internet access. Charges may apply.</string>
+
+ <!-- A toast might be shown if the device switches to another network type (e.g., mobile data) because it detects that the network it was using (e.g., Wi-Fi) has lost Internet connectivity. This is the text of the toast. %1$s is the network that the device switched from, e.g., Wi-Fi. %2$s is the network type the device switched from, e.g., cellular data. Both are strings in the network_switch_type_name array. -->
+ <string name="network_switch_metered_toast">Switched from <xliff:g id="previous_network">%1$s</xliff:g> to <xliff:g id="new_network">%2$s</xliff:g></string>
+
+ <!-- Network type names used in the network_switch_metered and network_switch_metered_detail strings. These must be kept in the sync with the values NetworkCapabilities.TRANSPORT_xxx values, and in the same order. -->
+ <string-array name="network_switch_type_name">
+ <item>mobile data</item>
+ <item>Wi-Fi</item>
+ <item>Bluetooth</item>
+ <item>Ethernet</item>
+ <item>VPN</item>
+ </string-array>
+
+ <!-- Network type name displayed if one of the types is not found in network_switch_type_name. -->
+ <string name="network_switch_type_name_unknown">an unknown network type</string>
+
+</resources>
diff --git a/packages/Connectivity/service/jarjar-rules.txt b/packages/Connectivity/service/jarjar-rules.txt
index d8205bf..5caa11b 100644
--- a/packages/Connectivity/service/jarjar-rules.txt
+++ b/packages/Connectivity/service/jarjar-rules.txt
@@ -1,2 +1,17 @@
+rule android.sysprop.** com.android.connectivity.sysprop.@1
rule com.android.net.module.util.** com.android.connectivity.net-utils.@1
-rule com.android.modules.utils.** com.android.connectivity.modules-utils.@1
\ No newline at end of file
+rule com.android.modules.utils.** com.android.connectivity.modules-utils.@1
+
+# internal util classes
+# Exclude AsyncChannel. TODO: remove AsyncChannel usage in ConnectivityService
+rule com.android.internal.util.AsyncChannel* @0
+# Exclude LocationPermissionChecker. This is going to be moved to libs/net
+rule com.android.internal.util.LocationPermissionChecker* @0
+rule android.util.LocalLog* com.android.connectivity.util.LocalLog@1
+# android.util.IndentingPrintWriter* should use a different package name from
+# the one in com.android.internal.util
+rule android.util.IndentingPrintWriter* android.connectivity.util.IndentingPrintWriter@1
+rule com.android.internal.util.** com.android.connectivity.util.@1
+
+rule com.android.internal.messages.** com.android.connectivity.messages.@1
+rule com.google.protobuf.** com.android.connectivity.protobuf.@1
diff --git a/packages/Connectivity/framework/src/android/net/IOnSetOemNetworkPreferenceListener.aidl b/packages/Connectivity/service/proto/connectivityproto.proto
similarity index 69%
copy from packages/Connectivity/framework/src/android/net/IOnSetOemNetworkPreferenceListener.aidl
copy to packages/Connectivity/service/proto/connectivityproto.proto
index 7979afc..a992d7c 100644
--- a/packages/Connectivity/framework/src/android/net/IOnSetOemNetworkPreferenceListener.aidl
+++ b/packages/Connectivity/service/proto/connectivityproto.proto
@@ -1,12 +1,11 @@
-/**
- *
+/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * 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,
@@ -15,9 +14,7 @@
* limitations under the License.
*/
-package android.net;
+syntax = "proto2";
-/** @hide */
-oneway interface IOnSetOemNetworkPreferenceListener {
- void onComplete();
-}
+// Connectivity protos can be created in this directory. Note this file must be included before
+// building system-messages-proto, otherwise it will not build by itself.
diff --git a/packages/CtsShim/apk/arm/CtsShim.apk b/packages/CtsShim/apk/arm/CtsShim.apk
index 180dfb6..784a747 100644
--- a/packages/CtsShim/apk/arm/CtsShim.apk
+++ b/packages/CtsShim/apk/arm/CtsShim.apk
Binary files differ
diff --git a/packages/CtsShim/apk/arm/CtsShimPriv.apk b/packages/CtsShim/apk/arm/CtsShimPriv.apk
index d87ea7f..5b7bda4 100644
--- a/packages/CtsShim/apk/arm/CtsShimPriv.apk
+++ b/packages/CtsShim/apk/arm/CtsShimPriv.apk
Binary files differ
diff --git a/packages/CtsShim/apk/x86/CtsShim.apk b/packages/CtsShim/apk/x86/CtsShim.apk
index 180dfb6..784a747 100644
--- a/packages/CtsShim/apk/x86/CtsShim.apk
+++ b/packages/CtsShim/apk/x86/CtsShim.apk
Binary files differ
diff --git a/packages/CtsShim/apk/x86/CtsShimPriv.apk b/packages/CtsShim/apk/x86/CtsShimPriv.apk
index 3124651..780cb8a 100644
--- a/packages/CtsShim/apk/x86/CtsShimPriv.apk
+++ b/packages/CtsShim/apk/x86/CtsShimPriv.apk
Binary files differ
diff --git a/packages/CtsShim/build/shim/AndroidManifest.xml b/packages/CtsShim/build/shim/AndroidManifest.xml
index 3e546f1e..58e8522 100644
--- a/packages/CtsShim/build/shim/AndroidManifest.xml
+++ b/packages/CtsShim/build/shim/AndroidManifest.xml
@@ -52,6 +52,9 @@
</intent-filter>
</activity>
+ <!-- The stub shared library for package visibility test -->
+ <library android:name="com.android.cts.ctsshim.shared_library" />
+
</application>
</manifest>
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
index c1dca5d..16a946d 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
@@ -138,9 +138,6 @@
private long mCurrentPartitionSize;
private long mCurrentPartitionInstalledSize;
- private boolean mJustCancelledByUser;
- private boolean mKeepNotification;
-
// This is for testing only now
private boolean mEnableWhenCompleted;
@@ -174,11 +171,6 @@
if (cache != null) {
cache.flush();
}
-
- if (!mKeepNotification) {
- // Cancel the persistent notification.
- mNM.cancel(NOTIFICATION_ID);
- }
}
@Override
@@ -231,9 +223,11 @@
return;
}
+ boolean removeNotification = false;
switch (result) {
case RESULT_CANCELLED:
postStatus(STATUS_NOT_STARTED, CAUSE_INSTALL_CANCELLED, null);
+ removeNotification = true;
break;
case RESULT_ERROR_IO:
@@ -251,7 +245,7 @@
}
// if it's not successful, reset the task and stop self.
- resetTaskAndStop();
+ resetTaskAndStop(removeNotification);
}
private void executeInstallCommand(Intent intent) {
@@ -302,12 +296,12 @@
return;
}
- stopForeground(true);
- mJustCancelledByUser = true;
-
if (mInstallTask.cancel(false)) {
- // Will stopSelf() in onResult()
+ // onResult() would call resetTaskAndStop() upon task completion.
Log.d(TAG, "Cancel request filed successfully");
+ // Dismiss the notification as soon as possible as DynamicSystemManager.remove() may
+ // block.
+ stopForeground(STOP_FOREGROUND_REMOVE);
} else {
Log.e(TAG, "Trying to cancel installation while it's already completed.");
}
@@ -322,8 +316,7 @@
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();
+ resetTaskAndStop(true);
return;
}
@@ -331,8 +324,8 @@
getString(R.string.toast_dynsystem_discarded),
Toast.LENGTH_LONG).show();
- resetTaskAndStop();
postStatus(STATUS_NOT_STARTED, CAUSE_INSTALL_CANCELLED, null);
+ resetTaskAndStop(true);
mDynSystem.remove();
}
@@ -412,12 +405,13 @@
}
private void resetTaskAndStop() {
- mInstallTask = null;
+ resetTaskAndStop(/* removeNotification= */ false);
+ }
- new Handler().postDelayed(() -> {
- stopForeground(STOP_FOREGROUND_DETACH);
- stopSelf();
- }, 50);
+ private void resetTaskAndStop(boolean removeNotification) {
+ mInstallTask = null;
+ stopForeground(removeNotification ? STOP_FOREGROUND_REMOVE : STOP_FOREGROUND_DETACH);
+ stopSelf();
}
private void prepareNotification() {
@@ -525,7 +519,7 @@
private void postStatus(int status, int cause, Throwable detail) {
String statusString;
String causeString;
- mKeepNotification = false;
+ boolean notifyOnNotificationBar = true;
switch (status) {
case STATUS_NOT_STARTED:
@@ -551,18 +545,16 @@
break;
case CAUSE_INSTALL_CANCELLED:
causeString = "INSTALL_CANCELLED";
+ notifyOnNotificationBar = false;
break;
case CAUSE_ERROR_IO:
causeString = "ERROR_IO";
- mKeepNotification = true;
break;
case CAUSE_ERROR_INVALID_URL:
causeString = "ERROR_INVALID_URL";
- mKeepNotification = true;
break;
case CAUSE_ERROR_EXCEPTION:
causeString = "ERROR_EXCEPTION";
- mKeepNotification = true;
break;
default:
causeString = "CAUSE_NOT_SPECIFIED";
@@ -571,16 +563,6 @@
Log.d(TAG, "status=" + statusString + ", cause=" + causeString + ", detail=" + detail);
- boolean notifyOnNotificationBar = true;
-
- if (status == STATUS_NOT_STARTED
- && cause == CAUSE_INSTALL_CANCELLED
- && mJustCancelledByUser) {
- // if task is cancelled by user, do not notify them
- notifyOnNotificationBar = false;
- mJustCancelledByUser = false;
- }
-
if (notifyOnNotificationBar) {
mNM.notify(NOTIFICATION_ID, buildNotification(status, cause, detail));
}
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
index 4ef5e2b..59ea9f0 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
@@ -320,7 +320,7 @@
}
}
- private void installScratch() throws IOException, InterruptedException {
+ private void installScratch() throws IOException {
final long scratchSize = mDynSystem.suggestScratchSize();
Thread thread = new Thread() {
@Override
@@ -347,7 +347,11 @@
publishProgress(progress);
}
- Thread.sleep(100);
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ // Ignore the error.
+ }
}
if (mInstallationSession == null) {
@@ -361,7 +365,7 @@
}
}
- private void installUserdata() throws IOException, InterruptedException {
+ private void installUserdata() throws IOException {
Thread thread = new Thread(() -> {
mInstallationSession = mDynSystem.createPartition("userdata", mUserdataSize, false);
});
@@ -383,7 +387,11 @@
publishProgress(progress);
}
- Thread.sleep(100);
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ // Ignore the error.
+ }
}
if (mInstallationSession == null) {
@@ -397,8 +405,7 @@
}
}
- private void installImages()
- throws IOException, InterruptedException, ImageValidationException {
+ private void installImages() throws IOException, ImageValidationException {
if (mStream != null) {
if (mIsZip) {
installStreamingZipUpdate();
@@ -410,14 +417,12 @@
}
}
- private void installStreamingGzUpdate()
- throws IOException, InterruptedException, ImageValidationException {
+ private void installStreamingGzUpdate() throws IOException, ImageValidationException {
Log.d(TAG, "To install a streaming GZ update");
installImage("system", mSystemSize, new GZIPInputStream(mStream));
}
- private void installStreamingZipUpdate()
- throws IOException, InterruptedException, ImageValidationException {
+ private void installStreamingZipUpdate() throws IOException, ImageValidationException {
Log.d(TAG, "To install a streaming ZIP update");
ZipInputStream zis = new ZipInputStream(mStream);
@@ -432,8 +437,7 @@
}
}
- private void installLocalZipUpdate()
- throws IOException, InterruptedException, ImageValidationException {
+ private void installLocalZipUpdate() throws IOException, ImageValidationException {
Log.d(TAG, "To install a local ZIP update");
Enumeration<? extends ZipEntry> entries = mZipFile.entries();
@@ -449,7 +453,7 @@
}
private boolean installImageFromAnEntry(ZipEntry entry, InputStream is)
- throws IOException, InterruptedException, ImageValidationException {
+ throws IOException, ImageValidationException {
String name = entry.getName();
Log.d(TAG, "ZipEntry: " + name);
@@ -473,7 +477,7 @@
}
private void installImage(String partitionName, long uncompressedSize, InputStream is)
- throws IOException, InterruptedException, ImageValidationException {
+ throws IOException, ImageValidationException {
SparseInputStream sis = new SparseInputStream(new BufferedInputStream(is));
@@ -504,7 +508,11 @@
return;
}
- Thread.sleep(100);
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ // Ignore the error.
+ }
}
if (mInstallationSession == null) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index ad459a4..40a457f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -22,7 +22,6 @@
import android.graphics.drawable.Drawable;
import android.location.LocationManager;
import android.media.AudioManager;
-import android.net.ConnectivityManager;
import android.net.TetheringManager;
import android.os.BatteryManager;
import android.os.SystemProperties;
@@ -33,6 +32,7 @@
import android.telephony.AccessNetworkConstants;
import android.telephony.NetworkRegistrationInfo;
import android.telephony.ServiceState;
+import android.telephony.TelephonyManager;
import androidx.annotation.NonNull;
import androidx.core.graphics.drawable.RoundedBitmapDrawable;
@@ -435,8 +435,7 @@
}
public static boolean isWifiOnly(Context context) {
- return !context.getSystemService(ConnectivityManager.class)
- .isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
+ return !context.getSystemService(TelephonyManager.class).isDataCapable();
}
/** Returns if the automatic storage management feature is turned on or not. **/
diff --git a/packages/SettingsLib/src/com/android/settingslib/connectivity/OWNERS b/packages/SettingsLib/src/com/android/settingslib/connectivity/OWNERS
index e7a20b3..c88ed8e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/connectivity/OWNERS
+++ b/packages/SettingsLib/src/com/android/settingslib/connectivity/OWNERS
@@ -1,6 +1,7 @@
# Default reviewers for this and subdirectories.
andychou@google.com
arcwang@google.com
+changbetty@google.com
goldmanj@google.com
qal@google.com
wengsu@google.com
diff --git a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractIpAddressPreferenceController.java b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractIpAddressPreferenceController.java
index 3bb3a0c..7f12cc8 100644
--- a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractIpAddressPreferenceController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractIpAddressPreferenceController.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.net.ConnectivityManager;
+import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.wifi.WifiManager;
@@ -28,7 +29,6 @@
import com.android.settingslib.R;
import com.android.settingslib.core.lifecycle.Lifecycle;
-import java.net.InetAddress;
import java.util.Iterator;
/**
@@ -93,19 +93,19 @@
* @return the formatted and newline-separated IP addresses, or null if none.
*/
private static String getDefaultIpAddresses(ConnectivityManager cm) {
- LinkProperties prop = cm.getActiveLinkProperties();
+ LinkProperties prop = cm.getLinkProperties(cm.getActiveNetwork());
return formatIpAddresses(prop);
}
private static String formatIpAddresses(LinkProperties prop) {
if (prop == null) return null;
- Iterator<InetAddress> iter = prop.getAllAddresses().iterator();
+ Iterator<LinkAddress> iter = prop.getAllLinkAddresses().iterator();
// If there are no entries, return null
if (!iter.hasNext()) return null;
// Concatenate all available addresses, newline separated
StringBuilder addresses = new StringBuilder();
while (iter.hasNext()) {
- addresses.append(iter.next().getHostAddress());
+ addresses.append(iter.next().getAddress().getHostAddress());
if (iter.hasNext()) addresses.append("\n");
}
return addresses.toString();
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java b/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java
index 092cbf3..60bcf37 100644
--- a/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java
@@ -16,7 +16,6 @@
package com.android.settingslib.net;
-import static android.net.ConnectivityManager.TYPE_MOBILE;
import static android.net.NetworkStatsHistory.FIELD_RX_BYTES;
import static android.net.NetworkStatsHistory.FIELD_TX_BYTES;
import static android.net.TrafficStats.MB_IN_BYTES;
@@ -59,7 +58,6 @@
PERIOD_BUILDER, Locale.getDefault());
private final Context mContext;
- private final ConnectivityManager mConnectivityManager;
private final INetworkStatsService mStatsService;
private final NetworkPolicyManager mPolicyManager;
private final NetworkStatsManager mNetworkStatsManager;
@@ -71,7 +69,6 @@
public DataUsageController(Context context) {
mContext = context;
- mConnectivityManager = ConnectivityManager.from(context);
mStatsService = INetworkStatsService.Stub.asInterface(
ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
mPolicyManager = NetworkPolicyManager.from(mContext);
@@ -236,7 +233,7 @@
public boolean isMobileDataSupported() {
// require both supported network and ready SIM
- return mConnectivityManager.isNetworkSupported(TYPE_MOBILE)
+ return getTelephonyManager().isDataCapable()
&& getTelephonyManager().getSimState() == SIM_STATE_READY;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/OWNERS b/packages/SettingsLib/src/com/android/settingslib/wifi/OWNERS
index 0bde5c0..f3b600c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/OWNERS
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/OWNERS
@@ -2,6 +2,7 @@
andychou@google.com
arcwang@google.com
asapperstein@google.com
+changbetty@google.com
goldmanj@google.com
qal@google.com
wengsu@google.com
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 6568bff..268603f 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -2445,8 +2445,8 @@
R.bool.def_auto_time_zone); // Sync timezone to NITZ
loadSetting(stmt, Settings.Global.STAY_ON_WHILE_PLUGGED_IN,
- ("1".equals(SystemProperties.get("ro.kernel.qemu")) ||
- res.getBoolean(R.bool.def_stay_on_while_plugged_in))
+ ("1".equals(SystemProperties.get("ro.boot.qemu"))
+ || res.getBoolean(R.bool.def_stay_on_while_plugged_in))
? 1 : 0);
loadIntegerSetting(stmt, Settings.Global.WIFI_SLEEP_POLICY,
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 3fed29a..b7ce2a3 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -367,6 +367,7 @@
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
<uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" />
<uses-permission android:name="android.permission.BIND_RESUME_ON_REBOOT_SERVICE" />
+ <uses-permission android:name="android.permission.MANAGE_APP_HIBERNATION"/>
<application android:label="@string/app_label"
android:theme="@android:style/Theme.DeviceDefault.DayNight"
diff --git a/packages/VpnDialogs/res/values/strings.xml b/packages/VpnDialogs/res/values/strings.xml
index 443a9bc..f971a09 100644
--- a/packages/VpnDialogs/res/values/strings.xml
+++ b/packages/VpnDialogs/res/values/strings.xml
@@ -28,6 +28,17 @@
]]> appears at the top of your screen when VPN is active.
</string>
+ <!-- TV specific dialog message to warn about the risk of using a VPN application. [CHAR LIMIT=NONE] -->
+ <string name="warning" product="tv">
+ <xliff:g id="app">%s</xliff:g> wants to set up a VPN connection
+ that allows it to monitor network traffic. Only accept if you trust the source.
+ <![CDATA[
+ <br />
+ <br />
+ <img src="vpn_icon" />
+ ]]> appears on your screen when VPN is active.
+ </string>
+
<!-- Dialog title for built-in VPN. [CHAR LIMIT=40] -->
<string name="legacy_title">VPN is connected</string>
<!-- Label for the name of the current VPN session. [CHAR LIMIT=20] -->
diff --git a/packages/services/Proxy/src/com/android/proxyhandler/ProxyServer.java b/packages/services/Proxy/src/com/android/proxyhandler/ProxyServer.java
index f8b9309..f0de811 100644
--- a/packages/services/Proxy/src/com/android/proxyhandler/ProxyServer.java
+++ b/packages/services/Proxy/src/com/android/proxyhandler/ProxyServer.java
@@ -360,7 +360,7 @@
try {
mCallback.setProxyPort(port);
} catch (RemoteException e) {
- Log.w(TAG, "Proxy failed to report port to PacProxyInstaller", e);
+ Log.w(TAG, "Proxy failed to report port to PacProxyService", e);
}
}
mPort = port;
@@ -371,7 +371,7 @@
try {
callback.setProxyPort(mPort);
} catch (RemoteException e) {
- Log.w(TAG, "Proxy failed to report port to PacProxyInstaller", e);
+ Log.w(TAG, "Proxy failed to report port to PacProxyService", e);
}
}
mCallback = callback;
diff --git a/packages/services/Proxy/src/com/android/proxyhandler/ProxyService.java b/packages/services/Proxy/src/com/android/proxyhandler/ProxyService.java
index bdf478d..a8e2622 100644
--- a/packages/services/Proxy/src/com/android/proxyhandler/ProxyService.java
+++ b/packages/services/Proxy/src/com/android/proxyhandler/ProxyService.java
@@ -30,7 +30,7 @@
private static ProxyServer server = null;
- /** Keep these values up-to-date with PacProxyInstaller.java */
+ /** Keep these values up-to-date with PacProxyService.java */
public static final String KEY_PROXY = "keyProxy";
public static final String HOST = "localhost";
public static final String EXCL_LIST = "";
diff --git a/services/core/Android.bp b/services/core/Android.bp
index f1ab2aa..0ac8f74 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -81,9 +81,18 @@
out: ["services.core.protolog.json"],
}
+genrule {
+ name: "statslog-art-java-gen",
+ tools: ["stats-log-api-gen"],
+ cmd: "$(location stats-log-api-gen) --java $(out) --module art" +
+ " --javaPackage com.android.internal.art --javaClass ArtStatsLog --worksource",
+ out: ["com/android/internal/art/ArtStatsLog.java"],
+}
+
java_library_static {
name: "services.core.unboosted",
srcs: [
+ ":statslog-art-java-gen",
":services.core.protologsrc",
":dumpstate_aidl",
":framework_native_aidl",
@@ -201,6 +210,7 @@
"java/com/android/server/connectivity/AutodestructReference.java",
"java/com/android/server/connectivity/ConnectivityConstants.java",
"java/com/android/server/connectivity/DnsManager.java",
+ "java/com/android/server/connectivity/FullScore.java",
"java/com/android/server/connectivity/KeepaliveTracker.java",
"java/com/android/server/connectivity/LingerMonitor.java",
"java/com/android/server/connectivity/MockableSystemProperties.java",
diff --git a/services/core/java/com/android/server/BluetoothDeviceConfigListener.java b/services/core/java/com/android/server/BluetoothDeviceConfigListener.java
index 2dcf82f..611a37d 100644
--- a/services/core/java/com/android/server/BluetoothDeviceConfigListener.java
+++ b/services/core/java/com/android/server/BluetoothDeviceConfigListener.java
@@ -17,6 +17,9 @@
package com.android.server;
import android.provider.DeviceConfig;
+import android.util.Slog;
+
+import java.util.ArrayList;
/**
* The BluetoothDeviceConfigListener handles system device config change callback and checks
@@ -30,10 +33,12 @@
class BluetoothDeviceConfigListener {
private static final String TAG = "BluetoothDeviceConfigListener";
- BluetoothManagerService mService;
+ private final BluetoothManagerService mService;
+ private final boolean mLogDebug;
- BluetoothDeviceConfigListener(BluetoothManagerService service) {
+ BluetoothDeviceConfigListener(BluetoothManagerService service, boolean logDebug) {
mService = service;
+ mLogDebug = logDebug;
DeviceConfig.addOnPropertiesChangedListener(
DeviceConfig.NAMESPACE_BLUETOOTH,
(Runnable r) -> r.run(),
@@ -47,6 +52,13 @@
if (!properties.getNamespace().equals(DeviceConfig.NAMESPACE_BLUETOOTH)) {
return;
}
+ if (mLogDebug) {
+ ArrayList<String> flags = new ArrayList<>();
+ for (String name : properties.getKeyset()) {
+ flags.add(name + "='" + properties.getString(name, "") + "'");
+ }
+ Slog.d(TAG, "onPropertiesChanged: " + String.join(",", flags));
+ }
boolean foundInit = false;
for (String name : properties.getKeyset()) {
if (name.startsWith("INIT_")) {
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index aab0553..992ef26 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -453,6 +453,7 @@
if (mHandler.hasMessages(MESSAGE_INIT_FLAGS_CHANGED)
&& state == BluetoothProfile.STATE_DISCONNECTED
&& !mBluetoothModeChangeHelper.isA2dpOrHearingAidConnected()) {
+ Slog.i(TAG, "Device disconnected, reactivating pending flag changes");
onInitFlagsChanged();
}
}
@@ -810,6 +811,35 @@
return enabledProfiles;
}
+ private boolean isDeviceProvisioned() {
+ return Settings.Global.getInt(mContentResolver, Settings.Global.DEVICE_PROVISIONED,
+ 0) != 0;
+ }
+
+ // Monitor change of BLE scan only mode settings.
+ private void registerForProvisioningStateChange() {
+ ContentObserver contentObserver = new ContentObserver(null) {
+ @Override
+ public void onChange(boolean selfChange) {
+ if (!isDeviceProvisioned()) {
+ if (DBG) {
+ Slog.d(TAG, "DEVICE_PROVISIONED setting changed, but device is not "
+ + "provisioned");
+ }
+ return;
+ }
+ if (mHandler.hasMessages(MESSAGE_INIT_FLAGS_CHANGED)) {
+ Slog.i(TAG, "Device provisioned, reactivating pending flag changes");
+ onInitFlagsChanged();
+ }
+ }
+ };
+
+ mContentResolver.registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED), false,
+ contentObserver);
+ }
+
// Monitor change of BLE scan only mode settings.
private void registerForBleScanModeChange() {
ContentObserver contentObserver = new ContentObserver(null) {
@@ -1375,7 +1405,8 @@
if (mBluetoothAirplaneModeListener != null) {
mBluetoothAirplaneModeListener.start(mBluetoothModeChangeHelper);
}
- mBluetoothDeviceConfigListener = new BluetoothDeviceConfigListener(this);
+ registerForProvisioningStateChange();
+ mBluetoothDeviceConfigListener = new BluetoothDeviceConfigListener(this, DBG);
}
/**
@@ -2219,12 +2250,25 @@
}
mHandler.removeMessages(MESSAGE_INIT_FLAGS_CHANGED);
if (mBluetoothModeChangeHelper.isA2dpOrHearingAidConnected()) {
+ Slog.i(TAG, "Delaying MESSAGE_INIT_FLAGS_CHANGED by "
+ + DELAY_FOR_RETRY_INIT_FLAG_CHECK_MS
+ + " ms due to existing connections");
+ mHandler.sendEmptyMessageDelayed(
+ MESSAGE_INIT_FLAGS_CHANGED,
+ DELAY_FOR_RETRY_INIT_FLAG_CHECK_MS);
+ break;
+ }
+ if (!isDeviceProvisioned()) {
+ Slog.i(TAG, "Delaying MESSAGE_INIT_FLAGS_CHANGED by "
+ + DELAY_FOR_RETRY_INIT_FLAG_CHECK_MS
+ + "ms because device is not provisioned");
mHandler.sendEmptyMessageDelayed(
MESSAGE_INIT_FLAGS_CHANGED,
DELAY_FOR_RETRY_INIT_FLAG_CHECK_MS);
break;
}
if (mBluetooth != null && isEnabled()) {
+ Slog.i(TAG, "Restarting Bluetooth due to init flag change");
restartForReason(
BluetoothProtoEnums.ENABLE_DISABLE_REASON_INIT_FLAGS_CHANGED);
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 07b473c..0c42585 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -17,6 +17,10 @@
package com.android.server;
import static android.Manifest.permission.RECEIVE_DATA_ACTIVITY_CHANGE;
+import static android.content.pm.PackageManager.FEATURE_BLUETOOTH;
+import static android.content.pm.PackageManager.FEATURE_WATCH;
+import static android.content.pm.PackageManager.FEATURE_WIFI;
+import static android.content.pm.PackageManager.FEATURE_WIFI_DIRECT;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.KEY_NETWORK_PROBES_ATTEMPTED_BITMASK;
import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.KEY_NETWORK_PROBES_SUCCEEDED_BITMASK;
@@ -26,17 +30,35 @@
import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_DNS_CONSECUTIVE_TIMEOUTS;
import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS;
import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_TCP_PACKET_FAIL_RATE;
+import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_MASK;
+import static android.net.ConnectivityManager.BLOCKED_REASON_LOCKDOWN_VPN;
+import static android.net.ConnectivityManager.BLOCKED_REASON_NONE;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
+import static android.net.ConnectivityManager.TYPE_BLUETOOTH;
import static android.net.ConnectivityManager.TYPE_ETHERNET;
+import static android.net.ConnectivityManager.TYPE_MOBILE;
+import static android.net.ConnectivityManager.TYPE_MOBILE_CBS;
+import static android.net.ConnectivityManager.TYPE_MOBILE_DUN;
+import static android.net.ConnectivityManager.TYPE_MOBILE_EMERGENCY;
+import static android.net.ConnectivityManager.TYPE_MOBILE_FOTA;
+import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI;
+import static android.net.ConnectivityManager.TYPE_MOBILE_IA;
+import static android.net.ConnectivityManager.TYPE_MOBILE_IMS;
+import static android.net.ConnectivityManager.TYPE_MOBILE_MMS;
+import static android.net.ConnectivityManager.TYPE_MOBILE_SUPL;
import static android.net.ConnectivityManager.TYPE_NONE;
+import static android.net.ConnectivityManager.TYPE_PROXY;
import static android.net.ConnectivityManager.TYPE_VPN;
+import static android.net.ConnectivityManager.TYPE_WIFI;
+import static android.net.ConnectivityManager.TYPE_WIFI_P2P;
import static android.net.ConnectivityManager.getNetworkTypeName;
import static android.net.ConnectivityManager.isNetworkTypeValid;
import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_PRIVDNS;
import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_PARTIAL;
import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_VALID;
import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_ENTERPRISE;
import static android.net.NetworkCapabilities.NET_CAPABILITY_FOREGROUND;
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED;
@@ -50,11 +72,14 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE;
import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY;
import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
+import static android.net.NetworkCapabilities.REDACT_FOR_ACCESS_FINE_LOCATION;
+import static android.net.NetworkCapabilities.REDACT_FOR_LOCAL_MAC_ADDRESS;
+import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_TEST;
import static android.net.NetworkCapabilities.TRANSPORT_VPN;
-import static android.net.NetworkPolicyManager.RULE_NONE;
-import static android.net.NetworkPolicyManager.uidRulesToString;
+import static android.net.NetworkPolicyManager.blockedReasonsToString;
+import static android.net.NetworkRequest.Type.LISTEN_FOR_BEST;
import static android.net.shared.NetworkMonitorUtils.isPrivateDnsValidationRequired;
import static android.os.Process.INVALID_UID;
import static android.os.Process.VPN_UID;
@@ -85,6 +110,11 @@
import android.net.ConnectivityDiagnosticsManager.ConnectivityReport;
import android.net.ConnectivityDiagnosticsManager.DataStallReport;
import android.net.ConnectivityManager;
+import android.net.ConnectivityManager.BlockedReason;
+import android.net.ConnectivityManager.NetworkCallback;
+import android.net.ConnectivityManager.RestrictBackgroundStatus;
+import android.net.ConnectivityResources;
+import android.net.ConnectivitySettingsManager;
import android.net.DataStallReportParcelable;
import android.net.DnsResolverServiceManager;
import android.net.ICaptivePortal;
@@ -93,10 +123,10 @@
import android.net.IDnsResolver;
import android.net.INetd;
import android.net.INetworkActivityListener;
+import android.net.INetworkAgent;
import android.net.INetworkMonitor;
import android.net.INetworkMonitorCallbacks;
-import android.net.INetworkPolicyListener;
-import android.net.IOnSetOemNetworkPreferenceListener;
+import android.net.IOnCompleteListener;
import android.net.IQosCallback;
import android.net.ISocketKeepaliveCallback;
import android.net.InetAddresses;
@@ -109,13 +139,14 @@
import android.net.NetworkAgent;
import android.net.NetworkAgentConfig;
import android.net.NetworkCapabilities;
-import android.net.NetworkConfig;
import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
import android.net.NetworkMonitorManager;
import android.net.NetworkPolicyManager;
+import android.net.NetworkPolicyManager.NetworkPolicyCallback;
import android.net.NetworkProvider;
import android.net.NetworkRequest;
+import android.net.NetworkScore;
import android.net.NetworkSpecifier;
import android.net.NetworkStack;
import android.net.NetworkStackClient;
@@ -175,6 +206,7 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
+import android.sysprop.NetworkProperties;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.ArrayMap;
@@ -185,23 +217,18 @@
import android.util.SparseArray;
import android.util.SparseIntArray;
-import com.android.connectivity.aidl.INetworkAgent;
-import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.app.IBatteryStats;
-import com.android.internal.util.AsyncChannel;
import com.android.internal.util.IndentingPrintWriter;
-import com.android.internal.util.LocationPermissionChecker;
import com.android.internal.util.MessageUtils;
import com.android.modules.utils.BasicShellCommandHandler;
import com.android.net.module.util.BaseNetdUnsolicitedEventListener;
import com.android.net.module.util.CollectionUtils;
import com.android.net.module.util.LinkPropertiesUtils.CompareOrUpdateResult;
import com.android.net.module.util.LinkPropertiesUtils.CompareResult;
+import com.android.net.module.util.LocationPermissionChecker;
import com.android.net.module.util.NetworkCapabilitiesUtils;
import com.android.net.module.util.PermissionUtils;
-import com.android.server.am.BatteryStatsService;
import com.android.server.connectivity.AutodestructReference;
import com.android.server.connectivity.DnsManager;
import com.android.server.connectivity.DnsManager.PrivateDnsValidationUpdate;
@@ -214,10 +241,9 @@
import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
import com.android.server.connectivity.NetworkRanker;
import com.android.server.connectivity.PermissionMonitor;
+import com.android.server.connectivity.ProfileNetworkPreferences;
import com.android.server.connectivity.ProxyTracker;
import com.android.server.connectivity.QosCallbackTracker;
-import com.android.server.net.NetworkPolicyManagerInternal;
-import com.android.server.utils.PriorityDump;
import libcore.io.IoUtils;
@@ -265,7 +291,7 @@
/**
* Default URL to use for {@link #getCaptivePortalServerUrl()}. This should not be changed
* by OEMs for configuration purposes, as this value is overridden by
- * Settings.Global.CAPTIVE_PORTAL_HTTP_URL.
+ * ConnectivitySettingsManager.CAPTIVE_PORTAL_HTTP_URL.
* R.string.config_networkCaptivePortalServerUrl should be overridden instead for this purpose
* (preferably via runtime resource overlays).
*/
@@ -298,7 +324,7 @@
protected int mNascentDelayMs;
// How long to delay to removal of a pending intent based request.
- // See Settings.Secure.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS
+ // See ConnectivitySettingsManager.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS
private final int mReleasePendingIntentDelayMs;
private MockableSystemProperties mSystemProperties;
@@ -311,14 +337,13 @@
private volatile boolean mLockdownEnabled;
/**
- * Stale copy of uid rules provided by NPMS. As long as they are accessed only in internal
- * handler thread, they don't need a lock.
+ * Stale copy of uid blocked reasons provided by NPMS. As long as they are accessed only in
+ * internal handler thread, they don't need a lock.
*/
- private SparseIntArray mUidRules = new SparseIntArray();
- /** Flag indicating if background data is restricted. */
- private boolean mRestrictBackground;
+ private SparseIntArray mUidBlockedReasons = new SparseIntArray();
private final Context mContext;
+ private final ConnectivityResources mResources;
// The Context is created for UserHandle.ALL.
private final Context mUserAllContext;
private final Dependencies mDeps;
@@ -331,7 +356,6 @@
protected INetd mNetd;
private NetworkStatsManager mStatsManager;
private NetworkPolicyManager mPolicyManager;
- private NetworkPolicyManagerInternal mPolicyManagerInternal;
private final NetdCallback mNetdCallback;
/**
@@ -346,8 +370,7 @@
private String mCurrentTcpBufferSizes;
private static final SparseArray<String> sMagicDecoderRing = MessageUtils.findMessageNames(
- new Class[] { AsyncChannel.class, ConnectivityService.class, NetworkAgent.class,
- NetworkAgentInfo.class });
+ new Class[] { ConnectivityService.class, NetworkAgent.class, NetworkAgentInfo.class });
private enum ReapUnvalidatedNetworks {
// Tear down networks that have no chance (e.g. even if validated) of becoming
@@ -490,16 +513,6 @@
// Handle private DNS validation status updates.
private static final int EVENT_PRIVATE_DNS_VALIDATION_UPDATE = 38;
- /**
- * Used to handle onUidRulesChanged event from NetworkPolicyManagerService.
- */
- private static final int EVENT_UID_RULES_CHANGED = 39;
-
- /**
- * Used to handle onRestrictBackgroundChanged event from NetworkPolicyManagerService.
- */
- private static final int EVENT_DATA_SAVER_CHANGED = 40;
-
/**
* Event for NetworkMonitor/NetworkAgentInfo to inform ConnectivityService that the network has
* been tested.
@@ -559,8 +572,8 @@
private static final int EVENT_SET_REQUIRE_VPN_FOR_UIDS = 47;
/**
- * used internally when setting the default networks for OemNetworkPreferences.
- * obj = OemNetworkPreferences
+ * Used internally when setting the default networks for OemNetworkPreferences.
+ * obj = Pair<OemNetworkPreferences, listener>
*/
private static final int EVENT_SET_OEM_NETWORK_PREFERENCE = 48;
@@ -570,6 +583,19 @@
private static final int EVENT_REPORT_NETWORK_ACTIVITY = 49;
/**
+ * Used internally when setting a network preference for a user profile.
+ * obj = Pair<ProfileNetworkPreference, Listener>
+ */
+ private static final int EVENT_SET_PROFILE_NETWORK_PREFERENCE = 50;
+
+ /**
+ * Event to specify that reasons for why an uid is blocked changed.
+ * arg1 = uid
+ * arg2 = blockedReasons
+ */
+ private static final int EVENT_UID_BLOCKED_REASON_CHANGED = 51;
+
+ /**
* Argument for {@link #EVENT_PROVISIONING_NOTIFICATION} to indicate that the notification
* should be shown.
*/
@@ -607,7 +633,6 @@
private Intent mInitialBroadcast;
private PowerManager.WakeLock mNetTransitionWakeLock;
- private int mNetTransitionWakeLockTimeout;
private final PowerManager.WakeLock mPendingIntentWakeLock;
// A helper object to track the current default HTTP proxy. ConnectivityService needs to tell
@@ -619,11 +644,8 @@
private UserManager mUserManager;
- private NetworkConfig[] mNetConfigs;
- private int mNetworksDefined;
-
// the set of network types that can only be enabled by system/sig apps
- private List mProtectedNetworks;
+ private List<Integer> mProtectedNetworks;
private Set<String> mWolSupportedInterfaces;
@@ -713,18 +735,63 @@
* They are therefore not thread-safe with respect to each other.
* - getNetworkForType() can be called at any time on binder threads. It is synchronized
* on mTypeLists to be thread-safe with respect to a concurrent remove call.
+ * - getRestoreTimerForType(type) is also synchronized on mTypeLists.
* - dump is thread-safe with respect to concurrent add and remove calls.
*/
private final ArrayList<NetworkAgentInfo> mTypeLists[];
@NonNull
private final ConnectivityService mService;
+ // Restore timers for requestNetworkForFeature (network type -> timer in ms). Types without
+ // an entry have no timer (equivalent to -1). Lazily loaded.
+ @NonNull
+ private ArrayMap<Integer, Integer> mRestoreTimers = new ArrayMap<>();
+
LegacyTypeTracker(@NonNull ConnectivityService service) {
mService = service;
mTypeLists = new ArrayList[ConnectivityManager.MAX_NETWORK_TYPE + 1];
}
- public void addSupportedType(int type) {
+ public void loadSupportedTypes(@NonNull Context ctx, @NonNull TelephonyManager tm) {
+ final PackageManager pm = ctx.getPackageManager();
+ if (pm.hasSystemFeature(FEATURE_WIFI)) {
+ addSupportedType(TYPE_WIFI);
+ }
+ if (pm.hasSystemFeature(FEATURE_WIFI_DIRECT)) {
+ addSupportedType(TYPE_WIFI_P2P);
+ }
+ if (tm.isDataCapable()) {
+ // Telephony does not have granular support for these types: they are either all
+ // supported, or none is supported
+ addSupportedType(TYPE_MOBILE);
+ addSupportedType(TYPE_MOBILE_MMS);
+ addSupportedType(TYPE_MOBILE_SUPL);
+ addSupportedType(TYPE_MOBILE_DUN);
+ addSupportedType(TYPE_MOBILE_HIPRI);
+ addSupportedType(TYPE_MOBILE_FOTA);
+ addSupportedType(TYPE_MOBILE_IMS);
+ addSupportedType(TYPE_MOBILE_CBS);
+ addSupportedType(TYPE_MOBILE_IA);
+ addSupportedType(TYPE_MOBILE_EMERGENCY);
+ }
+ if (pm.hasSystemFeature(FEATURE_BLUETOOTH)) {
+ addSupportedType(TYPE_BLUETOOTH);
+ }
+ if (pm.hasSystemFeature(FEATURE_WATCH)) {
+ // TYPE_PROXY is only used on Wear
+ addSupportedType(TYPE_PROXY);
+ }
+ // Ethernet is often not specified in the configs, although many devices can use it via
+ // USB host adapters. Add it as long as the ethernet service is here.
+ if (ctx.getSystemService(Context.ETHERNET_SERVICE) != null) {
+ addSupportedType(TYPE_ETHERNET);
+ }
+
+ // Always add TYPE_VPN as a supported type
+ addSupportedType(TYPE_VPN);
+ }
+
+ private void addSupportedType(int type) {
if (mTypeLists[type] != null) {
throw new IllegalStateException(
"legacy list for type " + type + "already initialized");
@@ -745,6 +812,35 @@
return null;
}
+ public int getRestoreTimerForType(int type) {
+ synchronized (mTypeLists) {
+ if (mRestoreTimers == null) {
+ mRestoreTimers = loadRestoreTimers();
+ }
+ return mRestoreTimers.getOrDefault(type, -1);
+ }
+ }
+
+ private ArrayMap<Integer, Integer> loadRestoreTimers() {
+ final String[] configs = mService.mResources.get().getStringArray(
+ com.android.connectivity.resources.R.array
+ .config_legacy_networktype_restore_timers);
+ final ArrayMap<Integer, Integer> ret = new ArrayMap<>(configs.length);
+ for (final String config : configs) {
+ final String[] splits = TextUtils.split(config, ",");
+ if (splits.length != 2) {
+ logwtf("Invalid restore timer token count: " + config);
+ continue;
+ }
+ try {
+ ret.put(Integer.parseInt(splits[0]), Integer.parseInt(splits[1]));
+ } catch (NumberFormatException e) {
+ logwtf("Invalid restore timer number format: " + config, e);
+ }
+ }
+ return ret;
+ }
+
private void maybeLogBroadcast(NetworkAgentInfo nai, DetailedState state, int type,
boolean isDefaultNetwork) {
if (DBG) {
@@ -884,27 +980,59 @@
}
private final LegacyTypeTracker mLegacyTypeTracker = new LegacyTypeTracker(this);
+ final LocalPriorityDump mPriorityDumper = new LocalPriorityDump();
/**
* Helper class which parses out priority arguments and dumps sections according to their
* priority. If priority arguments are omitted, function calls the legacy dump command.
*/
- private final PriorityDump.PriorityDumper mPriorityDumper = new PriorityDump.PriorityDumper() {
- @Override
- public void dumpHigh(FileDescriptor fd, PrintWriter pw, String[] args, boolean asProto) {
- doDump(fd, pw, new String[] {DIAG_ARG}, asProto);
- doDump(fd, pw, new String[] {SHORT_ARG}, asProto);
+ private class LocalPriorityDump {
+ private static final String PRIORITY_ARG = "--dump-priority";
+ private static final String PRIORITY_ARG_HIGH = "HIGH";
+ private static final String PRIORITY_ARG_NORMAL = "NORMAL";
+
+ LocalPriorityDump() {}
+
+ private void dumpHigh(FileDescriptor fd, PrintWriter pw) {
+ doDump(fd, pw, new String[] {DIAG_ARG});
+ doDump(fd, pw, new String[] {SHORT_ARG});
}
- @Override
- public void dumpNormal(FileDescriptor fd, PrintWriter pw, String[] args, boolean asProto) {
- doDump(fd, pw, args, asProto);
+ private void dumpNormal(FileDescriptor fd, PrintWriter pw, String[] args) {
+ doDump(fd, pw, args);
}
- @Override
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args, boolean asProto) {
- doDump(fd, pw, args, asProto);
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (args == null) {
+ dumpNormal(fd, pw, args);
+ return;
+ }
+
+ String priority = null;
+ for (int argIndex = 0; argIndex < args.length; argIndex++) {
+ if (args[argIndex].equals(PRIORITY_ARG) && argIndex + 1 < args.length) {
+ argIndex++;
+ priority = args[argIndex];
+ }
+ }
+
+ if (PRIORITY_ARG_HIGH.equals(priority)) {
+ dumpHigh(fd, pw);
+ } else if (PRIORITY_ARG_NORMAL.equals(priority)) {
+ dumpNormal(fd, pw, args);
+ } else {
+ // ConnectivityService publishes binder service using publishBinderService() with
+ // no priority assigned will be treated as NORMAL priority. Dumpsys does not send
+ // "--dump-priority" arguments to the service. Thus, dump both NORMAL and HIGH to
+ // align the legacy design.
+ // TODO: Integrate into signal dump.
+ dumpNormal(fd, pw, args);
+ pw.println();
+ pw.println("DUMP OF SERVICE HIGH connectivity");
+ pw.println();
+ dumpHigh(fd, pw);
+ }
}
- };
+ }
/**
* Keeps track of the number of requests made under different uids.
@@ -983,6 +1111,13 @@
}
/**
+ * Get the {@link ConnectivityResources} to use in ConnectivityService.
+ */
+ public ConnectivityResources getResources(@NonNull Context ctx) {
+ return new ConnectivityResources(ctx);
+ }
+
+ /**
* Create a HandlerThread to use in ConnectivityService.
*/
public HandlerThread makeHandlerThread() {
@@ -1014,8 +1149,8 @@
/**
* @see NetworkUtils#queryUserAccess(int, int)
*/
- public boolean queryUserAccess(int uid, int netId) {
- return NetworkUtils.queryUserAccess(uid, netId);
+ public boolean queryUserAccess(int uid, Network network, ConnectivityService cs) {
+ return cs.queryUserAccess(uid, network);
}
/**
@@ -1035,19 +1170,19 @@
return new MultinetworkPolicyTracker(c, h, r);
}
- public IBatteryStats getBatteryStatsService() {
- return BatteryStatsService.getService();
- }
-
/**
* @see BatteryStatsManager
*/
public void reportNetworkInterfaceForTransports(Context context, String iface,
int[] transportTypes) {
- final BatteryStatsManager batteryStats =
+ final BatteryStatsManager batteryStats =
context.getSystemService(BatteryStatsManager.class);
batteryStats.reportNetworkInterfaceForTransports(iface, transportTypes);
}
+
+ public boolean getCellular464XlatEnabled() {
+ return NetworkProperties.isCellular464XlatEnabled().orElse(true);
+ }
}
public ConnectivityService(Context context) {
@@ -1064,13 +1199,15 @@
mSystemProperties = mDeps.getSystemProperties();
mNetIdManager = mDeps.makeNetIdManager();
mContext = Objects.requireNonNull(context, "missing Context");
+ mResources = deps.getResources(mContext);
mNetworkRequestCounter = new PerUidCounter(MAX_NETWORK_REQUESTS_PER_UID);
mMetricsLog = logger;
mNetworkRanker = new NetworkRanker();
final NetworkRequest defaultInternetRequest = createDefaultRequest();
mDefaultRequest = new NetworkRequestInfo(
- defaultInternetRequest, null, new Binder(),
+ Process.myUid(), defaultInternetRequest, null,
+ new Binder(), NetworkCallback.FLAG_INCLUDE_LOCATION_INFO,
null /* attributionTags */);
mNetworkRequests.put(defaultInternetRequest, mDefaultRequest);
mDefaultNetworkRequests.add(mDefaultRequest);
@@ -1097,7 +1234,7 @@
new ConnectivityDiagnosticsHandler(mHandlerThread.getLooper());
mReleasePendingIntentDelayMs = Settings.Secure.getInt(context.getContentResolver(),
- Settings.Secure.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS, 5_000);
+ ConnectivitySettingsManager.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS, 5_000);
mLingerDelayMs = mSystemProperties.getInt(LINGER_DELAY_PROPERTY, DEFAULT_LINGER_DELAY_MS);
// TODO: Consider making the timer customizable.
@@ -1105,9 +1242,6 @@
mStatsManager = mContext.getSystemService(NetworkStatsManager.class);
mPolicyManager = mContext.getSystemService(NetworkPolicyManager.class);
- mPolicyManagerInternal = Objects.requireNonNull(
- LocalServices.getService(NetworkPolicyManagerInternal.class),
- "missing NetworkPolicyManagerInternal");
mDnsResolver = Objects.requireNonNull(dnsresolver, "missing IDnsResolver");
mProxyTracker = mDeps.makeProxyTracker(mContext, mHandler);
@@ -1116,86 +1250,28 @@
mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
mLocationPermissionChecker = new LocationPermissionChecker(mContext);
- // To ensure uid rules are synchronized with Network Policy, register for
+ // To ensure uid state is synchronized with Network Policy, register for
// NetworkPolicyManagerService events must happen prior to NetworkPolicyManagerService
// reading existing policy from disk.
- mPolicyManager.registerListener(mPolicyListener);
+ mPolicyManager.registerNetworkPolicyCallback(null, mPolicyCallback);
final PowerManager powerManager = (PowerManager) context.getSystemService(
Context.POWER_SERVICE);
mNetTransitionWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
- mNetTransitionWakeLockTimeout = mContext.getResources().getInteger(
- com.android.internal.R.integer.config_networkTransitionTimeout);
mPendingIntentWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
- mNetConfigs = new NetworkConfig[ConnectivityManager.MAX_NETWORK_TYPE+1];
-
- // TODO: What is the "correct" way to do determine if this is a wifi only device?
- boolean wifiOnly = mSystemProperties.getBoolean("ro.radio.noril", false);
- log("wifiOnly=" + wifiOnly);
- String[] naStrings = context.getResources().getStringArray(
- com.android.internal.R.array.networkAttributes);
- for (String naString : naStrings) {
- try {
- NetworkConfig n = new NetworkConfig(naString);
- if (VDBG) log("naString=" + naString + " config=" + n);
- if (n.type > ConnectivityManager.MAX_NETWORK_TYPE) {
- loge("Error in networkAttributes - ignoring attempt to define type " +
- n.type);
- continue;
- }
- if (wifiOnly && ConnectivityManager.isNetworkTypeMobile(n.type)) {
- log("networkAttributes - ignoring mobile as this dev is wifiOnly " +
- n.type);
- continue;
- }
- if (mNetConfigs[n.type] != null) {
- loge("Error in networkAttributes - ignoring attempt to redefine type " +
- n.type);
- continue;
- }
- mLegacyTypeTracker.addSupportedType(n.type);
-
- mNetConfigs[n.type] = n;
- mNetworksDefined++;
- } catch(Exception e) {
- // ignore it - leave the entry null
- }
- }
-
- // Forcibly add TYPE_VPN as a supported type, if it has not already been added via config.
- if (mNetConfigs[TYPE_VPN] == null) {
- // mNetConfigs is used only for "restore time", which isn't applicable to VPNs, so we
- // don't need to add TYPE_VPN to mNetConfigs.
- mLegacyTypeTracker.addSupportedType(TYPE_VPN);
- mNetworksDefined++; // used only in the log() statement below.
- }
-
- // Do the same for Ethernet, since it's often not specified in the configs, although many
- // devices can use it via USB host adapters.
- if (mNetConfigs[TYPE_ETHERNET] == null
- && mContext.getSystemService(Context.ETHERNET_SERVICE) != null) {
- mLegacyTypeTracker.addSupportedType(TYPE_ETHERNET);
- mNetworksDefined++;
- }
-
- if (VDBG) log("mNetworksDefined=" + mNetworksDefined);
-
- mProtectedNetworks = new ArrayList<Integer>();
+ mLegacyTypeTracker.loadSupportedTypes(mContext, mTelephonyManager);
+ mProtectedNetworks = new ArrayList<>();
int[] protectedNetworks = context.getResources().getIntArray(
com.android.internal.R.array.config_protectedNetworks);
for (int p : protectedNetworks) {
- if ((mNetConfigs[p] != null) && (mProtectedNetworks.contains(p) == false)) {
+ if (mLegacyTypeTracker.isTypeSupported(p) && !mProtectedNetworks.contains(p)) {
mProtectedNetworks.add(p);
} else {
if (DBG) loge("Ignoring protectedNetwork " + p);
}
}
- mWolSupportedInterfaces = new ArraySet(
- mContext.getResources().getStringArray(
- com.android.internal.R.array.config_wakeonlan_supported_interfaces));
-
mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
mPermissionMonitor = new PermissionMonitor(mContext, mNetd);
@@ -1227,10 +1303,10 @@
mQosCallbackTracker = new QosCallbackTracker(mHandler, mNetworkRequestCounter);
final int dailyLimit = Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT,
+ ConnectivitySettingsManager.NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT,
LingerMonitor.DEFAULT_NOTIFICATION_DAILY_LIMIT);
final long rateLimit = Settings.Global.getLong(mContext.getContentResolver(),
- Settings.Global.NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS,
+ ConnectivitySettingsManager.NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS,
LingerMonitor.DEFAULT_NOTIFICATION_RATE_LIMIT_MILLIS);
mLingerMonitor = new LingerMonitor(mContext, mNotifier, dailyLimit, rateLimit);
@@ -1241,21 +1317,31 @@
mDnsManager = new DnsManager(mContext, mDnsResolver);
registerPrivateDnsSettingsCallbacks();
+ // This NAI is a sentinel used to offer no service to apps that are on a multi-layer
+ // request that doesn't allow fallback to the default network. It should never be visible
+ // to apps. As such, it's not in the list of NAIs and doesn't need many of the normal
+ // arguments like the handler or the DnsResolver.
+ // TODO : remove this ; it is probably better handled with a sentinel request.
mNoServiceNetwork = new NetworkAgentInfo(null,
new Network(NO_SERVICE_NET_ID),
new NetworkInfo(TYPE_NONE, 0, "", ""),
- new LinkProperties(), new NetworkCapabilities(), 0, mContext,
- null, new NetworkAgentConfig(), this, null,
- null, 0, INVALID_UID,
- mQosCallbackTracker);
+ new LinkProperties(), new NetworkCapabilities(),
+ new NetworkScore.Builder().setLegacyInt(0).build(), mContext, null,
+ new NetworkAgentConfig(), this, null, null, 0, INVALID_UID, mQosCallbackTracker,
+ mDeps);
}
private static NetworkCapabilities createDefaultNetworkCapabilitiesForUid(int uid) {
+ return createDefaultNetworkCapabilitiesForUidRange(new UidRange(uid, uid));
+ }
+
+ private static NetworkCapabilities createDefaultNetworkCapabilitiesForUidRange(
+ @NonNull final UidRange uids) {
final NetworkCapabilities netCap = new NetworkCapabilities();
netCap.addCapability(NET_CAPABILITY_INTERNET);
netCap.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
netCap.removeCapability(NET_CAPABILITY_NOT_VPN);
- netCap.setSingleUid(uid);
+ netCap.setUids(UidRange.toIntRanges(Collections.singleton(uids)));
return netCap;
}
@@ -1327,7 +1413,8 @@
if (enable) {
handleRegisterNetworkRequest(new NetworkRequestInfo(
- networkRequest, null, new Binder(),
+ Process.myUid(), networkRequest, null, new Binder(),
+ NetworkCallback.FLAG_INCLUDE_LOCATION_INFO,
null /* attributionTags */));
} else {
handleReleaseNetworkRequest(networkRequest, Process.SYSTEM_UID,
@@ -1336,10 +1423,10 @@
}
private void handleConfigureAlwaysOnNetworks() {
- handleAlwaysOnNetworkRequest(
- mDefaultMobileDataRequest, Settings.Global.MOBILE_DATA_ALWAYS_ON, true);
- handleAlwaysOnNetworkRequest(mDefaultWifiRequest, Settings.Global.WIFI_ALWAYS_REQUESTED,
- false);
+ handleAlwaysOnNetworkRequest(mDefaultMobileDataRequest,
+ ConnectivitySettingsManager.MOBILE_DATA_ALWAYS_ON, true /* defaultValue */);
+ handleAlwaysOnNetworkRequest(mDefaultWifiRequest,
+ ConnectivitySettingsManager.WIFI_ALWAYS_REQUESTED, false /* defaultValue */);
handleAlwaysOnNetworkRequest(mDefaultVehicleRequest,
com.android.internal.R.bool.config_vehicleInternalNetworkAlwaysRequested);
}
@@ -1352,12 +1439,12 @@
// Watch for whether or not to keep mobile data always on.
mSettingsObserver.observe(
- Settings.Global.getUriFor(Settings.Global.MOBILE_DATA_ALWAYS_ON),
+ Settings.Global.getUriFor(ConnectivitySettingsManager.MOBILE_DATA_ALWAYS_ON),
EVENT_CONFIGURE_ALWAYS_ON_NETWORKS);
// Watch for whether or not to keep wifi always on.
mSettingsObserver.observe(
- Settings.Global.getUriFor(Settings.Global.WIFI_ALWAYS_REQUESTED),
+ Settings.Global.getUriFor(ConnectivitySettingsManager.WIFI_ALWAYS_REQUESTED),
EVENT_CONFIGURE_ALWAYS_ON_NETWORKS);
}
@@ -1473,7 +1560,7 @@
final int requestId = nri.getActiveRequest() != null
? nri.getActiveRequest().requestId : nri.mRequests.get(0).requestId;
mNetworkInfoBlockingLogs.log(String.format(
- "%s %d(%d) on netId %d", action, nri.mUid, requestId, net.getNetId()));
+ "%s %d(%d) on netId %d", action, nri.mAsUid, requestId, net.getNetId()));
}
/**
@@ -1489,11 +1576,11 @@
// but only exists if an app asks about them or requests them. Ensure the requesting app
// gets the type it asks for.
filtered.setType(type);
- final DetailedState state = isNetworkWithCapabilitiesBlocked(nc, uid, ignoreBlocked)
- ? DetailedState.BLOCKED
- : filtered.getDetailedState();
- filtered.setDetailedState(getLegacyLockdownState(state),
- "" /* reason */, null /* extraInfo */);
+ if (isNetworkWithCapabilitiesBlocked(nc, uid, ignoreBlocked)) {
+ filtered.setDetailedState(DetailedState.BLOCKED, null /* reason */,
+ null /* extraInfo */);
+ }
+ filterForLegacyLockdown(filtered);
return filtered;
}
@@ -1569,8 +1656,8 @@
final DetailedState state = isNetworkWithCapabilitiesBlocked(nc, uid, false)
? DetailedState.BLOCKED
: DetailedState.DISCONNECTED;
- info.setDetailedState(getLegacyLockdownState(state),
- "" /* reason */, null /* extraInfo */);
+ info.setDetailedState(state, null /* reason */, null /* extraInfo */);
+ filterForLegacyLockdown(info);
return info;
}
@@ -1688,13 +1775,14 @@
result.put(
nai.network,
createWithLocationInfoSanitizedIfNecessaryWhenParceled(
- nc, mDeps.getCallingUid(), callingPackageName,
+ nc, false /* includeLocationSensitiveInfo */,
+ getCallingPid(), mDeps.getCallingUid(), callingPackageName,
callingAttributionTag));
}
}
// No need to check mLockdownEnabled. If it's true, getVpnUnderlyingNetworks returns null.
- final Network[] networks = getVpnUnderlyingNetworks(Binder.getCallingUid());
+ final Network[] networks = getVpnUnderlyingNetworks(mDeps.getCallingUid());
if (null != networks) {
for (final Network network : networks) {
final NetworkCapabilities nc = getNetworkCapabilitiesInternal(network);
@@ -1702,7 +1790,9 @@
result.put(
network,
createWithLocationInfoSanitizedIfNecessaryWhenParceled(
- nc, mDeps.getCallingUid(), callingPackageName,
+ nc,
+ false /* includeLocationSensitiveInfo */,
+ getCallingPid(), mDeps.getCallingUid(), callingPackageName,
callingAttributionTag));
}
}
@@ -1784,7 +1874,8 @@
enforceAccessPermission();
return createWithLocationInfoSanitizedIfNecessaryWhenParceled(
getNetworkCapabilitiesInternal(network),
- mDeps.getCallingUid(), callingPackageName, callingAttributionTag);
+ false /* includeLocationSensitiveInfo */,
+ getCallingPid(), mDeps.getCallingUid(), callingPackageName, callingAttributionTag);
}
@VisibleForTesting
@@ -1803,38 +1894,137 @@
return newNc;
}
- private boolean hasLocationPermission(int callerUid, @NonNull String callerPkgName,
- @Nullable String callingAttributionTag) {
- final long token = Binder.clearCallingIdentity();
- try {
- return mLocationPermissionChecker.checkLocationPermission(
- callerPkgName, callingAttributionTag, callerUid, null /* message */);
- } finally {
- Binder.restoreCallingIdentity(token);
+ /**
+ * Wrapper used to cache the permission check results performed for the corresponding
+ * app. This avoid performing multiple permission checks for different fields in
+ * NetworkCapabilities.
+ * Note: This wrapper does not support any sort of invalidation and thus must not be
+ * persistent or long-lived. It may only be used for the time necessary to
+ * compute the redactions required by one particular NetworkCallback or
+ * synchronous call.
+ */
+ private class RedactionPermissionChecker {
+ private final int mCallingPid;
+ private final int mCallingUid;
+ @NonNull private final String mCallingPackageName;
+ @Nullable private final String mCallingAttributionTag;
+
+ private Boolean mHasLocationPermission = null;
+ private Boolean mHasLocalMacAddressPermission = null;
+ private Boolean mHasSettingsPermission = null;
+
+ RedactionPermissionChecker(int callingPid, int callingUid,
+ @NonNull String callingPackageName, @Nullable String callingAttributionTag) {
+ mCallingPid = callingPid;
+ mCallingUid = callingUid;
+ mCallingPackageName = callingPackageName;
+ mCallingAttributionTag = callingAttributionTag;
}
+
+ private boolean hasLocationPermissionInternal() {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ return mLocationPermissionChecker.checkLocationPermission(
+ mCallingPackageName, mCallingAttributionTag, mCallingUid,
+ null /* message */);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ /**
+ * Returns whether the app holds location permission or not (might return cached result
+ * if the permission was already checked before).
+ */
+ public boolean hasLocationPermission() {
+ if (mHasLocationPermission == null) {
+ // If there is no cached result, perform the check now.
+ mHasLocationPermission = hasLocationPermissionInternal();
+ }
+ return mHasLocationPermission;
+ }
+
+ /**
+ * Returns whether the app holds local mac address permission or not (might return cached
+ * result if the permission was already checked before).
+ */
+ public boolean hasLocalMacAddressPermission() {
+ if (mHasLocalMacAddressPermission == null) {
+ // If there is no cached result, perform the check now.
+ mHasLocalMacAddressPermission =
+ checkLocalMacAddressPermission(mCallingPid, mCallingUid);
+ }
+ return mHasLocalMacAddressPermission;
+ }
+
+ /**
+ * Returns whether the app holds settings permission or not (might return cached
+ * result if the permission was already checked before).
+ */
+ public boolean hasSettingsPermission() {
+ if (mHasSettingsPermission == null) {
+ // If there is no cached result, perform the check now.
+ mHasSettingsPermission = checkSettingsPermission(mCallingPid, mCallingUid);
+ }
+ return mHasSettingsPermission;
+ }
+ }
+
+ private static boolean shouldRedact(@NetworkCapabilities.RedactionType long redactions,
+ @NetworkCapabilities.NetCapability long redaction) {
+ return (redactions & redaction) != 0;
+ }
+
+ /**
+ * Use the provided |applicableRedactions| to check the receiving app's
+ * permissions and clear/set the corresponding bit in the returned bitmask. The bitmask
+ * returned will be used to ensure the necessary redactions are performed by NetworkCapabilities
+ * before being sent to the corresponding app.
+ */
+ private @NetworkCapabilities.RedactionType long retrieveRequiredRedactions(
+ @NetworkCapabilities.RedactionType long applicableRedactions,
+ @NonNull RedactionPermissionChecker redactionPermissionChecker,
+ boolean includeLocationSensitiveInfo) {
+ long redactions = applicableRedactions;
+ if (shouldRedact(redactions, REDACT_FOR_ACCESS_FINE_LOCATION)) {
+ if (includeLocationSensitiveInfo
+ && redactionPermissionChecker.hasLocationPermission()) {
+ redactions &= ~REDACT_FOR_ACCESS_FINE_LOCATION;
+ }
+ }
+ if (shouldRedact(redactions, REDACT_FOR_LOCAL_MAC_ADDRESS)) {
+ if (redactionPermissionChecker.hasLocalMacAddressPermission()) {
+ redactions &= ~REDACT_FOR_LOCAL_MAC_ADDRESS;
+ }
+ }
+ if (shouldRedact(redactions, REDACT_FOR_NETWORK_SETTINGS)) {
+ if (redactionPermissionChecker.hasSettingsPermission()) {
+ redactions &= ~REDACT_FOR_NETWORK_SETTINGS;
+ }
+ }
+ return redactions;
}
@VisibleForTesting
@Nullable
NetworkCapabilities createWithLocationInfoSanitizedIfNecessaryWhenParceled(
- @Nullable NetworkCapabilities nc, int callerUid, @NonNull String callerPkgName,
+ @Nullable NetworkCapabilities nc, boolean includeLocationSensitiveInfo,
+ int callingPid, int callingUid, @NonNull String callingPkgName,
@Nullable String callingAttributionTag) {
if (nc == null) {
return null;
}
- Boolean hasLocationPermission = null;
- final NetworkCapabilities newNc;
// Avoid doing location permission check if the transport info has no location sensitive
// data.
- if (nc.getTransportInfo() != null && nc.getTransportInfo().hasLocationSensitiveFields()) {
- hasLocationPermission =
- hasLocationPermission(callerUid, callerPkgName, callingAttributionTag);
- newNc = new NetworkCapabilities(nc, hasLocationPermission);
- } else {
- newNc = new NetworkCapabilities(nc, false /* parcelLocationSensitiveFields */);
- }
+ final RedactionPermissionChecker redactionPermissionChecker =
+ new RedactionPermissionChecker(callingPid, callingUid, callingPkgName,
+ callingAttributionTag);
+ final long redactions = retrieveRequiredRedactions(
+ nc.getApplicableRedactions(), redactionPermissionChecker,
+ includeLocationSensitiveInfo);
+ final NetworkCapabilities newNc = new NetworkCapabilities(nc, redactions);
// Reset owner uid if not destined for the owner app.
- if (callerUid != nc.getOwnerUid()) {
+ if (callingUid != nc.getOwnerUid()) {
newNc.setOwnerUid(INVALID_UID);
return newNc;
}
@@ -1843,13 +2033,17 @@
// Owner UIDs already checked above. No need to re-check.
return newNc;
}
- if (hasLocationPermission == null) {
- // Location permission not checked yet, check now for masking owner UID.
- hasLocationPermission =
- hasLocationPermission(callerUid, callerPkgName, callingAttributionTag);
+ // If the calling does not want location sensitive data & target SDK >= S, then mask info.
+ // Else include the owner UID iff the calling has location permission to provide backwards
+ // compatibility for older apps.
+ if (!includeLocationSensitiveInfo
+ && isTargetSdkAtleast(
+ Build.VERSION_CODES.S, callingUid, callingPkgName)) {
+ newNc.setOwnerUid(INVALID_UID);
+ return newNc;
}
// Reset owner uid if the app has no location permission.
- if (!hasLocationPermission) {
+ if (!redactionPermissionChecker.hasLocationPermission()) {
newNc.setOwnerUid(INVALID_UID);
}
return newNc;
@@ -1881,6 +2075,8 @@
private void restrictRequestUidsForCallerAndSetRequestorInfo(NetworkCapabilities nc,
int callerUid, String callerPackageName) {
if (!checkSettingsPermission()) {
+ // There is no need to track the effective UID of the request here. If the caller lacks
+ // the settings permission, the effective UID is the same as the calling ID.
nc.setSingleUid(callerUid);
}
nc.setRequestorUidAndPackageName(callerUid, callerPackageName);
@@ -1896,6 +2092,18 @@
}
}
+ @Override
+ public @RestrictBackgroundStatus int getRestrictBackgroundStatusByCaller() {
+ enforceAccessPermission();
+ final int callerUid = Binder.getCallingUid();
+ final long token = Binder.clearCallingIdentity();
+ try {
+ return mPolicyManager.getRestrictBackgroundStatus(callerUid);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
// TODO: Consider delete this function or turn it into a no-op method.
@Override
public NetworkState[] getAllNetworkState() {
@@ -2131,53 +2339,17 @@
}
}
- private final INetworkPolicyListener mPolicyListener = new NetworkPolicyManager.Listener() {
+ private final NetworkPolicyCallback mPolicyCallback = new NetworkPolicyCallback() {
@Override
- public void onUidRulesChanged(int uid, int uidRules) {
- mHandler.sendMessage(mHandler.obtainMessage(EVENT_UID_RULES_CHANGED, uid, uidRules));
- }
- @Override
- public void onRestrictBackgroundChanged(boolean restrictBackground) {
- // caller is NPMS, since we only register with them
- if (LOGD_BLOCKED_NETWORKINFO) {
- log("onRestrictBackgroundChanged(restrictBackground=" + restrictBackground + ")");
- }
- mHandler.sendMessage(mHandler.obtainMessage(
- EVENT_DATA_SAVER_CHANGED, restrictBackground ? 1 : 0, 0));
+ public void onUidBlockedReasonChanged(int uid, @BlockedReason int blockedReasons) {
+ mHandler.sendMessage(mHandler.obtainMessage(EVENT_UID_BLOCKED_REASON_CHANGED,
+ uid, blockedReasons));
}
};
- void handleUidRulesChanged(int uid, int newRules) {
- // skip update when we've already applied rules
- final int oldRules = mUidRules.get(uid, RULE_NONE);
- if (oldRules == newRules) return;
-
- maybeNotifyNetworkBlockedForNewUidRules(uid, newRules);
-
- if (newRules == RULE_NONE) {
- mUidRules.delete(uid);
- } else {
- mUidRules.put(uid, newRules);
- }
- }
-
- void handleRestrictBackgroundChanged(boolean restrictBackground) {
- if (mRestrictBackground == restrictBackground) return;
-
- final List<UidRange> blockedRanges = mVpnBlockedUidRanges;
- for (final NetworkAgentInfo nai : mNetworkAgentInfos) {
- final boolean curMetered = nai.networkCapabilities.isMetered();
- maybeNotifyNetworkBlocked(nai, curMetered, curMetered, mRestrictBackground,
- restrictBackground, blockedRanges, blockedRanges);
- }
-
- mRestrictBackground = restrictBackground;
- }
-
- private boolean isUidBlockedByRules(int uid, int uidRules, boolean isNetworkMetered,
- boolean isBackgroundRestricted) {
- return mPolicyManager.checkUidNetworkingBlocked(uid, uidRules, isNetworkMetered,
- isBackgroundRestricted);
+ private void handleUidBlockedReasonChanged(int uid, @BlockedReason int blockedReasons) {
+ maybeNotifyNetworkBlockedForNewState(uid, blockedReasons);
+ setUidBlockedReasons(uid, blockedReasons);
}
private boolean checkAnyPermissionOf(String... permissions) {
@@ -2364,9 +2536,12 @@
mContext.enforceCallingOrSelfPermission(KeepaliveTracker.PERMISSION, "ConnectivityService");
}
- // Public because it's used by mLockdownTracker.
- public void sendConnectedBroadcast(NetworkInfo info) {
- PermissionUtils.enforceNetworkStackPermission(mContext);
+ private boolean checkLocalMacAddressPermission(int pid, int uid) {
+ return PERMISSION_GRANTED == mContext.checkPermission(
+ Manifest.permission.LOCAL_MAC_ADDRESS, pid, uid);
+ }
+
+ private void sendConnectedBroadcast(NetworkInfo info) {
sendGeneralBroadcast(info, CONNECTIVITY_ACTION);
}
@@ -2550,13 +2725,6 @@
} catch (RemoteException | ServiceSpecificException e) {
loge("Can't set TCP buffer sizes:" + e);
}
-
- final Integer rwndValue = Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.TCP_DEFAULT_INIT_RWND,
- mSystemProperties.getInt("net.tcp.default_init_rwnd", 0));
- if (rwndValue != 0) {
- mSystemProperties.setTcpInitRwnd(rwndValue);
- }
}
@Override
@@ -2573,9 +2741,8 @@
// if the system property isn't set, use the value for the apn type
int ret = RESTORE_DEFAULT_NETWORK_DELAY;
- if ((networkType <= ConnectivityManager.MAX_NETWORK_TYPE) &&
- (mNetConfigs[networkType] != null)) {
- ret = mNetConfigs[networkType].restoreTime;
+ if (mLegacyTypeTracker.isTypeSupported(networkType)) {
+ ret = mLegacyTypeTracker.getRestoreTimerForType(networkType);
}
return ret;
}
@@ -2603,7 +2770,7 @@
@Override
protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter writer,
@Nullable String[] args) {
- PriorityDump.dump(mPriorityDumper, fd, writer, args);
+ mPriorityDumper.dump(fd, writer, args);
}
private boolean checkDumpPermission(Context context, String tag, PrintWriter pw) {
@@ -2618,10 +2785,9 @@
}
}
- private void doDump(FileDescriptor fd, PrintWriter writer, String[] args, boolean asProto) {
+ private void doDump(FileDescriptor fd, PrintWriter writer, String[] args) {
final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ");
if (!checkDumpPermission(mContext, TAG, pw)) return;
- if (asProto) return;
if (CollectionUtils.contains(args, DIAG_ARG)) {
dumpNetworkDiagnostics(pw);
@@ -2662,19 +2828,16 @@
pw.decreaseIndent();
pw.println();
- pw.print("Restrict background: ");
- pw.println(mRestrictBackground);
- pw.println();
-
pw.println("Status for known UIDs:");
pw.increaseIndent();
- final int size = mUidRules.size();
+ final int size = mUidBlockedReasons.size();
for (int i = 0; i < size; i++) {
// Don't crash if the array is modified while dumping in bugreports.
try {
- final int uid = mUidRules.keyAt(i);
- final int uidRules = mUidRules.get(uid, RULE_NONE);
- pw.println("UID=" + uid + " rules=" + uidRulesToString(uidRules));
+ final int uid = mUidBlockedReasons.keyAt(i);
+ final int blockedReasons = mUidBlockedReasons.valueAt(i);
+ pw.println("UID=" + uid + " blockedReasons="
+ + blockedReasonsToString(blockedReasons));
} catch (ArrayIndexOutOfBoundsException e) {
pw.println(" ArrayIndexOutOfBoundsException");
} catch (ConcurrentModificationException e) {
@@ -2809,7 +2972,7 @@
if (0 == defaultRequest.mRequests.size()) {
pw.println("none, this should never occur.");
} else {
- pw.println(defaultRequest.mRequests.get(0).networkCapabilities.getUids());
+ pw.println(defaultRequest.mRequests.get(0).networkCapabilities.getUidRanges());
}
pw.decreaseIndent();
pw.decreaseIndent();
@@ -2864,22 +3027,6 @@
super(looper);
}
- private boolean maybeHandleAsyncChannelMessage(Message msg) {
- switch (msg.what) {
- default:
- return false;
- case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {
- handleAsyncChannelHalfConnect(msg);
- break;
- }
- case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
- handleAsyncChannelDisconnected(msg);
- break;
- }
- }
- return true;
- }
-
private void maybeHandleNetworkAgentMessage(Message msg) {
final Pair<NetworkAgentInfo, Object> arg = (Pair<NetworkAgentInfo, Object>) msg.obj;
final NetworkAgentInfo nai = arg.first;
@@ -2920,12 +3067,15 @@
break;
}
case NetworkAgent.EVENT_NETWORK_SCORE_CHANGED: {
- updateNetworkScore(nai, msg.arg1);
+ updateNetworkScore(nai, (NetworkScore) arg.second);
break;
}
case NetworkAgent.EVENT_SET_EXPLICITLY_SELECTED: {
if (nai.everConnected) {
loge("ERROR: cannot call explicitlySelected on already-connected network");
+ // Note that if the NAI had been connected, this would affect the
+ // score, and therefore would require re-mixing the score and performing
+ // a rematch.
}
nai.networkAgentConfig.explicitlySelected = toBool(msg.arg1);
nai.networkAgentConfig.acceptUnvalidated = toBool(msg.arg1) && toBool(msg.arg2);
@@ -3031,7 +3181,8 @@
nai.lastCaptivePortalDetected = visible;
nai.everCaptivePortalDetected |= visible;
if (nai.lastCaptivePortalDetected &&
- Settings.Global.CAPTIVE_PORTAL_MODE_AVOID == getCaptivePortalMode()) {
+ ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE_AVOID
+ == getCaptivePortalMode()) {
if (DBG) log("Avoiding captive portal network: " + nai.toShortString());
nai.onPreventAutomaticReconnect();
teardownUnneededNetwork(nai);
@@ -3142,8 +3293,8 @@
private int getCaptivePortalMode() {
return Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.CAPTIVE_PORTAL_MODE,
- Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT);
+ ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE,
+ ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE_PROMPT);
}
private boolean maybeHandleNetworkAgentInfoMessage(Message msg) {
@@ -3171,8 +3322,7 @@
@Override
public void handleMessage(Message msg) {
- if (!maybeHandleAsyncChannelMessage(msg)
- && !maybeHandleNetworkMonitorMessage(msg)
+ if (!maybeHandleNetworkMonitorMessage(msg)
&& !maybeHandleNetworkAgentInfoMessage(msg)) {
maybeHandleNetworkAgentMessage(msg);
}
@@ -3436,21 +3586,6 @@
return false;
}
- private void handleAsyncChannelHalfConnect(Message msg) {
- ensureRunningOnConnectivityServiceThread();
- if (mNetworkProviderInfos.containsKey(msg.replyTo)) {
- if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
- if (VDBG) log("NetworkFactory connected");
- // Finish setting up the full connection
- NetworkProviderInfo npi = mNetworkProviderInfos.get(msg.replyTo);
- sendAllRequestsToProvider(npi);
- } else {
- loge("Error connecting NetworkFactory");
- mNetworkProviderInfos.remove(msg.obj);
- }
- }
- }
-
private void handleNetworkAgentRegistered(Message msg) {
final NetworkAgentInfo nai = (NetworkAgentInfo) msg.obj;
if (!mNetworkAgentInfos.contains(nai)) {
@@ -3481,14 +3616,6 @@
}
}
- // This is a no-op if it's called with a message designating a provider that has
- // already been destroyed, because its reference will not be found in the relevant
- // maps.
- private void handleAsyncChannelDisconnected(Message msg) {
- NetworkProviderInfo npi = mNetworkProviderInfos.remove(msg.replyTo);
- if (DBG && npi != null) log("unregisterNetworkFactory for " + npi.name);
- }
-
// Destroys a network, remove references to it from the internal state managed by
// ConnectivityService, free its interfaces and clean up.
// Must be called on the Handler thread.
@@ -3577,6 +3704,7 @@
mDnsManager.removeNetwork(nai.network);
}
mNetIdManager.releaseNetId(nai.network.getNetId());
+ nai.onNetworkDisconnected();
}
private boolean createNativeNetwork(@NonNull NetworkAgentInfo networkAgent) {
@@ -3635,7 +3763,7 @@
log("Replacing " + existingRequest.mRequests.get(0) + " with "
+ nri.mRequests.get(0) + " because their intents matched.");
}
- handleReleaseNetworkRequest(existingRequest.mRequests.get(0), getCallingUid(),
+ handleReleaseNetworkRequest(existingRequest.mRequests.get(0), mDeps.getCallingUid(),
/* callOnUnavailable */ false);
}
handleRegisterNetworkRequest(nri);
@@ -3651,6 +3779,7 @@
mNetworkRequestInfoLogs.log("REGISTER " + nri);
for (final NetworkRequest req : nri.mRequests) {
mNetworkRequests.put(req, nri);
+ // TODO: Consider update signal strength for other types.
if (req.isListen()) {
for (final NetworkAgentInfo network : mNetworkAgentInfos) {
if (req.networkCapabilities.hasSignalStrength()
@@ -3743,18 +3872,19 @@
// listen requests won't keep up a network satisfying it. If this is not a multilayer
// request, return immediately. For multilayer requests, check to see if any of the
// multilayer requests may have a potential satisfier.
- if (!nri.isMultilayerRequest() && nri.mRequests.get(0).isListen()) {
+ if (!nri.isMultilayerRequest() && (nri.mRequests.get(0).isListen()
+ || nri.mRequests.get(0).isListenForBest())) {
return false;
}
for (final NetworkRequest req : nri.mRequests) {
// This multilayer listen request is satisfied therefore no further requests need to be
// evaluated deeming this network not a potential satisfier.
- if (req.isListen() && nri.getActiveRequest() == req) {
+ if ((req.isListen() || req.isListenForBest()) && nri.getActiveRequest() == req) {
return false;
}
// As non-multilayer listen requests have already returned, the below would only happen
// for a multilayer request therefore continue to the next request if available.
- if (req.isListen()) {
+ if (req.isListen() || req.isListenForBest()) {
continue;
}
// If this Network is already the highest scoring Network for a request, or if
@@ -3794,8 +3924,7 @@
? mNetworkRequests.get(request) : getNriForAppRequest(request);
if (nri != null) {
- if (Process.SYSTEM_UID != callingUid && Process.NETWORK_STACK_UID != callingUid
- && nri.mUid != callingUid) {
+ if (Process.SYSTEM_UID != callingUid && nri.mUid != callingUid) {
log(String.format("UID %d attempted to %s for unowned request %s",
callingUid, requestedOperation, nri));
return null;
@@ -4032,6 +4161,7 @@
// network, we should respect the user's option and don't need to popup the
// PARTIAL_CONNECTIVITY notification to user again.
nai.networkAgentConfig.acceptPartialConnectivity = accept;
+ nai.updateScoreForNetworkAgentConfigUpdate();
rematchAllNetworksAndRequests();
sendUpdatedScoreToFactories(nai);
}
@@ -4294,7 +4424,7 @@
Intent intent = new Intent(action);
if (type != NotificationType.PRIVATE_DNS_BROKEN) {
- intent.setData(Uri.fromParts("netId", Integer.toString(nai.network.getNetId()), null));
+ intent.putExtra(ConnectivityManager.EXTRA_NETWORK, nai.network);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// Some OEMs have their own Settings package. Thus, need to get the current using
// Settings package name instead of just use default name "com.android.settings".
@@ -4390,7 +4520,13 @@
final NetworkPolicyManager netPolicyManager =
mContext.getSystemService(NetworkPolicyManager.class);
- final int networkPreference = netPolicyManager.getMultipathPreference(network);
+ final long token = Binder.clearCallingIdentity();
+ final int networkPreference;
+ try {
+ networkPreference = netPolicyManager.getMultipathPreference(network);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
if (networkPreference != 0) {
return networkPreference;
}
@@ -4420,7 +4556,8 @@
break;
}
case EVENT_PROXY_HAS_CHANGED: {
- handleApplyDefaultProxy((ProxyInfo)msg.obj);
+ final Pair<Network, ProxyInfo> arg = (Pair<Network, ProxyInfo>) msg.obj;
+ handleApplyDefaultProxy(arg.second);
break;
}
case EVENT_REGISTER_NETWORK_PROVIDER: {
@@ -4508,22 +4645,24 @@
handlePrivateDnsValidationUpdate(
(PrivateDnsValidationUpdate) msg.obj);
break;
- case EVENT_UID_RULES_CHANGED:
- handleUidRulesChanged(msg.arg1, msg.arg2);
- break;
- case EVENT_DATA_SAVER_CHANGED:
- handleRestrictBackgroundChanged(toBool(msg.arg1));
+ case EVENT_UID_BLOCKED_REASON_CHANGED:
+ handleUidBlockedReasonChanged(msg.arg1, msg.arg2);
break;
case EVENT_SET_REQUIRE_VPN_FOR_UIDS:
handleSetRequireVpnForUids(toBool(msg.arg1), (UidRange[]) msg.obj);
break;
case EVENT_SET_OEM_NETWORK_PREFERENCE: {
- final Pair<OemNetworkPreferences, IOnSetOemNetworkPreferenceListener> arg =
- (Pair<OemNetworkPreferences,
- IOnSetOemNetworkPreferenceListener>) msg.obj;
+ final Pair<OemNetworkPreferences, IOnCompleteListener> arg =
+ (Pair<OemNetworkPreferences, IOnCompleteListener>) msg.obj;
handleSetOemNetworkPreference(arg.first, arg.second);
break;
}
+ case EVENT_SET_PROFILE_NETWORK_PREFERENCE: {
+ final Pair<ProfileNetworkPreferences.Preference, IOnCompleteListener> arg =
+ (Pair<ProfileNetworkPreferences.Preference, IOnCompleteListener>)
+ msg.obj;
+ handleSetProfileNetworkPreference(arg.first, arg.second);
+ }
case EVENT_REPORT_NETWORK_ACTIVITY:
mNetworkActivityTracker.handleReportNetworkActivity();
break;
@@ -4597,7 +4736,9 @@
}
mWakelockLogs.log("ACQUIRE for " + forWhom);
Message msg = mHandler.obtainMessage(EVENT_EXPIRE_NET_TRANSITION_WAKELOCK);
- mHandler.sendMessageDelayed(msg, mNetTransitionWakeLockTimeout);
+ final int lockTimeout = mResources.get().getInteger(
+ com.android.connectivity.resources.R.integer.config_networkTransitionTimeout);
+ mHandler.sendMessageDelayed(msg, lockTimeout);
}
// Called when we gain a new default network to release the network transition wakelock in a
@@ -4702,6 +4843,42 @@
nai.networkMonitor().forceReevaluation(uid);
}
+ // TODO: call into netd.
+ private boolean queryUserAccess(int uid, Network network) {
+ final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
+ if (nai == null) return false;
+
+ // Any UID can use its default network.
+ if (nai == getDefaultNetworkForUid(uid)) return true;
+
+ // Privileged apps can use any network.
+ if (mPermissionMonitor.hasRestrictedNetworksPermission(uid)) {
+ return true;
+ }
+
+ // An unprivileged UID can use a VPN iff the VPN applies to it.
+ if (nai.isVPN()) {
+ return nai.networkCapabilities.appliesToUid(uid);
+ }
+
+ // An unprivileged UID can bypass the VPN that applies to it only if it can protect its
+ // sockets, i.e., if it is the owner.
+ final NetworkAgentInfo vpn = getVpnForUid(uid);
+ if (vpn != null && !vpn.networkAgentConfig.allowBypass
+ && uid != vpn.networkCapabilities.getOwnerUid()) {
+ return false;
+ }
+
+ // The UID's permission must be at least sufficient for the network. Since the restricted
+ // permission was already checked above, that just leaves background networks.
+ if (!nai.networkCapabilities.hasCapability(NET_CAPABILITY_FOREGROUND)) {
+ return mPermissionMonitor.hasUseBackgroundNetworksPermission(uid);
+ }
+
+ // Unrestricted network. Anyone gets to use it.
+ return true;
+ }
+
/**
* Returns information about the proxy a certain network is using. If given a null network, it
* it will return the proxy for the bound network for the caller app or the default proxy if
@@ -4722,7 +4899,7 @@
return null;
}
return getLinkPropertiesProxyInfo(activeNetwork);
- } else if (mDeps.queryUserAccess(mDeps.getCallingUid(), network.getNetId())) {
+ } else if (mDeps.queryUserAccess(mDeps.getCallingUid(), network, this)) {
// Don't call getLinkProperties() as it requires ACCESS_NETWORK_STATE permission, which
// caller may not have.
return getLinkPropertiesProxyInfo(network);
@@ -4820,6 +4997,10 @@
Log.wtf(TAG, s);
}
+ private static void logwtf(String s, Throwable t) {
+ Log.wtf(TAG, s, t);
+ }
+
private static void loge(String s) {
Log.e(TAG, s);
}
@@ -4945,7 +5126,7 @@
@Override
public void setRequireVpnForUids(boolean requireVpn, UidRange[] ranges) {
- PermissionUtils.enforceNetworkStackPermission(mContext);
+ enforceNetworkStackOrSettingsPermission();
mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_REQUIRE_VPN_FOR_UIDS,
encodeBool(requireVpn), 0 /* arg2 */, ranges));
}
@@ -4974,8 +5155,8 @@
for (final NetworkAgentInfo nai : mNetworkAgentInfos) {
final boolean curMetered = nai.networkCapabilities.isMetered();
- maybeNotifyNetworkBlocked(nai, curMetered, curMetered, mRestrictBackground,
- mRestrictBackground, mVpnBlockedUidRanges, newVpnBlockedUidRanges);
+ maybeNotifyNetworkBlocked(nai, curMetered, curMetered,
+ mVpnBlockedUidRanges, newVpnBlockedUidRanges);
}
mVpnBlockedUidRanges = newVpnBlockedUidRanges;
@@ -4983,7 +5164,7 @@
@Override
public void setLegacyLockdownVpnEnabled(boolean enabled) {
- enforceSettingsPermission();
+ enforceNetworkStackOrSettingsPermission();
mHandler.post(() -> mLockdownEnabled = enabled);
}
@@ -5012,8 +5193,8 @@
// The legacy lockdown VPN always uses the default network.
// If the VPN's underlying network is no longer the current default network, it means that
// the default network has just switched, and the VPN is about to disconnect.
- // Report that the VPN is not connected, so when the state of NetworkInfo objects
- // overwritten by getLegacyLockdownState will be set to CONNECTING and not CONNECTED.
+ // Report that the VPN is not connected, so the state of NetworkInfo objects overwritten
+ // by filterForLegacyLockdown will be set to CONNECTING and not CONNECTED.
final NetworkAgentInfo defaultNetwork = getDefaultNetwork();
if (defaultNetwork == null || !defaultNetwork.network.equals(underlying[0])) {
return null;
@@ -5022,6 +5203,9 @@
return nai;
};
+ // TODO: move all callers to filterForLegacyLockdown and delete this method.
+ // This likely requires making sendLegacyNetworkBroadcast take a NetworkInfo object instead of
+ // just a DetailedState object.
private DetailedState getLegacyLockdownState(DetailedState origState) {
if (origState != DetailedState.CONNECTED) {
return origState;
@@ -5031,6 +5215,23 @@
: DetailedState.CONNECTED;
}
+ private void filterForLegacyLockdown(NetworkInfo ni) {
+ if (!mLockdownEnabled || !ni.isConnected()) return;
+ // The legacy lockdown VPN replaces the state of every network in CONNECTED state with the
+ // state of its VPN. This is to ensure that when an underlying network connects, apps will
+ // not see a CONNECTIVITY_ACTION broadcast for a network in state CONNECTED until the VPN
+ // comes up, at which point there is a new CONNECTIVITY_ACTION broadcast for the underlying
+ // network, this time with a state of CONNECTED.
+ //
+ // Now that the legacy lockdown code lives in ConnectivityService, and no longer has access
+ // to the internal state of the Vpn object, always replace the state with CONNECTING. This
+ // is not too far off the truth, since an always-on VPN, when not connected, is always
+ // trying to reconnect.
+ if (getLegacyLockdownNai() == null) {
+ ni.setDetailedState(DetailedState.CONNECTING, "", null);
+ }
+ }
+
@Override
public void setProvisioningNotificationVisible(boolean visible, int networkType,
String action) {
@@ -5072,6 +5273,9 @@
private void onUserRemoved(UserHandle user) {
mPermissionMonitor.onUserRemoved(user);
+ // If there was a network preference for this user, remove it.
+ handleSetProfileNetworkPreference(new ProfileNetworkPreferences.Preference(user, null),
+ null /* listener */);
if (mOemNetworkPreferences.getNetworkPreferences().size() > 0) {
handleSetOemNetworkPreference(mOemNetworkPreferences, null);
}
@@ -5109,8 +5313,8 @@
private final IBinder.DeathRecipient mDeathRecipient;
public final int providerId;
- NetworkProviderInfo(String name, Messenger messenger, AsyncChannel asyncChannel,
- int providerId, @NonNull IBinder.DeathRecipient deathRecipient) {
+ NetworkProviderInfo(String name, Messenger messenger, int providerId,
+ @NonNull IBinder.DeathRecipient deathRecipient) {
this.name = name;
this.messenger = messenger;
this.providerId = providerId;
@@ -5200,12 +5404,22 @@
boolean mPendingIntentSent;
@Nullable
final Messenger mMessenger;
+
+ // Information about the caller that caused this object to be created.
@Nullable
private final IBinder mBinder;
final int mPid;
final int mUid;
+ final @NetworkCallback.Flag int mCallbackFlags;
@Nullable
final String mCallingAttributionTag;
+
+ // Effective UID of this request. This is different from mUid when a privileged process
+ // files a request on behalf of another UID. This UID is used to determine blocked status,
+ // UID matching, and so on. mUid above is used for permission checks and to enforce the
+ // maximum limit of registered callbacks per UID.
+ final int mAsUid;
+
// In order to preserve the mapping of NetworkRequest-to-callback when apps register
// callbacks using a returned NetworkRequest, the original NetworkRequest needs to be
// maintained for keying off of. This is only a concern when the original nri
@@ -5229,17 +5443,16 @@
private Set<UidRange> getUids() {
// networkCapabilities.getUids() returns a defensive copy.
// multilayer requests will all have the same uids so return the first one.
- final Set<UidRange> uids = null == mRequests.get(0).networkCapabilities.getUids()
- ? new ArraySet<>() : mRequests.get(0).networkCapabilities.getUids();
- return uids;
+ final Set<UidRange> uids = mRequests.get(0).networkCapabilities.getUidRanges();
+ return (null == uids) ? new ArraySet<>() : uids;
}
- NetworkRequestInfo(@NonNull final NetworkRequest r, @Nullable final PendingIntent pi,
- @Nullable String callingAttributionTag) {
- this(Collections.singletonList(r), r, pi, callingAttributionTag);
+ NetworkRequestInfo(int asUid, @NonNull final NetworkRequest r,
+ @Nullable final PendingIntent pi, @Nullable String callingAttributionTag) {
+ this(asUid, Collections.singletonList(r), r, pi, callingAttributionTag);
}
- NetworkRequestInfo(@NonNull final List<NetworkRequest> r,
+ NetworkRequestInfo(int asUid, @NonNull final List<NetworkRequest> r,
@NonNull final NetworkRequest requestForCallback, @Nullable final PendingIntent pi,
@Nullable String callingAttributionTag) {
ensureAllNetworkRequestsHaveType(r);
@@ -5250,18 +5463,29 @@
mBinder = null;
mPid = getCallingPid();
mUid = mDeps.getCallingUid();
+ mAsUid = asUid;
mNetworkRequestCounter.incrementCountOrThrow(mUid);
+ /**
+ * Location sensitive data not included in pending intent. Only included in
+ * {@link NetworkCallback}.
+ */
+ mCallbackFlags = NetworkCallback.FLAG_NONE;
mCallingAttributionTag = callingAttributionTag;
}
- NetworkRequestInfo(@NonNull final NetworkRequest r, @Nullable final Messenger m,
- @Nullable final IBinder binder, @Nullable String callingAttributionTag) {
- this(Collections.singletonList(r), r, m, binder, callingAttributionTag);
+ NetworkRequestInfo(int asUid, @NonNull final NetworkRequest r, @Nullable final Messenger m,
+ @Nullable final IBinder binder,
+ @NetworkCallback.Flag int callbackFlags,
+ @Nullable String callingAttributionTag) {
+ this(asUid, Collections.singletonList(r), r, m, binder, callbackFlags,
+ callingAttributionTag);
}
- NetworkRequestInfo(@NonNull final List<NetworkRequest> r,
+ NetworkRequestInfo(int asUid, @NonNull final List<NetworkRequest> r,
@NonNull final NetworkRequest requestForCallback, @Nullable final Messenger m,
- @Nullable final IBinder binder, @Nullable String callingAttributionTag) {
+ @Nullable final IBinder binder,
+ @NetworkCallback.Flag int callbackFlags,
+ @Nullable String callingAttributionTag) {
super();
ensureAllNetworkRequestsHaveType(r);
mRequests = initializeRequests(r);
@@ -5270,8 +5494,10 @@
mBinder = binder;
mPid = getCallingPid();
mUid = mDeps.getCallingUid();
+ mAsUid = asUid;
mPendingIntent = null;
mNetworkRequestCounter.incrementCountOrThrow(mUid);
+ mCallbackFlags = callbackFlags;
mCallingAttributionTag = callingAttributionTag;
try {
@@ -5311,17 +5537,19 @@
mBinder = nri.mBinder;
mPid = nri.mPid;
mUid = nri.mUid;
+ mAsUid = nri.mAsUid;
mPendingIntent = nri.mPendingIntent;
mNetworkRequestCounter.incrementCountOrThrow(mUid);
+ mCallbackFlags = nri.mCallbackFlags;
mCallingAttributionTag = nri.mCallingAttributionTag;
}
- NetworkRequestInfo(@NonNull final NetworkRequest r) {
- this(Collections.singletonList(r));
+ NetworkRequestInfo(int asUid, @NonNull final NetworkRequest r) {
+ this(asUid, Collections.singletonList(r));
}
- NetworkRequestInfo(@NonNull final List<NetworkRequest> r) {
- this(r, r.get(0), null /* pi */, null /* callingAttributionTag */);
+ NetworkRequestInfo(int asUid, @NonNull final List<NetworkRequest> r) {
+ this(asUid, r, r.get(0), null /* pi */, null /* callingAttributionTag */);
}
// True if this NRI is being satisfied. It also accounts for if the nri has its satisifer
@@ -5357,12 +5585,14 @@
@Override
public String toString() {
- return "uid/pid:" + mUid + "/" + mPid + " active request Id: "
+ final String asUidString = (mAsUid == mUid) ? "" : " asUid: " + mAsUid;
+ return "uid/pid:" + mUid + "/" + mPid + asUidString + " activeRequest: "
+ (mActiveRequest == null ? null : mActiveRequest.requestId)
- + " callback request Id: "
+ + " callbackRequest: "
+ mNetworkRequestForCallback.requestId
+ " " + mRequests
- + (mPendingIntent == null ? "" : " to trigger " + mPendingIntent);
+ + (mPendingIntent == null ? "" : " to trigger " + mPendingIntent)
+ + "callback flags: " + mCallbackFlags;
}
}
@@ -5446,30 +5676,37 @@
}
}
- private boolean checkUnsupportedStartingFrom(int version, String callingPackageName) {
- final UserHandle user = UserHandle.getUserHandleForUid(mDeps.getCallingUid());
+ private boolean isTargetSdkAtleast(int version, int callingUid,
+ @NonNull String callingPackageName) {
+ final UserHandle user = UserHandle.getUserHandleForUid(callingUid);
final PackageManager pm =
mContext.createContextAsUser(user, 0 /* flags */).getPackageManager();
try {
- final int callingVersion = pm.getApplicationInfo(
- callingPackageName, 0 /* flags */).targetSdkVersion;
+ final int callingVersion = pm.getTargetSdkVersion(callingPackageName);
if (callingVersion < version) return false;
} catch (PackageManager.NameNotFoundException e) { }
return true;
}
@Override
- public NetworkRequest requestNetwork(NetworkCapabilities networkCapabilities,
+ public NetworkRequest requestNetwork(int asUid, NetworkCapabilities networkCapabilities,
int reqTypeInt, Messenger messenger, int timeoutMs, IBinder binder,
- int legacyType, @NonNull String callingPackageName,
+ int legacyType, int callbackFlags, @NonNull String callingPackageName,
@Nullable String callingAttributionTag) {
if (legacyType != TYPE_NONE && !checkNetworkStackPermission()) {
- if (checkUnsupportedStartingFrom(Build.VERSION_CODES.M, callingPackageName)) {
+ if (isTargetSdkAtleast(Build.VERSION_CODES.M, mDeps.getCallingUid(),
+ callingPackageName)) {
throw new SecurityException("Insufficient permissions to specify legacy type");
}
}
final NetworkCapabilities defaultNc = mDefaultRequest.mRequests.get(0).networkCapabilities;
final int callingUid = mDeps.getCallingUid();
+ // Privileged callers can track the default network of another UID by passing in a UID.
+ if (asUid != Process.INVALID_UID) {
+ enforceSettingsPermission();
+ } else {
+ asUid = callingUid;
+ }
final NetworkRequest.Type reqType;
try {
reqType = NetworkRequest.Type.values()[reqTypeInt];
@@ -5479,10 +5716,10 @@
switch (reqType) {
case TRACK_DEFAULT:
// If the request type is TRACK_DEFAULT, the passed {@code networkCapabilities}
- // is unused and will be replaced by ones appropriate for the caller.
- // This allows callers to keep track of the default network for their app.
+ // is unused and will be replaced by ones appropriate for the UID (usually, the
+ // calling app). This allows callers to keep track of the default network.
networkCapabilities = copyDefaultNetworkCapabilitiesForUid(
- defaultNc, callingUid, callingPackageName);
+ defaultNc, asUid, callingUid, callingPackageName);
enforceAccessPermission();
break;
case TRACK_SYSTEM_DEFAULT:
@@ -5501,6 +5738,10 @@
// request if the app changes network state. http://b/29964605
enforceMeteredApnPolicy(networkCapabilities);
break;
+ case LISTEN_FOR_BEST:
+ enforceAccessPermission();
+ networkCapabilities = new NetworkCapabilities(networkCapabilities);
+ break;
default:
throw new IllegalArgumentException("Unsupported request type " + reqType);
}
@@ -5508,11 +5749,17 @@
ensureSufficientPermissionsForRequest(networkCapabilities,
Binder.getCallingPid(), callingUid, callingPackageName);
- // Set the UID range for this request to the single UID of the requester, or to an empty
- // set of UIDs if the caller has the appropriate permission and UIDs have not been set.
+ // Enforce FOREGROUND if the caller does not have permission to use background network.
+ if (reqType == LISTEN_FOR_BEST) {
+ restrictBackgroundRequestForCaller(networkCapabilities);
+ }
+
+ // Set the UID range for this request to the single UID of the requester, unless the
+ // requester has the permission to specify other UIDs.
// This will overwrite any allowed UIDs in the requested capabilities. Though there
// are no visible methods to set the UIDs, an app could use reflection to try and get
// networks for other apps so it's essential that the UIDs are overwritten.
+ // Also set the requester UID and package name in the request.
restrictRequestUidsForCallerAndSetRequestorInfo(networkCapabilities,
callingUid, callingPackageName);
@@ -5524,7 +5771,8 @@
final NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, legacyType,
nextNetworkRequestId(), reqType);
final NetworkRequestInfo nri = getNriToRegister(
- networkRequest, messenger, binder, callingAttributionTag);
+ asUid, networkRequest, messenger, binder, callbackFlags,
+ callingAttributionTag);
if (DBG) log("requestNetwork for " + nri);
// For TRACK_SYSTEM_DEFAULT callbacks, the capabilities have been modified since they were
@@ -5551,23 +5799,27 @@
* requests registered to track the default request. If there is currently a per-app default
* tracking the app requestor, then we need to create a version of this nri that mirrors that of
* the tracking per-app default so that callbacks are sent to the app requestor appropriately.
+ * @param asUid the uid on behalf of which to file the request. Different from requestorUid
+ * when a privileged caller is tracking the default network for another uid.
* @param nr the network request for the nri.
* @param msgr the messenger for the nri.
* @param binder the binder for the nri.
* @param callingAttributionTag the calling attribution tag for the nri.
* @return the nri to register.
*/
- private NetworkRequestInfo getNriToRegister(@NonNull final NetworkRequest nr,
+ private NetworkRequestInfo getNriToRegister(final int asUid, @NonNull final NetworkRequest nr,
@Nullable final Messenger msgr, @Nullable final IBinder binder,
+ @NetworkCallback.Flag int callbackFlags,
@Nullable String callingAttributionTag) {
final List<NetworkRequest> requests;
if (NetworkRequest.Type.TRACK_DEFAULT == nr.type) {
requests = copyDefaultNetworkRequestsForUid(
- nr.getRequestorUid(), nr.getRequestorPackageName());
+ asUid, nr.getRequestorUid(), nr.getRequestorPackageName());
} else {
requests = Collections.singletonList(nr);
}
- return new NetworkRequestInfo(requests, nr, msgr, binder, callingAttributionTag);
+ return new NetworkRequestInfo(
+ asUid, requests, nr, msgr, binder, callbackFlags, callingAttributionTag);
}
private void enforceNetworkRequestPermissions(NetworkCapabilities networkCapabilities,
@@ -5648,8 +5900,8 @@
NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, TYPE_NONE,
nextNetworkRequestId(), NetworkRequest.Type.REQUEST);
- NetworkRequestInfo nri =
- new NetworkRequestInfo(networkRequest, operation, callingAttributionTag);
+ NetworkRequestInfo nri = new NetworkRequestInfo(callingUid, networkRequest, operation,
+ callingAttributionTag);
if (DBG) log("pendingRequest for " + nri);
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_REQUEST_WITH_INTENT,
nri));
@@ -5659,14 +5911,14 @@
private void releasePendingNetworkRequestWithDelay(PendingIntent operation) {
mHandler.sendMessageDelayed(
mHandler.obtainMessage(EVENT_RELEASE_NETWORK_REQUEST_WITH_INTENT,
- getCallingUid(), 0, operation), mReleasePendingIntentDelayMs);
+ mDeps.getCallingUid(), 0, operation), mReleasePendingIntentDelayMs);
}
@Override
public void releasePendingNetworkRequest(PendingIntent operation) {
Objects.requireNonNull(operation, "PendingIntent cannot be null.");
mHandler.sendMessage(mHandler.obtainMessage(EVENT_RELEASE_NETWORK_REQUEST_WITH_INTENT,
- getCallingUid(), 0, operation));
+ mDeps.getCallingUid(), 0, operation));
}
// In order to implement the compatibility measure for pre-M apps that call
@@ -5693,8 +5945,9 @@
@Override
public NetworkRequest listenForNetwork(NetworkCapabilities networkCapabilities,
- Messenger messenger, IBinder binder, @NonNull String callingPackageName,
- @Nullable String callingAttributionTag) {
+ Messenger messenger, IBinder binder,
+ @NetworkCallback.Flag int callbackFlags,
+ @NonNull String callingPackageName, @NonNull String callingAttributionTag) {
final int callingUid = mDeps.getCallingUid();
if (!hasWifiNetworkListenPermission(networkCapabilities)) {
enforceAccessPermission();
@@ -5715,7 +5968,8 @@
NetworkRequest networkRequest = new NetworkRequest(nc, TYPE_NONE, nextNetworkRequestId(),
NetworkRequest.Type.LISTEN);
NetworkRequestInfo nri =
- new NetworkRequestInfo(networkRequest, messenger, binder, callingAttributionTag);
+ new NetworkRequestInfo(callingUid, networkRequest, messenger, binder, callbackFlags,
+ callingAttributionTag);
if (VDBG) log("listenForNetwork for " + nri);
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_LISTENER, nri));
@@ -5739,8 +5993,8 @@
NetworkRequest networkRequest = new NetworkRequest(nc, TYPE_NONE, nextNetworkRequestId(),
NetworkRequest.Type.LISTEN);
- NetworkRequestInfo nri =
- new NetworkRequestInfo(networkRequest, operation, callingAttributionTag);
+ NetworkRequestInfo nri = new NetworkRequestInfo(callingUid, networkRequest, operation,
+ callingAttributionTag);
if (VDBG) log("pendingListenForNetwork for " + nri);
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_LISTENER, nri));
@@ -5761,7 +6015,7 @@
public void releaseNetworkRequest(NetworkRequest networkRequest) {
ensureNetworkRequestHasType(networkRequest);
mHandler.sendMessage(mHandler.obtainMessage(
- EVENT_RELEASE_NETWORK_REQUEST, getCallingUid(), 0, networkRequest));
+ EVENT_RELEASE_NETWORK_REQUEST, mDeps.getCallingUid(), 0, networkRequest));
}
private void handleRegisterNetworkProvider(NetworkProviderInfo npi) {
@@ -5784,8 +6038,7 @@
public int registerNetworkProvider(Messenger messenger, String name) {
enforceNetworkFactoryOrSettingsPermission();
NetworkProviderInfo npi = new NetworkProviderInfo(name, messenger,
- null /* asyncChannel */, nextNetworkProviderId(),
- () -> unregisterNetworkProvider(messenger));
+ nextNetworkProviderId(), () -> unregisterNetworkProvider(messenger));
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_PROVIDER, npi));
return npi.providerId;
}
@@ -5843,10 +6096,16 @@
@GuardedBy("mBlockedAppUids")
private final HashSet<Integer> mBlockedAppUids = new HashSet<>();
- // Current OEM network preferences.
+ // Current OEM network preferences. This object must only be written to on the handler thread.
+ // Since it is immutable and always non-null, other threads may read it if they only care
+ // about seeing a consistent object but not that it is current.
@NonNull
private OemNetworkPreferences mOemNetworkPreferences =
new OemNetworkPreferences.Builder().build();
+ // Current per-profile network preferences. This object follows the same threading rules as
+ // the OEM network preferences above.
+ @NonNull
+ private ProfileNetworkPreferences mProfileNetworkPreferences = new ProfileNetworkPreferences();
// The always-on request for an Internet-capable network that apps without a specific default
// fall back to.
@@ -5885,33 +6144,37 @@
/**
* Get a copy of the network requests of the default request that is currently tracking the
* given uid.
+ * @param asUid the uid on behalf of which to file the request. Different from requestorUid
+ * when a privileged caller is tracking the default network for another uid.
* @param requestorUid the uid to check the default for.
* @param requestorPackageName the requestor's package name.
* @return a copy of the default's NetworkRequest that is tracking the given uid.
*/
@NonNull
private List<NetworkRequest> copyDefaultNetworkRequestsForUid(
- @NonNull final int requestorUid, @NonNull final String requestorPackageName) {
+ final int asUid, final int requestorUid, @NonNull final String requestorPackageName) {
return copyNetworkRequestsForUid(
- getDefaultRequestTrackingUid(requestorUid).mRequests,
- requestorUid, requestorPackageName);
+ getDefaultRequestTrackingUid(asUid).mRequests,
+ asUid, requestorUid, requestorPackageName);
}
/**
* Copy the given nri's NetworkRequest collection.
* @param requestsToCopy the NetworkRequest collection to be copied.
+ * @param asUid the uid on behalf of which to file the request. Different from requestorUid
+ * when a privileged caller is tracking the default network for another uid.
* @param requestorUid the uid to set on the copied collection.
* @param requestorPackageName the package name to set on the copied collection.
* @return the copied NetworkRequest collection.
*/
@NonNull
private List<NetworkRequest> copyNetworkRequestsForUid(
- @NonNull final List<NetworkRequest> requestsToCopy, @NonNull final int requestorUid,
- @NonNull final String requestorPackageName) {
+ @NonNull final List<NetworkRequest> requestsToCopy, final int asUid,
+ final int requestorUid, @NonNull final String requestorPackageName) {
final List<NetworkRequest> requests = new ArrayList<>();
for (final NetworkRequest nr : requestsToCopy) {
requests.add(new NetworkRequest(copyDefaultNetworkCapabilitiesForUid(
- nr.networkCapabilities, requestorUid, requestorPackageName),
+ nr.networkCapabilities, asUid, requestorUid, requestorPackageName),
nr.legacyType, nextNetworkRequestId(), nr.type));
}
return requests;
@@ -5919,12 +6182,17 @@
@NonNull
private NetworkCapabilities copyDefaultNetworkCapabilitiesForUid(
- @NonNull final NetworkCapabilities netCapToCopy, @NonNull final int requestorUid,
- @NonNull final String requestorPackageName) {
+ @NonNull final NetworkCapabilities netCapToCopy, final int asUid,
+ final int requestorUid, @NonNull final String requestorPackageName) {
+ // These capabilities are for a TRACK_DEFAULT callback, so:
+ // 1. Remove NET_CAPABILITY_VPN, because it's (currently!) the only difference between
+ // mDefaultRequest and a per-UID default request.
+ // TODO: stop depending on the fact that these two unrelated things happen to be the same
+ // 2. Always set the UIDs to asUid. restrictRequestUidsForCallerAndSetRequestorInfo will
+ // not do this in the case of a privileged application.
final NetworkCapabilities netCap = new NetworkCapabilities(netCapToCopy);
netCap.removeCapability(NET_CAPABILITY_NOT_VPN);
- netCap.setSingleUid(requestorUid);
- netCap.setUids(new ArraySet<>());
+ netCap.setSingleUid(asUid);
restrictRequestUidsForCallerAndSetRequestorInfo(
netCap, requestorUid, requestorPackageName);
return netCap;
@@ -6005,7 +6273,7 @@
for (final NetworkRequestInfo nri : mDefaultNetworkRequests) {
// Currently, all network requests will have the same uids therefore checking the first
// one is sufficient. If/when uids are tracked at the nri level, this can change.
- final Set<UidRange> uids = nri.mRequests.get(0).networkCapabilities.getUids();
+ final Set<UidRange> uids = nri.mRequests.get(0).networkCapabilities.getUidRanges();
if (null == uids) {
continue;
}
@@ -6036,20 +6304,6 @@
return nai == getDefaultNetwork();
}
- // TODO : remove this method. It's a stopgap measure to help sheperding a number of dependent
- // changes that would conflict throughout the automerger graph. Having this method temporarily
- // helps with the process of going through with all these dependent changes across the entire
- // tree.
- /**
- * Register a new agent. {@see #registerNetworkAgent} below.
- */
- public Network registerNetworkAgent(INetworkAgent na, NetworkInfo networkInfo,
- LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
- int currentScore, NetworkAgentConfig networkAgentConfig) {
- return registerNetworkAgent(na, networkInfo, linkProperties, networkCapabilities,
- currentScore, networkAgentConfig, NetworkProvider.ID_NONE);
- }
-
/**
* Register a new agent with ConnectivityService to handle a network.
*
@@ -6060,7 +6314,7 @@
* later : see {@link #updateLinkProperties}.
* @param networkCapabilities the initial capabilites of this network. They can be updated
* later : see {@link #updateCapabilities}.
- * @param currentScore the initial score of the network. See
+ * @param initialScore the initial score of the network. See
* {@link NetworkAgentInfo#getCurrentScore}.
* @param networkAgentConfig metadata about the network. This is never updated.
* @param providerId the ID of the provider owning this NetworkAgent.
@@ -6068,10 +6322,12 @@
*/
public Network registerNetworkAgent(INetworkAgent na, NetworkInfo networkInfo,
LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
- int currentScore, NetworkAgentConfig networkAgentConfig, int providerId) {
+ @NonNull NetworkScore initialScore, NetworkAgentConfig networkAgentConfig,
+ int providerId) {
Objects.requireNonNull(networkInfo, "networkInfo must not be null");
Objects.requireNonNull(linkProperties, "linkProperties must not be null");
Objects.requireNonNull(networkCapabilities, "networkCapabilities must not be null");
+ Objects.requireNonNull(initialScore, "initialScore must not be null");
Objects.requireNonNull(networkAgentConfig, "networkAgentConfig must not be null");
if (networkCapabilities.hasTransport(TRANSPORT_TEST)) {
enforceAnyPermissionOf(Manifest.permission.MANAGE_TEST_NETWORKS);
@@ -6083,7 +6339,7 @@
final long token = Binder.clearCallingIdentity();
try {
return registerNetworkAgentInternal(na, networkInfo, linkProperties,
- networkCapabilities, currentScore, networkAgentConfig, providerId, uid);
+ networkCapabilities, initialScore, networkAgentConfig, providerId, uid);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -6091,7 +6347,8 @@
private Network registerNetworkAgentInternal(INetworkAgent na, NetworkInfo networkInfo,
LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
- int currentScore, NetworkAgentConfig networkAgentConfig, int providerId, int uid) {
+ NetworkScore currentScore, NetworkAgentConfig networkAgentConfig, int providerId,
+ int uid) {
if (networkCapabilities.hasTransport(TRANSPORT_TEST)) {
// Strictly, sanitizing here is unnecessary as the capabilities will be sanitized in
// the call to mixInCapabilities below anyway, but sanitizing here means the NAI never
@@ -6106,7 +6363,7 @@
final NetworkAgentInfo nai = new NetworkAgentInfo(na,
new Network(mNetIdManager.reserveNetId()), new NetworkInfo(networkInfo), lp, nc,
currentScore, mContext, mTrackerHandler, new NetworkAgentConfig(networkAgentConfig),
- this, mNetd, mDnsResolver, providerId, uid, mQosCallbackTracker);
+ this, mNetd, mDnsResolver, providerId, uid, mQosCallbackTracker, mDeps);
// Make sure the LinkProperties and NetworkCapabilities reflect what the agent info says.
processCapabilitiesFromAgent(nai, nc);
@@ -6457,7 +6714,7 @@
return;
}
- final Set<UidRange> ranges = nai.networkCapabilities.getUids();
+ final Set<UidRange> ranges = nai.networkCapabilities.getUidRanges();
final int vpnAppUid = nai.networkCapabilities.getOwnerUid();
// TODO: this create a window of opportunity for apps to receive traffic between the time
// when the old rules are removed and the time when new rules are added. To fix this,
@@ -6472,6 +6729,11 @@
}
private void updateWakeOnLan(@NonNull LinkProperties lp) {
+ if (mWolSupportedInterfaces == null) {
+ mWolSupportedInterfaces = new ArraySet<>(mResources.get().getStringArray(
+ com.android.connectivity.resources.R.array
+ .config_wakeonlan_supported_interfaces));
+ }
lp.setWakeOnLanSupported(mWolSupportedInterfaces.contains(lp.getInterfaceName()));
}
@@ -6708,8 +6970,8 @@
final boolean meteredChanged = oldMetered != newMetered;
if (meteredChanged) {
- maybeNotifyNetworkBlocked(nai, oldMetered, newMetered, mRestrictBackground,
- mRestrictBackground, mVpnBlockedUidRanges, mVpnBlockedUidRanges);
+ maybeNotifyNetworkBlocked(nai, oldMetered, newMetered,
+ mVpnBlockedUidRanges, mVpnBlockedUidRanges);
}
final boolean roamingChanged = prevNc.hasCapability(NET_CAPABILITY_NOT_ROAMING)
@@ -6817,8 +7079,8 @@
private void updateUids(NetworkAgentInfo nai, NetworkCapabilities prevNc,
NetworkCapabilities newNc) {
- Set<UidRange> prevRanges = null == prevNc ? null : prevNc.getUids();
- Set<UidRange> newRanges = null == newNc ? null : newNc.getUids();
+ Set<UidRange> prevRanges = null == prevNc ? null : prevNc.getUidRanges();
+ Set<UidRange> newRanges = null == newNc ? null : newNc.getUidRanges();
if (null == prevRanges) prevRanges = new ArraySet<>();
if (null == newRanges) newRanges = new ArraySet<>();
final Set<UidRange> prevRangesCopy = new ArraySet<>(prevRanges);
@@ -7044,6 +7306,8 @@
if (notificationType != ConnectivityManager.CALLBACK_UNAVAIL) {
putParcelable(bundle, networkAgent.network);
}
+ final boolean includeLocationSensitiveInfo =
+ (nri.mCallbackFlags & NetworkCallback.FLAG_INCLUDE_LOCATION_INFO) != 0;
switch (notificationType) {
case ConnectivityManager.CALLBACK_AVAILABLE: {
final NetworkCapabilities nc =
@@ -7052,7 +7316,8 @@
putParcelable(
bundle,
createWithLocationInfoSanitizedIfNecessaryWhenParceled(
- nc, nri.mUid, nrForCallback.getRequestorPackageName(),
+ nc, includeLocationSensitiveInfo, nri.mPid, nri.mUid,
+ nrForCallback.getRequestorPackageName(),
nri.mCallingAttributionTag));
putParcelable(bundle, linkPropertiesRestrictedForCallerPermissions(
networkAgent.linkProperties, nri.mPid, nri.mUid));
@@ -7072,7 +7337,8 @@
putParcelable(
bundle,
createWithLocationInfoSanitizedIfNecessaryWhenParceled(
- netCap, nri.mUid, nrForCallback.getRequestorPackageName(),
+ netCap, includeLocationSensitiveInfo, nri.mPid, nri.mUid,
+ nrForCallback.getRequestorPackageName(),
nri.mCallingAttributionTag));
break;
}
@@ -7738,6 +8004,7 @@
updateCapabilitiesForNetwork(networkAgent);
}
networkAgent.created = true;
+ networkAgent.onNetworkCreated();
}
if (!networkAgent.everConnected && state == NetworkInfo.State.CONNECTED) {
@@ -7806,7 +8073,7 @@
}
}
- private void updateNetworkScore(@NonNull final NetworkAgentInfo nai, final int score) {
+ private void updateNetworkScore(@NonNull final NetworkAgentInfo nai, final NetworkScore score) {
if (VDBG || DDBG) log("updateNetworkScore for " + nai.toShortString() + " to " + score);
nai.setScore(score);
rematchAllNetworksAndRequests();
@@ -7825,12 +8092,11 @@
return;
}
+ final int blockedReasons = mUidBlockedReasons.get(nri.mAsUid, BLOCKED_REASON_NONE);
final boolean metered = nai.networkCapabilities.isMetered();
- boolean blocked;
- blocked = isUidBlockedByVpn(nri.mUid, mVpnBlockedUidRanges);
- blocked |= isUidBlockedByRules(nri.mUid, mUidRules.get(nri.mUid),
- metered, mRestrictBackground);
- callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_AVAILABLE, blocked ? 1 : 0);
+ final boolean vpnBlocked = isUidBlockedByVpn(nri.mAsUid, mVpnBlockedUidRanges);
+ callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_AVAILABLE,
+ getBlockedState(blockedReasons, metered, vpnBlocked));
}
// Notify the requests on this NAI that the network is now lingered.
@@ -7839,6 +8105,21 @@
notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOSING, lingerTime);
}
+ private static int getBlockedState(int reasons, boolean metered, boolean vpnBlocked) {
+ if (!metered) reasons &= ~BLOCKED_METERED_REASON_MASK;
+ return vpnBlocked
+ ? reasons | BLOCKED_REASON_LOCKDOWN_VPN
+ : reasons & ~BLOCKED_REASON_LOCKDOWN_VPN;
+ }
+
+ private void setUidBlockedReasons(int uid, @BlockedReason int blockedReasons) {
+ if (blockedReasons == BLOCKED_REASON_NONE) {
+ mUidBlockedReasons.delete(uid);
+ } else {
+ mUidBlockedReasons.put(uid, blockedReasons);
+ }
+ }
+
/**
* Notify of the blocked state apps with a registered callback matching a given NAI.
*
@@ -7846,59 +8127,56 @@
* any given nai, all requests need to be considered according to the uid who filed it.
*
* @param nai The target NetworkAgentInfo.
- * @param oldMetered True if the previous network capabilities is metered.
- * @param newRestrictBackground True if data saver is enabled.
+ * @param oldMetered True if the previous network capabilities were metered.
+ * @param newMetered True if the current network capabilities are metered.
+ * @param oldBlockedUidRanges list of UID ranges previously blocked by lockdown VPN.
+ * @param newBlockedUidRanges list of UID ranges blocked by lockdown VPN.
*/
private void maybeNotifyNetworkBlocked(NetworkAgentInfo nai, boolean oldMetered,
- boolean newMetered, boolean oldRestrictBackground, boolean newRestrictBackground,
- List<UidRange> oldBlockedUidRanges, List<UidRange> newBlockedUidRanges) {
+ boolean newMetered, List<UidRange> oldBlockedUidRanges,
+ List<UidRange> newBlockedUidRanges) {
for (int i = 0; i < nai.numNetworkRequests(); i++) {
NetworkRequest nr = nai.requestAt(i);
NetworkRequestInfo nri = mNetworkRequests.get(nr);
- final int uidRules = mUidRules.get(nri.mUid);
- final boolean oldBlocked, newBlocked, oldVpnBlocked, newVpnBlocked;
- oldVpnBlocked = isUidBlockedByVpn(nri.mUid, oldBlockedUidRanges);
- newVpnBlocked = (oldBlockedUidRanges != newBlockedUidRanges)
- ? isUidBlockedByVpn(nri.mUid, newBlockedUidRanges)
+ final int blockedReasons = mUidBlockedReasons.get(nri.mAsUid, BLOCKED_REASON_NONE);
+ final boolean oldVpnBlocked = isUidBlockedByVpn(nri.mAsUid, oldBlockedUidRanges);
+ final boolean newVpnBlocked = (oldBlockedUidRanges != newBlockedUidRanges)
+ ? isUidBlockedByVpn(nri.mAsUid, newBlockedUidRanges)
: oldVpnBlocked;
- oldBlocked = oldVpnBlocked || isUidBlockedByRules(nri.mUid, uidRules, oldMetered,
- oldRestrictBackground);
- newBlocked = newVpnBlocked || isUidBlockedByRules(nri.mUid, uidRules, newMetered,
- newRestrictBackground);
-
- if (oldBlocked != newBlocked) {
+ final int oldBlockedState = getBlockedState(blockedReasons, oldMetered, oldVpnBlocked);
+ final int newBlockedState = getBlockedState(blockedReasons, newMetered, newVpnBlocked);
+ if (oldBlockedState != newBlockedState) {
callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_BLK_CHANGED,
- encodeBool(newBlocked));
+ newBlockedState);
}
}
}
/**
- * Notify apps with a given UID of the new blocked state according to new uid rules.
+ * Notify apps with a given UID of the new blocked state according to new uid state.
* @param uid The uid for which the rules changed.
- * @param newRules The new rules to apply.
+ * @param blockedReasons The reasons for why an uid is blocked.
*/
- private void maybeNotifyNetworkBlockedForNewUidRules(int uid, int newRules) {
+ private void maybeNotifyNetworkBlockedForNewState(int uid, @BlockedReason int blockedReasons) {
for (final NetworkAgentInfo nai : mNetworkAgentInfos) {
final boolean metered = nai.networkCapabilities.isMetered();
final boolean vpnBlocked = isUidBlockedByVpn(uid, mVpnBlockedUidRanges);
- final boolean oldBlocked, newBlocked;
- oldBlocked = vpnBlocked || isUidBlockedByRules(
- uid, mUidRules.get(uid), metered, mRestrictBackground);
- newBlocked = vpnBlocked || isUidBlockedByRules(
- uid, newRules, metered, mRestrictBackground);
- if (oldBlocked == newBlocked) {
+
+ final int oldBlockedState = getBlockedState(
+ mUidBlockedReasons.get(uid, BLOCKED_REASON_NONE), metered, vpnBlocked);
+ final int newBlockedState = getBlockedState(blockedReasons, metered, vpnBlocked);
+ if (oldBlockedState == newBlockedState) {
continue;
}
- final int arg = encodeBool(newBlocked);
for (int i = 0; i < nai.numNetworkRequests(); i++) {
NetworkRequest nr = nai.requestAt(i);
NetworkRequestInfo nri = mNetworkRequests.get(nr);
- if (nri != null && nri.mUid == uid) {
- callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_BLK_CHANGED, arg);
+ if (nri != null && nri.mAsUid == uid) {
+ callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_BLK_CHANGED,
+ newBlockedState);
}
}
}
@@ -7914,6 +8192,7 @@
// and is still connected.
NetworkInfo info = new NetworkInfo(nai.networkInfo);
info.setType(type);
+ filterForLegacyLockdown(info);
if (state != DetailedState.DISCONNECTED) {
info.setDetailedState(state, null, info.getExtraInfo());
sendConnectedBroadcast(info);
@@ -8028,15 +8307,15 @@
@Override
public String getCaptivePortalServerUrl() {
enforceNetworkStackOrSettingsPermission();
- String settingUrl = mContext.getResources().getString(
- R.string.config_networkCaptivePortalServerUrl);
+ String settingUrl = mResources.get().getString(
+ com.android.connectivity.resources.R.string.config_networkCaptivePortalServerUrl);
if (!TextUtils.isEmpty(settingUrl)) {
return settingUrl;
}
settingUrl = Settings.Global.getString(mContext.getContentResolver(),
- Settings.Global.CAPTIVE_PORTAL_HTTP_URL);
+ ConnectivitySettingsManager.CAPTIVE_PORTAL_HTTP_URL);
if (!TextUtils.isEmpty(settingUrl)) {
return settingUrl;
}
@@ -8118,11 +8397,11 @@
// restore private DNS settings to default mode (opportunistic)
if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_PRIVATE_DNS)) {
Settings.Global.putString(mContext.getContentResolver(),
- Settings.Global.PRIVATE_DNS_MODE, PRIVATE_DNS_MODE_OPPORTUNISTIC);
+ ConnectivitySettingsManager.PRIVATE_DNS_MODE, PRIVATE_DNS_MODE_OPPORTUNISTIC);
}
Settings.Global.putString(mContext.getContentResolver(),
- Settings.Global.NETWORK_AVOID_BAD_WIFI, null);
+ ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI, null);
}
@Override
@@ -8235,7 +8514,7 @@
final NetworkAgentInfo vpn = getVpnForUid(uid);
if (vpn == null || getVpnType(vpn) != VpnManager.TYPE_VPN_SERVICE
- || vpn.networkCapabilities.getOwnerUid() != Binder.getCallingUid()) {
+ || vpn.networkCapabilities.getOwnerUid() != mDeps.getCallingUid()) {
return INVALID_UID;
}
@@ -8661,7 +8940,7 @@
// nri is not bound to the death of callback. Instead, callback.bindToDeath() is set in
// handleRegisterConnectivityDiagnosticsCallback(). nri will be cleaned up as part of the
// callback's binder death.
- final NetworkRequestInfo nri = new NetworkRequestInfo(requestWithId);
+ final NetworkRequestInfo nri = new NetworkRequestInfo(callingUid, requestWithId);
final ConnectivityDiagnosticsCallbackInfo cbInfo =
new ConnectivityDiagnosticsCallbackInfo(callback, nri, callingPackageName);
@@ -8827,13 +9106,13 @@
private int transportTypeToLegacyType(int type) {
switch (type) {
case NetworkCapabilities.TRANSPORT_CELLULAR:
- return ConnectivityManager.TYPE_MOBILE;
+ return TYPE_MOBILE;
case NetworkCapabilities.TRANSPORT_WIFI:
- return ConnectivityManager.TYPE_WIFI;
+ return TYPE_WIFI;
case NetworkCapabilities.TRANSPORT_BLUETOOTH:
- return ConnectivityManager.TYPE_BLUETOOTH;
+ return TYPE_BLUETOOTH;
case NetworkCapabilities.TRANSPORT_ETHERNET:
- return ConnectivityManager.TYPE_ETHERNET;
+ return TYPE_ETHERNET;
default:
loge("Unexpected transport in transportTypeToLegacyType: " + type);
}
@@ -8874,13 +9153,13 @@
if (networkAgent.networkCapabilities.hasTransport(
NetworkCapabilities.TRANSPORT_CELLULAR)) {
timeout = Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.DATA_ACTIVITY_TIMEOUT_MOBILE,
+ ConnectivitySettingsManager.DATA_ACTIVITY_TIMEOUT_MOBILE,
10);
type = NetworkCapabilities.TRANSPORT_CELLULAR;
} else if (networkAgent.networkCapabilities.hasTransport(
NetworkCapabilities.TRANSPORT_WIFI)) {
timeout = Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.DATA_ACTIVITY_TIMEOUT_WIFI,
+ ConnectivitySettingsManager.DATA_ACTIVITY_TIMEOUT_WIFI,
15);
type = NetworkCapabilities.TRANSPORT_WIFI;
} else {
@@ -9048,6 +9327,143 @@
mQosCallbackTracker.unregisterCallback(callback);
}
+ // Network preference per-profile and OEM network preferences can't be set at the same
+ // time, because it is unclear what should happen if both preferences are active for
+ // one given UID. To make it possible, the stack would have to clarify what would happen
+ // in case both are active at the same time. The implementation may have to be adjusted
+ // to implement the resulting rules. For example, a priority could be defined between them,
+ // where the OEM preference would be considered less or more important than the enterprise
+ // preference ; this would entail implementing the priorities somehow, e.g. by doing
+ // UID arithmetic with UID ranges or passing a priority to netd so that the routing rules
+ // are set at the right level. Other solutions are possible, e.g. merging of the
+ // preferences for the relevant UIDs.
+ private static void throwConcurrentPreferenceException() {
+ throw new IllegalStateException("Can't set NetworkPreferenceForUser and "
+ + "set OemNetworkPreference at the same time");
+ }
+
+ /**
+ * Request that a user profile is put by default on a network matching a given preference.
+ *
+ * See the documentation for the individual preferences for a description of the supported
+ * behaviors.
+ *
+ * @param profile the profile concerned.
+ * @param preference the preference for this profile, as one of the PROFILE_NETWORK_PREFERENCE_*
+ * constants.
+ * @param listener an optional listener to listen for completion of the operation.
+ */
+ @Override
+ public void setProfileNetworkPreference(@NonNull final UserHandle profile,
+ @ConnectivityManager.ProfileNetworkPreference final int preference,
+ @Nullable final IOnCompleteListener listener) {
+ Objects.requireNonNull(profile);
+ PermissionUtils.enforceNetworkStackPermission(mContext);
+ if (DBG) {
+ log("setProfileNetworkPreference " + profile + " to " + preference);
+ }
+ if (profile.getIdentifier() < 0) {
+ throw new IllegalArgumentException("Must explicitly specify a user handle ("
+ + "UserHandle.CURRENT not supported)");
+ }
+ final UserManager um;
+ try {
+ um = mContext.createContextAsUser(profile, 0 /* flags */)
+ .getSystemService(UserManager.class);
+ } catch (IllegalStateException e) {
+ throw new IllegalArgumentException("Profile does not exist");
+ }
+ if (!um.isManagedProfile()) {
+ throw new IllegalArgumentException("Profile must be a managed profile");
+ }
+ // Strictly speaking, mOemNetworkPreferences should only be touched on the
+ // handler thread. However it is an immutable object, so reading the reference is
+ // safe - it's just possible the value is slightly outdated. For the final check,
+ // see #handleSetProfileNetworkPreference. But if this can be caught here it is a
+ // lot easier to understand, so opportunistically check it.
+ if (!mOemNetworkPreferences.isEmpty()) {
+ throwConcurrentPreferenceException();
+ }
+ final NetworkCapabilities nc;
+ switch (preference) {
+ case ConnectivityManager.PROFILE_NETWORK_PREFERENCE_DEFAULT:
+ nc = null;
+ break;
+ case ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE:
+ final UidRange uids = UidRange.createForUser(profile);
+ nc = createDefaultNetworkCapabilitiesForUidRange(uids);
+ nc.addCapability(NET_CAPABILITY_ENTERPRISE);
+ nc.removeCapability(NET_CAPABILITY_NOT_RESTRICTED);
+ break;
+ default:
+ throw new IllegalArgumentException(
+ "Invalid preference in setProfileNetworkPreference");
+ }
+ mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_PROFILE_NETWORK_PREFERENCE,
+ new Pair<>(new ProfileNetworkPreferences.Preference(profile, nc), listener)));
+ }
+
+ private void validateNetworkCapabilitiesOfProfileNetworkPreference(
+ @Nullable final NetworkCapabilities nc) {
+ if (null == nc) return; // Null caps are always allowed. It means to remove the setting.
+ ensureRequestableCapabilities(nc);
+ }
+
+ private ArraySet<NetworkRequestInfo> createNrisFromProfileNetworkPreferences(
+ @NonNull final ProfileNetworkPreferences prefs) {
+ final ArraySet<NetworkRequestInfo> result = new ArraySet<>();
+ for (final ProfileNetworkPreferences.Preference pref : prefs.preferences) {
+ // The NRI for a user should be comprised of two layers:
+ // - The request for the capabilities
+ // - The request for the default network, for fallback. Create an image of it to
+ // have the correct UIDs in it (also a request can only be part of one NRI, because
+ // of lookups in 1:1 associations like mNetworkRequests).
+ // Note that denying a fallback can be implemented simply by not adding the second
+ // request.
+ final ArrayList<NetworkRequest> nrs = new ArrayList<>();
+ nrs.add(createNetworkRequest(NetworkRequest.Type.REQUEST, pref.capabilities));
+ nrs.add(createDefaultRequest());
+ setNetworkRequestUids(nrs, UidRange.fromIntRanges(pref.capabilities.getUids()));
+ final NetworkRequestInfo nri = new NetworkRequestInfo(Process.myUid(), nrs);
+ result.add(nri);
+ }
+ return result;
+ }
+
+ private void handleSetProfileNetworkPreference(
+ @NonNull final ProfileNetworkPreferences.Preference preference,
+ @Nullable final IOnCompleteListener listener) {
+ // setProfileNetworkPreference and setOemNetworkPreference are mutually exclusive, in
+ // particular because it's not clear what preference should win in case both apply
+ // to the same app.
+ // The binder call has already checked this, but as mOemNetworkPreferences is only
+ // touched on the handler thread, it's theoretically not impossible that it has changed
+ // since.
+ if (!mOemNetworkPreferences.isEmpty()) {
+ // This may happen on a device with an OEM preference set when a user is removed.
+ // In this case, it's safe to ignore. In particular this happens in the tests.
+ loge("handleSetProfileNetworkPreference, but OEM network preferences not empty");
+ return;
+ }
+
+ validateNetworkCapabilitiesOfProfileNetworkPreference(preference.capabilities);
+
+ mProfileNetworkPreferences = mProfileNetworkPreferences.plus(preference);
+ final ArraySet<NetworkRequestInfo> nris =
+ createNrisFromProfileNetworkPreferences(mProfileNetworkPreferences);
+ replaceDefaultNetworkRequestsForPreference(nris);
+ // Finally, rematch.
+ rematchAllNetworksAndRequests();
+
+ if (null != listener) {
+ try {
+ listener.onComplete();
+ } catch (RemoteException e) {
+ loge("Listener for setProfileNetworkPreference has died");
+ }
+ }
+ }
+
private void enforceAutomotiveDevice() {
final boolean isAutomotiveDevice =
mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
@@ -9066,17 +9482,26 @@
* Calling this will overwrite the existing preference.
*
* @param preference {@link OemNetworkPreferences} The application network preference to be set.
- * @param listener {@link ConnectivityManager.OnSetOemNetworkPreferenceListener} Listener used
+ * @param listener {@link ConnectivityManager.OnCompleteListener} Listener used
* to communicate completion of setOemNetworkPreference();
*/
@Override
public void setOemNetworkPreference(
@NonNull final OemNetworkPreferences preference,
- @Nullable final IOnSetOemNetworkPreferenceListener listener) {
+ @Nullable final IOnCompleteListener listener) {
enforceAutomotiveDevice();
enforceOemNetworkPreferencesPermission();
+ if (!mProfileNetworkPreferences.isEmpty()) {
+ // Strictly speaking, mProfileNetworkPreferences should only be touched on the
+ // handler thread. However it is an immutable object, so reading the reference is
+ // safe - it's just possible the value is slightly outdated. For the final check,
+ // see #handleSetOemPreference. But if this can be caught here it is a
+ // lot easier to understand, so opportunistically check it.
+ throwConcurrentPreferenceException();
+ }
+
Objects.requireNonNull(preference, "OemNetworkPreferences must be non-null");
validateOemNetworkPreferences(preference);
mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_OEM_NETWORK_PREFERENCE,
@@ -9095,11 +9520,22 @@
private void handleSetOemNetworkPreference(
@NonNull final OemNetworkPreferences preference,
- @Nullable final IOnSetOemNetworkPreferenceListener listener) {
+ @Nullable final IOnCompleteListener listener) {
Objects.requireNonNull(preference, "OemNetworkPreferences must be non-null");
if (DBG) {
log("set OEM network preferences :" + preference.toString());
}
+ // setProfileNetworkPreference and setOemNetworkPreference are mutually exclusive, in
+ // particular because it's not clear what preference should win in case both apply
+ // to the same app.
+ // The binder call has already checked this, but as mOemNetworkPreferences is only
+ // touched on the handler thread, it's theoretically not impossible that it has changed
+ // since.
+ if (!mProfileNetworkPreferences.isEmpty()) {
+ logwtf("handleSetOemPreference, but per-profile network preferences not empty");
+ return;
+ }
+
final ArraySet<NetworkRequestInfo> nris =
new OemNetworkRequestFactory().createNrisFromOemNetworkPreferences(preference);
replaceDefaultNetworkRequestsForPreference(nris);
@@ -9159,7 +9595,7 @@
}
// Include this nri if it will be tracked by the new per-app default requests.
final boolean isNriGoingToBeTracked =
- getDefaultRequestTrackingUid(nri.mUid) != mDefaultRequest;
+ getDefaultRequestTrackingUid(nri.mAsUid) != mDefaultRequest;
if (isNriGoingToBeTracked) {
defaultCallbackRequests.add(nri);
}
@@ -9181,7 +9617,7 @@
final ArraySet<NetworkRequestInfo> callbackRequestsToRegister = new ArraySet<>();
for (final NetworkRequestInfo callbackRequest : perAppCallbackRequestsForUpdate) {
final NetworkRequestInfo trackingNri =
- getDefaultRequestTrackingUid(callbackRequest.mUid);
+ getDefaultRequestTrackingUid(callbackRequest.mAsUid);
// If this nri is not being tracked, the change it back to an untracked nri.
if (trackingNri == mDefaultRequest) {
@@ -9191,21 +9627,20 @@
continue;
}
- final String requestorPackageName =
- callbackRequest.mRequests.get(0).getRequestorPackageName();
+ final NetworkRequest request = callbackRequest.mRequests.get(0);
callbackRequestsToRegister.add(new NetworkRequestInfo(
callbackRequest,
copyNetworkRequestsForUid(
- trackingNri.mRequests, callbackRequest.mUid, requestorPackageName)));
+ trackingNri.mRequests, callbackRequest.mAsUid,
+ callbackRequest.mUid, request.getRequestorPackageName())));
}
return callbackRequestsToRegister;
}
private static void setNetworkRequestUids(@NonNull final List<NetworkRequest> requests,
@NonNull final Set<UidRange> uids) {
- final Set<UidRange> ranges = new ArraySet<>(uids);
for (final NetworkRequest req : requests) {
- req.networkCapabilities.setUids(ranges);
+ req.networkCapabilities.setUids(UidRange.toIntRanges(uids));
}
}
@@ -9301,7 +9736,7 @@
ranges.add(new UidRange(uid, uid));
}
setNetworkRequestUids(requests, ranges);
- return new NetworkRequestInfo(requests);
+ return new NetworkRequestInfo(Process.myUid(), requests);
}
private NetworkRequest createUnmeteredNetworkRequest() {
diff --git a/services/core/java/com/android/server/ConnectivityServiceInitializer.java b/services/core/java/com/android/server/ConnectivityServiceInitializer.java
index b992208..2465479 100644
--- a/services/core/java/com/android/server/ConnectivityServiceInitializer.java
+++ b/services/core/java/com/android/server/ConnectivityServiceInitializer.java
@@ -16,9 +16,6 @@
package com.android.server;
-import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_HIGH;
-import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
-
import android.content.Context;
import android.util.Log;
@@ -42,6 +39,6 @@
public void onStart() {
Log.i(TAG, "Registering " + Context.CONNECTIVITY_SERVICE);
publishBinderService(Context.CONNECTIVITY_SERVICE, mConnectivity,
- /* allowIsolated= */ false, DUMP_FLAG_PRIORITY_HIGH | DUMP_FLAG_PRIORITY_NORMAL);
+ /* allowIsolated= */ false);
}
}
diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
index 81d4b9d..794cb93 100644
--- a/services/core/java/com/android/server/IpSecService.java
+++ b/services/core/java/com/android/server/IpSecService.java
@@ -56,6 +56,7 @@
import android.system.OsConstants;
import android.text.TextUtils;
import android.util.Log;
+import android.util.Range;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
@@ -756,13 +757,9 @@
}
}
- // These values have been reserved in NetIdManager
- @VisibleForTesting static final int TUN_INTF_NETID_START = 0xFC00;
-
- public static final int TUN_INTF_NETID_RANGE = 0x0400;
-
private final SparseBooleanArray mTunnelNetIds = new SparseBooleanArray();
- private int mNextTunnelNetIdIndex = 0;
+ final Range<Integer> mNetIdRange = ConnectivityManager.getIpSecNetIdRange();
+ private int mNextTunnelNetId = mNetIdRange.getLower();
/**
* Reserves a netId within the range of netIds allocated for IPsec tunnel interfaces
@@ -775,11 +772,13 @@
*/
@VisibleForTesting
int reserveNetId() {
+ final int range = mNetIdRange.getUpper() - mNetIdRange.getLower() + 1;
synchronized (mTunnelNetIds) {
- for (int i = 0; i < TUN_INTF_NETID_RANGE; i++) {
- int index = mNextTunnelNetIdIndex;
- int netId = index + TUN_INTF_NETID_START;
- if (++mNextTunnelNetIdIndex >= TUN_INTF_NETID_RANGE) mNextTunnelNetIdIndex = 0;
+ for (int i = 0; i < range; i++) {
+ final int netId = mNextTunnelNetId;
+ if (++mNextTunnelNetId > mNetIdRange.getUpper()) {
+ mNextTunnelNetId = mNetIdRange.getLower();
+ }
if (!mTunnelNetIds.get(netId)) {
mTunnelNetIds.put(netId, true);
return netId;
@@ -1652,7 +1651,7 @@
c.getMode(),
c.getSourceAddress(),
c.getDestinationAddress(),
- (c.getNetwork() != null) ? c.getNetwork().netId : 0,
+ (c.getNetwork() != null) ? c.getNetwork().getNetId() : 0,
spiRecord.getSpi(),
c.getMarkValue(),
c.getMarkMask(),
diff --git a/services/core/java/com/android/server/NetIdManager.java b/services/core/java/com/android/server/NetIdManager.java
index 097fb3a..61925c8 100644
--- a/services/core/java/com/android/server/NetIdManager.java
+++ b/services/core/java/com/android/server/NetIdManager.java
@@ -17,6 +17,7 @@
package com.android.server;
import android.annotation.NonNull;
+import android.net.ConnectivityManager;
import android.util.SparseBooleanArray;
import com.android.internal.annotations.GuardedBy;
@@ -31,7 +32,7 @@
// Sequence number for Networks; keep in sync with system/netd/NetworkController.cpp
public static final int MIN_NET_ID = 100; // some reserved marks
// Top IDs reserved by IpSecService
- public static final int MAX_NET_ID = 65535 - IpSecService.TUN_INTF_NETID_RANGE;
+ public static final int MAX_NET_ID = ConnectivityManager.getIpSecNetIdRange().getLower() - 1;
@GuardedBy("mNetIdInUse")
private final SparseBooleanArray mNetIdInUse = new SparseBooleanArray();
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 10d6570..3ea0ce1 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -643,7 +643,7 @@
String route, String gateway, String ifName) throws RemoteException {
final RouteInfo processRoute = new RouteInfo(new IpPrefix(route),
("".equals(gateway)) ? null : InetAddresses.parseNumericAddress(gateway),
- ifName);
+ ifName, RouteInfo.RTN_UNICAST);
mDaemonHandler.post(() -> notifyRouteChange(updated, processRoute));
}
diff --git a/services/core/java/com/android/server/OWNERS b/services/core/java/com/android/server/OWNERS
index 222c96f..3bcde12 100644
--- a/services/core/java/com/android/server/OWNERS
+++ b/services/core/java/com/android/server/OWNERS
@@ -19,6 +19,7 @@
per-file *Alarm* = file:/apex/jobscheduler/OWNERS
per-file *AppOp* = file:/core/java/android/permission/OWNERS
+per-file *Battery* = file:/BATTERY_STATS_OWNERS
per-file *Bluetooth* = file:/core/java/android/bluetooth/OWNERS
per-file *Gnss* = file:/services/core/java/com/android/server/location/OWNERS
per-file *Location* = file:/services/core/java/com/android/server/location/OWNERS
diff --git a/services/core/java/com/android/server/PersistentDataBlockService.java b/services/core/java/com/android/server/PersistentDataBlockService.java
index 00d8b0f..351e616 100644
--- a/services/core/java/com/android/server/PersistentDataBlockService.java
+++ b/services/core/java/com/android/server/PersistentDataBlockService.java
@@ -23,6 +23,7 @@
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Binder;
+import android.os.FileUtils;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.SystemProperties;
@@ -103,6 +104,9 @@
public class PersistentDataBlockService extends SystemService {
private static final String TAG = PersistentDataBlockService.class.getSimpleName();
+ private static final String GSI_SANDBOX = "/data/gsi_persistent_data";
+ private static final String GSI_RUNNING_PROP = "ro.gsid.image_running";
+
private static final String PERSISTENT_DATA_BLOCK_PROP = "ro.frp.pst";
private static final int HEADER_SIZE = 8;
// Magic number to mark block device as adhering to the format consumed by this service
@@ -127,12 +131,13 @@
private static final String FLASH_LOCK_UNLOCKED = "0";
private final Context mContext;
- private final String mDataBlockFile;
+ private final boolean mIsRunningDSU;
private final Object mLock = new Object();
private final CountDownLatch mInitDoneSignal = new CountDownLatch(1);
private int mAllowedUid = -1;
private long mBlockDeviceSize;
+ private String mDataBlockFile;
@GuardedBy("mLock")
private boolean mIsWritable = true;
@@ -141,6 +146,7 @@
super(context);
mContext = context;
mDataBlockFile = SystemProperties.get(PERSISTENT_DATA_BLOCK_PROP);
+ mIsRunningDSU = SystemProperties.getBoolean(GSI_RUNNING_PROP, false);
mBlockDeviceSize = -1; // Load lazily
}
@@ -284,14 +290,28 @@
return true;
}
+ private FileOutputStream getBlockOutputStream() throws IOException {
+ if (!mIsRunningDSU) {
+ return new FileOutputStream(new File(mDataBlockFile));
+ } else {
+ File sandbox = new File(GSI_SANDBOX);
+ File realpdb = new File(SystemProperties.get(PERSISTENT_DATA_BLOCK_PROP));
+ if (!sandbox.exists()) {
+ FileUtils.copy(realpdb, sandbox);
+ mDataBlockFile = GSI_SANDBOX;
+ }
+ Slog.i(TAG, "PersistentDataBlock copy-on-write");
+ return new FileOutputStream(sandbox);
+ }
+ }
+
private boolean computeAndWriteDigestLocked() {
byte[] digest = computeDigestLocked(null);
if (digest != null) {
DataOutputStream outputStream;
try {
- outputStream = new DataOutputStream(
- new FileOutputStream(new File(mDataBlockFile)));
- } catch (FileNotFoundException e) {
+ outputStream = new DataOutputStream(getBlockOutputStream());
+ } catch (IOException e) {
Slog.e(TAG, "partition not available?", e);
return false;
}
@@ -356,8 +376,8 @@
private void formatPartitionLocked(boolean setOemUnlockEnabled) {
DataOutputStream outputStream;
try {
- outputStream = new DataOutputStream(new FileOutputStream(new File(mDataBlockFile)));
- } catch (FileNotFoundException e) {
+ outputStream = new DataOutputStream(getBlockOutputStream());
+ } catch (IOException e) {
Slog.e(TAG, "partition not available?", e);
return;
}
@@ -382,8 +402,8 @@
private void doSetOemUnlockEnabledLocked(boolean enabled) {
FileOutputStream outputStream;
try {
- outputStream = new FileOutputStream(new File(mDataBlockFile));
- } catch (FileNotFoundException e) {
+ outputStream = getBlockOutputStream();
+ } catch (IOException e) {
Slog.e(TAG, "partition not available", e);
return;
}
@@ -459,8 +479,8 @@
DataOutputStream outputStream;
try {
- outputStream = new DataOutputStream(new FileOutputStream(new File(mDataBlockFile)));
- } catch (FileNotFoundException e) {
+ outputStream = new DataOutputStream(getBlockOutputStream());
+ } catch (IOException e) {
Slog.e(TAG, "partition not available?", e);
return -1;
}
@@ -545,6 +565,17 @@
public void wipe() {
enforceOemUnlockWritePermission();
+ if (mIsRunningDSU) {
+ File sandbox = new File(GSI_SANDBOX);
+ if (sandbox.exists()) {
+ if (sandbox.delete()) {
+ mDataBlockFile = SystemProperties.get(PERSISTENT_DATA_BLOCK_PROP);
+ } else {
+ Slog.e(TAG, "Failed to wipe sandbox persistent data block");
+ }
+ }
+ return;
+ }
synchronized (mLock) {
int ret = nativeWipe(mDataBlockFile);
@@ -704,8 +735,8 @@
private void writeDataBuffer(long offset, ByteBuffer dataBuffer) {
FileOutputStream outputStream;
try {
- outputStream = new FileOutputStream(new File(mDataBlockFile));
- } catch (FileNotFoundException e) {
+ outputStream = getBlockOutputStream();
+ } catch (IOException e) {
Slog.e(TAG, "partition not available", e);
return;
}
diff --git a/services/core/java/com/android/server/PinnerService.java b/services/core/java/com/android/server/PinnerService.java
index 3148a62..1241b7779 100644
--- a/services/core/java/com/android/server/PinnerService.java
+++ b/services/core/java/com/android/server/PinnerService.java
@@ -270,18 +270,9 @@
* Handler for on start pinning message
*/
private void handlePinOnStart() {
- final String bootImage = SystemProperties.get("dalvik.vm.boot-image", "");
- String[] filesToPin = null;
- if (bootImage.endsWith("boot-image.prof")) {
- // Use the files listed for that specific boot image.
- // TODO: find a better way to know we're using the JIT zygote configuration.
- filesToPin = mContext.getResources().getStringArray(
- com.android.internal.R.array.config_jitzygoteBootImagePinnerServiceFiles);
- } else {
- // Files to pin come from the overlay and can be specified per-device config
- filesToPin = mContext.getResources().getStringArray(
- com.android.internal.R.array.config_defaultPinnerServiceFiles);
- }
+ // Files to pin come from the overlay and can be specified per-device config
+ String[] filesToPin = mContext.getResources().getStringArray(
+ com.android.internal.R.array.config_defaultPinnerServiceFiles);
// Continue trying to pin each file even if we fail to pin some of them
for (String fileToPin : filesToPin) {
PinnedFile pf = pinFile(fileToPin,
@@ -291,10 +282,32 @@
Slog.e(TAG, "Failed to pin file = " + fileToPin);
continue;
}
-
synchronized (this) {
mPinnedFiles.add(pf);
}
+ if (fileToPin.endsWith(".jar") | fileToPin.endsWith(".apk")) {
+ // Check whether the runtime has compilation artifacts to pin.
+ String arch = VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]);
+ String[] files = null;
+ try {
+ files = DexFile.getDexFileOutputPaths(fileToPin, arch);
+ } catch (IOException ioe) { }
+ if (files == null) {
+ continue;
+ }
+ for (String file : files) {
+ PinnedFile df = pinFile(file,
+ Integer.MAX_VALUE,
+ /*attemptPinIntrospection=*/false);
+ if (df == null) {
+ Slog.i(TAG, "Failed to pin ART file = " + file);
+ continue;
+ }
+ synchronized (this) {
+ mPinnedFiles.add(df);
+ }
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index dce919d..a95589b 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -60,6 +60,7 @@
import android.telephony.CellSignalStrengthTdscdma;
import android.telephony.CellSignalStrengthWcdma;
import android.telephony.DisconnectCause;
+import android.telephony.LinkCapacityEstimate;
import android.telephony.LocationAccessPolicy;
import android.telephony.PhoneCapability;
import android.telephony.PhoneStateListener;
@@ -318,7 +319,10 @@
private int[] mDataEnabledReason;
- private Map<Integer, Long> mAllowedNetworkTypesList;
+ private int[] mAllowedNetworkTypeReason;
+ private long[] mAllowedNetworkTypeValue;
+
+ private List<List<LinkCapacityEstimate>> mLinkCapacityEstimateLists;
/**
* Per-phone map of precise data connection state. The key of the map is the pair of transport
@@ -350,6 +354,8 @@
TelephonyCallback.EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED);
REQUIRE_PRECISE_PHONE_STATE_PERMISSION.add(
TelephonyCallback.EVENT_DATA_ENABLED_CHANGED);
+ REQUIRE_PRECISE_PHONE_STATE_PERMISSION.add(
+ TelephonyCallback.EVENT_LINK_CAPACITY_ESTIMATE_CHANGED);
}
private boolean isLocationPermissionRequired(Set<Integer> events) {
@@ -383,7 +389,8 @@
private boolean isPrivilegedPhoneStatePermissionRequired(Set<Integer> events) {
return events.contains(TelephonyCallback.EVENT_SRVCC_STATE_CHANGED)
|| events.contains(TelephonyCallback.EVENT_VOICE_ACTIVATION_STATE_CHANGED)
- || events.contains(TelephonyCallback.EVENT_RADIO_POWER_STATE_CHANGED);
+ || events.contains(TelephonyCallback.EVENT_RADIO_POWER_STATE_CHANGED)
+ || events.contains(TelephonyCallback.EVENT_ALLOWED_NETWORK_TYPE_LIST_CHANGED);
}
private static final int MSG_USER_SWITCHED = 1;
@@ -527,6 +534,8 @@
mTelephonyDisplayInfos = copyOf(mTelephonyDisplayInfos, mNumPhones);
mIsDataEnabled= copyOf(mIsDataEnabled, mNumPhones);
mDataEnabledReason = copyOf(mDataEnabledReason, mNumPhones);
+ mAllowedNetworkTypeReason = copyOf(mAllowedNetworkTypeReason, mNumPhones);
+ mAllowedNetworkTypeValue = copyOf(mAllowedNetworkTypeValue, mNumPhones);
// ds -> ss switch.
if (mNumPhones < oldNumPhones) {
@@ -535,6 +544,7 @@
cutListToSize(mPreciseDataConnectionStates, mNumPhones);
cutListToSize(mBarringInfo, mNumPhones);
cutListToSize(mPhysicalChannelConfigs, mNumPhones);
+ cutListToSize(mLinkCapacityEstimateLists, mNumPhones);
return;
}
@@ -571,6 +581,9 @@
mPhysicalChannelConfigs.add(i, new PhysicalChannelConfig.Builder().build());
mIsDataEnabled[i] = false;
mDataEnabledReason[i] = TelephonyManager.DATA_ENABLED_REASON_USER;
+ mAllowedNetworkTypeReason[i] = -1;
+ mAllowedNetworkTypeValue[i] = -1;
+ mLinkCapacityEstimateLists.add(i, new ArrayList<>());
}
}
@@ -630,9 +643,12 @@
mBarringInfo = new ArrayList<>();
mTelephonyDisplayInfos = new TelephonyDisplayInfo[numPhones];
mPhysicalChannelConfigs = new ArrayList<>();
+ mAllowedNetworkTypeReason = new int[numPhones];
+ mAllowedNetworkTypeValue = new long[numPhones];
mIsDataEnabled = new boolean[numPhones];
mDataEnabledReason = new int[numPhones];
- mAllowedNetworkTypesList = new HashMap<>();
+ mLinkCapacityEstimateLists = new ArrayList<>();
+
for (int i = 0; i < numPhones; i++) {
mCallState[i] = TelephonyManager.CALL_STATE_IDLE;
mDataActivity[i] = TelephonyManager.DATA_ACTIVITY_NONE;
@@ -665,6 +681,9 @@
mPhysicalChannelConfigs.add(i, new PhysicalChannelConfig.Builder().build());
mIsDataEnabled[i] = false;
mDataEnabledReason[i] = TelephonyManager.DATA_ENABLED_REASON_USER;
+ mAllowedNetworkTypeReason[i] = -1;
+ mAllowedNetworkTypeValue[i] = -1;
+ mLinkCapacityEstimateLists.add(i, new ArrayList<>());
}
mAppOps = mContext.getSystemService(AppOpsManager.class);
@@ -1151,7 +1170,9 @@
TelephonyCallback.EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED)) {
try {
r.callback.onPhysicalChannelConfigChanged(
- mPhysicalChannelConfigs);
+ shouldSanitizeLocationForPhysicalChannelConfig(r)
+ ? getLocationSanitizedConfigs(mPhysicalChannelConfigs)
+ : mPhysicalChannelConfigs);
} catch (RemoteException ex) {
remove(r.binder);
}
@@ -1166,9 +1187,12 @@
}
}
if (events.contains(
- TelephonyCallback.EVENT_ALLOWED_NETWORK_TYPE_LIST_CHANGED)) {
+ TelephonyCallback.EVENT_LINK_CAPACITY_ESTIMATE_CHANGED)) {
try {
- r.callback.onAllowedNetworkTypesChanged(mAllowedNetworkTypesList);
+ if (mLinkCapacityEstimateLists.get(phoneId) != null) {
+ r.callback.onLinkCapacityEstimateChanged(mLinkCapacityEstimateLists
+ .get(phoneId));
+ }
} catch (RemoteException ex) {
remove(r.binder);
}
@@ -2349,8 +2373,10 @@
return;
}
+ List<PhysicalChannelConfig> sanitizedConfigs = getLocationSanitizedConfigs(configs);
if (VDBG) {
- log("notifyPhysicalChannelConfig: subId=" + subId + " configs=" + configs);
+ log("notifyPhysicalChannelConfig: subId=" + subId + " configs=" + configs
+ + " sanitizedConfigs=" + sanitizedConfigs);
}
synchronized (mRecords) {
@@ -2363,11 +2389,14 @@
&& idMatch(r.subId, subId, phoneId)) {
try {
if (DBG_LOC) {
- log("notifyPhysicalChannelConfig: "
- + "mPhysicalChannelConfigs="
- + configs + " r=" + r);
+ log("notifyPhysicalChannelConfig: mPhysicalChannelConfigs="
+ + (shouldSanitizeLocationForPhysicalChannelConfig(r)
+ ? sanitizedConfigs : configs)
+ + " r=" + r);
}
- r.callback.onPhysicalChannelConfigChanged(configs);
+ r.callback.onPhysicalChannelConfigChanged(
+ shouldSanitizeLocationForPhysicalChannelConfig(r)
+ ? sanitizedConfigs : configs);
} catch (RemoteException ex) {
mRemoveList.add(r.binder);
}
@@ -2378,6 +2407,25 @@
}
}
+ private static boolean shouldSanitizeLocationForPhysicalChannelConfig(Record record) {
+ // Always redact location info from PhysicalChannelConfig if the registrant is from neither
+ // PHONE nor SYSTEM process. There is no user case that the registrant needs the location
+ // info (e.g. physicalCellId). This also remove the need for the location permissions check.
+ return record.callerUid != Process.PHONE_UID && record.callerUid != Process.SYSTEM_UID;
+ }
+
+ /**
+ * Return a copy of the PhysicalChannelConfig list but with location info removed.
+ */
+ private static List<PhysicalChannelConfig> getLocationSanitizedConfigs(
+ List<PhysicalChannelConfig> configs) {
+ List<PhysicalChannelConfig> sanitizedConfigs = new ArrayList<>(configs.size());
+ for (PhysicalChannelConfig config : configs) {
+ sanitizedConfigs.add(config.createLocationInfoSanitizedCopy());
+ }
+ return sanitizedConfigs;
+ }
+
/**
* Notify that the data enabled has changed.
*
@@ -2423,18 +2471,19 @@
*
* @param phoneId the phone id.
* @param subId the subId.
- * @param allowedNetworkTypesList Map associating all allowed network type reasons with reason's
- * allowed network type values.
+ * @param reason the allowed network type reason.
+ * @param allowedNetworkType the allowed network type value.
*/
- public void notifyAllowedNetworkTypesChanged(int phoneId, int subId,
- Map allowedNetworkTypesList) {
+ public void notifyAllowedNetworkTypesChanged(int phoneId, int subId, int reason,
+ long allowedNetworkType) {
if (!checkNotifyPermission("notifyAllowedNetworkTypesChanged()")) {
return;
}
synchronized (mRecords) {
if (validatePhoneId(phoneId)) {
- mAllowedNetworkTypesList = allowedNetworkTypesList;
+ mAllowedNetworkTypeReason[phoneId] = reason;
+ mAllowedNetworkTypeValue[phoneId] = allowedNetworkType;
for (Record r : mRecords) {
if (r.matchTelephonyCallbackEvent(
@@ -2442,10 +2491,48 @@
&& idMatch(r.subId, subId, phoneId)) {
try {
if (VDBG) {
- log("notifyAllowedNetworkTypesChanged: AllowedNetworkTypesList= "
- + mAllowedNetworkTypesList.toString());
+ log("notifyAllowedNetworkTypesChanged: reason= " + reason
+ + ", allowed network type:"
+ + TelephonyManager.convertNetworkTypeBitmaskToString(
+ allowedNetworkType));
}
- r.callback.onAllowedNetworkTypesChanged(mAllowedNetworkTypesList);
+ r.callback.onAllowedNetworkTypesChanged(reason, allowedNetworkType);
+ } catch (RemoteException ex) {
+ mRemoveList.add(r.binder);
+ }
+ }
+ }
+ }
+ handleRemoveListLocked();
+ }
+ }
+
+ /**
+ * Notify that the link capacity estimate has changed.
+ * @param phoneId the phone id.
+ * @param subId the subscription id.
+ * @param linkCapacityEstimateList a list of {@link LinkCapacityEstimate}
+ */
+ public void notifyLinkCapacityEstimateChanged(int phoneId, int subId,
+ List<LinkCapacityEstimate> linkCapacityEstimateList) {
+ if (!checkNotifyPermission("notifyLinkCapacityEstimateChanged()")) {
+ return;
+ }
+
+ if (VDBG) {
+ log("notifyLinkCapacityEstimateChanged: linkCapacityEstimateList ="
+ + linkCapacityEstimateList);
+ }
+
+ synchronized (mRecords) {
+ if (validatePhoneId(phoneId)) {
+ mLinkCapacityEstimateLists.set(phoneId, linkCapacityEstimateList);
+ for (Record r : mRecords) {
+ if (r.matchTelephonyCallbackEvent(
+ TelephonyCallback.EVENT_LINK_CAPACITY_ESTIMATE_CHANGED)
+ && idMatch(r.subId, subId, phoneId)) {
+ try {
+ r.callback.onLinkCapacityEstimateChanged(linkCapacityEstimateList);
} catch (RemoteException ex) {
mRemoveList.add(r.binder);
}
@@ -2500,6 +2587,9 @@
pw.println("mTelephonyDisplayInfo=" + mTelephonyDisplayInfos[i]);
pw.println("mIsDataEnabled=" + mIsDataEnabled);
pw.println("mDataEnabledReason=" + mDataEnabledReason);
+ pw.println("mAllowedNetworkTypeReason=" + mAllowedNetworkTypeReason[i]);
+ pw.println("mAllowedNetworkTypeValue=" + mAllowedNetworkTypeValue[i]);
+ pw.println("mLinkCapacityEstimateList=" + mLinkCapacityEstimateLists.get(i));
pw.decreaseIndent();
}
pw.println("mCarrierNetworkChangeState=" + mCarrierNetworkChangeState);
@@ -2764,6 +2854,7 @@
LocationAccessPolicy.LocationPermissionQuery.Builder locationQueryBuilder =
new LocationAccessPolicy.LocationPermissionQuery.Builder()
.setCallingPackage(callingPackage)
+ .setCallingFeatureId(callingFeatureId)
.setMethod(message + " events: " + events)
.setCallingPid(Binder.getCallingPid())
.setCallingUid(Binder.getCallingUid());
@@ -2913,6 +3004,7 @@
LocationAccessPolicy.LocationPermissionQuery query =
new LocationAccessPolicy.LocationPermissionQuery.Builder()
.setCallingPackage(r.callingPackage)
+ .setCallingFeatureId(r.callingFeatureId)
.setCallingPid(r.callerPid)
.setCallingUid(r.callerUid)
.setMethod("TelephonyRegistry push")
@@ -2936,6 +3028,7 @@
LocationAccessPolicy.LocationPermissionQuery query =
new LocationAccessPolicy.LocationPermissionQuery.Builder()
.setCallingPackage(r.callingPackage)
+ .setCallingFeatureId(r.callingFeatureId)
.setCallingPid(r.callerPid)
.setCallingUid(r.callerUid)
.setMethod("TelephonyRegistry push")
diff --git a/services/core/java/com/android/server/TestNetworkService.java b/services/core/java/com/android/server/TestNetworkService.java
index 55408ea..f566277 100644
--- a/services/core/java/com/android/server/TestNetworkService.java
+++ b/services/core/java/com/android/server/TestNetworkService.java
@@ -33,8 +33,8 @@
import android.net.NetworkCapabilities;
import android.net.NetworkProvider;
import android.net.RouteInfo;
-import android.net.StringNetworkSpecifier;
import android.net.TestNetworkInterface;
+import android.net.TestNetworkSpecifier;
import android.net.util.NetdService;
import android.os.Binder;
import android.os.Handler;
@@ -90,7 +90,12 @@
mCm = mContext.getSystemService(ConnectivityManager.class);
mNetworkProvider = new NetworkProvider(mContext, mHandler.getLooper(),
TEST_NETWORK_PROVIDER_NAME);
- mCm.registerNetworkProvider(mNetworkProvider);
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mCm.registerNetworkProvider(mNetworkProvider);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
/**
@@ -242,7 +247,7 @@
nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED);
nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED);
- nc.setNetworkSpecifier(new StringNetworkSpecifier(iface));
+ nc.setNetworkSpecifier(new TestNetworkSpecifier(iface));
nc.setAdministratorUids(administratorUids);
if (!isMetered) {
nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java
index 502e74a..4622e98 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -29,7 +29,10 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AppOpsManager;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.LinkProperties;
import android.net.NetworkCapabilities;
@@ -64,7 +67,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting.Visibility;
-import com.android.internal.util.LocationPermissionChecker;
+import com.android.net.module.util.LocationPermissionChecker;
import com.android.server.vcn.TelephonySubscriptionTracker;
import com.android.server.vcn.Vcn;
import com.android.server.vcn.VcnContext;
@@ -158,6 +161,7 @@
@NonNull private final TelephonySubscriptionTrackerCallback mTelephonySubscriptionTrackerCb;
@NonNull private final TelephonySubscriptionTracker mTelephonySubscriptionTracker;
@NonNull private final VcnContext mVcnContext;
+ @NonNull private final BroadcastReceiver mPkgChangeReceiver;
/** Can only be assigned when {@link #systemReady()} is called, since it uses AppOpsManager. */
@Nullable private LocationPermissionChecker mLocationPermissionChecker;
@@ -203,6 +207,29 @@
mConfigDiskRwHelper = mDeps.newPersistableBundleLockingReadWriteHelper(VCN_CONFIG_FILE);
mVcnContext = mDeps.newVcnContext(mContext, mLooper, mNetworkProvider);
+ mPkgChangeReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+
+ if (Intent.ACTION_PACKAGE_ADDED.equals(action)
+ || Intent.ACTION_PACKAGE_REPLACED.equals(action)
+ || Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
+ mTelephonySubscriptionTracker.handleSubscriptionsChanged();
+ } else {
+ Log.wtf(TAG, "received unexpected intent: " + action);
+ }
+ }
+ };
+
+ final IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
+ intentFilter.addAction(Intent.ACTION_PACKAGE_REPLACED);
+ intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ intentFilter.addDataScheme("package");
+ mContext.registerReceiver(
+ mPkgChangeReceiver, intentFilter, null /* broadcastPermission */, mHandler);
+
// Run on handler to ensure I/O does not block system server startup
mHandler.post(() -> {
PersistableBundle configBundle = null;
@@ -349,7 +376,8 @@
}
}
- private void enforceCallingUserAndCarrierPrivilege(ParcelUuid subscriptionGroup) {
+ private void enforceCallingUserAndCarrierPrivilege(
+ ParcelUuid subscriptionGroup, String pkgName) {
// Only apps running in the primary (system) user are allowed to configure the VCN. This is
// in line with Telephony's behavior with regards to binding to a Carrier App provided
// CarrierConfigService.
@@ -363,12 +391,15 @@
subscriptionInfos.addAll(subMgr.getSubscriptionsInGroup(subscriptionGroup));
});
- final TelephonyManager telMgr = mContext.getSystemService(TelephonyManager.class);
for (SubscriptionInfo info : subscriptionInfos) {
+ final TelephonyManager telMgr = mContext.getSystemService(TelephonyManager.class)
+ .createForSubscriptionId(info.getSubscriptionId());
+
// Check subscription is active first; much cheaper/faster check, and an app (currently)
// cannot be carrier privileged for inactive subscriptions.
if (subMgr.isValidSlotIndex(info.getSimSlotIndex())
- && telMgr.hasCarrierPrivileges(info.getSubscriptionId())) {
+ && telMgr.checkCarrierPrivilegesForPackage(pkgName)
+ == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
// TODO (b/173717728): Allow configuration for inactive, but manageable
// subscriptions.
// TODO (b/173718661): Check for whole subscription groups at a time.
@@ -536,7 +567,7 @@
mContext.getSystemService(AppOpsManager.class)
.checkPackage(mDeps.getBinderCallingUid(), config.getProvisioningPackageName());
- enforceCallingUserAndCarrierPrivilege(subscriptionGroup);
+ enforceCallingUserAndCarrierPrivilege(subscriptionGroup, opPkgName);
Binder.withCleanCallingIdentity(() -> {
synchronized (mLock) {
@@ -554,11 +585,14 @@
* <p>Implements the IVcnManagementService Binder interface.
*/
@Override
- public void clearVcnConfig(@NonNull ParcelUuid subscriptionGroup) {
+ public void clearVcnConfig(@NonNull ParcelUuid subscriptionGroup, @NonNull String opPkgName) {
requireNonNull(subscriptionGroup, "subscriptionGroup was null");
+ requireNonNull(opPkgName, "opPkgName was null");
Slog.v(TAG, "VCN config cleared for subGrp: " + subscriptionGroup);
- enforceCallingUserAndCarrierPrivilege(subscriptionGroup);
+ mContext.getSystemService(AppOpsManager.class)
+ .checkPackage(mDeps.getBinderCallingUid(), opPkgName);
+ enforceCallingUserAndCarrierPrivilege(subscriptionGroup, opPkgName);
Binder.withCleanCallingIdentity(() -> {
synchronized (mLock) {
@@ -667,6 +701,10 @@
@NonNull IVcnUnderlyingNetworkPolicyListener listener) {
requireNonNull(listener, "listener was null");
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.NETWORK_FACTORY,
+ "Must have permission NETWORK_FACTORY to unregister a policy listener");
+
Binder.withCleanCallingIdentity(() -> {
synchronized (mLock) {
PolicyListenerBinderDeath listenerBinderDeath =
@@ -817,8 +855,7 @@
final IBinder cbBinder = callback.asBinder();
final VcnStatusCallbackInfo cbInfo =
- new VcnStatusCallbackInfo(
- subGroup, callback, opPkgName, mDeps.getBinderCallingUid());
+ new VcnStatusCallbackInfo(subGroup, callback, opPkgName, callingUid);
try {
cbBinder.linkToDeath(cbInfo, 0 /* flags */);
diff --git a/services/core/java/com/android/server/VpnManagerService.java b/services/core/java/com/android/server/VpnManagerService.java
index 56aabc20..d756c1f 100644
--- a/services/core/java/com/android/server/VpnManagerService.java
+++ b/services/core/java/com/android/server/VpnManagerService.java
@@ -352,7 +352,10 @@
@Override
public void startLegacyVpn(VpnProfile profile) {
int user = UserHandle.getUserId(mDeps.getCallingUid());
- final LinkProperties egress = mCm.getActiveLinkProperties();
+ // Note that if the caller is not system (uid >= Process.FIRST_APPLICATION_UID),
+ // the code might not work well since getActiveNetwork might return null if the uid is
+ // blocked by NetworkPolicyManagerService.
+ final LinkProperties egress = mCm.getLinkProperties(mCm.getActiveNetwork());
if (egress == null) {
throw new IllegalStateException("Missing active network connection");
}
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index a847847..a37115d 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -75,7 +75,8 @@
// can trigger the watchdog.
// Note 2: The debug value is already below the wait time in ZygoteConnection. Wrapped
// applications may not work with a debug build. CTS will fail.
- private static final long DEFAULT_TIMEOUT = DB ? 10 * 1000 : 60 * 1000;
+ private static final long DEFAULT_TIMEOUT =
+ (DB ? 10 * 1000 : 60 * 1000) * Build.HW_TIMEOUT_MULTIPLIER;
private static final long CHECK_INTERVAL = DEFAULT_TIMEOUT / 2;
// These are temporally ordered: larger values as lateness increases
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index dd0e1f6..ca4b9c3 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -140,14 +140,14 @@
private static final int DEBUG_FGS_ENFORCE_TYPE = 1;
// How long we wait for a service to finish executing.
- static final int SERVICE_TIMEOUT = 20*1000;
+ static final int SERVICE_TIMEOUT = 20 * 1000 * Build.HW_TIMEOUT_MULTIPLIER;
// How long we wait for a service to finish executing.
static final int SERVICE_BACKGROUND_TIMEOUT = SERVICE_TIMEOUT * 10;
// How long the startForegroundService() grace period is to get around to
// calling startForeground() before we ANR + stop it.
- static final int SERVICE_START_FOREGROUND_TIMEOUT = 10*1000;
+ static final int SERVICE_START_FOREGROUND_TIMEOUT = 10 * 1000 * Build.HW_TIMEOUT_MULTIPLIER;
final ActivityManagerService mAm;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index bd08b62..cc5a25a 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -478,7 +478,7 @@
// How long we wait for a launched process to attach to the activity manager
// before we decide it's never going to come up for real.
- static final int PROC_START_TIMEOUT = 10*1000;
+ static final int PROC_START_TIMEOUT = 10 * 1000 * Build.HW_TIMEOUT_MULTIPLIER;
// How long we wait to kill an application zygote, after the last process using
// it has gone away.
static final int KILL_APP_ZYGOTE_DELAY_MS = 5 * 1000;
@@ -490,8 +490,8 @@
static final int PROC_START_TIMEOUT_WITH_WRAPPER = 1200*1000;
// How long we allow a receiver to run before giving up on it.
- static final int BROADCAST_FG_TIMEOUT = 10*1000;
- static final int BROADCAST_BG_TIMEOUT = 60*1000;
+ static final int BROADCAST_FG_TIMEOUT = 10 * 1000 * Build.HW_TIMEOUT_MULTIPLIER;
+ static final int BROADCAST_BG_TIMEOUT = 60 * 1000 * Build.HW_TIMEOUT_MULTIPLIER;
public static final int MY_PID = myPid();
@@ -573,7 +573,8 @@
private static final int MAX_BUGREPORT_TITLE_SIZE = 50;
private static final int MAX_BUGREPORT_DESCRIPTION_SIZE = 150;
- private static final int NATIVE_DUMP_TIMEOUT_MS = 2000; // 2 seconds;
+ private static final int NATIVE_DUMP_TIMEOUT_MS =
+ 2000 * Build.HW_TIMEOUT_MULTIPLIER; // 2 seconds;
private static final int JAVA_DUMP_MINIMUM_SIZE = 100; // 100 bytes.
OomAdjuster mOomAdjuster;
diff --git a/services/core/java/com/android/server/am/BroadcastConstants.java b/services/core/java/com/android/server/am/BroadcastConstants.java
index be17b1b..54b3e64 100644
--- a/services/core/java/com/android/server/am/BroadcastConstants.java
+++ b/services/core/java/com/android/server/am/BroadcastConstants.java
@@ -18,6 +18,7 @@
import android.content.ContentResolver;
import android.database.ContentObserver;
+import android.os.Build;
import android.os.Handler;
import android.provider.Settings;
import android.util.KeyValueListParser;
@@ -42,12 +43,13 @@
"bcast_allow_bg_activity_start_timeout";
// All time intervals are in milliseconds
- private static final long DEFAULT_TIMEOUT = 10_000;
- private static final long DEFAULT_SLOW_TIME = 5_000;
- private static final long DEFAULT_DEFERRAL = 5_000;
+ private static final long DEFAULT_TIMEOUT = 10_000 * Build.HW_TIMEOUT_MULTIPLIER;
+ private static final long DEFAULT_SLOW_TIME = 5_000 * Build.HW_TIMEOUT_MULTIPLIER;
+ private static final long DEFAULT_DEFERRAL = 5_000 * Build.HW_TIMEOUT_MULTIPLIER;
private static final float DEFAULT_DEFERRAL_DECAY_FACTOR = 0.75f;
private static final long DEFAULT_DEFERRAL_FLOOR = 0;
- private static final long DEFAULT_ALLOW_BG_ACTIVITY_START_TIMEOUT = 10_000;
+ private static final long DEFAULT_ALLOW_BG_ACTIVITY_START_TIMEOUT =
+ 10_000 * Build.HW_TIMEOUT_MULTIPLIER;
// All time constants are in milliseconds
diff --git a/services/core/java/com/android/server/am/OWNERS b/services/core/java/com/android/server/am/OWNERS
index 1c38c86..90d9409 100644
--- a/services/core/java/com/android/server/am/OWNERS
+++ b/services/core/java/com/android/server/am/OWNERS
@@ -30,6 +30,10 @@
michaelwr@google.com
narayan@google.com
+# Voice Interaction
+per-file *Assist* = file:/core/java/android/service/voice/OWNERS
+per-file *Voice* = file:/core/java/android/service/voice/OWNERS
+
per-file SettingsToPropertiesMapper.java = omakoto@google.com, svetoslavganov@google.com, yamasani@google.com
per-file CarUserSwitchingDialog.java = keunyoung@google.com, felipeal@google.com, gurunagarajan@google.com
diff --git a/services/core/java/com/android/server/apphibernation/AppHibernationManagerInternal.java b/services/core/java/com/android/server/apphibernation/AppHibernationManagerInternal.java
new file mode 100644
index 0000000..b0335fe
--- /dev/null
+++ b/services/core/java/com/android/server/apphibernation/AppHibernationManagerInternal.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.apphibernation;
+
+/**
+ * App hibernation manager local system service interface.
+ *
+ * @hide Only for use within the system server.
+ */
+public abstract class AppHibernationManagerInternal {
+
+ /**
+ * @see AppHibernationService#isHibernatingForUser
+ */
+ public abstract boolean isHibernatingForUser(String packageName, int userId);
+
+ /**
+ * @see AppHibernationService#setHibernatingForUser
+ */
+ public abstract void setHibernatingForUser(String packageName, int userId,
+ boolean isHibernating);
+
+ /**
+ * @see AppHibernationService#isHibernatingGlobally
+ */
+ public abstract boolean isHibernatingGlobally(String packageName);
+
+ /**
+ * @see AppHibernationService#setHibernatingGlobally
+ */
+ public abstract void setHibernatingGlobally(String packageName, boolean isHibernating);
+}
diff --git a/services/core/java/com/android/server/apphibernation/AppHibernationService.java b/services/core/java/com/android/server/apphibernation/AppHibernationService.java
index 32ae878..351231f 100644
--- a/services/core/java/com/android/server/apphibernation/AppHibernationService.java
+++ b/services/core/java/com/android/server/apphibernation/AppHibernationService.java
@@ -59,6 +59,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.LocalServices;
import com.android.server.SystemService;
import java.io.File;
@@ -68,6 +69,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
@@ -100,6 +102,7 @@
private final Map<String, GlobalLevelState> mGlobalHibernationStates = new ArrayMap<>();
private final HibernationStateDiskStore<GlobalLevelState> mGlobalLevelHibernationDiskStore;
private final Injector mInjector;
+ private final Executor mBackgroundExecutor;
@VisibleForTesting
boolean mIsServiceEnabled;
@@ -125,6 +128,7 @@
mIActivityManager = injector.getActivityManager();
mUserManager = injector.getUserManager();
mGlobalLevelHibernationDiskStore = injector.getGlobalLevelDiskStore();
+ mBackgroundExecutor = injector.getBackgroundExecutor();
mInjector = injector;
final Context userAllContext = mContext.createContextAsUser(UserHandle.ALL, 0 /* flags */);
@@ -134,6 +138,8 @@
intentFilter.addAction(ACTION_PACKAGE_REMOVED);
intentFilter.addDataScheme("package");
userAllContext.registerReceiver(mBroadcastReceiver, intentFilter);
+
+ LocalServices.addService(AppHibernationManagerInternal.class, mLocalService);
}
@Override
@@ -144,11 +150,13 @@
@Override
public void onBootPhase(int phase) {
if (phase == PHASE_BOOT_COMPLETED) {
- List<GlobalLevelState> states =
- mGlobalLevelHibernationDiskStore.readHibernationStates();
- synchronized (mLock) {
- initializeGlobalHibernationStates(states);
- }
+ mBackgroundExecutor.execute(() -> {
+ List<GlobalLevelState> states =
+ mGlobalLevelHibernationDiskStore.readHibernationStates();
+ synchronized (mLock) {
+ initializeGlobalHibernationStates(states);
+ }
+ });
}
if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
mIsServiceEnabled = isAppHibernationEnabled();
@@ -167,14 +175,15 @@
* @return true if package is hibernating for the user
*/
boolean isHibernatingForUser(String packageName, int userId) {
- if (!checkHibernationEnabled("isHibernatingForUser")) {
+ String methodName = "isHibernatingForUser";
+ if (!checkHibernationEnabled(methodName)) {
return false;
}
-
- userId = handleIncomingUser(userId, "isHibernating");
- if (!mUserManager.isUserUnlockingOrUnlocked(userId)) {
- Slog.e(TAG, "Attempt to get hibernation state of stopped or nonexistent user "
- + userId);
+ getContext().enforceCallingOrSelfPermission(
+ android.Manifest.permission.MANAGE_APP_HIBERNATION,
+ "Caller does not have MANAGE_APP_HIBERNATION permission.");
+ userId = handleIncomingUser(userId, methodName);
+ if (!checkUserStatesExist(userId, methodName)) {
return false;
}
synchronized (mLock) {
@@ -199,6 +208,9 @@
if (!checkHibernationEnabled("isHibernatingGlobally")) {
return false;
}
+ getContext().enforceCallingOrSelfPermission(
+ android.Manifest.permission.MANAGE_APP_HIBERNATION,
+ "Caller does not have MANAGE_APP_HIBERNATION permission.");
synchronized (mLock) {
GlobalLevelState state = mGlobalHibernationStates.get(packageName);
if (state == null) {
@@ -217,13 +229,15 @@
* @param isHibernating new hibernation state
*/
void setHibernatingForUser(String packageName, int userId, boolean isHibernating) {
- if (!checkHibernationEnabled("setHibernatingForUser")) {
+ String methodName = "setHibernatingForUser";
+ if (!checkHibernationEnabled(methodName)) {
return;
}
- userId = handleIncomingUser(userId, "setHibernating");
- if (!mUserManager.isUserUnlockingOrUnlocked(userId)) {
- Slog.w(TAG, "Attempt to set hibernation state for a stopped or nonexistent user "
- + userId);
+ getContext().enforceCallingOrSelfPermission(
+ android.Manifest.permission.MANAGE_APP_HIBERNATION,
+ "Caller does not have MANAGE_APP_HIBERNATION permission.");
+ userId = handleIncomingUser(userId, methodName);
+ if (!checkUserStatesExist(userId, methodName)) {
return;
}
synchronized (mLock) {
@@ -260,6 +274,9 @@
if (!checkHibernationEnabled("setHibernatingGlobally")) {
return;
}
+ getContext().enforceCallingOrSelfPermission(
+ android.Manifest.permission.MANAGE_APP_HIBERNATION,
+ "Caller does not have MANAGE_APP_HIBERNATION permission.");
synchronized (mLock) {
GlobalLevelState state = mGlobalHibernationStates.get(packageName);
if (state == null) {
@@ -279,6 +296,34 @@
}
/**
+ * Get the hibernating packages for the given user. This is equivalent to the list of
+ * packages for the user that return true for {@link #isHibernatingForUser}.
+ */
+ @NonNull List<String> getHibernatingPackagesForUser(int userId) {
+ ArrayList<String> hibernatingPackages = new ArrayList<>();
+ String methodName = "getHibernatingPackagesForUser";
+ if (!checkHibernationEnabled(methodName)) {
+ return hibernatingPackages;
+ }
+ getContext().enforceCallingOrSelfPermission(
+ android.Manifest.permission.MANAGE_APP_HIBERNATION,
+ "Caller does not have MANAGE_APP_HIBERNATION permission.");
+ userId = handleIncomingUser(userId, methodName);
+ if (!checkUserStatesExist(userId, methodName)) {
+ return hibernatingPackages;
+ }
+ synchronized (mLock) {
+ Map<String, UserLevelState> userStates = mUserStates.get(userId);
+ for (UserLevelState state : userStates.values()) {
+ if (state.hibernated) {
+ hibernatingPackages.add(state.packageName);
+ }
+ }
+ return hibernatingPackages;
+ }
+ }
+
+ /**
* Put an app into hibernation for a given user, allowing user-level optimizations to occur.
*
* @param pkgState package hibernation state
@@ -434,10 +479,15 @@
HibernationStateDiskStore<UserLevelState> diskStore =
mInjector.getUserLevelDiskStore(userId);
mUserDiskStores.put(userId, diskStore);
- List<UserLevelState> storedStates = diskStore.readHibernationStates();
- synchronized (mLock) {
- initializeUserHibernationStates(userId, storedStates);
- }
+ mBackgroundExecutor.execute(() -> {
+ List<UserLevelState> storedStates = diskStore.readHibernationStates();
+ synchronized (mLock) {
+ // Ensure user hasn't stopped in the time to execute.
+ if (mUserManager.isUserUnlockingOrUnlocked(userId)) {
+ initializeUserHibernationStates(userId, storedStates);
+ }
+ }
+ });
}
@Override
@@ -507,6 +557,20 @@
}
}
+ private boolean checkUserStatesExist(int userId, String methodName) {
+ if (!mUserManager.isUserUnlockingOrUnlocked(userId)) {
+ Slog.e(TAG, String.format(
+ "Attempt to call %s on stopped or nonexistent user %d", methodName, userId));
+ return false;
+ }
+ if (!mUserStates.contains(userId)) {
+ Slog.w(TAG, String.format(
+ "Attempt to call %s before states have been read from disk", methodName));
+ return false;
+ }
+ return true;
+ }
+
private boolean checkHibernationEnabled(String methodName) {
if (!mIsServiceEnabled) {
Slog.w(TAG, String.format("Attempted to call %s on unsupported device.", methodName));
@@ -545,6 +609,36 @@
}
}
+ private final AppHibernationManagerInternal mLocalService = new LocalService(this);
+
+ private static final class LocalService extends AppHibernationManagerInternal {
+ private final AppHibernationService mService;
+
+ LocalService(AppHibernationService service) {
+ mService = service;
+ }
+
+ @Override
+ public boolean isHibernatingForUser(String packageName, int userId) {
+ return mService.isHibernatingForUser(packageName, userId);
+ }
+
+ @Override
+ public void setHibernatingForUser(String packageName, int userId, boolean isHibernating) {
+ mService.setHibernatingForUser(packageName, userId, isHibernating);
+ }
+
+ @Override
+ public void setHibernatingGlobally(String packageName, boolean isHibernating) {
+ mService.setHibernatingGlobally(packageName, isHibernating);
+ }
+
+ @Override
+ public boolean isHibernatingGlobally(String packageName) {
+ return mService.isHibernatingGlobally(packageName);
+ }
+ }
+
private final AppHibernationServiceStub mServiceStub = new AppHibernationServiceStub(this);
static final class AppHibernationServiceStub extends IAppHibernationService.Stub {
@@ -575,6 +669,11 @@
}
@Override
+ public List<String> getHibernatingPackagesForUser(int userId) {
+ return mService.getHibernatingPackagesForUser(userId);
+ }
+
+ @Override
public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,
@Nullable FileDescriptor err, @NonNull String[] args,
@Nullable ShellCallback callback, @NonNull ResultReceiver resultReceiver) {
@@ -642,6 +741,8 @@
UserManager getUserManager();
+ Executor getBackgroundExecutor();
+
HibernationStateDiskStore<GlobalLevelState> getGlobalLevelDiskStore();
HibernationStateDiskStore<UserLevelState> getUserLevelDiskStore(int userId);
@@ -680,6 +781,11 @@
}
@Override
+ public Executor getBackgroundExecutor() {
+ return mScheduledExecutorService;
+ }
+
+ @Override
public HibernationStateDiskStore<GlobalLevelState> getGlobalLevelDiskStore() {
File dir = new File(Environment.getDataSystemDirectory(), HIBERNATION_DIR_NAME);
return new HibernationStateDiskStore<>(
diff --git a/services/core/java/com/android/server/apphibernation/HibernationStateDiskStore.java b/services/core/java/com/android/server/apphibernation/HibernationStateDiskStore.java
index c83659d..24cf433 100644
--- a/services/core/java/com/android/server/apphibernation/HibernationStateDiskStore.java
+++ b/services/core/java/com/android/server/apphibernation/HibernationStateDiskStore.java
@@ -109,6 +109,7 @@
* @return the parsed list of hibernation states, null if file does not exist
*/
@Nullable
+ @WorkerThread
List<T> readHibernationStates() {
synchronized (this) {
if (!mHibernationFile.exists()) {
diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java
index ed3a223..6aec9fc 100644
--- a/services/core/java/com/android/server/clipboard/ClipboardService.java
+++ b/services/core/java/com/android/server/clipboard/ClipboardService.java
@@ -65,6 +65,7 @@
import java.io.IOException;
import java.io.RandomAccessFile;
+import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
@@ -80,27 +81,52 @@
private static final String PIPE_NAME = "pipe:clipboard";
private static final String PIPE_DEVICE = "/dev/qemu_pipe";
- private void openPipe() {
+ private static byte[] createOpenHandshake() {
+ // String.getBytes doesn't include the null terminator,
+ // but the QEMU pipe device requires the pipe service name
+ // to be null-terminated.
+
+ final byte[] bits = Arrays.copyOf(PIPE_NAME.getBytes(), PIPE_NAME.length() + 1);
+ bits[PIPE_NAME.length()] = 0;
+ return bits;
+ }
+
+ private boolean openPipe() {
try {
- // String.getBytes doesn't include the null terminator,
- // but the QEMU pipe device requires the pipe service name
- // to be null-terminated.
- byte[] b = new byte[PIPE_NAME.length() + 1];
- b[PIPE_NAME.length()] = 0;
- System.arraycopy(
- PIPE_NAME.getBytes(),
- 0,
- b,
- 0,
- PIPE_NAME.length());
- mPipe = new RandomAccessFile(PIPE_DEVICE, "rw");
- mPipe.write(b);
- } catch (IOException e) {
+ final RandomAccessFile pipe = new RandomAccessFile(PIPE_DEVICE, "rw");
try {
- if (mPipe != null) mPipe.close();
- } catch (IOException ee) {}
- mPipe = null;
+ pipe.write(createOpenHandshake());
+ mPipe = pipe;
+ return true;
+ } catch (IOException ignore) {
+ pipe.close();
+ }
+ } catch (IOException ignore) {
}
+ return false;
+ }
+
+ private void closePipe() {
+ try {
+ final RandomAccessFile pipe = mPipe;
+ mPipe = null;
+ if (pipe != null) {
+ pipe.close();
+ }
+ } catch (IOException ignore) {
+ }
+ }
+
+ private byte[] receiveMessage() throws IOException {
+ final int size = Integer.reverseBytes(mPipe.readInt());
+ final byte[] receivedData = new byte[size];
+ mPipe.readFully(receivedData);
+ return receivedData;
+ }
+
+ private void sendMessage(byte[] message) throws IOException {
+ mPipe.writeInt(Integer.reverseBytes(message.length));
+ mPipe.write(message);
}
public HostClipboardMonitor(HostClipboardCallback cb) {
@@ -114,21 +140,15 @@
// There's no guarantee that QEMU pipes will be ready at the moment
// this method is invoked. We simply try to get the pipe open and
// retry on failure indefinitely.
- while (mPipe == null) {
- openPipe();
+ while ((mPipe == null) && !openPipe()) {
Thread.sleep(100);
}
- int size = mPipe.readInt();
- size = Integer.reverseBytes(size);
- byte[] receivedData = new byte[size];
- mPipe.readFully(receivedData);
+
+ final byte[] receivedData = receiveMessage();
mHostClipboardCallback.onHostClipboardUpdated(
new String(receivedData));
} catch (IOException e) {
- try {
- mPipe.close();
- } catch (IOException ee) {}
- mPipe = null;
+ closePipe();
} catch (InterruptedException e) {}
}
}
@@ -136,8 +156,7 @@
public void setHostClipboard(String content) {
try {
if (mPipe != null) {
- mPipe.writeInt(Integer.reverseBytes(content.getBytes().length));
- mPipe.write(content.getBytes());
+ sendMessage(content.getBytes());
}
} catch(IOException e) {
Slog.e("HostClipboardMonitor",
@@ -158,7 +177,7 @@
private static final String TAG = "ClipboardService";
private static final boolean IS_EMULATOR =
- SystemProperties.getBoolean("ro.kernel.qemu", false);
+ SystemProperties.getBoolean("ro.boot.qemu", false);
private final ActivityManagerInternal mAmInternal;
private final IUriGrantsManager mUgm;
diff --git a/services/core/java/com/android/server/compat/CompatChange.java b/services/core/java/com/android/server/compat/CompatChange.java
index df83df9..d29a0c7 100644
--- a/services/core/java/com/android/server/compat/CompatChange.java
+++ b/services/core/java/com/android/server/compat/CompatChange.java
@@ -23,11 +23,14 @@
import android.annotation.Nullable;
import android.app.compat.PackageOverride;
import android.compat.annotation.ChangeId;
+import android.compat.annotation.Disabled;
import android.compat.annotation.EnabledSince;
+import android.compat.annotation.Overridable;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import com.android.internal.compat.AndroidBuildClassifier;
import com.android.internal.compat.CompatibilityChangeInfo;
import com.android.internal.compat.OverrideAllowedState;
import com.android.server.compat.config.Change;
@@ -55,10 +58,19 @@
* A change ID to be used only in the CTS test for this SystemApi
*/
@ChangeId
- @EnabledSince(targetSdkVersion = 1235) // Needs to be > test APK targetSdkVersion.
+ @EnabledSince(targetSdkVersion = 31) // Needs to be > test APK targetSdkVersion.
static final long CTS_SYSTEM_API_CHANGEID = 149391281; // This is a bug id.
/**
+ * An overridable change ID to be used only in the CTS test for this SystemApi
+ */
+ @ChangeId
+ @Disabled
+ @Overridable
+ static final long CTS_SYSTEM_API_OVERRIDABLE_CHANGEID = 174043039; // This is a bug id.
+
+
+ /**
* Callback listener for when compat changes are updated for a package.
* See {@link #registerListener(ChangeListener)} for more details.
*/
@@ -80,6 +92,15 @@
}
/**
+ * @param change an object generated by services/core/xsd/platform-compat-config.xsd
+ */
+ public CompatChange(Change change) {
+ this(change.getId(), change.getName(), change.getEnableAfterTargetSdk(),
+ change.getEnableSinceTargetSdk(), change.getDisabled(), change.getLoggingOnly(),
+ change.getDescription(), change.getOverridable());
+ }
+
+ /**
* @param changeId Unique ID for the change. See {@link android.compat.Compatibility}.
* @param name Short descriptive name.
* @param enableAfterTargetSdk {@code targetSdkVersion} restriction. See {@link EnabledAfter};
@@ -93,15 +114,10 @@
boolean overridable) {
super(changeId, name, enableAfterTargetSdk, enableSinceTargetSdk, disabled, loggingOnly,
description, overridable);
- }
- /**
- * @param change an object generated by services/core/xsd/platform-compat-config.xsd
- */
- public CompatChange(Change change) {
- super(change.getId(), change.getName(), change.getEnableAfterTargetSdk(),
- change.getEnableSinceTargetSdk(), change.getDisabled(), change.getLoggingOnly(),
- change.getDescription(), change.getOverridable());
+ // Initialize override maps.
+ mEvaluatedOverrides = new HashMap<>();
+ mRawOverrides = new HashMap<>();
}
void registerListener(ChangeListener listener) {
@@ -127,18 +143,13 @@
throw new IllegalArgumentException(
"Can't add overrides for a logging only change " + toString());
}
- if (mEvaluatedOverrides == null) {
- mEvaluatedOverrides = new HashMap<>();
- }
mEvaluatedOverrides.put(pname, enabled);
notifyListener(pname);
}
private void removePackageOverrideInternal(String pname) {
- if (mEvaluatedOverrides != null) {
- if (mEvaluatedOverrides.remove(pname) != null) {
- notifyListener(pname);
- }
+ if (mEvaluatedOverrides.remove(pname) != null) {
+ notifyListener(pname);
}
}
@@ -157,9 +168,6 @@
throw new IllegalArgumentException(
"Can't add overrides for a logging only change " + toString());
}
- if (mRawOverrides == null) {
- mRawOverrides = new HashMap<>();
- }
mRawOverrides.put(packageName, override);
recheckOverride(packageName, allowedState, context);
}
@@ -212,8 +220,9 @@
}
boolean hasPackageOverride(String pname) {
- return mRawOverrides != null && mRawOverrides.containsKey(pname);
+ return mRawOverrides.containsKey(pname);
}
+
/**
* Remove any package override for the given package name, restoring the default behaviour.
*
@@ -223,7 +232,7 @@
*/
boolean removePackageOverride(String pname, OverrideAllowedState allowedState,
Context context) {
- if (mRawOverrides != null && (mRawOverrides.remove(pname) != null)) {
+ if (mRawOverrides.remove(pname) != null) {
recheckOverride(pname, allowedState, context);
return true;
}
@@ -237,18 +246,24 @@
* @param app Info about the app in question
* @return {@code true} if the change should be enabled for the package.
*/
- boolean isEnabled(ApplicationInfo app) {
+ boolean isEnabled(ApplicationInfo app, AndroidBuildClassifier buildClassifier) {
if (app == null) {
return defaultValue();
}
- if (mEvaluatedOverrides != null && mEvaluatedOverrides.containsKey(app.packageName)) {
+ if (mEvaluatedOverrides.containsKey(app.packageName)) {
return mEvaluatedOverrides.get(app.packageName);
}
if (getDisabled()) {
return false;
}
if (getEnableSinceTargetSdk() != -1) {
- return app.targetSdkVersion >= getEnableSinceTargetSdk();
+ // If the change is gated by a platform version newer than the one currently installed
+ // on the device, disregard the app's target sdk version.
+ int compareSdk = Math.min(app.targetSdkVersion, buildClassifier.platformTargetSdk());
+ if (compareSdk != app.targetSdkVersion) {
+ compareSdk = app.targetSdkVersion;
+ }
+ return compareSdk >= getEnableSinceTargetSdk();
}
return true;
}
@@ -289,7 +304,7 @@
* @return true if there is such override
*/
private boolean hasOverride(String packageName) {
- return mEvaluatedOverrides != null && mEvaluatedOverrides.containsKey(packageName);
+ return mEvaluatedOverrides.containsKey(packageName);
}
/**
@@ -298,20 +313,15 @@
* @return true if there is such a deferred override
*/
private boolean hasRawOverride(String packageName) {
- return mRawOverrides != null && mRawOverrides.containsKey(packageName);
+ return mRawOverrides.containsKey(packageName);
+ }
+
+ void clearOverrides() {
+ mRawOverrides.clear();
+ mEvaluatedOverrides.clear();
}
void loadOverrides(ChangeOverrides changeOverrides) {
- if (mRawOverrides == null) {
- mRawOverrides = new HashMap<>();
- }
- mRawOverrides.clear();
-
- if (mEvaluatedOverrides == null) {
- mEvaluatedOverrides = new HashMap<>();
- }
- mEvaluatedOverrides.clear();
-
// Load deferred overrides for backwards compatibility
if (changeOverrides.getDeferred() != null) {
for (OverrideValue override : changeOverrides.getDeferred().getOverrideValue()) {
@@ -345,34 +355,30 @@
}
ChangeOverrides saveOverrides() {
- if (mRawOverrides == null || mRawOverrides.isEmpty()) {
+ if (mRawOverrides.isEmpty()) {
return null;
}
ChangeOverrides changeOverrides = new ChangeOverrides();
changeOverrides.setChangeId(getId());
ChangeOverrides.Raw rawOverrides = new ChangeOverrides.Raw();
List<RawOverrideValue> rawList = rawOverrides.getRawOverrideValue();
- if (mRawOverrides != null) {
- for (Map.Entry<String, PackageOverride> entry : mRawOverrides.entrySet()) {
- RawOverrideValue override = new RawOverrideValue();
- override.setPackageName(entry.getKey());
- override.setMinVersionCode(entry.getValue().getMinVersionCode());
- override.setMaxVersionCode(entry.getValue().getMaxVersionCode());
- override.setEnabled(entry.getValue().getEnabled());
- rawList.add(override);
- }
+ for (Map.Entry<String, PackageOverride> entry : mRawOverrides.entrySet()) {
+ RawOverrideValue override = new RawOverrideValue();
+ override.setPackageName(entry.getKey());
+ override.setMinVersionCode(entry.getValue().getMinVersionCode());
+ override.setMaxVersionCode(entry.getValue().getMaxVersionCode());
+ override.setEnabled(entry.getValue().isEnabled());
+ rawList.add(override);
}
changeOverrides.setRaw(rawOverrides);
ChangeOverrides.Validated validatedOverrides = new ChangeOverrides.Validated();
List<OverrideValue> validatedList = validatedOverrides.getOverrideValue();
- if (mEvaluatedOverrides != null) {
- for (Map.Entry<String, Boolean> entry : mEvaluatedOverrides.entrySet()) {
- OverrideValue override = new OverrideValue();
- override.setPackageName(entry.getKey());
- override.setEnabled(entry.getValue());
- validatedList.add(override);
- }
+ for (Map.Entry<String, Boolean> entry : mEvaluatedOverrides.entrySet()) {
+ OverrideValue override = new OverrideValue();
+ override.setPackageName(entry.getKey());
+ override.setEnabled(entry.getValue());
+ validatedList.add(override);
}
changeOverrides.setValidated(validatedOverrides);
return changeOverrides;
@@ -394,10 +400,10 @@
if (getLoggingOnly()) {
sb.append("; loggingOnly");
}
- if (mEvaluatedOverrides != null && mEvaluatedOverrides.size() > 0) {
+ if (!mEvaluatedOverrides.isEmpty()) {
sb.append("; packageOverrides=").append(mEvaluatedOverrides);
}
- if (mRawOverrides != null && mRawOverrides.size() > 0) {
+ if (!mRawOverrides.isEmpty()) {
sb.append("; rawOverrides=").append(mRawOverrides);
}
if (getOverridable()) {
diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java
index 66a6520..55e2696 100644
--- a/services/core/java/com/android/server/compat/CompatConfig.java
+++ b/services/core/java/com/android/server/compat/CompatConfig.java
@@ -67,18 +67,21 @@
private static final String TAG = "CompatConfig";
private static final String APP_COMPAT_DATA_DIR = "/data/misc/appcompat";
+ private static final String STATIC_OVERRIDES_PRODUCT_DIR = "/product/etc/appcompat";
private static final String OVERRIDES_FILE = "compat_framework_overrides.xml";
@GuardedBy("mChanges")
private final LongSparseArray<CompatChange> mChanges = new LongSparseArray<>();
private final OverrideValidatorImpl mOverrideValidator;
+ private final AndroidBuildClassifier mAndroidBuildClassifier;
private Context mContext;
private File mOverridesFile;
@VisibleForTesting
CompatConfig(AndroidBuildClassifier androidBuildClassifier, Context context) {
mOverrideValidator = new OverrideValidatorImpl(androidBuildClassifier, context, this);
+ mAndroidBuildClassifier = androidBuildClassifier;
mContext = context;
}
@@ -94,8 +97,7 @@
config.initConfigFromLib(Environment.buildPath(
apex.apexDirectory, "etc", "compatconfig"));
}
- File overridesFile = new File(APP_COMPAT_DATA_DIR, OVERRIDES_FILE);
- config.initOverrides(overridesFile);
+ config.initOverrides();
config.invalidateCache();
return config;
}
@@ -133,7 +135,7 @@
synchronized (mChanges) {
for (int i = 0; i < mChanges.size(); ++i) {
CompatChange c = mChanges.valueAt(i);
- if (!c.isEnabled(app)) {
+ if (!c.isEnabled(app, mAndroidBuildClassifier)) {
disabled.add(c.getId());
}
}
@@ -175,7 +177,7 @@
// we know nothing about this change: default behaviour is enabled.
return true;
}
- return c.isEnabled(app);
+ return c.isEnabled(app, mAndroidBuildClassifier);
}
}
@@ -302,6 +304,16 @@
}
/**
+ * Returns whether the change is overridable.
+ */
+ boolean isOverridable(long changeId) {
+ synchronized (mChanges) {
+ CompatChange c = mChanges.get(changeId);
+ return c != null && c.getOverridable();
+ }
+ }
+
+ /**
* Removes an override previously added via {@link #addOverride(long, String, boolean)}.
*
* <p>This restores the default behaviour for the given change and app, once any app processes
@@ -341,7 +353,7 @@
/**
* Removes all overrides previously added via {@link #addOverride(long, String, boolean)} or
- * {@link #addOverrides(CompatibilityChangeConfig, String)} for a certain package.
+ * {@link #addOverrides(CompatibilityOverrideConfig, String)} for a certain package.
*
* <p>This restores the default behaviour for the given app.
*
@@ -475,7 +487,7 @@
synchronized (mChanges) {
for (int i = 0; i < mChanges.size(); ++i) {
CompatChange c = mChanges.valueAt(i);
- if (c.isEnabled(applicationInfo)) {
+ if (c.isEnabled(applicationInfo, mAndroidBuildClassifier)) {
enabled.add(c.getId());
} else {
disabled.add(c.getId());
@@ -525,10 +537,34 @@
}
}
- void initOverrides(File overridesFile) {
+ private void initOverrides() {
+ initOverrides(new File(APP_COMPAT_DATA_DIR, OVERRIDES_FILE),
+ new File(STATIC_OVERRIDES_PRODUCT_DIR, OVERRIDES_FILE));
+ }
+
+ @VisibleForTesting
+ void initOverrides(File dynamicOverridesFile, File staticOverridesFile) {
+ // Clear overrides from all changes before loading.
+ synchronized (mChanges) {
+ for (int i = 0; i < mChanges.size(); ++i) {
+ mChanges.valueAt(i).clearOverrides();
+ }
+ }
+
+ loadOverrides(staticOverridesFile);
+
+ mOverridesFile = dynamicOverridesFile;
+ loadOverrides(dynamicOverridesFile);
+
+ if (staticOverridesFile.exists()) {
+ // Only save overrides if there is a static overrides file.
+ saveOverrides();
+ }
+ }
+
+ private void loadOverrides(File overridesFile) {
if (!overridesFile.exists()) {
- mOverridesFile = overridesFile;
- // There have not been any overrides added yet.
+ // Overrides file doesn't exist.
return;
}
@@ -548,7 +584,6 @@
Slog.w(TAG, "Error processing " + overridesFile + " " + e.toString());
return;
}
- mOverridesFile = overridesFile;
}
/**
@@ -607,8 +642,11 @@
}
boolean shouldInvalidateCache = false;
for (CompatChange c: changes) {
+ if (!c.hasPackageOverride(packageName)) {
+ continue;
+ }
OverrideAllowedState allowedState =
- mOverrideValidator.getOverrideAllowedState(c.getId(), packageName);
+ mOverrideValidator.getOverrideAllowedStateForRecheck(c.getId(), packageName);
shouldInvalidateCache |= c.recheckOverride(packageName, allowedState, mContext);
}
if (shouldInvalidateCache) {
diff --git a/services/core/java/com/android/server/compat/OverrideValidatorImpl.java b/services/core/java/com/android/server/compat/OverrideValidatorImpl.java
index fe5b4a9..b500691 100644
--- a/services/core/java/com/android/server/compat/OverrideValidatorImpl.java
+++ b/services/core/java/com/android/server/compat/OverrideValidatorImpl.java
@@ -16,13 +16,18 @@
package com.android.server.compat;
+import static android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+
import static com.android.internal.compat.OverrideAllowedState.ALLOWED;
import static com.android.internal.compat.OverrideAllowedState.DEFERRED_VERIFICATION;
import static com.android.internal.compat.OverrideAllowedState.DISABLED_NON_TARGET_SDK;
import static com.android.internal.compat.OverrideAllowedState.DISABLED_NOT_DEBUGGABLE;
import static com.android.internal.compat.OverrideAllowedState.DISABLED_TARGET_SDK_TOO_HIGH;
import static com.android.internal.compat.OverrideAllowedState.LOGGING_ONLY_CHANGE;
+import static com.android.internal.compat.OverrideAllowedState.PLATFORM_TOO_OLD;
+import android.annotation.NonNull;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
@@ -68,8 +73,25 @@
mForceNonDebuggableFinalBuild = false;
}
+ /**
+ * Check the allowed state for the given changeId and packageName on a recheck.
+ *
+ * <p>Recheck happens when the given app is getting updated. In this case we cannot do a
+ * permission check on the caller, so we're using the fact that the override was present as
+ * proof that the original caller was allowed to set this override.
+ */
+ OverrideAllowedState getOverrideAllowedStateForRecheck(long changeId,
+ @NonNull String packageName) {
+ return getOverrideAllowedStateInternal(changeId, packageName, true);
+ }
+
@Override
public OverrideAllowedState getOverrideAllowedState(long changeId, String packageName) {
+ return getOverrideAllowedStateInternal(changeId, packageName, false);
+ }
+
+ private OverrideAllowedState getOverrideAllowedStateInternal(long changeId, String packageName,
+ boolean isRecheck) {
if (mCompatConfig.isLoggingOnly(changeId)) {
return new OverrideAllowedState(LOGGING_ONLY_CHANGE, -1, -1);
}
@@ -85,6 +107,9 @@
if (debuggableBuild) {
return new OverrideAllowedState(ALLOWED, -1, -1);
}
+ if (maxTargetSdk >= mAndroidBuildClassifier.platformTargetSdk()) {
+ return new OverrideAllowedState(PLATFORM_TOO_OLD, -1, maxTargetSdk);
+ }
PackageManager packageManager = mContext.getPackageManager();
if (packageManager == null) {
throw new IllegalStateException("No PackageManager!");
@@ -95,6 +120,16 @@
} catch (NameNotFoundException e) {
return new OverrideAllowedState(DEFERRED_VERIFICATION, -1, -1);
}
+ // If the change is annotated as @Overridable, apps with the specific permission can
+ // set the override even on production builds. When rechecking the override, e.g. during an
+ // app update we can bypass this check, as it wouldn't have been here in the first place.
+ if (mCompatConfig.isOverridable(changeId)
+ && (isRecheck
+ || mContext.checkCallingOrSelfPermission(
+ OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD)
+ == PERMISSION_GRANTED)) {
+ return new OverrideAllowedState(ALLOWED, -1, -1);
+ }
int appTargetSdk = applicationInfo.targetSdkVersion;
// Only allow overriding debuggable apps.
if ((applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
@@ -126,5 +161,4 @@
void forceNonDebuggableFinalForTest(boolean value) {
mForceNonDebuggableFinalBuild = value;
}
-
}
diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java
index edfc8b8..20469a2 100644
--- a/services/core/java/com/android/server/compat/PlatformCompat.java
+++ b/services/core/java/com/android/server/compat/PlatformCompat.java
@@ -18,6 +18,7 @@
import static android.Manifest.permission.LOG_COMPAT_CHANGE;
import static android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG;
+import static android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD;
import static android.Manifest.permission.READ_COMPAT_CHANGE_CONFIG;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.Process.SYSTEM_UID;
@@ -66,18 +67,22 @@
private final Context mContext;
private final ChangeReporter mChangeReporter;
private final CompatConfig mCompatConfig;
+ private final AndroidBuildClassifier mBuildClassifier;
public PlatformCompat(Context context) {
mContext = context;
mChangeReporter = new ChangeReporter(ChangeReporter.SOURCE_SYSTEM_SERVER);
- mCompatConfig = CompatConfig.create(new AndroidBuildClassifier(), mContext);
+ mBuildClassifier = new AndroidBuildClassifier();
+ mCompatConfig = CompatConfig.create(mBuildClassifier, mContext);
}
@VisibleForTesting
- PlatformCompat(Context context, CompatConfig compatConfig) {
+ PlatformCompat(Context context, CompatConfig compatConfig,
+ AndroidBuildClassifier buildClassifier) {
mContext = context;
mChangeReporter = new ChangeReporter(ChangeReporter.SOURCE_SYSTEM_SERVER);
mCompatConfig = compatConfig;
+ mBuildClassifier = buildClassifier;
registerPackageReceiver(context);
}
@@ -178,11 +183,12 @@
}
@Override
- public void setOverridesFromInstaller(CompatibilityOverrideConfig overrides,
+ public void setOverridesOnReleaseBuilds(CompatibilityOverrideConfig overrides,
String packageName) {
- checkCompatChangeOverridePermission();
+ // TODO(b/183630314): Unify the permission enforcement with the other setOverrides* methods.
+ checkCompatChangeOverrideOverridablePermission();
+ checkAllCompatOverridesAreOverridable(overrides);
mCompatConfig.addOverrides(overrides, packageName);
- killPackage(packageName);
}
@Override
@@ -379,6 +385,26 @@
}
}
+ private void checkCompatChangeOverrideOverridablePermission() {
+ // Don't check for permissions within the system process
+ if (Binder.getCallingUid() == SYSTEM_UID) {
+ return;
+ }
+ if (mContext.checkCallingOrSelfPermission(OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD)
+ != PERMISSION_GRANTED) {
+ throw new SecurityException("Cannot override compat change");
+ }
+ }
+
+ private void checkAllCompatOverridesAreOverridable(CompatibilityOverrideConfig overrides) {
+ for (Long changeId : overrides.overrides.keySet()) {
+ if (!mCompatConfig.isOverridable(changeId)) {
+ throw new SecurityException("Only change ids marked as Overridable can be "
+ + "overridden.");
+ }
+ }
+ }
+
private void checkCompatChangeReadAndLogPermission() {
checkCompatChangeReadPermission();
checkCompatChangeLogPermission();
@@ -392,7 +418,8 @@
return false;
}
if (change.getEnableSinceTargetSdk() > 0) {
- return change.getEnableSinceTargetSdk() >= Build.VERSION_CODES.Q;
+ return change.getEnableSinceTargetSdk() >= Build.VERSION_CODES.Q
+ && change.getEnableSinceTargetSdk() <= mBuildClassifier.platformTargetSdk();
}
return true;
}
diff --git a/services/core/java/com/android/server/connectivity/ConnectivityConstants.java b/services/core/java/com/android/server/connectivity/ConnectivityConstants.java
index 0fb6fec..325a2cd 100644
--- a/services/core/java/com/android/server/connectivity/ConnectivityConstants.java
+++ b/services/core/java/com/android/server/connectivity/ConnectivityConstants.java
@@ -18,18 +18,10 @@
/**
* A class encapsulating various constants used by Connectivity.
+ * TODO : remove this class.
* @hide
*/
public class ConnectivityConstants {
-
- // Penalty applied to scores of Networks that have not been validated.
- public static final int UNVALIDATED_SCORE_PENALTY = 40;
-
- // Score for explicitly connected network.
- //
- // This ensures that a) the explicitly selected network is never trumped by anything else, and
- // b) the explicitly selected network is never torn down.
- public static final int EXPLICITLY_SELECTED_NETWORK_SCORE = 100;
// VPNs typically have priority over other networks. Give them a score that will
// let them win every single time.
public static final int VPN_DEFAULT_SCORE = 101;
diff --git a/services/core/java/com/android/server/connectivity/DnsManager.java b/services/core/java/com/android/server/connectivity/DnsManager.java
index 4f6b530..ffeb77d 100644
--- a/services/core/java/com/android/server/connectivity/DnsManager.java
+++ b/services/core/java/com/android/server/connectivity/DnsManager.java
@@ -16,23 +16,23 @@
package com.android.server.connectivity;
-import static android.net.ConnectivityManager.PRIVATE_DNS_DEFAULT_MODE_FALLBACK;
import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF;
import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
+import static android.net.ConnectivitySettingsManager.DNS_RESOLVER_MAX_SAMPLES;
+import static android.net.ConnectivitySettingsManager.DNS_RESOLVER_MIN_SAMPLES;
+import static android.net.ConnectivitySettingsManager.DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS;
+import static android.net.ConnectivitySettingsManager.DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT;
+import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_DEFAULT_MODE;
+import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE;
+import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_SPECIFIER;
import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_FAILURE;
import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_SUCCESS;
-import static android.provider.Settings.Global.DNS_RESOLVER_MAX_SAMPLES;
-import static android.provider.Settings.Global.DNS_RESOLVER_MIN_SAMPLES;
-import static android.provider.Settings.Global.DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS;
-import static android.provider.Settings.Global.DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT;
-import static android.provider.Settings.Global.PRIVATE_DNS_DEFAULT_MODE;
-import static android.provider.Settings.Global.PRIVATE_DNS_MODE;
-import static android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER;
import android.annotation.NonNull;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
+import android.net.ConnectivityManager;
import android.net.IDnsResolver;
import android.net.InetAddresses;
import android.net.LinkProperties;
@@ -127,13 +127,17 @@
private static final int DNS_RESOLVER_DEFAULT_MIN_SAMPLES = 8;
private static final int DNS_RESOLVER_DEFAULT_MAX_SAMPLES = 64;
- public static PrivateDnsConfig getPrivateDnsConfig(ContentResolver cr) {
- final String mode = getPrivateDnsMode(cr);
+ /**
+ * Get PrivateDnsConfig.
+ */
+ public static PrivateDnsConfig getPrivateDnsConfig(Context context) {
+ final String mode = ConnectivityManager.getPrivateDnsMode(context);
final boolean useTls = !TextUtils.isEmpty(mode) && !PRIVATE_DNS_MODE_OFF.equals(mode);
if (PRIVATE_DNS_MODE_PROVIDER_HOSTNAME.equals(mode)) {
- final String specifier = getStringSetting(cr, PRIVATE_DNS_SPECIFIER);
+ final String specifier = getStringSetting(context.getContentResolver(),
+ PRIVATE_DNS_SPECIFIER);
return new PrivateDnsConfig(specifier, null);
}
@@ -268,7 +272,7 @@
}
public PrivateDnsConfig getPrivateDnsConfig() {
- return getPrivateDnsConfig(mContentResolver);
+ return getPrivateDnsConfig(mContext);
}
public void removeNetwork(Network network) {
@@ -479,13 +483,6 @@
return result;
}
- private static String getPrivateDnsMode(ContentResolver cr) {
- String mode = getStringSetting(cr, PRIVATE_DNS_MODE);
- if (TextUtils.isEmpty(mode)) mode = getStringSetting(cr, PRIVATE_DNS_DEFAULT_MODE);
- if (TextUtils.isEmpty(mode)) mode = PRIVATE_DNS_DEFAULT_MODE_FALLBACK;
- return mode;
- }
-
private static String getStringSetting(ContentResolver cr, String which) {
return Settings.Global.getString(cr, which);
}
diff --git a/services/core/java/com/android/server/connectivity/FullScore.java b/services/core/java/com/android/server/connectivity/FullScore.java
new file mode 100644
index 0000000..028cfee
--- /dev/null
+++ b/services/core/java/com/android/server/connectivity/FullScore.java
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.connectivity;
+
+import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
+import static android.net.NetworkCapabilities.TRANSPORT_VPN;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.net.NetworkAgentConfig;
+import android.net.NetworkCapabilities;
+import android.net.NetworkScore;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.StringJoiner;
+
+/**
+ * This class represents how desirable a network is.
+ *
+ * FullScore is very similar to NetworkScore, but it contains the bits that are managed
+ * by ConnectivityService. This provides static guarantee that all users must know whether
+ * they are handling a score that had the CS-managed bits set.
+ */
+public class FullScore {
+ // This will be removed soon. Do *NOT* depend on it for any new code that is not part of
+ // a migration.
+ private final int mLegacyInt;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"POLICY_"}, value = {
+ POLICY_IS_VALIDATED,
+ POLICY_IS_VPN,
+ POLICY_EVER_USER_SELECTED,
+ POLICY_ACCEPT_UNVALIDATED
+ })
+ public @interface Policy {
+ }
+
+ // Agent-managed policies are in NetworkScore. They start from 1.
+ // CS-managed policies, counting from 63 downward
+ // This network is validated. CS-managed because the source of truth is in NetworkCapabilities.
+ /** @hide */
+ public static final int POLICY_IS_VALIDATED = 63;
+
+ // This is a VPN and behaves as one for scoring purposes.
+ /** @hide */
+ public static final int POLICY_IS_VPN = 62;
+
+ // This network has been selected by the user manually from settings or a 3rd party app
+ // at least once. {@see NetworkAgentConfig#explicitlySelected}.
+ /** @hide */
+ public static final int POLICY_EVER_USER_SELECTED = 61;
+
+ // The user has indicated in UI that this network should be used even if it doesn't
+ // validate. {@see NetworkAgentConfig#acceptUnvalidated}.
+ /** @hide */
+ public static final int POLICY_ACCEPT_UNVALIDATED = 60;
+
+ // To help iterate when printing
+ @VisibleForTesting
+ static final int MIN_CS_MANAGED_POLICY = POLICY_ACCEPT_UNVALIDATED;
+ @VisibleForTesting
+ static final int MAX_CS_MANAGED_POLICY = POLICY_IS_VALIDATED;
+
+ @VisibleForTesting
+ static @NonNull String policyNameOf(final int policy) {
+ switch (policy) {
+ case POLICY_IS_VALIDATED: return "IS_VALIDATED";
+ case POLICY_IS_VPN: return "IS_VPN";
+ case POLICY_EVER_USER_SELECTED: return "EVER_USER_SELECTED";
+ case POLICY_ACCEPT_UNVALIDATED: return "ACCEPT_UNVALIDATED";
+ }
+ throw new IllegalArgumentException("Unknown policy : " + policy);
+ }
+
+ // Bitmask of all the policies applied to this score.
+ private final long mPolicies;
+
+ FullScore(final int legacyInt, final long policies) {
+ mLegacyInt = legacyInt;
+ mPolicies = policies;
+ }
+
+ /**
+ * Given a score supplied by the NetworkAgent and CS-managed objects, produce a full score.
+ *
+ * @param score the score supplied by the agent
+ * @param caps the NetworkCapabilities of the network
+ * @param config the NetworkAgentConfig of the network
+ * @return an FullScore that is appropriate to use for ranking.
+ */
+ public static FullScore fromNetworkScore(@NonNull final NetworkScore score,
+ @NonNull final NetworkCapabilities caps, @NonNull final NetworkAgentConfig config) {
+ return withPolicies(score.getLegacyInt(), caps.hasCapability(NET_CAPABILITY_VALIDATED),
+ caps.hasTransport(TRANSPORT_VPN),
+ config.explicitlySelected,
+ config.acceptUnvalidated);
+ }
+
+ /**
+ * Return a new score given updated caps and config.
+ *
+ * @param caps the NetworkCapabilities of the network
+ * @param config the NetworkAgentConfig of the network
+ * @return a score with the policies from the arguments reset
+ */
+ public FullScore mixInScore(@NonNull final NetworkCapabilities caps,
+ @NonNull final NetworkAgentConfig config) {
+ return withPolicies(mLegacyInt, caps.hasCapability(NET_CAPABILITY_VALIDATED),
+ caps.hasTransport(TRANSPORT_VPN),
+ config.explicitlySelected,
+ config.acceptUnvalidated);
+ }
+
+ private static FullScore withPolicies(@NonNull final int legacyInt,
+ final boolean isValidated,
+ final boolean isVpn,
+ final boolean everUserSelected,
+ final boolean acceptUnvalidated) {
+ return new FullScore(legacyInt,
+ (isValidated ? 1L << POLICY_IS_VALIDATED : 0)
+ | (isVpn ? 1L << POLICY_IS_VPN : 0)
+ | (everUserSelected ? 1L << POLICY_EVER_USER_SELECTED : 0)
+ | (acceptUnvalidated ? 1L << POLICY_ACCEPT_UNVALIDATED : 0));
+ }
+
+ /**
+ * For backward compatibility, get the legacy int.
+ * This will be removed before S is published.
+ */
+ public int getLegacyInt() {
+ return getLegacyInt(false /* pretendValidated */);
+ }
+
+ public int getLegacyIntAsValidated() {
+ return getLegacyInt(true /* pretendValidated */);
+ }
+
+ // TODO : remove these two constants
+ // Penalty applied to scores of Networks that have not been validated.
+ private static final int UNVALIDATED_SCORE_PENALTY = 40;
+
+ // Score for a network that can be used unvalidated
+ private static final int ACCEPT_UNVALIDATED_NETWORK_SCORE = 100;
+
+ private int getLegacyInt(boolean pretendValidated) {
+ // If the user has chosen this network at least once, give it the maximum score when
+ // checking to pretend it's validated, or if it doesn't need to validate because the
+ // user said to use it even if it doesn't validate.
+ // This ensures that networks that have been selected in UI are not torn down before the
+ // user gets a chance to prefer it when a higher-scoring network (e.g., Ethernet) is
+ // available.
+ if (hasPolicy(POLICY_EVER_USER_SELECTED)
+ && (hasPolicy(POLICY_ACCEPT_UNVALIDATED) || pretendValidated)) {
+ return ACCEPT_UNVALIDATED_NETWORK_SCORE;
+ }
+
+ int score = mLegacyInt;
+ // Except for VPNs, networks are subject to a penalty for not being validated.
+ // Apply the penalty unless the network is a VPN, or it's validated or pretending to be.
+ if (!hasPolicy(POLICY_IS_VALIDATED) && !pretendValidated && !hasPolicy(POLICY_IS_VPN)) {
+ score -= UNVALIDATED_SCORE_PENALTY;
+ }
+ if (score < 0) score = 0;
+ return score;
+ }
+
+ /**
+ * @return whether this score has a particular policy.
+ */
+ @VisibleForTesting
+ public boolean hasPolicy(final int policy) {
+ return 0 != (mPolicies & (1L << policy));
+ }
+
+ // Example output :
+ // Score(50 ; Policies : EVER_USER_SELECTED&IS_VALIDATED)
+ @Override
+ public String toString() {
+ final StringJoiner sj = new StringJoiner(
+ "&", // delimiter
+ "Score(" + mLegacyInt + " ; Policies : ", // prefix
+ ")"); // suffix
+ for (int i = NetworkScore.MIN_AGENT_MANAGED_POLICY;
+ i <= NetworkScore.MAX_AGENT_MANAGED_POLICY; ++i) {
+ if (hasPolicy(i)) sj.add(policyNameOf(i));
+ }
+ for (int i = MIN_CS_MANAGED_POLICY; i <= MAX_CS_MANAGED_POLICY; ++i) {
+ if (hasPolicy(i)) sj.add(policyNameOf(i));
+ }
+ return sj.toString();
+ }
+}
diff --git a/services/core/java/com/android/server/connectivity/MockableSystemProperties.java b/services/core/java/com/android/server/connectivity/MockableSystemProperties.java
index ef76734..a25b89a 100644
--- a/services/core/java/com/android/server/connectivity/MockableSystemProperties.java
+++ b/services/core/java/com/android/server/connectivity/MockableSystemProperties.java
@@ -17,7 +17,6 @@
package com.android.server.connectivity;
import android.os.SystemProperties;
-import android.sysprop.NetworkProperties;
public class MockableSystemProperties {
@@ -32,10 +31,4 @@
public boolean getBoolean(String key, boolean def) {
return SystemProperties.getBoolean(key, def);
}
- /**
- * Set net.tcp_def_init_rwnd to the tcp initial receive window size.
- */
- public void setTcpInitRwnd(int value) {
- NetworkProperties.tcp_init_rwnd(value);
- }
}
diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
index fa80b25..c66a280 100644
--- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java
+++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
@@ -16,6 +16,8 @@
package com.android.server.connectivity;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+
import static com.android.net.module.util.CollectionUtils.contains;
import android.annotation.NonNull;
@@ -35,6 +37,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.net.module.util.NetworkStackConstants;
+import com.android.server.ConnectivityService;
import java.net.Inet6Address;
import java.util.Objects;
@@ -94,12 +97,15 @@
private Inet6Address mIPv6Address;
private State mState = State.IDLE;
+ private boolean mEnableClatOnCellular;
private boolean mPrefixDiscoveryRunning;
- public Nat464Xlat(NetworkAgentInfo nai, INetd netd, IDnsResolver dnsResolver) {
+ public Nat464Xlat(NetworkAgentInfo nai, INetd netd, IDnsResolver dnsResolver,
+ ConnectivityService.Dependencies deps) {
mDnsResolver = dnsResolver;
mNetd = netd;
mNetwork = nai;
+ mEnableClatOnCellular = deps.getCellular464XlatEnabled();
}
/**
@@ -111,7 +117,7 @@
* @return true if the network requires clat, false otherwise.
*/
@VisibleForTesting
- protected static boolean requiresClat(NetworkAgentInfo nai) {
+ protected boolean requiresClat(NetworkAgentInfo nai) {
// TODO: migrate to NetworkCapabilities.TRANSPORT_*.
final boolean supported = contains(NETWORK_TYPES, nai.networkInfo.getType());
final boolean connected = contains(NETWORK_STATES, nai.networkInfo.getState());
@@ -126,7 +132,9 @@
final boolean skip464xlat = (nai.netAgentConfig() != null)
&& nai.netAgentConfig().skip464xlat;
- return supported && connected && isIpv6OnlyNetwork && !skip464xlat;
+ return supported && connected && isIpv6OnlyNetwork && !skip464xlat
+ && (nai.networkCapabilities.hasTransport(TRANSPORT_CELLULAR)
+ ? isCellular464XlatEnabled() : true);
}
/**
@@ -137,7 +145,7 @@
* @return true if the network should start clat, false otherwise.
*/
@VisibleForTesting
- protected static boolean shouldStartClat(NetworkAgentInfo nai) {
+ protected boolean shouldStartClat(NetworkAgentInfo nai) {
LinkProperties lp = nai.linkProperties;
return requiresClat(nai) && lp != null && lp.getNat64Prefix() != null;
}
@@ -507,4 +515,9 @@
protected int getNetId() {
return mNetwork.network.getNetId();
}
+
+ @VisibleForTesting
+ protected boolean isCellular464XlatEnabled() {
+ return mEnableClatOnCellular;
+ }
}
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 1d0e115..97df5bf 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -25,6 +25,8 @@
import android.net.CaptivePortalData;
import android.net.IDnsResolver;
import android.net.INetd;
+import android.net.INetworkAgent;
+import android.net.INetworkAgentRegistry;
import android.net.INetworkMonitor;
import android.net.LinkProperties;
import android.net.NattKeepalivePacketData;
@@ -35,6 +37,7 @@
import android.net.NetworkInfo;
import android.net.NetworkMonitorManager;
import android.net.NetworkRequest;
+import android.net.NetworkScore;
import android.net.NetworkStateSnapshot;
import android.net.QosCallbackException;
import android.net.QosFilter;
@@ -46,12 +49,11 @@
import android.os.RemoteException;
import android.os.SystemClock;
import android.telephony.data.EpsBearerQosSessionAttributes;
+import android.telephony.data.NrQosSessionAttributes;
import android.util.Log;
import android.util.Pair;
import android.util.SparseArray;
-import com.android.connectivity.aidl.INetworkAgent;
-import com.android.connectivity.aidl.INetworkAgentRegistry;
import com.android.internal.util.WakeupMessage;
import com.android.server.ConnectivityService;
@@ -302,8 +304,9 @@
// validated).
private boolean mInactive;
- // This represents the quality of the network with no clear scale.
- private int mScore;
+ // This represents the quality of the network. As opposed to NetworkScore, FullScore includes
+ // the ConnectivityService-managed bits.
+ private FullScore mScore;
// The list of NetworkRequests being satisfied by this Network.
private final SparseArray<NetworkRequest> mNetworkRequests = new SparseArray<>();
@@ -338,10 +341,11 @@
private final QosCallbackTracker mQosCallbackTracker;
public NetworkAgentInfo(INetworkAgent na, Network net, NetworkInfo info,
- @NonNull LinkProperties lp, @NonNull NetworkCapabilities nc, int score, Context context,
+ @NonNull LinkProperties lp, @NonNull NetworkCapabilities nc,
+ @NonNull NetworkScore score, Context context,
Handler handler, NetworkAgentConfig config, ConnectivityService connService, INetd netd,
IDnsResolver dnsResolver, int factorySerialNumber, int creatorUid,
- QosCallbackTracker qosCallbackTracker) {
+ QosCallbackTracker qosCallbackTracker, ConnectivityService.Dependencies deps) {
Objects.requireNonNull(net);
Objects.requireNonNull(info);
Objects.requireNonNull(lp);
@@ -354,12 +358,12 @@
networkInfo = info;
linkProperties = lp;
networkCapabilities = nc;
- mScore = score;
- clatd = new Nat464Xlat(this, netd, dnsResolver);
+ networkAgentConfig = config;
+ setScore(score); // uses members networkCapabilities and networkAgentConfig
+ clatd = new Nat464Xlat(this, netd, dnsResolver, deps);
mConnService = connService;
mContext = context;
mHandler = handler;
- networkAgentConfig = config;
this.factorySerialNumber = factorySerialNumber;
this.creatorUid = creatorUid;
mQosCallbackTracker = qosCallbackTracker;
@@ -573,6 +577,28 @@
}
}
+ /**
+ * Notify the NetworkAgent that the network is successfully connected.
+ */
+ public void onNetworkCreated() {
+ try {
+ networkAgent.onNetworkCreated();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error sending network created event", e);
+ }
+ }
+
+ /**
+ * Notify the NetworkAgent that the network is disconnected and destroyed.
+ */
+ public void onNetworkDisconnected() {
+ try {
+ networkAgent.onNetworkDisconnected();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error sending network disconnected event", e);
+ }
+ }
+
// TODO: consider moving out of NetworkAgentInfo into its own class
private class NetworkAgentMessageHandler extends INetworkAgentRegistry.Stub {
private final Handler mHandler;
@@ -603,9 +629,9 @@
}
@Override
- public void sendScore(int score) {
- mHandler.obtainMessage(NetworkAgent.EVENT_NETWORK_SCORE_CHANGED, score, 0,
- new Pair<>(NetworkAgentInfo.this, null)).sendToTarget();
+ public void sendScore(@NonNull final NetworkScore score) {
+ mHandler.obtainMessage(NetworkAgent.EVENT_NETWORK_SCORE_CHANGED,
+ new Pair<>(NetworkAgentInfo.this, score)).sendToTarget();
}
@Override
@@ -630,7 +656,13 @@
@Override
public void sendEpsQosSessionAvailable(final int qosCallbackId, final QosSession session,
final EpsBearerQosSessionAttributes attributes) {
- mQosCallbackTracker.sendEventQosSessionAvailable(qosCallbackId, session, attributes);
+ mQosCallbackTracker.sendEventEpsQosSessionAvailable(qosCallbackId, session, attributes);
+ }
+
+ @Override
+ public void sendNrQosSessionAvailable(final int qosCallbackId, final QosSession session,
+ final NrQosSessionAttributes attributes) {
+ mQosCallbackTracker.sendEventNrQosSessionAvailable(qosCallbackId, session, attributes);
}
@Override
@@ -665,6 +697,7 @@
@NonNull final NetworkCapabilities nc) {
final NetworkCapabilities oldNc = networkCapabilities;
networkCapabilities = nc;
+ mScore = mScore.mixInScore(networkCapabilities, networkAgentConfig);
final NetworkMonitorManager nm = mNetworkMonitor;
if (nm != null) {
nm.notifyNetworkCapabilitiesChanged(nc);
@@ -717,6 +750,7 @@
break;
case LISTEN:
+ case LISTEN_FOR_BEST:
case TRACK_DEFAULT:
case TRACK_SYSTEM_DEFAULT:
break;
@@ -841,30 +875,6 @@
return isVPN();
}
- private int getCurrentScore(boolean pretendValidated) {
- // TODO: We may want to refactor this into a NetworkScore class that takes a base score from
- // the NetworkAgent and signals from the NetworkAgent and uses those signals to modify the
- // score. The NetworkScore class would provide a nice place to centralize score constants
- // so they are not scattered about the transports.
-
- // If this network is explicitly selected and the user has decided to use it even if it's
- // unvalidated, give it the maximum score. Also give it the maximum score if it's explicitly
- // selected and we're trying to see what its score could be. This ensures that we don't tear
- // down an explicitly selected network before the user gets a chance to prefer it when
- // a higher-scoring network (e.g., Ethernet) is available.
- if (networkAgentConfig.explicitlySelected
- && (networkAgentConfig.acceptUnvalidated || pretendValidated)) {
- return ConnectivityConstants.EXPLICITLY_SELECTED_NETWORK_SCORE;
- }
-
- int score = mScore;
- if (!lastValidated && !pretendValidated && !ignoreWifiUnvalidationPenalty() && !isVPN()) {
- score -= ConnectivityConstants.UNVALIDATED_SCORE_PENALTY;
- }
- if (score < 0) score = 0;
- return score;
- }
-
// Return true on devices configured to ignore score penalty for wifi networks
// that become unvalidated (b/31075769).
private boolean ignoreWifiUnvalidationPenalty() {
@@ -877,17 +887,29 @@
// Get the current score for this Network. This may be modified from what the
// NetworkAgent sent, as it has modifiers applied to it.
public int getCurrentScore() {
- return getCurrentScore(false);
+ return mScore.getLegacyInt();
}
// Get the current score for this Network as if it was validated. This may be modified from
// what the NetworkAgent sent, as it has modifiers applied to it.
public int getCurrentScoreAsValidated() {
- return getCurrentScore(true);
+ return mScore.getLegacyIntAsValidated();
}
- public void setScore(final int score) {
- mScore = score;
+ /**
+ * Mix-in the ConnectivityService-managed bits in the score.
+ */
+ public void setScore(final NetworkScore score) {
+ mScore = FullScore.fromNetworkScore(score, networkCapabilities, networkAgentConfig);
+ }
+
+ /**
+ * Update the ConnectivityService-managed bits in the score.
+ *
+ * Call this after updating the network agent config.
+ */
+ public void updateScoreForNetworkAgentConfigUpdate() {
+ mScore = mScore.mixInScore(networkCapabilities, networkAgentConfig);
}
/**
diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
index 508739f..0c0d459 100644
--- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
+++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
@@ -28,6 +28,8 @@
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
+import android.graphics.drawable.Icon;
+import android.net.ConnectivityResources;
import android.net.NetworkSpecifier;
import android.net.TelephonyNetworkSpecifier;
import android.net.wifi.WifiInfo;
@@ -40,7 +42,7 @@
import android.util.SparseIntArray;
import android.widget.Toast;
-import com.android.internal.R;
+import com.android.connectivity.resources.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
@@ -82,6 +84,7 @@
// The context is for the current user (system server)
private final Context mContext;
+ private final Resources mResources;
private final TelephonyManager mTelephonyManager;
// The notification manager is created from a context for User.ALL, so notifications
// will be sent to all users.
@@ -96,6 +99,7 @@
(NotificationManager) c.createContextAsUser(UserHandle.ALL, 0 /* flags */)
.getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationTypeMap = new SparseIntArray();
+ mResources = new ConnectivityResources(mContext).get();
}
@VisibleForTesting
@@ -113,20 +117,19 @@
return -1;
}
- private static String getTransportName(final int transportType) {
- Resources r = Resources.getSystem();
- String[] networkTypes = r.getStringArray(R.array.network_switch_type_name);
+ private String getTransportName(final int transportType) {
+ String[] networkTypes = mResources.getStringArray(R.array.network_switch_type_name);
try {
return networkTypes[transportType];
} catch (IndexOutOfBoundsException e) {
- return r.getString(R.string.network_switch_type_name_unknown);
+ return mResources.getString(R.string.network_switch_type_name_unknown);
}
}
private static int getIcon(int transportType) {
return (transportType == TRANSPORT_WIFI)
- ? R.drawable.stat_notify_wifi_in_range : // TODO: Distinguish ! from ?.
- R.drawable.stat_notify_rssi_in_range;
+ ? R.drawable.stat_notify_wifi_in_range // TODO: Distinguish ! from ?.
+ : R.drawable.stat_notify_rssi_in_range;
}
/**
@@ -156,7 +159,7 @@
final String tag = tagFor(id);
final int eventId = notifyType.eventId;
final int transportType;
- final String name;
+ final CharSequence name;
if (nai != null) {
transportType = approximateTransportType(nai);
final String extraInfo = nai.networkInfo.getExtraInfo();
@@ -194,10 +197,10 @@
tag, nameOf(eventId), getTransportName(transportType), name, highPriority));
}
- Resources r = mContext.getResources();
+ final Resources r = mResources;
final CharSequence title;
final CharSequence details;
- int icon = getIcon(transportType);
+ Icon icon = Icon.createWithResource(r, getIcon(transportType));
if (notifyType == NotificationType.NO_INTERNET && transportType == TRANSPORT_WIFI) {
title = r.getString(R.string.wifi_no_internet, name);
details = r.getString(R.string.wifi_no_internet_detailed);
@@ -272,8 +275,7 @@
.setSmallIcon(icon)
.setAutoCancel(true)
.setTicker(title)
- .setColor(mContext.getColor(
- com.android.internal.R.color.system_notification_accent_color))
+ .setColor(mContext.getColor(android.R.color.system_notification_accent_color))
.setContentTitle(title)
.setContentIntent(intent)
.setLocalOnly(true)
@@ -353,7 +355,7 @@
public void showToast(NetworkAgentInfo fromNai, NetworkAgentInfo toNai) {
String fromTransport = getTransportName(approximateTransportType(fromNai));
String toTransport = getTransportName(approximateTransportType(toNai));
- String text = mContext.getResources().getString(
+ String text = mResources.getString(
R.string.network_switch_metered_toast, fromTransport, toTransport);
Toast.makeText(mContext, text, Toast.LENGTH_LONG).show();
}
diff --git a/services/core/java/com/android/server/connectivity/PacProxyInstaller.java b/services/core/java/com/android/server/connectivity/PacProxyService.java
similarity index 75%
rename from services/core/java/com/android/server/connectivity/PacProxyInstaller.java
rename to services/core/java/com/android/server/connectivity/PacProxyService.java
index aadaf4d..d23b488 100644
--- a/services/core/java/com/android/server/connectivity/PacProxyInstaller.java
+++ b/services/core/java/com/android/server/connectivity/PacProxyService.java
@@ -16,6 +16,8 @@
package com.android.server.connectivity;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.WorkerThread;
import android.app.AlarmManager;
import android.app.PendingIntent;
@@ -26,12 +28,16 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
+import android.net.IPacProxyInstalledListener;
+import android.net.IPacProxyManager;
import android.net.ProxyInfo;
import android.net.TrafficStats;
import android.net.Uri;
import android.os.Handler;
+import android.os.HandlerExecutor;
import android.os.HandlerThread;
import android.os.IBinder;
+import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
@@ -44,6 +50,7 @@
import com.android.net.IProxyCallback;
import com.android.net.IProxyPortListener;
import com.android.net.IProxyService;
+import com.android.net.module.util.PermissionUtils;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -53,7 +60,7 @@
/**
* @hide
*/
-public class PacProxyInstaller {
+public class PacProxyService extends IPacProxyManager.Stub {
private static final String PAC_PACKAGE = "com.android.pacprocessor";
private static final String PAC_SERVICE = "com.android.pacprocessor.PacService";
private static final String PAC_SERVICE_NAME = "com.android.net.IProxyService";
@@ -61,7 +68,7 @@
private static final String PROXY_PACKAGE = "com.android.proxyhandler";
private static final String PROXY_SERVICE = "com.android.proxyhandler.ProxyService";
- private static final String TAG = "PacProxyInstaller";
+ private static final String TAG = "PacProxyService";
private static final String ACTION_PAC_REFRESH = "android.net.proxy.PAC_REFRESH";
@@ -71,10 +78,6 @@
private static final int DELAY_LONG = 4;
private static final long MAX_PAC_SIZE = 20 * 1000 * 1000;
- // Return values for #setCurrentProxyScriptUrl
- public static final boolean DONT_SEND_BROADCAST = false;
- public static final boolean DO_SEND_BROADCAST = true;
-
private String mCurrentPac;
@GuardedBy("mProxyLock")
private volatile Uri mPacUrl = Uri.EMPTY;
@@ -93,8 +96,8 @@
private volatile boolean mHasSentBroadcast;
private volatile boolean mHasDownloaded;
- private Handler mConnectivityHandler;
- private final int mProxyMessage;
+ private final RemoteCallbackList<IPacProxyInstalledListener>
+ mCallbacks = new RemoteCallbackList<>();
/**
* Used for locking when setting mProxyService and all references to mCurrentPac.
@@ -102,6 +105,13 @@
private final Object mProxyLock = new Object();
/**
+ * Lock ensuring consistency between the values of mHasSentBroadcast, mHasDownloaded, the
+ * last URL and port, and the broadcast message being sent with the correct arguments.
+ * TODO : this should probably protect all instances of these variables
+ */
+ private final Object mBroadcastStateLock = new Object();
+
+ /**
* Runnable to download PAC script.
* The behavior relies on the assumption it always runs on mNetThread to guarantee that the
* latest data fetched from mPacUrl is stored in mProxyService.
@@ -146,10 +156,10 @@
}
}
- public PacProxyInstaller(Context context, Handler handler, int proxyMessage) {
+ public PacProxyService(@NonNull Context context) {
mContext = context;
mLastPort = -1;
- final HandlerThread netThread = new HandlerThread("android.pacproxyinstaller",
+ final HandlerThread netThread = new HandlerThread("android.pacproxyservice",
android.os.Process.THREAD_PRIORITY_DEFAULT);
netThread.start();
mNetThreadHandler = new Handler(netThread.getLooper());
@@ -158,8 +168,6 @@
context, 0, new Intent(ACTION_PAC_REFRESH), PendingIntent.FLAG_IMMUTABLE);
context.registerReceiver(new PacRefreshIntentReceiver(),
new IntentFilter(ACTION_PAC_REFRESH));
- mConnectivityHandler = handler;
- mProxyMessage = proxyMessage;
}
private AlarmManager getAlarmManager() {
@@ -169,38 +177,52 @@
return mAlarmManager;
}
+ @Override
+ public void addListener(IPacProxyInstalledListener listener) {
+ PermissionUtils.enforceNetworkStackPermissionOr(mContext,
+ android.Manifest.permission.NETWORK_SETTINGS);
+ mCallbacks.register(listener);
+ }
+
+ @Override
+ public void removeListener(IPacProxyInstalledListener listener) {
+ PermissionUtils.enforceNetworkStackPermissionOr(mContext,
+ android.Manifest.permission.NETWORK_SETTINGS);
+ mCallbacks.unregister(listener);
+ }
+
/**
* Updates the PAC Proxy Installer with current Proxy information. This is called by
- * the ProxyTracker directly before a broadcast takes place to allow
- * the PacProxyInstaller to indicate that the broadcast should not be sent and the
- * PacProxyInstaller will trigger a new broadcast when it is ready.
+ * the ProxyTracker through PacProxyManager before a broadcast takes place to allow
+ * the PacProxyService to indicate that the broadcast should not be sent and the
+ * PacProxyService will trigger a new broadcast when it is ready.
*
* @param proxy Proxy information that is about to be broadcast.
- * @return Returns whether the broadcast should be sent : either DO_ or DONT_SEND_BROADCAST
*/
- public synchronized boolean setCurrentProxyScriptUrl(ProxyInfo proxy) {
- if (!Uri.EMPTY.equals(proxy.getPacFileUrl())) {
- if (proxy.getPacFileUrl().equals(mPacUrl) && (proxy.getPort() > 0)) {
- // Allow to send broadcast, nothing to do.
- return DO_SEND_BROADCAST;
- }
- mPacUrl = proxy.getPacFileUrl();
- mCurrentDelay = DELAY_1;
- mHasSentBroadcast = false;
- mHasDownloaded = false;
- getAlarmManager().cancel(mPacRefreshIntent);
- bind();
- return DONT_SEND_BROADCAST;
- } else {
- getAlarmManager().cancel(mPacRefreshIntent);
- synchronized (mProxyLock) {
- mPacUrl = Uri.EMPTY;
- mCurrentPac = null;
- if (mProxyService != null) {
- unbind();
+ @Override
+ public void setCurrentProxyScriptUrl(@Nullable ProxyInfo proxy) {
+ PermissionUtils.enforceNetworkStackPermissionOr(mContext,
+ android.Manifest.permission.NETWORK_SETTINGS);
+
+ synchronized (mBroadcastStateLock) {
+ if (proxy != null && !Uri.EMPTY.equals(proxy.getPacFileUrl())) {
+ if (proxy.getPacFileUrl().equals(mPacUrl) && (proxy.getPort() > 0)) return;
+ mPacUrl = proxy.getPacFileUrl();
+ mCurrentDelay = DELAY_1;
+ mHasSentBroadcast = false;
+ mHasDownloaded = false;
+ getAlarmManager().cancel(mPacRefreshIntent);
+ bind();
+ } else {
+ getAlarmManager().cancel(mPacRefreshIntent);
+ synchronized (mProxyLock) {
+ mPacUrl = Uri.EMPTY;
+ mCurrentPac = null;
+ if (mProxyService != null) {
+ unbind();
+ }
}
}
- return DO_SEND_BROADCAST;
}
}
@@ -275,6 +297,7 @@
getAlarmManager().set(AlarmManager.ELAPSED_REALTIME, timeTillTrigger, mPacRefreshIntent);
}
+ @GuardedBy("mProxyLock")
private void setCurrentProxyScript(String script) {
if (mProxyService == null) {
Log.e(TAG, "setCurrentProxyScript: no proxy service");
@@ -347,6 +370,9 @@
public void setProxyPort(int port) {
if (mLastPort != -1) {
// Always need to send if port changed
+ // TODO: Here lacks synchronization because this write cannot
+ // guarantee that it's visible from sendProxyIfNeeded() when
+ // it's called by a Runnable which is post by mNetThread.
mHasSentBroadcast = false;
}
mLastPort = port;
@@ -365,8 +391,9 @@
}
}
};
- mContext.bindService(intent, mProxyConnection,
- Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND | Context.BIND_NOT_VISIBLE);
+ mContext.bindService(intent,
+ Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND | Context.BIND_NOT_VISIBLE,
+ new HandlerExecutor(mNetThreadHandler), mProxyConnection);
}
private void unbind() {
@@ -383,16 +410,28 @@
}
private void sendPacBroadcast(ProxyInfo proxy) {
- mConnectivityHandler.sendMessage(mConnectivityHandler.obtainMessage(mProxyMessage, proxy));
+ final int length = mCallbacks.beginBroadcast();
+ for (int i = 0; i < length; i++) {
+ final IPacProxyInstalledListener listener = mCallbacks.getBroadcastItem(i);
+ if (listener != null) {
+ try {
+ listener.onPacProxyInstalled(null /* network */, proxy);
+ } catch (RemoteException ignored) { }
+ }
+ }
+ mCallbacks.finishBroadcast();
}
- private synchronized void sendProxyIfNeeded() {
- if (!mHasDownloaded || (mLastPort == -1)) {
- return;
- }
- if (!mHasSentBroadcast) {
- sendPacBroadcast(ProxyInfo.buildPacProxy(mPacUrl, mLastPort));
- mHasSentBroadcast = true;
+ // This method must be called on mNetThreadHandler.
+ private void sendProxyIfNeeded() {
+ synchronized (mBroadcastStateLock) {
+ if (!mHasDownloaded || (mLastPort == -1)) {
+ return;
+ }
+ if (!mHasSentBroadcast) {
+ sendPacBroadcast(ProxyInfo.buildPacProxy(mPacUrl, mLastPort));
+ mHasSentBroadcast = true;
+ }
}
}
}
diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
index 9411e33..3711679 100644
--- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java
+++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
@@ -31,14 +31,17 @@
import static com.android.net.module.util.CollectionUtils.toIntArray;
import android.annotation.NonNull;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.PackageManagerInternal;
import android.net.INetd;
import android.net.UidRange;
+import android.net.Uri;
import android.os.Build;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
@@ -54,7 +57,6 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.IndentingPrintWriter;
import com.android.net.module.util.CollectionUtils;
-import com.android.server.LocalServices;
import java.util.ArrayList;
import java.util.HashMap;
@@ -71,7 +73,7 @@
*
* @hide
*/
-public class PermissionMonitor implements PackageManagerInternal.PackageListObserver {
+public class PermissionMonitor {
private static final String TAG = "PermissionMonitor";
private static final boolean DBG = true;
protected static final Boolean SYSTEM = Boolean.TRUE;
@@ -83,6 +85,7 @@
private final SystemConfigManager mSystemConfigManager;
private final INetd mNetd;
private final Dependencies mDeps;
+ private final Context mContext;
@GuardedBy("this")
private final Set<UserHandle> mUsers = new HashSet<>();
@@ -102,6 +105,25 @@
@GuardedBy("this")
private final Set<Integer> mAllApps = new HashSet<>();
+ private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
+ final Uri packageData = intent.getData();
+ final String packageName =
+ packageData != null ? packageData.getSchemeSpecificPart() : null;
+
+ if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
+ onPackageAdded(packageName, uid);
+ } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
+ onPackageRemoved(packageName, uid);
+ } else {
+ Log.wtf(TAG, "received unexpected intent: " + action);
+ }
+ }
+ };
+
/**
* Dependencies of PermissionMonitor, for injection in tests.
*/
@@ -127,6 +149,7 @@
mSystemConfigManager = context.getSystemService(SystemConfigManager.class);
mNetd = netd;
mDeps = deps;
+ mContext = context;
}
// Intended to be called only once at startup, after the system is ready. Installs a broadcast
@@ -134,12 +157,14 @@
public synchronized void startMonitoring() {
log("Monitoring");
- PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
- if (pmi != null) {
- pmi.getPackageList(this);
- } else {
- loge("failed to get the PackageManagerInternal service");
- }
+ final IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
+ intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ intentFilter.addDataScheme("package");
+ mContext.createContextAsUser(UserHandle.ALL, 0 /* flags */).registerReceiver(
+ mIntentReceiver, intentFilter, null /* broadcastPermission */,
+ null /* scheduler */);
+
List<PackageInfo> apps = mPackageManager.getInstalledPackages(GET_PERMISSIONS
| MATCH_ANY_USER);
if (apps == null) {
@@ -246,6 +271,13 @@
return mApps.containsKey(uid);
}
+ /**
+ * Returns whether the given uid has permission to use restricted networks.
+ */
+ public synchronized boolean hasRestrictedNetworksPermission(int uid) {
+ return Boolean.TRUE.equals(mApps.get(uid));
+ }
+
private void update(Set<UserHandle> users, Map<Integer, Boolean> apps, boolean add) {
List<Integer> network = new ArrayList<>();
List<Integer> system = new ArrayList<>();
@@ -347,9 +379,10 @@
*
* @hide
*/
- @Override
public synchronized void onPackageAdded(@NonNull final String packageName, final int uid) {
- sendPackagePermissionsForUid(uid, getPermissionForUid(uid));
+ // TODO: Netd is using appId for checking traffic permission. Correct the methods that are
+ // using appId instead of uid actually
+ sendPackagePermissionsForUid(UserHandle.getAppId(uid), getPermissionForUid(uid));
// If multiple packages share a UID (cf: android:sharedUserId) and ask for different
// permissions, don't downgrade (i.e., if it's already SYSTEM, leave it as is).
@@ -384,9 +417,10 @@
*
* @hide
*/
- @Override
public synchronized void onPackageRemoved(@NonNull final String packageName, final int uid) {
- sendPackagePermissionsForUid(uid, getPermissionForUid(uid));
+ // TODO: Netd is using appId for checking traffic permission. Correct the methods that are
+ // using appId instead of uid actually
+ sendPackagePermissionsForUid(UserHandle.getAppId(uid), getPermissionForUid(uid));
// If the newly-removed package falls within some VPN's uid range, update Netd with it.
// This needs to happen before the mApps update below, since removeBypassingUids() depends
@@ -432,19 +466,6 @@
}
}
- /**
- * Called when a package is changed.
- *
- * @param packageName The name of the changed package.
- * @param uid The uid of the changed package.
- *
- * @hide
- */
- @Override
- public synchronized void onPackageChanged(@NonNull final String packageName, final int uid) {
- sendPackagePermissionsForUid(uid, getPermissionForUid(uid));
- }
-
private static int getNetdPermissionMask(String[] requestedPermissions,
int[] requestedPermissionsFlags) {
int permissions = 0;
diff --git a/services/core/java/com/android/server/connectivity/ProfileNetworkPreferences.java b/services/core/java/com/android/server/connectivity/ProfileNetworkPreferences.java
new file mode 100644
index 0000000..dd2815d
--- /dev/null
+++ b/services/core/java/com/android/server/connectivity/ProfileNetworkPreferences.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.connectivity;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.NetworkCapabilities;
+import android.os.UserHandle;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * A data class containing all the per-profile network preferences.
+ *
+ * A given profile can only have one preference.
+ */
+public class ProfileNetworkPreferences {
+ /**
+ * A single preference, as it applies to a given user profile.
+ */
+ public static class Preference {
+ @NonNull public final UserHandle user;
+ // Capabilities are only null when sending an object to remove the setting for a user
+ @Nullable public final NetworkCapabilities capabilities;
+
+ public Preference(@NonNull final UserHandle user,
+ @Nullable final NetworkCapabilities capabilities) {
+ this.user = user;
+ this.capabilities = null == capabilities ? null : new NetworkCapabilities(capabilities);
+ }
+
+ /** toString */
+ public String toString() {
+ return "[ProfileNetworkPreference user=" + user + " caps=" + capabilities + "]";
+ }
+ }
+
+ @NonNull public final List<Preference> preferences;
+
+ public ProfileNetworkPreferences() {
+ preferences = Collections.EMPTY_LIST;
+ }
+
+ private ProfileNetworkPreferences(@NonNull final List<Preference> list) {
+ preferences = Collections.unmodifiableList(list);
+ }
+
+ /**
+ * Returns a new object consisting of this object plus the passed preference.
+ *
+ * If a preference already exists for the same user, it will be replaced by the passed
+ * preference. Passing a Preference object containing a null capabilities object is equivalent
+ * to (and indeed, implemented as) removing the preference for this user.
+ */
+ public ProfileNetworkPreferences plus(@NonNull final Preference pref) {
+ final ArrayList<Preference> newPrefs = new ArrayList<>();
+ for (final Preference existingPref : preferences) {
+ if (!existingPref.user.equals(pref.user)) {
+ newPrefs.add(existingPref);
+ }
+ }
+ if (null != pref.capabilities) {
+ newPrefs.add(pref);
+ }
+ return new ProfileNetworkPreferences(newPrefs);
+ }
+
+ public boolean isEmpty() {
+ return preferences.isEmpty();
+ }
+}
diff --git a/services/core/java/com/android/server/connectivity/ProxyTracker.java b/services/core/java/com/android/server/connectivity/ProxyTracker.java
index d83ff83..f572b46 100644
--- a/services/core/java/com/android/server/connectivity/ProxyTracker.java
+++ b/services/core/java/com/android/server/connectivity/ProxyTracker.java
@@ -16,10 +16,10 @@
package com.android.server.connectivity;
-import static android.provider.Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST;
-import static android.provider.Settings.Global.GLOBAL_HTTP_PROXY_HOST;
-import static android.provider.Settings.Global.GLOBAL_HTTP_PROXY_PAC;
-import static android.provider.Settings.Global.GLOBAL_HTTP_PROXY_PORT;
+import static android.net.ConnectivitySettingsManager.GLOBAL_HTTP_PROXY_EXCLUSION_LIST;
+import static android.net.ConnectivitySettingsManager.GLOBAL_HTTP_PROXY_HOST;
+import static android.net.ConnectivitySettingsManager.GLOBAL_HTTP_PROXY_PAC;
+import static android.net.ConnectivitySettingsManager.GLOBAL_HTTP_PROXY_PORT;
import static android.provider.Settings.Global.HTTP_PROXY;
import android.annotation.NonNull;
@@ -27,6 +27,8 @@
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
+import android.net.Network;
+import android.net.PacProxyManager;
import android.net.Proxy;
import android.net.ProxyInfo;
import android.net.Uri;
@@ -36,6 +38,7 @@
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
+import android.util.Pair;
import com.android.internal.annotations.GuardedBy;
import com.android.net.module.util.ProxyUtils;
@@ -67,7 +70,7 @@
// is not set. Individual networks have their own settings that override this. This member
// is set through setDefaultProxy, which is called when the default network changes proxies
// in its LinkProperties, or when ConnectivityService switches to a new default network, or
- // when PacProxyInstaller resolves the proxy.
+ // when PacProxyService resolves the proxy.
@Nullable
@GuardedBy("mProxyLock")
private volatile ProxyInfo mDefaultProxy = null;
@@ -77,16 +80,31 @@
private final Handler mConnectivityServiceHandler;
- // The object responsible for Proxy Auto Configuration (PAC).
- @NonNull
- private final PacProxyInstaller mPacProxyInstaller;
+ private final PacProxyManager mPacProxyManager;
+
+ private class PacProxyInstalledListener implements PacProxyManager.PacProxyInstalledListener {
+ private final int mEvent;
+
+ PacProxyInstalledListener(int event) {
+ mEvent = event;
+ }
+
+ public void onPacProxyInstalled(@Nullable Network network, @NonNull ProxyInfo proxy) {
+ mConnectivityServiceHandler
+ .sendMessage(mConnectivityServiceHandler
+ .obtainMessage(mEvent, new Pair<>(network, proxy)));
+ }
+ }
public ProxyTracker(@NonNull final Context context,
@NonNull final Handler connectivityServiceInternalHandler, final int pacChangedEvent) {
mContext = context;
mConnectivityServiceHandler = connectivityServiceInternalHandler;
- mPacProxyInstaller = new PacProxyInstaller(
- context, connectivityServiceInternalHandler, pacChangedEvent);
+ mPacProxyManager = context.getSystemService(PacProxyManager.class);
+
+ PacProxyInstalledListener listener = new PacProxyInstalledListener(pacChangedEvent);
+ mPacProxyManager.addPacProxyInstalledListener(
+ mConnectivityServiceHandler::post, listener);
}
// Convert empty ProxyInfo's to null as null-checks are used to determine if proxies are present
@@ -182,7 +200,7 @@
if (!TextUtils.isEmpty(pacFileUrl)) {
mConnectivityServiceHandler.post(
- () -> mPacProxyInstaller.setCurrentProxyScriptUrl(proxyProperties));
+ () -> mPacProxyManager.setCurrentProxyScriptUrl(proxyProperties));
}
}
}
@@ -226,9 +244,9 @@
final ProxyInfo defaultProxy = getDefaultProxy();
final ProxyInfo proxyInfo = null != defaultProxy ?
defaultProxy : ProxyInfo.buildDirectProxy("", 0, Collections.emptyList());
+ mPacProxyManager.setCurrentProxyScriptUrl(proxyInfo);
- if (mPacProxyInstaller.setCurrentProxyScriptUrl(proxyInfo)
- == PacProxyInstaller.DONT_SEND_BROADCAST) {
+ if (!shouldSendBroadcast(proxyInfo)) {
return;
}
if (DBG) Log.d(TAG, "sending Proxy Broadcast for " + proxyInfo);
@@ -244,6 +262,10 @@
}
}
+ private boolean shouldSendBroadcast(ProxyInfo proxy) {
+ return Uri.EMPTY.equals(proxy.getPacFileUrl()) || proxy.getPort() > 0;
+ }
+
/**
* Sets the global proxy in memory. Also writes the values to the global settings of the device.
*
@@ -308,10 +330,10 @@
return;
}
- // This call could be coming from the PacProxyInstaller, containing the port of the
+ // This call could be coming from the PacProxyService, containing the port of the
// local proxy. If this new proxy matches the global proxy then copy this proxy to the
// global (to get the correct local port), and send a broadcast.
- // TODO: Switch PacProxyInstaller to have its own message to send back rather than
+ // TODO: Switch PacProxyService to have its own message to send back rather than
// reusing EVENT_HAS_CHANGED_PROXY and this call to handleApplyDefaultProxy.
if ((mGlobalProxy != null) && (proxyInfo != null)
&& (!Uri.EMPTY.equals(proxyInfo.getPacFileUrl()))
diff --git a/services/core/java/com/android/server/connectivity/QosCallbackAgentConnection.java b/services/core/java/com/android/server/connectivity/QosCallbackAgentConnection.java
index 0f5400d..534dbe7 100644
--- a/services/core/java/com/android/server/connectivity/QosCallbackAgentConnection.java
+++ b/services/core/java/com/android/server/connectivity/QosCallbackAgentConnection.java
@@ -27,6 +27,7 @@
import android.os.IBinder;
import android.os.RemoteException;
import android.telephony.data.EpsBearerQosSessionAttributes;
+import android.telephony.data.NrQosSessionAttributes;
import android.util.Log;
import java.util.Objects;
@@ -146,13 +147,23 @@
mNetworkAgentInfo.onQosCallbackUnregistered(mAgentCallbackId);
}
- void sendEventQosSessionAvailable(final QosSession session,
+ void sendEventEpsQosSessionAvailable(final QosSession session,
final EpsBearerQosSessionAttributes attributes) {
try {
- if (DBG) log("sendEventQosSessionAvailable: sending...");
+ if (DBG) log("sendEventEpsQosSessionAvailable: sending...");
mCallback.onQosEpsBearerSessionAvailable(session, attributes);
} catch (final RemoteException e) {
- loge("sendEventQosSessionAvailable: remote exception", e);
+ loge("sendEventEpsQosSessionAvailable: remote exception", e);
+ }
+ }
+
+ void sendEventNrQosSessionAvailable(final QosSession session,
+ final NrQosSessionAttributes attributes) {
+ try {
+ if (DBG) log("sendEventNrQosSessionAvailable: sending...");
+ mCallback.onNrQosSessionAvailable(session, attributes);
+ } catch (final RemoteException e) {
+ loge("sendEventNrQosSessionAvailable: remote exception", e);
}
}
diff --git a/services/core/java/com/android/server/connectivity/QosCallbackTracker.java b/services/core/java/com/android/server/connectivity/QosCallbackTracker.java
index 8bda532..b6ab47b 100644
--- a/services/core/java/com/android/server/connectivity/QosCallbackTracker.java
+++ b/services/core/java/com/android/server/connectivity/QosCallbackTracker.java
@@ -27,6 +27,7 @@
import android.os.Handler;
import android.os.IBinder;
import android.telephony.data.EpsBearerQosSessionAttributes;
+import android.telephony.data.NrQosSessionAttributes;
import android.util.Log;
import com.android.net.module.util.CollectionUtils;
@@ -179,17 +180,31 @@
}
/**
- * Called when the NetworkAgent sends the qos session available event
+ * Called when the NetworkAgent sends the qos session available event for EPS
*
* @param qosCallbackId the callback id that the qos session is now available to
* @param session the qos session that is now available
* @param attributes the qos attributes that are now available on the qos session
*/
- public void sendEventQosSessionAvailable(final int qosCallbackId,
+ public void sendEventEpsQosSessionAvailable(final int qosCallbackId,
final QosSession session,
final EpsBearerQosSessionAttributes attributes) {
- runOnAgentConnection(qosCallbackId, "sendEventQosSessionAvailable: ",
- ac -> ac.sendEventQosSessionAvailable(session, attributes));
+ runOnAgentConnection(qosCallbackId, "sendEventEpsQosSessionAvailable: ",
+ ac -> ac.sendEventEpsQosSessionAvailable(session, attributes));
+ }
+
+ /**
+ * Called when the NetworkAgent sends the qos session available event for NR
+ *
+ * @param qosCallbackId the callback id that the qos session is now available to
+ * @param session the qos session that is now available
+ * @param attributes the qos attributes that are now available on the qos session
+ */
+ public void sendEventNrQosSessionAvailable(final int qosCallbackId,
+ final QosSession session,
+ final NrQosSessionAttributes attributes) {
+ runOnAgentConnection(qosCallbackId, "sendEventNrQosSessionAvailable: ",
+ ac -> ac.sendEventNrQosSessionAvailable(session, attributes));
}
/**
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 124c374..e5ce4f0 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -17,11 +17,11 @@
package com.android.server.connectivity;
import static android.Manifest.permission.BIND_VPN_SERVICE;
-import static android.net.ConnectivityManager.NETID_UNSET;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import static android.net.RouteInfo.RTN_THROW;
import static android.net.RouteInfo.RTN_UNREACHABLE;
import static android.net.VpnManager.NOTIFICATION_CHANNEL_VPN;
+import static android.os.UserHandle.PER_USER_RANGE;
import static com.android.internal.util.Preconditions.checkArgument;
import static com.android.internal.util.Preconditions.checkNotNull;
@@ -68,8 +68,8 @@
import android.net.NetworkInfo.DetailedState;
import android.net.NetworkProvider;
import android.net.NetworkRequest;
+import android.net.NetworkScore;
import android.net.RouteInfo;
-import android.net.UidRange;
import android.net.UidRangeParcel;
import android.net.UnderlyingNetworkInfo;
import android.net.VpnManager;
@@ -222,7 +222,7 @@
protected NetworkAgent mNetworkAgent;
private final Looper mLooper;
@VisibleForTesting
- protected final NetworkCapabilities mNetworkCapabilities;
+ protected NetworkCapabilities mNetworkCapabilities;
private final SystemServices mSystemServices;
private final Ikev2SessionCreator mIkev2SessionCreator;
private final UserManager mUserManager;
@@ -459,11 +459,12 @@
mLegacyState = LegacyVpnInfo.STATE_DISCONNECTED;
mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_VPN, 0 /* subtype */, NETWORKTYPE,
"" /* subtypeName */);
- mNetworkCapabilities = new NetworkCapabilities();
- mNetworkCapabilities.addTransportType(NetworkCapabilities.TRANSPORT_VPN);
- mNetworkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN);
- mNetworkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED);
- mNetworkCapabilities.setTransportInfo(new VpnTransportInfo(VpnManager.TYPE_VPN_NONE));
+ mNetworkCapabilities = new NetworkCapabilities.Builder()
+ .addTransportType(NetworkCapabilities.TRANSPORT_VPN)
+ .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)
+ .setTransportInfo(new VpnTransportInfo(VpnManager.TYPE_VPN_NONE))
+ .build();
loadAlwaysOnPackage();
}
@@ -524,8 +525,10 @@
}
private void resetNetworkCapabilities() {
- mNetworkCapabilities.setUids(null);
- mNetworkCapabilities.setTransportInfo(new VpnTransportInfo(VpnManager.TYPE_VPN_NONE));
+ mNetworkCapabilities = new NetworkCapabilities.Builder(mNetworkCapabilities)
+ .setUids(null)
+ .setTransportInfo(new VpnTransportInfo(VpnManager.TYPE_VPN_NONE))
+ .build();
}
/**
@@ -1123,17 +1126,19 @@
}
/**
- * Return netId of current running VPN network.
+ * Return Network of current running VPN network.
*
- * @return a netId if there is a running VPN network or NETID_UNSET if there is no running VPN
+ * @return a Network if there is a running VPN network or null if there is no running VPN
* network or network is null.
*/
- public synchronized int getNetId() {
+ @VisibleForTesting
+ @Nullable
+ public synchronized Network getNetwork() {
final NetworkAgent agent = mNetworkAgent;
- if (null == agent) return NETID_UNSET;
+ if (null == agent) return null;
final Network network = agent.getNetwork();
- if (null == network) return NETID_UNSET;
- return network.getNetId();
+ if (null == network) return null;
+ return network;
}
private LinkProperties makeLinkProperties() {
@@ -1174,11 +1179,13 @@
if (!allowIPv4) {
lp.addRoute(new RouteInfo(new IpPrefix(
- NetworkStackConstants.IPV4_ADDR_ANY, 0), RTN_UNREACHABLE));
+ NetworkStackConstants.IPV4_ADDR_ANY, 0), null /*gateway*/,
+ null /*iface*/, RTN_UNREACHABLE));
}
if (!allowIPv6) {
lp.addRoute(new RouteInfo(new IpPrefix(
- NetworkStackConstants.IPV6_ADDR_ANY, 0), RTN_UNREACHABLE));
+ NetworkStackConstants.IPV6_ADDR_ANY, 0), null /*gateway*/,
+ null /*iface*/, RTN_UNREACHABLE));
}
// Concatenate search domains into a string.
@@ -1234,33 +1241,39 @@
// registered with registerDefaultNetworkCallback. This in turn protects the invariant
// that an app calling ConnectivityManager#bindProcessToNetwork(getDefaultNetwork())
// behaves the same as when it uses the default network.
- mNetworkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
+ final NetworkCapabilities.Builder capsBuilder =
+ new NetworkCapabilities.Builder(mNetworkCapabilities);
+ capsBuilder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
mLegacyState = LegacyVpnInfo.STATE_CONNECTING;
updateState(DetailedState.CONNECTING, "agentConnect");
- NetworkAgentConfig networkAgentConfig = new NetworkAgentConfig();
- networkAgentConfig.allowBypass = mConfig.allowBypass && !mLockdown;
+ final NetworkAgentConfig networkAgentConfig = new NetworkAgentConfig.Builder()
+ .setBypassableVpn(mConfig.allowBypass && !mLockdown)
+ .build();
- mNetworkCapabilities.setOwnerUid(mOwnerUID);
- mNetworkCapabilities.setAdministratorUids(new int[] {mOwnerUID});
- mNetworkCapabilities.setUids(createUserAndRestrictedProfilesRanges(mUserId,
+ capsBuilder.setOwnerUid(mOwnerUID);
+ capsBuilder.setAdministratorUids(new int[] {mOwnerUID});
+ capsBuilder.setUids(createUserAndRestrictedProfilesRanges(mUserId,
mConfig.allowedApplications, mConfig.disallowedApplications));
- mNetworkCapabilities.setTransportInfo(new VpnTransportInfo(getActiveVpnType()));
+ capsBuilder.setTransportInfo(new VpnTransportInfo(getActiveVpnType()));
// Only apps targeting Q and above can explicitly declare themselves as metered.
// These VPNs are assumed metered unless they state otherwise.
if (mIsPackageTargetingAtLeastQ && mConfig.isMetered) {
- mNetworkCapabilities.removeCapability(NET_CAPABILITY_NOT_METERED);
+ capsBuilder.removeCapability(NET_CAPABILITY_NOT_METERED);
} else {
- mNetworkCapabilities.addCapability(NET_CAPABILITY_NOT_METERED);
+ capsBuilder.addCapability(NET_CAPABILITY_NOT_METERED);
}
+ mNetworkCapabilities = capsBuilder.build();
mNetworkAgent = new NetworkAgent(mContext, mLooper, NETWORKTYPE /* logtag */,
- mNetworkCapabilities, lp, VPN_DEFAULT_SCORE, networkAgentConfig, mNetworkProvider) {
+ mNetworkCapabilities, lp,
+ new NetworkScore.Builder().setLegacyInt(VPN_DEFAULT_SCORE).build(),
+ networkAgentConfig, mNetworkProvider) {
@Override
- public void unwanted() {
+ public void onNetworkUnwanted() {
// We are user controlled, not driven by NetworkRequest.
}
};
@@ -1275,7 +1288,6 @@
});
mNetworkAgent.setUnderlyingNetworks((mConfig.underlyingNetworks != null)
? Arrays.asList(mConfig.underlyingNetworks) : null);
- mNetworkInfo.setIsAvailable(true);
updateState(DetailedState.CONNECTED, "agentConnect");
}
@@ -1346,7 +1358,7 @@
String oldInterface = mInterface;
Connection oldConnection = mConnection;
NetworkAgent oldNetworkAgent = mNetworkAgent;
- Set<UidRange> oldUsers = mNetworkCapabilities.getUids();
+ Set<Range<Integer>> oldUsers = mNetworkCapabilities.getUids();
// Configure the interface. Abort if any of these steps fails.
ParcelFileDescriptor tun = ParcelFileDescriptor.adoptFd(jniCreate(config.mtu));
@@ -1421,7 +1433,8 @@
// restore old state
mConfig = oldConfig;
mConnection = oldConnection;
- mNetworkCapabilities.setUids(oldUsers);
+ mNetworkCapabilities =
+ new NetworkCapabilities.Builder(mNetworkCapabilities).setUids(oldUsers).build();
mNetworkAgent = oldNetworkAgent;
mInterface = oldInterface;
throw e;
@@ -1452,7 +1465,7 @@
}
/**
- * Creates a {@link Set} of non-intersecting {@link UidRange} objects including all UIDs
+ * Creates a {@link Set} of non-intersecting {@code Range<Integer>} objects including all UIDs
* associated with one user, and any restricted profiles attached to that user.
*
* <p>If one of {@param allowedApplications} or {@param disallowedApplications} is provided,
@@ -1465,10 +1478,10 @@
* @param disallowedApplications (optional) List of applications to deny.
*/
@VisibleForTesting
- Set<UidRange> createUserAndRestrictedProfilesRanges(@UserIdInt int userId,
+ Set<Range<Integer>> createUserAndRestrictedProfilesRanges(@UserIdInt int userId,
@Nullable List<String> allowedApplications,
@Nullable List<String> disallowedApplications) {
- final Set<UidRange> ranges = new ArraySet<>();
+ final Set<Range<Integer>> ranges = new ArraySet<>();
// Assign the top-level user to the set of ranges
addUserToRanges(ranges, userId, allowedApplications, disallowedApplications);
@@ -1492,20 +1505,20 @@
}
/**
- * Updates a {@link Set} of non-intersecting {@link UidRange} objects to include all UIDs
+ * Updates a {@link Set} of non-intersecting {@code Range<Integer>} objects to include all UIDs
* associated with one user.
*
* <p>If one of {@param allowedApplications} or {@param disallowedApplications} is provided,
* the UID ranges will match the app allowlist or denylist specified there. Otherwise, all UIDs
* in the user will be included.
*
- * @param ranges {@link Set} of {@link UidRange}s to which to add.
+ * @param ranges {@link Set} of {@code Range<Integer>}s to which to add.
* @param userId The userId to add to {@param ranges}.
* @param allowedApplications (optional) allowlist of applications to include.
* @param disallowedApplications (optional) denylist of applications to exclude.
*/
@VisibleForTesting
- void addUserToRanges(@NonNull Set<UidRange> ranges, @UserIdInt int userId,
+ void addUserToRanges(@NonNull Set<Range<Integer>> ranges, @UserIdInt int userId,
@Nullable List<String> allowedApplications,
@Nullable List<String> disallowedApplications) {
if (allowedApplications != null) {
@@ -1515,40 +1528,41 @@
if (start == -1) {
start = uid;
} else if (uid != stop + 1) {
- ranges.add(new UidRange(start, stop));
+ ranges.add(new Range<Integer>(start, stop));
start = uid;
}
stop = uid;
}
- if (start != -1) ranges.add(new UidRange(start, stop));
+ if (start != -1) ranges.add(new Range<Integer>(start, stop));
} else if (disallowedApplications != null) {
// Add all ranges for user skipping UIDs for disallowedApplications.
- final UidRange userRange = UidRange.createForUser(UserHandle.of(userId));
- int start = userRange.start;
+ final Range<Integer> userRange = createUidRangeForUser(userId);
+ int start = userRange.getLower();
for (int uid : getAppsUids(disallowedApplications, userId)) {
if (uid == start) {
start++;
} else {
- ranges.add(new UidRange(start, uid - 1));
+ ranges.add(new Range<Integer>(start, uid - 1));
start = uid + 1;
}
}
- if (start <= userRange.stop) ranges.add(new UidRange(start, userRange.stop));
+ if (start <= userRange.getUpper()) {
+ ranges.add(new Range<Integer>(start, userRange.getUpper()));
+ }
} else {
// Add all UIDs for the user.
- ranges.add(UidRange.createForUser(UserHandle.of(userId)));
+ ranges.add(createUidRangeForUser(userId));
}
}
// Returns the subset of the full list of active UID ranges the VPN applies to (mVpnUsers) that
// apply to userId.
- private static List<UidRange> uidRangesForUser(int userId, Set<UidRange> existingRanges) {
- // UidRange#createForUser returns the entire range of UIDs available to a macro-user.
- // This is something like 0-99999 ; {@see UserHandle#PER_USER_RANGE}
- final UidRange userRange = UidRange.createForUser(UserHandle.of(userId));
- final List<UidRange> ranges = new ArrayList<>();
- for (UidRange range : existingRanges) {
- if (userRange.containsRange(range)) {
+ private static List<Range<Integer>> uidRangesForUser(int userId,
+ Set<Range<Integer>> existingRanges) {
+ final Range<Integer> userRange = createUidRangeForUser(userId);
+ final List<Range<Integer>> ranges = new ArrayList<>();
+ for (Range<Integer> range : existingRanges) {
+ if (userRange.contains(range)) {
ranges.add(range);
}
}
@@ -1565,12 +1579,13 @@
UserInfo user = mUserManager.getUserInfo(userId);
if (user.isRestricted() && user.restrictedProfileParentId == mUserId) {
synchronized(Vpn.this) {
- final Set<UidRange> existingRanges = mNetworkCapabilities.getUids();
+ final Set<Range<Integer>> existingRanges = mNetworkCapabilities.getUids();
if (existingRanges != null) {
try {
addUserToRanges(existingRanges, userId, mConfig.allowedApplications,
mConfig.disallowedApplications);
- mNetworkCapabilities.setUids(existingRanges);
+ mNetworkCapabilities = new NetworkCapabilities.Builder(mNetworkCapabilities)
+ .setUids(existingRanges).build();
} catch (Exception e) {
Log.wtf(TAG, "Failed to add restricted user to owner", e);
}
@@ -1593,13 +1608,14 @@
UserInfo user = mUserManager.getUserInfo(userId);
if (user.isRestricted() && user.restrictedProfileParentId == mUserId) {
synchronized(Vpn.this) {
- final Set<UidRange> existingRanges = mNetworkCapabilities.getUids();
+ final Set<Range<Integer>> existingRanges = mNetworkCapabilities.getUids();
if (existingRanges != null) {
try {
- final List<UidRange> removedRanges =
+ final List<Range<Integer>> removedRanges =
uidRangesForUser(userId, existingRanges);
existingRanges.removeAll(removedRanges);
- mNetworkCapabilities.setUids(existingRanges);
+ mNetworkCapabilities = new NetworkCapabilities.Builder(mNetworkCapabilities)
+ .setUids(existingRanges).build();
} catch (Exception e) {
Log.wtf(TAG, "Failed to remove restricted user to owner", e);
}
@@ -1657,7 +1673,7 @@
final Set<UidRangeParcel> rangesToRemove = new ArraySet<>(mBlockedUidsAsToldToConnectivity);
final Set<UidRangeParcel> rangesToAdd;
if (enforce) {
- final Set<UidRange> restrictedProfilesRanges =
+ final Set<Range<Integer>> restrictedProfilesRanges =
createUserAndRestrictedProfilesRanges(mUserId,
/* allowedApplications */ null,
/* disallowedApplications */ exemptedPackages);
@@ -1666,11 +1682,12 @@
// The UID range of the first user (0-99999) would block the IPSec traffic, which comes
// directly from the kernel and is marked as uid=0. So we adjust the range to allow
// it through (b/69873852).
- for (UidRange range : restrictedProfilesRanges) {
- if (range.start == 0 && range.stop != 0) {
- rangesThatShouldBeBlocked.add(new UidRangeParcel(1, range.stop));
- } else if (range.start != 0) {
- rangesThatShouldBeBlocked.add(new UidRangeParcel(range.start, range.stop));
+ for (Range<Integer> range : restrictedProfilesRanges) {
+ if (range.getLower() == 0 && range.getUpper() != 0) {
+ rangesThatShouldBeBlocked.add(new UidRangeParcel(1, range.getUpper()));
+ } else if (range.getLower() != 0) {
+ rangesThatShouldBeBlocked.add(
+ new UidRangeParcel(range.getLower(), range.getUpper()));
}
}
@@ -1692,12 +1709,12 @@
}
/**
- * Tell ConnectivityService to add or remove a list of {@link UidRange}s to the list of UIDs
- * that are only allowed to make connections through sockets that have had {@code protect()}
- * called on them.
+ * Tell ConnectivityService to add or remove a list of {@link UidRangeParcel}s to the list of
+ * UIDs that are only allowed to make connections through sockets that have had
+ * {@code protect()} called on them.
*
* @param enforce {@code true} to add to the denylist, {@code false} to remove.
- * @param ranges {@link Collection} of {@link UidRange}s to add (if {@param enforce} is
+ * @param ranges {@link Collection} of {@link UidRangeParcel}s to add (if {@param enforce} is
* {@code true}) or to remove.
* @return {@code true} if all of the UIDs were added/removed. {@code false} otherwise,
* including added ranges that already existed or removed ones that didn't.
@@ -1842,22 +1859,13 @@
/**
* Updates underlying network set.
*/
- public synchronized boolean setUnderlyingNetworks(Network[] networks) {
+ public synchronized boolean setUnderlyingNetworks(@Nullable Network[] networks) {
if (!isCallerEstablishedOwnerLocked()) {
return false;
}
- if (networks == null) {
- mConfig.underlyingNetworks = null;
- } else {
- mConfig.underlyingNetworks = new Network[networks.length];
- for (int i = 0; i < networks.length; ++i) {
- if (networks[i] == null) {
- mConfig.underlyingNetworks[i] = null;
- } else {
- mConfig.underlyingNetworks[i] = new Network(networks[i].getNetId());
- }
- }
- }
+ // Make defensive copy since the content of array might be altered by the caller.
+ mConfig.underlyingNetworks =
+ (networks != null) ? Arrays.copyOf(networks, networks.length) : null;
mNetworkAgent.setUnderlyingNetworks((mConfig.underlyingNetworks != null)
? Arrays.asList(mConfig.underlyingNetworks) : null);
return true;
@@ -1879,7 +1887,12 @@
if (!isRunningLocked()) {
return false;
}
- return mNetworkCapabilities.appliesToUid(uid);
+ final Set<Range<Integer>> uids = mNetworkCapabilities.getUids();
+ if (uids == null) return true;
+ for (final Range<Integer> range : uids) {
+ if (range.contains(uid)) return true;
+ }
+ return false;
}
/**
@@ -2696,7 +2709,8 @@
mConfig.routes.clear();
for (final RouteInfo route : oldRoutes) {
- mConfig.routes.add(new RouteInfo(route.getDestination(), RTN_UNREACHABLE));
+ mConfig.routes.add(new RouteInfo(route.getDestination(), null /*gateway*/,
+ null /*iface*/, RTN_UNREACHABLE));
}
if (mNetworkAgent != null) {
mNetworkAgent.sendLinkProperties(makeLinkProperties());
@@ -3035,10 +3049,12 @@
// Add a throw route for the VPN server endpoint, if one was specified.
if (endpointAddress instanceof Inet4Address) {
mConfig.routes.add(new RouteInfo(
- new IpPrefix(endpointAddress, 32), RTN_THROW));
+ new IpPrefix(endpointAddress, 32), null /*gateway*/,
+ null /*iface*/, RTN_THROW));
} else if (endpointAddress instanceof Inet6Address) {
mConfig.routes.add(new RouteInfo(
- new IpPrefix(endpointAddress, 128), RTN_THROW));
+ new IpPrefix(endpointAddress, 128), null /*gateway*/,
+ null /*iface*/, RTN_THROW));
} else {
Log.e(TAG, "Unknown IP address family for VPN endpoint: "
+ endpointAddress);
@@ -3338,4 +3354,12 @@
firstChildSessionCallback);
}
}
+
+ /**
+ * Returns the entire range of UIDs available to a macro-user. This is something like 0-99999.
+ */
+ @VisibleForTesting
+ static Range<Integer> createUidRangeForUser(int userId) {
+ return new Range<Integer>(userId * PER_USER_RANGE, (userId + 1) * PER_USER_RANGE - 1);
+ }
}
diff --git a/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java b/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java
index fa03e59..47eb3eb 100644
--- a/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java
+++ b/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java
@@ -405,7 +405,8 @@
for (final IkeTrafficSelector selector : trafficSelectors) {
for (final IpPrefix prefix :
new IpRange(selector.startingAddress, selector.endingAddress).asIpPrefixes()) {
- routes.add(new RouteInfo(prefix, null));
+ routes.add(new RouteInfo(prefix, null /*gateway*/, null /*iface*/,
+ RouteInfo.RTN_UNICAST));
}
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index f658e33..58a7025 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -619,8 +619,10 @@
}
}
- addAndStartAction(new NewDeviceAction(this, activeSource.logicalAddress,
- activeSource.physicalAddress, deviceType));
+ if (!mService.isPowerStandbyOrTransient()) {
+ addAndStartAction(new NewDeviceAction(this, activeSource.logicalAddress,
+ activeSource.physicalAddress, deviceType));
+ }
}
private boolean handleNewDeviceAtTheTailOfActivePath(int path) {
@@ -796,10 +798,12 @@
@ServiceThreadOnly
void onNewAvrAdded(HdmiDeviceInfo avr) {
assertRunOnServiceThread();
- addAndStartAction(new SystemAudioAutoInitiationAction(this, avr.getLogicalAddress()));
- if (isConnected(avr.getPortId()) && isArcFeatureEnabled(avr.getPortId())
- && !hasAction(SetArcTransmissionStateAction.class)) {
- startArcAction(true);
+ if (!mService.isPowerStandbyOrTransient()) {
+ addAndStartAction(new SystemAudioAutoInitiationAction(this, avr.getLogicalAddress()));
+ if (isConnected(avr.getPortId()) && isArcFeatureEnabled(avr.getPortId())
+ && !hasAction(SetArcTransmissionStateAction.class)) {
+ startArcAction(true);
+ }
}
}
@@ -1656,6 +1660,7 @@
// Remove recording actions.
removeAction(OneTouchRecordAction.class);
removeAction(TimerRecordingAction.class);
+ removeAction(NewDeviceAction.class);
disableSystemAudioIfExist();
disableArcIfExist();
@@ -1696,12 +1701,20 @@
setArcStatus(false);
// Seq #44.
- removeAction(RequestArcInitiationAction.class);
+ removeAllRunningArcAction();
if (!hasAction(RequestArcTerminationAction.class) && isArcEstablished()) {
addAndStartAction(new RequestArcTerminationAction(this, avr.getLogicalAddress()));
}
}
+ @ServiceThreadOnly
+ private void removeAllRunningArcAction() {
+ // Running or pending actions make TV fail to broadcast <Standby> to connected devices
+ removeAction(RequestArcTerminationAction.class);
+ removeAction(RequestArcInitiationAction.class);
+ removeAction(SetArcTransmissionStateAction.class);
+ }
+
@Override
@ServiceThreadOnly
protected void onStandby(boolean initiatedByCec, int standbyAction) {
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 294d7e2..0215188 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -92,7 +92,6 @@
import android.security.AndroidKeyStoreMaintenance;
import android.security.Authorization;
import android.security.KeyStore;
-import android.security.keystore.AndroidKeyStoreProvider;
import android.security.keystore.KeyProperties;
import android.security.keystore.KeyProtection;
import android.security.keystore.UserNotAuthenticatedException;
@@ -157,7 +156,6 @@
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
-import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -264,13 +262,7 @@
@Override
public void onStart() {
- Optional<Boolean> keystore2_enabled =
- android.sysprop.Keystore2Properties.keystore2_enabled();
- if (keystore2_enabled.isPresent() && keystore2_enabled.get()) {
- android.security.keystore2.AndroidKeyStoreProvider.install();
- } else {
- AndroidKeyStoreProvider.install();
- }
+ android.security.keystore2.AndroidKeyStoreProvider.install();
mLockSettingsService = new LockSettingsService(getContext());
publishBinderService("lock_settings", mLockSettingsService);
}
diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
index 48382a9..76ecc1a 100644
--- a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
+++ b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
@@ -15,14 +15,17 @@
*/
package com.android.server.locksettings;
+
import static android.os.UserHandle.USER_SYSTEM;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.content.Context;
import android.content.pm.UserInfo;
import android.os.Handler;
import android.os.SystemClock;
+import android.os.SystemProperties;
import android.os.UserManager;
import android.provider.DeviceConfig;
import android.provider.Settings;
@@ -35,6 +38,8 @@
import com.android.internal.widget.RebootEscrowListener;
import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
@@ -64,6 +69,24 @@
@VisibleForTesting
public static final String REBOOT_ESCROW_ARMED_KEY = "reboot_escrow_armed_count";
+ static final String REBOOT_ESCROW_KEY_ARMED_TIMESTAMP = "reboot_escrow_key_stored_timestamp";
+ static final String REBOOT_ESCROW_KEY_PROVIDER = "reboot_escrow_key_provider";
+
+ /**
+ * The verified boot 2.0 vbmeta digest of the current slot, the property value is always
+ * available after boot.
+ */
+ static final String VBMETA_DIGEST_PROP_NAME = "ro.boot.vbmeta.digest";
+ /**
+ * The system prop contains vbmeta digest of the inactive slot. The build property is set after
+ * an OTA update. RebootEscrowManager will store it in disk before the OTA reboot, so the value
+ * is available for vbmeta digest verification after the device reboots.
+ */
+ static final String OTHER_VBMETA_DIGEST_PROP_NAME = "ota.other.vbmeta_digest";
+ static final String REBOOT_ESCROW_KEY_VBMETA_DIGEST = "reboot_escrow_key_vbmeta_digest";
+ static final String REBOOT_ESCROW_KEY_OTHER_VBMETA_DIGEST =
+ "reboot_escrow_key_other_vbmeta_digest";
+
/**
* Number of boots until we consider the escrow data to be stale for the purposes of metrics.
* <p>
@@ -84,6 +107,31 @@
private static final int DEFAULT_LOAD_ESCROW_DATA_RETRY_COUNT = 3;
private static final int DEFAULT_LOAD_ESCROW_DATA_RETRY_INTERVAL_SECONDS = 30;
+ @IntDef(prefix = {"ERROR_"}, value = {
+ ERROR_NONE,
+ ERROR_UNKNOWN,
+ ERROR_NO_PROVIDER,
+ ERROR_LOAD_ESCROW_KEY,
+ ERROR_RETRY_COUNT_EXHAUSTED,
+ ERROR_UNLOCK_ALL_USERS,
+ ERROR_PROVIDER_MISMATCH,
+ ERROR_KEYSTORE_FAILURE,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface RebootEscrowErrorCode {
+ }
+
+ static final int ERROR_NONE = 0;
+ static final int ERROR_UNKNOWN = 1;
+ static final int ERROR_NO_PROVIDER = 2;
+ static final int ERROR_LOAD_ESCROW_KEY = 3;
+ static final int ERROR_RETRY_COUNT_EXHAUSTED = 4;
+ static final int ERROR_UNLOCK_ALL_USERS = 5;
+ static final int ERROR_PROVIDER_MISMATCH = 6;
+ static final int ERROR_KEYSTORE_FAILURE = 7;
+
+ private @RebootEscrowErrorCode int mLoadEscrowDataErrorCode = ERROR_NONE;
+
/**
* Logs events for later debugging in bugreports.
*/
@@ -144,8 +192,7 @@
private RebootEscrowProviderInterface createRebootEscrowProvider() {
RebootEscrowProviderInterface rebootEscrowProvider;
- if (DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_OTA,
- "server_based_ror_enabled", false)) {
+ if (serverBasedResumeOnReboot()) {
Slog.i(TAG, "Using server based resume on reboot");
rebootEscrowProvider = new RebootEscrowProviderServerBasedImpl(mContext, mStorage);
} else {
@@ -166,6 +213,11 @@
handler.postDelayed(runnable, delayMillis);
}
+ public boolean serverBasedResumeOnReboot() {
+ return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_OTA,
+ "server_based_ror_enabled", false);
+ }
+
public Context getContext() {
return mContext;
}
@@ -193,6 +245,10 @@
0);
}
+ public long getCurrentTimeMillis() {
+ return System.currentTimeMillis();
+ }
+
public int getLoadEscrowDataRetryLimit() {
return DeviceConfig.getInt(DeviceConfig.NAMESPACE_OTA,
"load_escrow_data_retry_count", DEFAULT_LOAD_ESCROW_DATA_RETRY_COUNT);
@@ -204,15 +260,22 @@
DEFAULT_LOAD_ESCROW_DATA_RETRY_INTERVAL_SECONDS);
}
- public void reportMetric(boolean success) {
- // TODO(b/179105110) design error code; and report the true value for other fields.
- FrameworkStatsLog.write(FrameworkStatsLog.REBOOT_ESCROW_RECOVERY_REPORTED, 0, 1, 1,
- -1, 0, -1);
+ public void reportMetric(boolean success, int errorCode, int serviceType, int attemptCount,
+ int escrowDurationInSeconds, int vbmetaDigestStatus,
+ int durationSinceBootCompleteInSeconds) {
+ FrameworkStatsLog.write(FrameworkStatsLog.REBOOT_ESCROW_RECOVERY_REPORTED, success,
+ errorCode, serviceType, attemptCount, escrowDurationInSeconds,
+ vbmetaDigestStatus, durationSinceBootCompleteInSeconds);
}
public RebootEscrowEventLog getEventLog() {
return new RebootEscrowEventLog();
}
+
+ public String getVbmetaDigest(boolean other) {
+ return other ? SystemProperties.get(OTHER_VBMETA_DIGEST_PROP_NAME)
+ : SystemProperties.get(VBMETA_DIGEST_PROP_NAME);
+ }
}
RebootEscrowManager(Context context, Callbacks callbacks, LockSettingsStorage storage) {
@@ -230,7 +293,7 @@
mKeyStoreManager = injector.getKeyStoreManager();
}
- private void onGetRebootEscrowKeyFailed(List<UserInfo> users) {
+ private void onGetRebootEscrowKeyFailed(List<UserInfo> users, int attemptCount) {
Slog.w(TAG, "Had reboot escrow data for users, but no key; removing escrow storage.");
for (UserInfo user : users) {
mStorage.removeRebootEscrow(user.id);
@@ -238,7 +301,7 @@
// Clear the old key in keystore.
mKeyStoreManager.clearKeyStoreEncryptionKey();
- onEscrowRestoreComplete(false);
+ onEscrowRestoreComplete(false, attemptCount);
}
void loadRebootEscrowDataIfAvailable(Handler retryHandler) {
@@ -251,6 +314,9 @@
}
if (rebootEscrowUsers.isEmpty()) {
+ Slog.i(TAG, "No reboot escrow data found for users,"
+ + " skipping loading escrow data");
+ clearMetricsStorage();
return;
}
@@ -274,7 +340,8 @@
}
Slog.w(TAG, "Failed to load reboot escrow data after " + attemptNumber + " attempts");
- onGetRebootEscrowKeyFailed(users);
+ mLoadEscrowDataErrorCode = ERROR_RETRY_COUNT_EXHAUSTED;
+ onGetRebootEscrowKeyFailed(users, attemptNumber);
}
void loadRebootEscrowDataWithRetry(Handler retryHandler, int attemptNumber,
@@ -297,7 +364,18 @@
}
if (escrowKey == null) {
- onGetRebootEscrowKeyFailed(users);
+ if (mLoadEscrowDataErrorCode == ERROR_NONE) {
+ // Specifically check if the RoR provider has changed after reboot.
+ int providerType = mInjector.serverBasedResumeOnReboot()
+ ? RebootEscrowProviderInterface.TYPE_SERVER_BASED
+ : RebootEscrowProviderInterface.TYPE_HAL;
+ if (providerType != mStorage.getInt(REBOOT_ESCROW_KEY_PROVIDER, -1, USER_SYSTEM)) {
+ mLoadEscrowDataErrorCode = ERROR_PROVIDER_MISMATCH;
+ } else {
+ mLoadEscrowDataErrorCode = ERROR_LOAD_ESCROW_KEY;
+ }
+ }
+ onGetRebootEscrowKeyFailed(users, attemptNumber + 1);
return;
}
@@ -311,17 +389,82 @@
// Clear the old key in keystore. A new key will be generated by new RoR requests.
mKeyStoreManager.clearKeyStoreEncryptionKey();
- onEscrowRestoreComplete(allUsersUnlocked);
+ if (!allUsersUnlocked && mLoadEscrowDataErrorCode == ERROR_NONE) {
+ mLoadEscrowDataErrorCode = ERROR_UNLOCK_ALL_USERS;
+ }
+ onEscrowRestoreComplete(allUsersUnlocked, attemptNumber + 1);
}
- private void onEscrowRestoreComplete(boolean success) {
- int previousBootCount = mStorage.getInt(REBOOT_ESCROW_ARMED_KEY, -1, USER_SYSTEM);
+ private void clearMetricsStorage() {
mStorage.removeKey(REBOOT_ESCROW_ARMED_KEY, USER_SYSTEM);
+ mStorage.removeKey(REBOOT_ESCROW_KEY_ARMED_TIMESTAMP, USER_SYSTEM);
+ mStorage.removeKey(REBOOT_ESCROW_KEY_VBMETA_DIGEST, USER_SYSTEM);
+ mStorage.removeKey(REBOOT_ESCROW_KEY_OTHER_VBMETA_DIGEST, USER_SYSTEM);
+ mStorage.removeKey(REBOOT_ESCROW_KEY_PROVIDER, USER_SYSTEM);
+ }
+
+ private int getVbmetaDigestStatusOnRestoreComplete() {
+ String currentVbmetaDigest = mInjector.getVbmetaDigest(false);
+ String vbmetaDigestStored = mStorage.getString(REBOOT_ESCROW_KEY_VBMETA_DIGEST,
+ "", USER_SYSTEM);
+ String vbmetaDigestOtherStored = mStorage.getString(REBOOT_ESCROW_KEY_OTHER_VBMETA_DIGEST,
+ "", USER_SYSTEM);
+
+ // The other vbmeta digest is never set, assume no slot switch is attempted.
+ if (vbmetaDigestOtherStored.isEmpty()) {
+ if (currentVbmetaDigest.equals(vbmetaDigestStored)) {
+ return FrameworkStatsLog
+ .REBOOT_ESCROW_RECOVERY_REPORTED__VBMETA_DIGEST_STATUS__MATCH_EXPECTED_SLOT;
+ }
+ return FrameworkStatsLog
+ .REBOOT_ESCROW_RECOVERY_REPORTED__VBMETA_DIGEST_STATUS__MISMATCH;
+ }
+
+ // The other vbmeta digest is set, we expect to boot into the new slot.
+ if (currentVbmetaDigest.equals(vbmetaDigestOtherStored)) {
+ return FrameworkStatsLog
+ .REBOOT_ESCROW_RECOVERY_REPORTED__VBMETA_DIGEST_STATUS__MATCH_EXPECTED_SLOT;
+ } else if (currentVbmetaDigest.equals(vbmetaDigestStored)) {
+ return FrameworkStatsLog
+ .REBOOT_ESCROW_RECOVERY_REPORTED__VBMETA_DIGEST_STATUS__MATCH_FALLBACK_SLOT;
+ }
+ return FrameworkStatsLog
+ .REBOOT_ESCROW_RECOVERY_REPORTED__VBMETA_DIGEST_STATUS__MISMATCH;
+ }
+
+ private void reportMetricOnRestoreComplete(boolean success, int attemptCount) {
+ int serviceType = mInjector.serverBasedResumeOnReboot()
+ ? FrameworkStatsLog.REBOOT_ESCROW_RECOVERY_REPORTED__TYPE__SERVER_BASED
+ : FrameworkStatsLog.REBOOT_ESCROW_RECOVERY_REPORTED__TYPE__HAL;
+
+ long armedTimestamp = mStorage.getLong(REBOOT_ESCROW_KEY_ARMED_TIMESTAMP, -1,
+ USER_SYSTEM);
+ int escrowDurationInSeconds = -1;
+ long currentTimeStamp = mInjector.getCurrentTimeMillis();
+ if (armedTimestamp != -1 && currentTimeStamp > armedTimestamp) {
+ escrowDurationInSeconds = (int) (currentTimeStamp - armedTimestamp) / 1000;
+ }
+
+ int vbmetaDigestStatus = getVbmetaDigestStatusOnRestoreComplete();
+ if (!success && mLoadEscrowDataErrorCode == ERROR_NONE) {
+ mLoadEscrowDataErrorCode = ERROR_UNKNOWN;
+ }
+
+ // TODO(179105110) report the duration since boot complete.
+ mInjector.reportMetric(success, mLoadEscrowDataErrorCode, serviceType, attemptCount,
+ escrowDurationInSeconds, vbmetaDigestStatus, -1);
+
+ mLoadEscrowDataErrorCode = ERROR_NONE;
+ }
+
+ private void onEscrowRestoreComplete(boolean success, int attemptCount) {
+ int previousBootCount = mStorage.getInt(REBOOT_ESCROW_ARMED_KEY, -1, USER_SYSTEM);
int bootCountDelta = mInjector.getBootCount() - previousBootCount;
if (success || (previousBootCount != -1 && bootCountDelta <= BOOT_COUNT_TOLERANCE)) {
- mInjector.reportMetric(success);
+ reportMetricOnRestoreComplete(success, attemptCount);
}
+ clearMetricsStorage();
}
private RebootEscrowKey getAndClearRebootEscrowKey(SecretKey kk) throws IOException {
@@ -329,6 +472,14 @@
if (rebootEscrowProvider == null) {
Slog.w(TAG,
"Had reboot escrow data for users, but RebootEscrowProvider is unavailable");
+ mLoadEscrowDataErrorCode = ERROR_NO_PROVIDER;
+ return null;
+ }
+
+ // Server based RoR always need the decryption key from keystore.
+ if (rebootEscrowProvider.getType() == RebootEscrowProviderInterface.TYPE_SERVER_BASED
+ && kk == null) {
+ mLoadEscrowDataErrorCode = ERROR_KEYSTORE_FAILURE;
return null;
}
@@ -434,7 +585,7 @@
return;
}
- mStorage.removeKey(REBOOT_ESCROW_ARMED_KEY, USER_SYSTEM);
+ clearMetricsStorage();
rebootEscrowProvider.clearRebootEscrowKey();
List<UserInfo> users = mUserManager.getUsers();
@@ -457,6 +608,9 @@
return false;
}
+ int actualProviderType = rebootEscrowProvider.getType();
+ // TODO(b/183140900) Fail the reboot if provider type mismatches.
+
RebootEscrowKey escrowKey;
synchronized (mKeyGenerationLock) {
escrowKey = mPendingRebootEscrowKey;
@@ -476,6 +630,14 @@
boolean armedRebootEscrow = rebootEscrowProvider.storeRebootEscrowKey(escrowKey, kk);
if (armedRebootEscrow) {
mStorage.setInt(REBOOT_ESCROW_ARMED_KEY, mInjector.getBootCount(), USER_SYSTEM);
+ mStorage.setLong(REBOOT_ESCROW_KEY_ARMED_TIMESTAMP, mInjector.getCurrentTimeMillis(),
+ USER_SYSTEM);
+ // Store the vbmeta digest of both slots.
+ mStorage.setString(REBOOT_ESCROW_KEY_VBMETA_DIGEST, mInjector.getVbmetaDigest(false),
+ USER_SYSTEM);
+ mStorage.setString(REBOOT_ESCROW_KEY_OTHER_VBMETA_DIGEST,
+ mInjector.getVbmetaDigest(true), USER_SYSTEM);
+ mStorage.setInt(REBOOT_ESCROW_KEY_PROVIDER, actualProviderType, USER_SYSTEM);
mEventLog.addEntry(RebootEscrowEvent.SET_ARMED_STATUS);
}
diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowProviderHalImpl.java b/services/core/java/com/android/server/locksettings/RebootEscrowProviderHalImpl.java
index 4b00772..e8f6f4a 100644
--- a/services/core/java/com/android/server/locksettings/RebootEscrowProviderHalImpl.java
+++ b/services/core/java/com/android/server/locksettings/RebootEscrowProviderHalImpl.java
@@ -60,6 +60,11 @@
}
@Override
+ public int getType() {
+ return TYPE_HAL;
+ }
+
+ @Override
public boolean hasRebootEscrowSupport() {
return mInjector.getRebootEscrow() != null;
}
diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowProviderInterface.java b/services/core/java/com/android/server/locksettings/RebootEscrowProviderInterface.java
index af6faad..e106d81 100644
--- a/services/core/java/com/android/server/locksettings/RebootEscrowProviderInterface.java
+++ b/services/core/java/com/android/server/locksettings/RebootEscrowProviderInterface.java
@@ -16,7 +16,11 @@
package com.android.server.locksettings;
+import android.annotation.IntDef;
+
import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import javax.crypto.SecretKey;
@@ -28,6 +32,21 @@
* @hide
*/
public interface RebootEscrowProviderInterface {
+ @IntDef(prefix = {"TYPE_"}, value = {
+ TYPE_HAL,
+ TYPE_SERVER_BASED,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface RebootEscrowProviderType {
+ }
+ int TYPE_HAL = 0;
+ int TYPE_SERVER_BASED = 1;
+
+ /**
+ * Returns the reboot escrow provider type.
+ */
+ @RebootEscrowProviderType int getType();
+
/**
* Returns true if the secure store/discard of reboot escrow key is supported.
*/
diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowProviderServerBasedImpl.java b/services/core/java/com/android/server/locksettings/RebootEscrowProviderServerBasedImpl.java
index 697bf08..2866987 100644
--- a/services/core/java/com/android/server/locksettings/RebootEscrowProviderServerBasedImpl.java
+++ b/services/core/java/com/android/server/locksettings/RebootEscrowProviderServerBasedImpl.java
@@ -95,6 +95,11 @@
}
@Override
+ public int getType() {
+ return TYPE_SERVER_BASED;
+ }
+
+ @Override
public boolean hasRebootEscrowSupport() {
return mInjector.getServiceConnection() != null;
}
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformDecryptionKey.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformDecryptionKey.java
index 35571f1..e75aae1 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformDecryptionKey.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformDecryptionKey.java
@@ -16,7 +16,7 @@
package com.android.server.locksettings.recoverablekeystore;
-import android.security.keystore.AndroidKeyStoreSecretKey;
+import javax.crypto.SecretKey;
/**
* Used to unwrap recoverable keys before syncing them with remote storage.
@@ -30,7 +30,7 @@
public class PlatformDecryptionKey {
private final int mGenerationId;
- private final AndroidKeyStoreSecretKey mKey;
+ private final SecretKey mKey;
/**
* A new instance.
@@ -40,7 +40,7 @@
*
* @hide
*/
- public PlatformDecryptionKey(int generationId, AndroidKeyStoreSecretKey key) {
+ public PlatformDecryptionKey(int generationId, SecretKey key) {
mGenerationId = generationId;
mKey = key;
}
@@ -59,7 +59,7 @@
*
* @hide
*/
- public AndroidKeyStoreSecretKey getKey() {
+ public SecretKey getKey() {
return mKey;
}
}
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformEncryptionKey.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformEncryptionKey.java
index 38f5b45..ee33446 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformEncryptionKey.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformEncryptionKey.java
@@ -16,7 +16,7 @@
package com.android.server.locksettings.recoverablekeystore;
-import android.security.keystore.AndroidKeyStoreSecretKey;
+import javax.crypto.SecretKey;
/**
* Private key stored in AndroidKeyStore. Used to wrap recoverable keys before writing them to disk.
@@ -33,7 +33,7 @@
public class PlatformEncryptionKey {
private final int mGenerationId;
- private final AndroidKeyStoreSecretKey mKey;
+ private final SecretKey mKey;
/**
* A new instance.
@@ -41,7 +41,7 @@
* @param generationId The generation ID of the key.
* @param key The secret key handle. Can be used to encrypt WITHOUT requiring screen unlock.
*/
- public PlatformEncryptionKey(int generationId, AndroidKeyStoreSecretKey key) {
+ public PlatformEncryptionKey(int generationId, SecretKey key) {
mGenerationId = generationId;
mKey = key;
}
@@ -56,7 +56,7 @@
/**
* Returns the actual key, which can only be used to encrypt.
*/
- public AndroidKeyStoreSecretKey getKey() {
+ public SecretKey getKey() {
return mKey;
}
}
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java
index 202dfe7..5e06205 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java
@@ -21,7 +21,6 @@
import android.os.RemoteException;
import android.os.UserHandle;
import android.security.GateKeeper;
-import android.security.keystore.AndroidKeyStoreSecretKey;
import android.security.keystore.KeyPermanentlyInvalidatedException;
import android.security.keystore.KeyProperties;
import android.security.keystore.KeyProtection;
@@ -237,7 +236,7 @@
if (!isKeyLoaded(userId, generationId)) {
throw new UnrecoverableKeyException("KeyStore doesn't contain key " + alias);
}
- AndroidKeyStoreSecretKey key = (AndroidKeyStoreSecretKey) mKeyStore.getKey(
+ SecretKey key = (SecretKey) mKeyStore.getKey(
alias, /*password=*/ null);
return new PlatformEncryptionKey(generationId, key);
}
@@ -289,7 +288,7 @@
if (!isKeyLoaded(userId, generationId)) {
throw new UnrecoverableKeyException("KeyStore doesn't contain key " + alias);
}
- AndroidKeyStoreSecretKey key = (AndroidKeyStoreSecretKey) mKeyStore.getKey(
+ SecretKey key = (SecretKey) mKeyStore.getKey(
alias, /*password=*/ null);
return new PlatformDecryptionKey(generationId, key);
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index aee0947..06a09ae 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -38,6 +38,15 @@
import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS;
import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_ADMIN_DISABLED;
+import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_DATA_SAVER;
+import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_MASK;
+import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_USER_RESTRICTED;
+import static android.net.ConnectivityManager.BLOCKED_REASON_APP_STANDBY;
+import static android.net.ConnectivityManager.BLOCKED_REASON_BATTERY_SAVER;
+import static android.net.ConnectivityManager.BLOCKED_REASON_DOZE;
+import static android.net.ConnectivityManager.BLOCKED_REASON_NONE;
+import static android.net.ConnectivityManager.BLOCKED_REASON_RESTRICTED_MODE;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED;
import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED;
@@ -56,6 +65,16 @@
import static android.net.NetworkPolicy.LIMIT_DISABLED;
import static android.net.NetworkPolicy.SNOOZE_NEVER;
import static android.net.NetworkPolicy.WARNING_DISABLED;
+import static android.net.NetworkPolicyManager.ALLOWED_METERED_REASON_FOREGROUND;
+import static android.net.NetworkPolicyManager.ALLOWED_METERED_REASON_MASK;
+import static android.net.NetworkPolicyManager.ALLOWED_METERED_REASON_SYSTEM;
+import static android.net.NetworkPolicyManager.ALLOWED_METERED_REASON_USER_EXEMPTED;
+import static android.net.NetworkPolicyManager.ALLOWED_REASON_FOREGROUND;
+import static android.net.NetworkPolicyManager.ALLOWED_REASON_NONE;
+import static android.net.NetworkPolicyManager.ALLOWED_REASON_POWER_SAVE_ALLOWLIST;
+import static android.net.NetworkPolicyManager.ALLOWED_REASON_POWER_SAVE_EXCEPT_IDLE_ALLOWLIST;
+import static android.net.NetworkPolicyManager.ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS;
+import static android.net.NetworkPolicyManager.ALLOWED_REASON_SYSTEM;
import static android.net.NetworkPolicyManager.EXTRA_NETWORK_TEMPLATE;
import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
import static android.net.NetworkPolicyManager.MASK_ALL_NETWORKS;
@@ -155,12 +174,10 @@
import android.database.ContentObserver;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
-import android.net.IConnectivityManager;
import android.net.INetworkManagementEventObserver;
import android.net.INetworkPolicyListener;
import android.net.INetworkPolicyManager;
import android.net.INetworkStatsService;
-import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkIdentity;
@@ -244,6 +261,7 @@
import com.android.internal.util.StatLogger;
import com.android.internal.util.XmlUtils;
import com.android.net.module.util.NetworkIdentityUtils;
+import com.android.net.module.util.PermissionUtils;
import com.android.server.EventLogTags;
import com.android.server.LocalServices;
import com.android.server.ServiceThread;
@@ -414,6 +432,14 @@
private static final int MSG_SET_NETWORK_TEMPLATE_ENABLED = 18;
private static final int MSG_SUBSCRIPTION_PLANS_CHANGED = 19;
private static final int MSG_STATS_PROVIDER_LIMIT_REACHED = 20;
+ // TODO: Add similar docs for other messages.
+ /**
+ * Message to indicate that reasons for why an uid is blocked changed.
+ * arg1 = uid
+ * arg2 = oldBlockedReasons
+ * obj = newBlockedReasons
+ */
+ private static final int MSG_BLOCKED_REASON_CHANGED = 21;
private static final int UID_MSG_STATE_CHANGED = 100;
private static final int UID_MSG_GONE = 101;
@@ -560,7 +586,10 @@
/** Foreground at UID granularity. */
@GuardedBy("mUidRulesFirstLock")
- final SparseArray<UidState> mUidState = new SparseArray<UidState>();
+ private final SparseArray<UidState> mUidState = new SparseArray<>();
+
+ @GuardedBy("mUidRulesFirstLock")
+ private final SparseArray<UidBlockedState> mUidBlockedState = new SparseArray<>();
/** Map from network ID to last observed meteredness state */
@GuardedBy("mNetworkPoliciesSecondLock")
@@ -1189,10 +1218,11 @@
private static boolean updateCapabilityChange(SparseBooleanArray lastValues, boolean newValue,
Network network) {
- final boolean lastValue = lastValues.get(network.netId, false);
- final boolean changed = (lastValue != newValue) || lastValues.indexOfKey(network.netId) < 0;
+ final boolean lastValue = lastValues.get(network.getNetId(), false);
+ final boolean changed = (lastValue != newValue)
+ || lastValues.indexOfKey(network.getNetId()) < 0;
if (changed) {
- lastValues.put(network.netId, newValue);
+ lastValues.put(network.getNetId(), newValue);
}
return changed;
}
@@ -1215,7 +1245,7 @@
mNetworkRoaming, newRoaming, network);
if (meteredChanged || roamingChanged) {
- mLogger.meterednessChanged(network.netId, newMetered);
+ mLogger.meterednessChanged(network.getNetId(), newMetered);
updateNetworkRulesNL();
}
}
@@ -1891,16 +1921,7 @@
* Collect all ifaces from a {@link NetworkStateSnapshot} into the given set.
*/
private static void collectIfaces(ArraySet<String> ifaces, NetworkStateSnapshot snapshot) {
- final String baseIface = snapshot.linkProperties.getInterfaceName();
- if (baseIface != null) {
- ifaces.add(baseIface);
- }
- for (LinkProperties stackedLink : snapshot.linkProperties.getStackedLinks()) {
- final String stackedIface = stackedLink.getInterfaceName();
- if (stackedIface != null) {
- ifaces.add(stackedIface);
- }
- }
+ ifaces.addAll(snapshot.linkProperties.getAllInterfaceNames());
}
/**
@@ -1981,7 +2002,7 @@
mNetIdToSubId.clear();
final ArrayMap<NetworkStateSnapshot, NetworkIdentity> identified = new ArrayMap<>();
for (final NetworkStateSnapshot snapshot : snapshots) {
- mNetIdToSubId.put(snapshot.network.netId, parseSubId(snapshot));
+ mNetIdToSubId.put(snapshot.network.getNetId(), parseSubId(snapshot));
// Policies matched by NPMS only match by subscriber ID or by ssid. Thus subtype
// in the object created here is never used and its value doesn't matter, so use
@@ -2879,15 +2900,18 @@
}
@Override
- public void registerListener(INetworkPolicyListener listener) {
+ public void registerListener(@NonNull INetworkPolicyListener listener) {
+ Objects.requireNonNull(listener);
// TODO: Remove CONNECTIVITY_INTERNAL and the *AnyPermissionOf methods above after all apps
// have declared OBSERVE_NETWORK_POLICY.
enforceAnyPermissionOf(CONNECTIVITY_INTERNAL, OBSERVE_NETWORK_POLICY);
mListeners.register(listener);
+ // TODO: Send callbacks to the newly registered listener
}
@Override
- public void unregisterListener(INetworkPolicyListener listener) {
+ public void unregisterListener(@NonNull INetworkPolicyListener listener) {
+ Objects.requireNonNull(listener);
// TODO: Remove CONNECTIVITY_INTERNAL and the *AnyPermissionOf methods above after all apps
// have declared OBSERVE_NETWORK_POLICY.
enforceAnyPermissionOf(CONNECTIVITY_INTERNAL, OBSERVE_NETWORK_POLICY);
@@ -3081,8 +3105,16 @@
@Override
public int getRestrictBackgroundByCaller() {
mContext.enforceCallingOrSelfPermission(ACCESS_NETWORK_STATE, TAG);
- final int uid = Binder.getCallingUid();
+ return getRestrictBackgroundStatusInternal(Binder.getCallingUid());
+ }
+ @Override
+ public int getRestrictBackgroundStatus(int uid) {
+ PermissionUtils.enforceNetworkStackPermission(mContext);
+ return getRestrictBackgroundStatusInternal(uid);
+ }
+
+ private int getRestrictBackgroundStatusInternal(int uid) {
synchronized (mUidRulesFirstLock) {
// Must clear identity because getUidPolicy() is restricted to system.
final long token = Binder.clearCallingIdentity();
@@ -3551,6 +3583,7 @@
* Get multipath preference value for the given network.
*/
public int getMultipathPreference(Network network) {
+ PermissionUtils.enforceNetworkStackPermission(mContext);
final Integer preference = mMultipathPolicyTracker.getMultipathPreference(network);
if (preference != null) {
return preference;
@@ -3923,6 +3956,7 @@
mUidRules.put(uid, newUidRule);
mHandler.obtainMessage(MSG_RULES_CHANGED, uid, newUidRule).sendToTarget();
}
+ updateBlockedReasonsForRestrictedModeUL(uid);
});
if (mRestrictedNetworkingMode) {
// firewall rules only need to be set when this mode is being enabled.
@@ -3943,6 +3977,7 @@
mUidRules.put(uid, newUidRule);
mHandler.obtainMessage(MSG_RULES_CHANGED, uid, newUidRule).sendToTarget();
}
+ updateBlockedReasonsForRestrictedModeUL(uid);
// if restricted networking mode is on, and the app has an access exemption, the uid rule
// will not change, but the firewall rule will have to be updated.
@@ -3954,6 +3989,31 @@
}
}
+ private void updateBlockedReasonsForRestrictedModeUL(int uid) {
+ UidBlockedState uidBlockedState = mUidBlockedState.get(uid);
+ if (uidBlockedState == null) {
+ uidBlockedState = new UidBlockedState();
+ mUidBlockedState.put(uid, uidBlockedState);
+ }
+ final int oldEffectiveBlockedReasons = uidBlockedState.effectiveBlockedReasons;
+ if (mRestrictedNetworkingMode) {
+ uidBlockedState.blockedReasons |= BLOCKED_REASON_RESTRICTED_MODE;
+ } else {
+ uidBlockedState.blockedReasons &= ~BLOCKED_REASON_RESTRICTED_MODE;
+ }
+ if (hasRestrictedModeAccess(uid)) {
+ uidBlockedState.allowedReasons |= ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS;
+ } else {
+ uidBlockedState.allowedReasons &= ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS;
+ }
+ uidBlockedState.updateEffectiveBlockedReasons();
+ if (oldEffectiveBlockedReasons != uidBlockedState.effectiveBlockedReasons) {
+ mHandler.obtainMessage(MSG_BLOCKED_REASON_CHANGED, uid,
+ uidBlockedState.effectiveBlockedReasons, oldEffectiveBlockedReasons)
+ .sendToTarget();
+ }
+ }
+
private int getNewRestrictedModeUidRule(int uid, int oldUidRule) {
int newRule = oldUidRule;
newRule &= ~MASK_RESTRICTED_MODE_NETWORKS;
@@ -4074,11 +4134,21 @@
boolean isWhitelisted = mPowerSaveTempWhitelistAppIds.get(appId)
|| mPowerSaveWhitelistAppIds.get(appId);
if (!deviceIdleMode) {
- isWhitelisted = isWhitelisted || mPowerSaveWhitelistExceptIdleAppIds.get(appId);
+ isWhitelisted = isWhitelisted || isWhitelistedFromPowerSaveExceptIdleUL(uid);
}
return isWhitelisted;
}
+ /**
+ * Returns whether a uid is allowlisted from power saving restrictions, except Device idle
+ * (eg: Battery Saver and app idle).
+ */
+ @GuardedBy("mUidRulesFirstLock")
+ private boolean isWhitelistedFromPowerSaveExceptIdleUL(int uid) {
+ final int appId = UserHandle.getAppId(uid);
+ return mPowerSaveWhitelistExceptIdleAppIds.get(appId);
+ }
+
// NOTE: since both fw_dozable and fw_powersave uses the same map
// (mPowerSaveTempWhitelistAppIds) for allowlisting, we can reuse their logic in this method.
@GuardedBy("mUidRulesFirstLock")
@@ -4523,6 +4593,11 @@
final int oldUidRules = mUidRules.get(uid, RULE_NONE);
final boolean isForeground = isUidForegroundOnRestrictBackgroundUL(uid);
final boolean isRestrictedByAdmin = isRestrictedByAdminUL(uid);
+ UidBlockedState uidBlockedState = mUidBlockedState.get(uid);
+ if (uidBlockedState == null) {
+ uidBlockedState = new UidBlockedState();
+ mUidBlockedState.put(uid, uidBlockedState);
+ }
final boolean isDenied = (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0;
final boolean isAllowed = (uidPolicy & POLICY_ALLOW_METERED_BACKGROUND) != 0;
@@ -4547,6 +4622,16 @@
}
}
+ int newBlockedReasons = BLOCKED_REASON_NONE;
+ int newAllowedReasons = ALLOWED_REASON_NONE;
+ newBlockedReasons |= (isRestrictedByAdmin ? BLOCKED_METERED_REASON_ADMIN_DISABLED : 0);
+ newBlockedReasons |= (mRestrictBackground ? BLOCKED_METERED_REASON_DATA_SAVER : 0);
+ newBlockedReasons |= (isDenied ? BLOCKED_METERED_REASON_USER_RESTRICTED : 0);
+
+ newAllowedReasons |= (isSystem(uid) ? ALLOWED_METERED_REASON_SYSTEM : 0);
+ newAllowedReasons |= (isForeground ? ALLOWED_METERED_REASON_FOREGROUND : 0);
+ newAllowedReasons |= (isAllowed ? ALLOWED_METERED_REASON_USER_EXEMPTED : 0);
+
if (LOGV) {
Log.v(TAG, "updateRuleForRestrictBackgroundUL(" + uid + ")"
+ ": isForeground=" +isForeground
@@ -4619,6 +4704,18 @@
// Dispatch changed rule to existing listeners.
mHandler.obtainMessage(MSG_RULES_CHANGED, uid, newUidRules).sendToTarget();
}
+
+ final int oldEffectiveBlockedReasons = uidBlockedState.effectiveBlockedReasons;
+ uidBlockedState.blockedReasons = (uidBlockedState.blockedReasons
+ & ~BLOCKED_METERED_REASON_MASK) | newBlockedReasons;
+ uidBlockedState.allowedReasons = (uidBlockedState.allowedReasons
+ & ~ALLOWED_METERED_REASON_MASK) | newAllowedReasons;
+ uidBlockedState.updateEffectiveBlockedReasons();
+ if (oldEffectiveBlockedReasons != uidBlockedState.effectiveBlockedReasons) {
+ mHandler.obtainMessage(MSG_BLOCKED_REASON_CHANGED, uid,
+ uidBlockedState.effectiveBlockedReasons, oldEffectiveBlockedReasons)
+ .sendToTarget();
+ }
}
/**
@@ -4692,6 +4789,12 @@
// Copy existing uid rules and clear ALL_NETWORK rules.
int newUidRules = oldUidRules & (~MASK_ALL_NETWORKS);
+ UidBlockedState uidBlockedState = mUidBlockedState.get(uid);
+ if (uidBlockedState == null) {
+ uidBlockedState = new UidBlockedState();
+ mUidBlockedState.put(uid, uidBlockedState);
+ }
+
// First step: define the new rule based on user restrictions and foreground state.
// NOTE: if statements below could be inlined, but it's easier to understand the logic
@@ -4704,6 +4807,20 @@
newUidRules |= isWhitelisted ? RULE_ALLOW_ALL : RULE_REJECT_ALL;
}
+ int newBlockedReasons = BLOCKED_REASON_NONE;
+ int newAllowedReasons = ALLOWED_REASON_NONE;
+ newBlockedReasons |= (mRestrictPower ? BLOCKED_REASON_BATTERY_SAVER : 0);
+ newBlockedReasons |= (mDeviceIdleMode ? BLOCKED_REASON_DOZE : 0);
+ newBlockedReasons |= (isUidIdle ? BLOCKED_REASON_APP_STANDBY : 0);
+ newBlockedReasons |= (uidBlockedState.blockedReasons & BLOCKED_REASON_RESTRICTED_MODE);
+
+ newAllowedReasons |= (isSystem(uid) ? ALLOWED_REASON_SYSTEM : 0);
+ newAllowedReasons |= (isForeground ? ALLOWED_REASON_FOREGROUND : 0);
+ newAllowedReasons |= (isWhitelistedFromPowerSaveUL(uid, true)
+ ? ALLOWED_REASON_POWER_SAVE_ALLOWLIST : 0);
+ newAllowedReasons |= (isWhitelistedFromPowerSaveExceptIdleUL(uid)
+ ? ALLOWED_REASON_POWER_SAVE_EXCEPT_IDLE_ALLOWLIST : 0);
+
if (LOGV) {
Log.v(TAG, "updateRulesForPowerRestrictionsUL(" + uid + ")"
+ ", isIdle: " + isUidIdle
@@ -4735,6 +4852,18 @@
mHandler.obtainMessage(MSG_RULES_CHANGED, uid, newUidRules).sendToTarget();
}
+ final int oldEffectiveBlockedReasons = uidBlockedState.effectiveBlockedReasons;
+ uidBlockedState.blockedReasons = (uidBlockedState.blockedReasons
+ & BLOCKED_METERED_REASON_MASK) | newBlockedReasons;
+ uidBlockedState.allowedReasons = (uidBlockedState.allowedReasons
+ & ALLOWED_METERED_REASON_MASK) | newAllowedReasons;
+ uidBlockedState.updateEffectiveBlockedReasons();
+ if (oldEffectiveBlockedReasons != uidBlockedState.effectiveBlockedReasons) {
+ mHandler.obtainMessage(MSG_BLOCKED_REASON_CHANGED, uid,
+ uidBlockedState.effectiveBlockedReasons, oldEffectiveBlockedReasons)
+ .sendToTarget();
+ }
+
return newUidRules;
}
@@ -4764,61 +4893,57 @@
}
private void dispatchUidRulesChanged(INetworkPolicyListener listener, int uid, int uidRules) {
- if (listener != null) {
- try {
- listener.onUidRulesChanged(uid, uidRules);
- } catch (RemoteException ignored) {
- }
+ try {
+ listener.onUidRulesChanged(uid, uidRules);
+ } catch (RemoteException ignored) {
}
}
private void dispatchMeteredIfacesChanged(INetworkPolicyListener listener,
String[] meteredIfaces) {
- if (listener != null) {
- try {
- listener.onMeteredIfacesChanged(meteredIfaces);
- } catch (RemoteException ignored) {
- }
+ try {
+ listener.onMeteredIfacesChanged(meteredIfaces);
+ } catch (RemoteException ignored) {
}
}
private void dispatchRestrictBackgroundChanged(INetworkPolicyListener listener,
boolean restrictBackground) {
- if (listener != null) {
- try {
- listener.onRestrictBackgroundChanged(restrictBackground);
- } catch (RemoteException ignored) {
- }
+ try {
+ listener.onRestrictBackgroundChanged(restrictBackground);
+ } catch (RemoteException ignored) {
}
}
private void dispatchUidPoliciesChanged(INetworkPolicyListener listener, int uid,
int uidPolicies) {
- if (listener != null) {
- try {
- listener.onUidPoliciesChanged(uid, uidPolicies);
- } catch (RemoteException ignored) {
- }
+ try {
+ listener.onUidPoliciesChanged(uid, uidPolicies);
+ } catch (RemoteException ignored) {
}
}
private void dispatchSubscriptionOverride(INetworkPolicyListener listener, int subId,
int overrideMask, int overrideValue, int[] networkTypes) {
- if (listener != null) {
- try {
- listener.onSubscriptionOverride(subId, overrideMask, overrideValue, networkTypes);
- } catch (RemoteException ignored) {
- }
+ try {
+ listener.onSubscriptionOverride(subId, overrideMask, overrideValue, networkTypes);
+ } catch (RemoteException ignored) {
}
}
private void dispatchSubscriptionPlansChanged(INetworkPolicyListener listener, int subId,
SubscriptionPlan[] plans) {
- if (listener != null) {
- try {
- listener.onSubscriptionPlansChanged(subId, plans);
- } catch (RemoteException ignored) {
- }
+ try {
+ listener.onSubscriptionPlansChanged(subId, plans);
+ } catch (RemoteException ignored) {
+ }
+ }
+
+ private void dispatchBlockedReasonChanged(INetworkPolicyListener listener, int uid,
+ int oldBlockedReasons, int newBlockedReasons) {
+ try {
+ listener.onBlockedReasonChanged(uid, oldBlockedReasons, newBlockedReasons);
+ } catch (RemoteException ignored) {
}
}
@@ -4975,6 +5100,19 @@
mListeners.finishBroadcast();
return true;
}
+ case MSG_BLOCKED_REASON_CHANGED: {
+ final int uid = msg.arg1;
+ final int newBlockedReasons = msg.arg2;
+ final int oldBlockedReasons = (int) msg.obj;
+ final int length = mListeners.beginBroadcast();
+ for (int i = 0; i < length; i++) {
+ final INetworkPolicyListener listener = mListeners.getBroadcastItem(i);
+ dispatchBlockedReasonChanged(listener, uid,
+ oldBlockedReasons, newBlockedReasons);
+ }
+ mListeners.finishBroadcast();
+ return true;
+ }
default: {
return false;
}
@@ -5634,7 +5772,7 @@
@GuardedBy("mNetworkPoliciesSecondLock")
private int getSubIdLocked(Network network) {
- return mNetIdToSubId.get(network.netId, INVALID_SUBSCRIPTION_ID);
+ return mNetIdToSubId.get(network.getNetId(), INVALID_SUBSCRIPTION_ID);
}
@GuardedBy("mNetworkPoliciesSecondLock")
@@ -5706,6 +5844,56 @@
return (bundle != null) ? bundle.getBoolean(key, defaultValue) : defaultValue;
}
+ private class UidBlockedState {
+ public int blockedReasons;
+ public int allowedReasons;
+ public int effectiveBlockedReasons;
+
+ UidBlockedState() {
+ blockedReasons = BLOCKED_REASON_NONE;
+ allowedReasons = ALLOWED_REASON_NONE;
+ effectiveBlockedReasons = BLOCKED_REASON_NONE;
+ }
+
+ void updateEffectiveBlockedReasons() {
+ effectiveBlockedReasons = blockedReasons;
+ // If the uid is not subject to any blocked reasons, then return early
+ if (blockedReasons == BLOCKED_REASON_NONE) {
+ return;
+ }
+ if ((allowedReasons & ALLOWED_REASON_SYSTEM) != 0) {
+ effectiveBlockedReasons = (blockedReasons & ALLOWED_METERED_REASON_MASK);
+ }
+ if ((allowedReasons & ALLOWED_METERED_REASON_SYSTEM) != 0) {
+ effectiveBlockedReasons = (blockedReasons & ~ALLOWED_METERED_REASON_MASK);
+ }
+ if ((allowedReasons & ALLOWED_REASON_FOREGROUND) != 0) {
+ effectiveBlockedReasons &= ~BLOCKED_REASON_BATTERY_SAVER;
+ effectiveBlockedReasons &= ~BLOCKED_REASON_DOZE;
+ effectiveBlockedReasons &= ~BLOCKED_REASON_APP_STANDBY;
+ }
+ if ((allowedReasons & ALLOWED_METERED_REASON_FOREGROUND) != 0) {
+ effectiveBlockedReasons &= ~BLOCKED_METERED_REASON_DATA_SAVER;
+ effectiveBlockedReasons &= ~BLOCKED_METERED_REASON_USER_RESTRICTED;
+ }
+ if ((allowedReasons & ALLOWED_REASON_POWER_SAVE_ALLOWLIST) != 0) {
+ effectiveBlockedReasons &= ~BLOCKED_REASON_BATTERY_SAVER;
+ effectiveBlockedReasons &= ~BLOCKED_REASON_DOZE;
+ effectiveBlockedReasons &= ~BLOCKED_REASON_APP_STANDBY;
+ }
+ if ((allowedReasons & ALLOWED_REASON_POWER_SAVE_EXCEPT_IDLE_ALLOWLIST) != 0) {
+ effectiveBlockedReasons &= ~BLOCKED_REASON_BATTERY_SAVER;
+ effectiveBlockedReasons &= ~BLOCKED_REASON_APP_STANDBY;
+ }
+ if ((allowedReasons & ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS) != 0) {
+ effectiveBlockedReasons &= ~BLOCKED_REASON_RESTRICTED_MODE;
+ }
+ if ((allowedReasons & ALLOWED_METERED_REASON_USER_EXEMPTED) != 0) {
+ effectiveBlockedReasons &= ~BLOCKED_METERED_REASON_DATA_SAVER;
+ }
+ }
+ }
+
private class NotificationId {
private final String mTag;
private final int mId;
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 7b376847..fc3174f 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -24,6 +24,7 @@
import static android.content.Intent.ACTION_USER_REMOVED;
import static android.content.Intent.EXTRA_UID;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkIdentity.SUBTYPE_COMBINED;
import static android.net.NetworkStack.checkNetworkStackPermission;
import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
@@ -65,6 +66,7 @@
import static android.provider.Settings.Global.NETSTATS_UID_TAG_DELETE_AGE;
import static android.provider.Settings.Global.NETSTATS_UID_TAG_PERSIST_BYTES;
import static android.provider.Settings.Global.NETSTATS_UID_TAG_ROTATE_AGE;
+import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
import static android.text.format.DateUtils.DAY_IN_MILLIS;
import static android.text.format.DateUtils.HOUR_IN_MILLIS;
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
@@ -92,7 +94,6 @@
import android.net.INetworkManagementEventObserver;
import android.net.INetworkStatsService;
import android.net.INetworkStatsSession;
-import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkIdentity;
@@ -101,7 +102,9 @@
import android.net.NetworkStats;
import android.net.NetworkStats.NonMonotonicObserver;
import android.net.NetworkStatsHistory;
+import android.net.NetworkSpecifier;
import android.net.NetworkTemplate;
+import android.net.TelephonyNetworkSpecifier;
import android.net.TrafficStats;
import android.net.UnderlyingNetworkInfo;
import android.net.Uri;
@@ -131,6 +134,7 @@
import android.service.NetworkStatsServiceDumpProto;
import android.telephony.PhoneStateListener;
import android.telephony.SubscriptionPlan;
+import android.text.TextUtils;
import android.text.format.DateUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -1320,8 +1324,9 @@
ident.getSubType(), ident.getSubscriberId(), ident.getNetworkId(),
ident.getRoaming(), true /* metered */,
true /* onDefaultNetwork */, ident.getOemManaged());
- findOrCreateNetworkIdentitySet(mActiveIfaces, IFACE_VT).add(vtIdent);
- findOrCreateNetworkIdentitySet(mActiveUidIfaces, IFACE_VT).add(vtIdent);
+ final String ifaceVt = IFACE_VT + getSubIdForMobile(snapshot);
+ findOrCreateNetworkIdentitySet(mActiveIfaces, ifaceVt).add(vtIdent);
+ findOrCreateNetworkIdentitySet(mActiveUidIfaces, ifaceVt).add(vtIdent);
}
if (isMobile) {
@@ -1358,17 +1363,18 @@
// (or non eBPF offloaded) TX they would appear on both, however egress interface
// accounting is explicitly bypassed for traffic from the clat uid.
//
- final List<LinkProperties> stackedLinks = snapshot.linkProperties.getStackedLinks();
- for (LinkProperties stackedLink : stackedLinks) {
- final String stackedIface = stackedLink.getInterfaceName();
- if (stackedIface != null) {
- findOrCreateNetworkIdentitySet(mActiveIfaces, stackedIface).add(ident);
- findOrCreateNetworkIdentitySet(mActiveUidIfaces, stackedIface).add(ident);
+ // TODO: This code might be combined to above code.
+ for (String iface : snapshot.linkProperties.getAllInterfaceNames()) {
+ // baseIface has been handled, so ignore it.
+ if (TextUtils.equals(baseIface, iface)) continue;
+ if (iface != null) {
+ findOrCreateNetworkIdentitySet(mActiveIfaces, iface).add(ident);
+ findOrCreateNetworkIdentitySet(mActiveUidIfaces, iface).add(ident);
if (isMobile) {
- mobileIfaces.add(stackedIface);
+ mobileIfaces.add(iface);
}
- mStatsFactory.noteStackedIface(stackedIface, baseIface);
+ mStatsFactory.noteStackedIface(iface, baseIface);
}
}
}
@@ -1376,6 +1382,20 @@
mMobileIfaces = mobileIfaces.toArray(new String[mobileIfaces.size()]);
}
+ private static int getSubIdForMobile(@NonNull NetworkStateSnapshot state) {
+ if (!state.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
+ throw new IllegalArgumentException("Mobile state need capability TRANSPORT_CELLULAR");
+ }
+
+ final NetworkSpecifier spec = state.networkCapabilities.getNetworkSpecifier();
+ if (spec instanceof TelephonyNetworkSpecifier) {
+ return ((TelephonyNetworkSpecifier) spec).getSubscriptionId();
+ } else {
+ Slog.wtf(TAG, "getSubIdForState invalid NetworkSpecifier");
+ return INVALID_SUBSCRIPTION_ID;
+ }
+ }
+
/**
* For networks with {@code TRANSPORT_CELLULAR}, get subType that was obtained through
* {@link PhoneStateListener}. Otherwise, return 0 given that other networks with different
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 7d1827d..0c1ba96 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -32,6 +32,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
+import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.app.Notification;
import android.app.NotificationChannel;
@@ -177,6 +178,8 @@
private Map<String, List<String>> mOemLockedApps = new HashMap();
+ private int mCurrentUserId = UserHandle.USER_NULL;
+
public PreferencesHelper(Context context, PackageManager pm, RankingHandler rankingHandler,
ZenModeHelper zenHelper, NotificationChannelLogger notificationChannelLogger,
AppOpsManager appOpsManager,
@@ -191,7 +194,8 @@
updateBadgingEnabled();
updateBubblesEnabled();
- syncChannelsBypassingDnd(mContext.getUserId());
+ mCurrentUserId = ActivityManager.getCurrentUser();
+ syncChannelsBypassingDnd();
}
public void readXml(XmlPullParser parser, boolean forRestore, int userId)
@@ -790,7 +794,7 @@
// but the system can
if (group.isBlocked() != oldGroup.isBlocked()) {
group.lockFields(NotificationChannelGroup.USER_LOCKED_BLOCKED_STATE);
- updateChannelsBypassingDnd(mContext.getUserId());
+ updateChannelsBypassingDnd();
}
}
}
@@ -871,13 +875,13 @@
// fields on the channel yet
if (existing.getUserLockedFields() == 0 && hasDndAccess) {
boolean bypassDnd = channel.canBypassDnd();
- if (bypassDnd != existing.canBypassDnd()) {
+ if (bypassDnd != existing.canBypassDnd() || wasUndeleted) {
existing.setBypassDnd(bypassDnd);
needsPolicyFileChange = true;
if (bypassDnd != mAreChannelsBypassingDnd
|| previousExistingImportance != existing.getImportance()) {
- updateChannelsBypassingDnd(mContext.getUserId());
+ updateChannelsBypassingDnd();
}
}
}
@@ -941,7 +945,7 @@
r.channels.put(channel.getId(), channel);
if (channel.canBypassDnd() != mAreChannelsBypassingDnd) {
- updateChannelsBypassingDnd(mContext.getUserId());
+ updateChannelsBypassingDnd();
}
MetricsLogger.action(getChannelLog(channel, pkg).setType(
com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_OPEN));
@@ -1013,7 +1017,7 @@
if (updatedChannel.canBypassDnd() != mAreChannelsBypassingDnd
|| channel.getImportance() != updatedChannel.getImportance()) {
- updateChannelsBypassingDnd(mContext.getUserId());
+ updateChannelsBypassingDnd();
}
}
updateConfig();
@@ -1110,7 +1114,7 @@
mNotificationChannelLogger.logNotificationChannelDeleted(channel, uid, pkg);
if (mAreChannelsBypassingDnd && channel.canBypassDnd()) {
- updateChannelsBypassingDnd(mContext.getUserId());
+ updateChannelsBypassingDnd();
}
}
}
@@ -1454,7 +1458,7 @@
}
}
if (!deletedChannelIds.isEmpty() && mAreChannelsBypassingDnd) {
- updateChannelsBypassingDnd(mContext.getUserId());
+ updateChannelsBypassingDnd();
}
return deletedChannelIds;
}
@@ -1600,29 +1604,29 @@
}
/**
- * Syncs {@link #mAreChannelsBypassingDnd} with the user's notification policy before
+ * Syncs {@link #mAreChannelsBypassingDnd} with the current user's notification policy before
* updating
- * @param userId
*/
- private void syncChannelsBypassingDnd(int userId) {
+ private void syncChannelsBypassingDnd() {
mAreChannelsBypassingDnd = (mZenModeHelper.getNotificationPolicy().state
& NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND) == 1;
- updateChannelsBypassingDnd(userId);
+ updateChannelsBypassingDnd();
}
/**
- * Updates the user's NotificationPolicy based on whether the given userId
+ * Updates the user's NotificationPolicy based on whether the current userId
* has channels bypassing DND
* @param userId
*/
- private void updateChannelsBypassingDnd(int userId) {
+ private void updateChannelsBypassingDnd() {
synchronized (mPackagePreferences) {
final int numPackagePreferences = mPackagePreferences.size();
for (int i = 0; i < numPackagePreferences; i++) {
final PackagePreferences r = mPackagePreferences.valueAt(i);
- // Package isn't associated with this userId or notifications from this package are
- // blocked
- if (userId != UserHandle.getUserId(r.uid) || r.importance == IMPORTANCE_NONE) {
+ // Package isn't associated with the current userId or notifications from this
+ // package are blocked
+ if (mCurrentUserId != UserHandle.getUserId(r.uid)
+ || r.importance == IMPORTANCE_NONE) {
continue;
}
@@ -2168,14 +2172,16 @@
* Called when user switches
*/
public void onUserSwitched(int userId) {
- syncChannelsBypassingDnd(userId);
+ mCurrentUserId = userId;
+ syncChannelsBypassingDnd();
}
/**
* Called when user is unlocked
*/
public void onUserUnlocked(int userId) {
- syncChannelsBypassingDnd(userId);
+ mCurrentUserId = userId;
+ syncChannelsBypassingDnd();
}
public void onUserRemoved(int userId) {
diff --git a/services/core/java/com/android/server/os/NativeTombstoneManager.java b/services/core/java/com/android/server/os/NativeTombstoneManager.java
index 9c4c510..cc6a824 100644
--- a/services/core/java/com/android/server/os/NativeTombstoneManager.java
+++ b/services/core/java/com/android/server/os/NativeTombstoneManager.java
@@ -411,8 +411,13 @@
processName = stream.readString(Tombstone.PROCESS_NAME);
break;
- case (int) Tombstone.CAUSE:
- long token = stream.start(Tombstone.CAUSE);
+ case (int) Tombstone.CAUSES:
+ if (!crashReason.equals("")) {
+ // Causes appear in decreasing order of likelihood. For now we only
+ // want the most likely crash reason here, so ignore all others.
+ break;
+ }
+ long token = stream.start(Tombstone.CAUSES);
cause:
while (stream.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (stream.getFieldNumber()) {
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index b39a6b4..6ad43ce 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -51,6 +51,7 @@
import android.os.PowerManager;
import android.os.SystemClock;
import android.os.SystemProperties;
+import android.os.Trace;
import android.os.UserHandle;
import android.os.WorkSource;
import android.os.storage.StorageManager;
@@ -62,6 +63,8 @@
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.pm.Installer.InstallerException;
import com.android.server.pm.dex.ArtManagerService;
+import com.android.server.pm.dex.ArtStatsLogUtils;
+import com.android.server.pm.dex.ArtStatsLogUtils.ArtStatsLogger;
import com.android.server.pm.dex.DexManager;
import com.android.server.pm.dex.DexoptOptions;
import com.android.server.pm.dex.DexoptUtils;
@@ -99,6 +102,8 @@
private final PowerManager.WakeLock mDexoptWakeLock;
private volatile boolean mSystemReady;
+ private final ArtStatsLogger mArtStatsLogger = new ArtStatsLogger();
+
PackageDexOptimizer(Installer installer, Object installLock, Context context,
String wakeLockTag) {
this.mInstaller = installer;
@@ -252,6 +257,29 @@
profileUpdated, classLoaderContexts[i], dexoptFlags, sharedGid,
packageStats, options.isDowngrade(), profileName, dexMetadataPath,
options.getCompilationReason());
+
+ // Only report metrics for base apk for now.
+ // TODO: add ISA and APK type to metrics.
+ // OTAPreopt doesn't have stats so don't report in that case.
+ if (pkg.getBaseCodePath().equals(path) && packageStats != null) {
+ Trace.traceBegin(Trace.TRACE_TAG_PACKAGE_MANAGER, "dex2oat-metrics");
+ try {
+ long sessionId = Math.randomLongInternal();
+ ArtStatsLogUtils.writeStatsLog(
+ mArtStatsLogger,
+ sessionId,
+ path,
+ compilerFilter,
+ sharedGid,
+ packageStats.getCompileTime(path),
+ dexMetadataPath,
+ options.getCompilationReason(),
+ newResult);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_PACKAGE_MANAGER);
+ }
+ }
+
// The end result is:
// - FAILED if any path failed,
// - PERFORMED if at least one path needed compilation,
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 06b54b5..4038bf2 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -203,7 +203,7 @@
newSigningDetails = ApkSignatureVerifier.verify(apexPath, minSignatureScheme);
} catch (PackageParserException e) {
throw new PackageManagerException(SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
- "Failed to parse APEX package " + apexPath, e);
+ "Failed to parse APEX package " + apexPath + " : " + e, e);
}
// Get signing details of the existing package
@@ -221,7 +221,8 @@
existingApexPkg.applicationInfo.sourceDir, SignatureSchemeVersion.JAR);
} catch (PackageParserException e) {
throw new PackageManagerException(SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
- "Failed to parse APEX package " + existingApexPkg.applicationInfo.sourceDir, e);
+ "Failed to parse APEX package " + existingApexPkg.applicationInfo.sourceDir
+ + " : " + e, e);
}
// Verify signing details for upgrade
@@ -283,7 +284,7 @@
}
} catch (PackageParserException e) {
throw new PackageManagerException(SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
- "Failed to parse APEX package " + apexInfo.modulePath, e);
+ "Failed to parse APEX package " + apexInfo.modulePath + " : " + e, e);
}
final PackageInfo activePackage = mApexManager.getPackageInfo(packageInfo.packageName,
ApexManager.MATCH_ACTIVE_PACKAGE);
diff --git a/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java b/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java
new file mode 100644
index 0000000..c8dc1b1
--- /dev/null
+++ b/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm.dex;
+
+import static com.android.internal.art.ArtStatsLog.ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INSTALL_BULK_DOWNGRADED;
+import static com.android.internal.art.ArtStatsLog.ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INSTALL_BULK_SECONDARY;
+import static com.android.internal.art.ArtStatsLog.ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INSTALL_BULK_SECONDARY_DOWNGRADED;
+import static com.android.internal.art.ArtStatsLog.ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_FAKE_RUN_FROM_APK_FALLBACK;
+import static com.android.internal.art.ArtStatsLog.ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_FAKE_RUN_FROM_VDEX_FALLBACK;
+
+import android.util.jar.StrictJarFile;
+import android.util.Slog;
+
+import com.android.internal.art.ArtStatsLog;
+import com.android.server.pm.PackageManagerService;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.zip.ZipEntry;
+
+/** Utils class to report ART metrics to statsd. */
+public class ArtStatsLogUtils {
+ private static final String TAG = ArtStatsLogUtils.class.getSimpleName();
+ private static final String PROFILE_DEX_METADATA = "primary.prof";
+ private static final String VDEX_DEX_METADATA = "primary.vdex";
+
+
+ private static final int ART_COMPILATION_REASON_INSTALL_BULK_SECONDARY =
+ ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INSTALL_BULK_SECONDARY;
+ private static final int ART_COMPILATION_REASON_INSTALL_BULK_DOWNGRADED =
+ ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INSTALL_BULK_DOWNGRADED;
+ private static final int ART_COMPILATION_REASON_INSTALL_BULK_SECONDARY_DOWNGRADED =
+ ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INSTALL_BULK_SECONDARY_DOWNGRADED;
+
+ private static final int ART_COMPILATION_FILTER_FAKE_RUN_FROM_APK_FALLBACK =
+ ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_FAKE_RUN_FROM_APK_FALLBACK;
+ private static final int ART_COMPILATION_FILTER_FAKE_RUN_FROM_VDEX_FALLBACK =
+ ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_FAKE_RUN_FROM_VDEX_FALLBACK;
+
+ private static final Map<Integer, Integer> COMPILATION_REASON_MAP = new HashMap();
+
+ static {
+ COMPILATION_REASON_MAP.put(PackageManagerService.REASON_UNKNOWN, ArtStatsLog.
+ ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_UNKNOWN);
+ COMPILATION_REASON_MAP.put(PackageManagerService.REASON_FIRST_BOOT, ArtStatsLog.
+ ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_FIRST_BOOT);
+ COMPILATION_REASON_MAP.put(PackageManagerService.REASON_BOOT_AFTER_OTA, ArtStatsLog.
+ ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_BOOT);
+ COMPILATION_REASON_MAP.put(PackageManagerService.REASON_POST_BOOT, ArtStatsLog.
+ ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_POST_BOOT);
+ COMPILATION_REASON_MAP.put(PackageManagerService.REASON_INSTALL, ArtStatsLog.
+ ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INSTALL);
+ COMPILATION_REASON_MAP.put(PackageManagerService.REASON_INSTALL_FAST, ArtStatsLog.
+ ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INSTALL_FAST);
+ COMPILATION_REASON_MAP.put(PackageManagerService.REASON_INSTALL_BULK, ArtStatsLog.
+ ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INSTALL_BULK);
+ COMPILATION_REASON_MAP.put(PackageManagerService.REASON_INSTALL_BULK_SECONDARY,
+ ART_COMPILATION_REASON_INSTALL_BULK_SECONDARY);
+ COMPILATION_REASON_MAP.put(PackageManagerService.REASON_INSTALL_BULK_DOWNGRADED,
+ ART_COMPILATION_REASON_INSTALL_BULK_DOWNGRADED);
+ COMPILATION_REASON_MAP.put(PackageManagerService.REASON_INSTALL_BULK_SECONDARY_DOWNGRADED,
+ ART_COMPILATION_REASON_INSTALL_BULK_SECONDARY_DOWNGRADED);
+ COMPILATION_REASON_MAP.put(PackageManagerService.REASON_BACKGROUND_DEXOPT, ArtStatsLog.
+ ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_BG_DEXOPT);
+ COMPILATION_REASON_MAP.put(PackageManagerService.REASON_AB_OTA, ArtStatsLog.
+ ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_AB_OTA);
+ COMPILATION_REASON_MAP.put(PackageManagerService.REASON_INACTIVE_PACKAGE_DOWNGRADE,
+ ArtStatsLog.
+ ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INACTIVE);
+ COMPILATION_REASON_MAP.put(PackageManagerService.REASON_SHARED,
+ ArtStatsLog.ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_SHARED);
+ }
+
+ private static final Map<String, Integer> COMPILE_FILTER_MAP = new HashMap();
+
+ static {
+ COMPILE_FILTER_MAP.put("error", ArtStatsLog.
+ ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_ERROR);
+ COMPILE_FILTER_MAP.put("unknown", ArtStatsLog.
+ ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_UNKNOWN);
+ COMPILE_FILTER_MAP.put("assume-verified", ArtStatsLog.
+ ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_ASSUMED_VERIFIED);
+ COMPILE_FILTER_MAP.put("extract", ArtStatsLog.
+ ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_EXTRACT);
+ COMPILE_FILTER_MAP.put("verify", ArtStatsLog.
+ ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_VERIFY);
+ COMPILE_FILTER_MAP.put("quicken", ArtStatsLog.
+ ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_QUICKEN);
+ COMPILE_FILTER_MAP.put("space-profile", ArtStatsLog.
+ ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_SPACE_PROFILE);
+ COMPILE_FILTER_MAP.put("space", ArtStatsLog.
+ ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_SPACE);
+ COMPILE_FILTER_MAP.put("speed-profile", ArtStatsLog.
+ ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_SPEED_PROFILE);
+ COMPILE_FILTER_MAP.put("speed", ArtStatsLog.
+ ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_SPEED);
+ COMPILE_FILTER_MAP.put("everything-profile", ArtStatsLog.
+ ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_EVERYTHING_PROFILE);
+ COMPILE_FILTER_MAP.put("everything", ArtStatsLog.
+ ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_EVERYTHING);
+ COMPILE_FILTER_MAP.put("run-from-apk", ArtStatsLog.
+ ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_FAKE_RUN_FROM_APK);
+ COMPILE_FILTER_MAP.put("run-from-apk-fallback",
+ ART_COMPILATION_FILTER_FAKE_RUN_FROM_APK_FALLBACK);
+ COMPILE_FILTER_MAP.put("run-from-vdex-fallback",
+ ART_COMPILATION_FILTER_FAKE_RUN_FROM_VDEX_FALLBACK);
+ }
+
+ public static void writeStatsLog(
+ ArtStatsLogger logger,
+ long sessionId,
+ String path,
+ String compilerFilter,
+ int uid,
+ long compileTime,
+ String dexMetadataPath,
+ int compilationReason,
+ int result) {
+ int dexMetadataType = getDexMetadataType(dexMetadataPath);
+ logger.write(
+ sessionId,
+ uid,
+ compilationReason,
+ compilerFilter,
+ ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_RESULT_CODE,
+ result,
+ dexMetadataType);
+ logger.write(
+ sessionId,
+ uid,
+ compilationReason,
+ compilerFilter,
+ ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_TOTAL_TIME,
+ compileTime,
+ dexMetadataType);
+ }
+
+ private static int getDexMetadataType(String dexMetadataPath) {
+ if (dexMetadataPath == null) {
+ return ArtStatsLog.ART_DATUM_REPORTED__DEX_METADATA_TYPE__ART_DEX_METADATA_TYPE_NONE;
+ }
+ StrictJarFile jarFile = null;
+ try {
+ jarFile = new StrictJarFile(dexMetadataPath,
+ /*verify=*/ false,
+ /*signatureSchemeRollbackProtectionsEnforced=*/false);
+ boolean hasProfile = findFileName(jarFile, PROFILE_DEX_METADATA);
+ boolean hasVdex = findFileName(jarFile, VDEX_DEX_METADATA);
+ if (hasProfile && hasVdex) {
+ return ArtStatsLog.
+ ART_DATUM_REPORTED__DEX_METADATA_TYPE__ART_DEX_METADATA_TYPE_PROFILE_AND_VDEX;
+ } else if (hasProfile) {
+ return ArtStatsLog.
+ ART_DATUM_REPORTED__DEX_METADATA_TYPE__ART_DEX_METADATA_TYPE_PROFILE;
+ } else if (hasVdex) {
+ return ArtStatsLog.
+ ART_DATUM_REPORTED__DEX_METADATA_TYPE__ART_DEX_METADATA_TYPE_VDEX;
+ } else {
+ return ArtStatsLog.
+ ART_DATUM_REPORTED__DEX_METADATA_TYPE__ART_DEX_METADATA_TYPE_UNKNOWN;
+ }
+ } catch (IOException ignore) {
+ Slog.e(TAG, "Error when parsing dex metadata " + dexMetadataPath);
+ return ArtStatsLog.ART_DATUM_REPORTED__DEX_METADATA_TYPE__ART_DEX_METADATA_TYPE_ERROR;
+ } finally {
+ try {
+ if (jarFile != null) {
+ jarFile.close();
+ }
+ } catch (IOException ignore) {
+ }
+ }
+ }
+
+ private static boolean findFileName(StrictJarFile jarFile, String filename) throws IOException {
+ Iterator<ZipEntry> it = jarFile.iterator();
+ while (it.hasNext()) {
+ ZipEntry entry = it.next();
+ if (entry.getName().equals(filename)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public static class ArtStatsLogger {
+ public void write(
+ long sessionId,
+ int uid,
+ int compilationReason,
+ String compilerFilter,
+ int kind,
+ long value,
+ int dexMetadataType) {
+ ArtStatsLog.write(
+ ArtStatsLog.ART_DATUM_REPORTED,
+ sessionId,
+ uid,
+ COMPILE_FILTER_MAP.getOrDefault(compilerFilter, ArtStatsLog.
+ ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_UNKNOWN),
+ COMPILATION_REASON_MAP.getOrDefault(compilationReason, ArtStatsLog.
+ ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_UNKNOWN),
+ /*timestamp_millis=*/ 0L,
+ ArtStatsLog.ART_DATUM_REPORTED__THREAD_TYPE__ART_THREAD_MAIN,
+ kind,
+ value,
+ dexMetadataType);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java
index 349561d..37f3175 100644
--- a/services/core/java/com/android/server/pm/dex/DexManager.java
+++ b/services/core/java/com/android/server/pm/dex/DexManager.java
@@ -986,7 +986,7 @@
* Fetches the battery manager object and caches it if it hasn't been fetched already.
*/
private BatteryManager getBatteryManager() {
- if (mBatteryManager == null) {
+ if (mBatteryManager == null && mContext != null) {
mBatteryManager = mContext.getSystemService(BatteryManager.class);
}
@@ -1008,10 +1008,6 @@
&& mPowerManager.getCurrentThermalStatus()
>= PowerManager.THERMAL_STATUS_SEVERE);
- if (DEBUG) {
- Log.d(TAG, "Battery, thermal, or memory are critical: " + isBtmCritical);
- }
-
return isBtmCritical;
}
diff --git a/services/core/java/com/android/server/policy/LegacyGlobalActions.java b/services/core/java/com/android/server/policy/LegacyGlobalActions.java
index 9c3a394..5b48abb 100644
--- a/services/core/java/com/android/server/policy/LegacyGlobalActions.java
+++ b/services/core/java/com/android/server/policy/LegacyGlobalActions.java
@@ -24,11 +24,11 @@
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.database.ContentObserver;
import android.graphics.drawable.Drawable;
import android.media.AudioManager;
-import android.net.ConnectivityManager;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
@@ -113,7 +113,7 @@
private boolean mDeviceProvisioned = false;
private ToggleAction.State mAirplaneState = ToggleAction.State.Off;
private boolean mIsWaitingForEcmExit = false;
- private boolean mHasTelephony;
+ private final boolean mHasTelephony;
private boolean mHasVibrator;
private final boolean mShowSilentToggle;
private final EmergencyAffordanceManager mEmergencyAffordanceManager;
@@ -137,9 +137,8 @@
filter.addAction(TelephonyManager.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
context.registerReceiver(mBroadcastReceiver, filter);
- ConnectivityManager cm = (ConnectivityManager)
- context.getSystemService(Context.CONNECTIVITY_SERVICE);
- mHasTelephony = cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
+ mHasTelephony =
+ context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
// get notified of phone state changes
TelephonyManager telephonyManager =
diff --git a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
index fd2d8e1..fe21201 100644
--- a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
+++ b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
@@ -16,14 +16,18 @@
package com.android.server.recoverysystem;
+import static android.os.UserHandle.USER_SYSTEM;
+
import android.annotation.IntDef;
import android.content.Context;
import android.content.IntentSender;
+import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.hardware.boot.V1_0.IBootControl;
import android.net.LocalSocket;
import android.net.LocalSocketAddress;
import android.os.Binder;
+import android.os.Environment;
import android.os.IRecoverySystem;
import android.os.IRecoverySystemProgressListener;
import android.os.PowerManager;
@@ -33,12 +37,14 @@
import android.os.ResultReceiver;
import android.os.ShellCallback;
import android.os.SystemProperties;
+import android.provider.DeviceConfig;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.widget.LockSettingsInternal;
import com.android.internal.widget.RebootEscrowListener;
import com.android.server.LocalServices;
@@ -48,10 +54,13 @@
import java.io.DataInputStream;
import java.io.DataOutputStream;
+import java.io.File;
import java.io.FileDescriptor;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
/**
* The recovery system service is responsible for coordinating recovery related
@@ -81,6 +90,12 @@
private static final int SOCKET_CONNECTION_MAX_RETRY = 30;
+ static final String REQUEST_LSKF_TIMESTAMP_PREF_SUFFIX = "_request_lskf_timestamp";
+ static final String REQUEST_LSKF_COUNT_PREF_SUFFIX = "_request_lskf_count";
+
+ static final String LSKF_CAPTURED_TIMESTAMP_PREF = "lskf_captured_timestamp";
+ static final String LSKF_CAPTURED_COUNT_PREF = "lskf_captured_count";
+
private final Injector mInjector;
private final Context mContext;
@@ -121,22 +136,93 @@
*/
@IntDef({ ROR_NEED_PREPARATION,
ROR_SKIP_PREPARATION_AND_NOTIFY,
- ROR_SKIP_PREPARATION_NOT_NOTIFY })
+ ROR_SKIP_PREPARATION_NOT_NOTIFY})
private @interface ResumeOnRebootActionsOnRequest {}
/**
* The action to perform upon resume on reboot clear request for a given client.
*/
- @IntDef({ROR_NOT_REQUESTED,
+ @IntDef({ ROR_NOT_REQUESTED,
ROR_REQUESTED_NEED_CLEAR,
ROR_REQUESTED_SKIP_CLEAR})
- private @interface ResumeOnRebootActionsOnClear{}
+ private @interface ResumeOnRebootActionsOnClear {}
+
+ /**
+ * The error codes for reboots initiated by resume on reboot clients.
+ */
+ private static final int REBOOT_ERROR_NONE = 0;
+ private static final int REBOOT_ERROR_UNKNOWN = 1;
+ private static final int REBOOT_ERROR_INVALID_PACKAGE_NAME = 2;
+ private static final int REBOOT_ERROR_LSKF_NOT_CAPTURED = 3;
+ private static final int REBOOT_ERROR_SLOT_MISMATCH = 4;
+ private static final int REBOOT_ERROR_ARM_REBOOT_ESCROW_FAILURE = 5;
+
+ @IntDef({ REBOOT_ERROR_NONE,
+ REBOOT_ERROR_UNKNOWN,
+ REBOOT_ERROR_INVALID_PACKAGE_NAME,
+ REBOOT_ERROR_LSKF_NOT_CAPTURED,
+ REBOOT_ERROR_SLOT_MISMATCH,
+ REBOOT_ERROR_ARM_REBOOT_ESCROW_FAILURE})
+ private @interface ResumeOnRebootRebootErrorCode {}
+
+ /**
+ * Manages shared preference, i.e. the storage used for metrics reporting.
+ */
+ public static class PreferencesManager {
+ private static final String METRICS_DIR = "recovery_system";
+ private static final String METRICS_PREFS_FILE = "RecoverySystemMetricsPrefs.xml";
+
+ protected final SharedPreferences mSharedPreferences;
+ private final File mMetricsPrefsFile;
+
+ PreferencesManager(Context context) {
+ File prefsDir = new File(Environment.getDataSystemCeDirectory(USER_SYSTEM),
+ METRICS_DIR);
+ mMetricsPrefsFile = new File(prefsDir, METRICS_PREFS_FILE);
+ mSharedPreferences = context.getSharedPreferences(mMetricsPrefsFile, 0);
+ }
+
+ /** Reads the value of a given key with type long. **/
+ public long getLong(String key, long defaultValue) {
+ return mSharedPreferences.getLong(key, defaultValue);
+ }
+
+ /** Reads the value of a given key with type int. **/
+ public int getInt(String key, int defaultValue) {
+ return mSharedPreferences.getInt(key, defaultValue);
+ }
+
+ /** Stores the value of a given key with type long. **/
+ public void putLong(String key, long value) {
+ mSharedPreferences.edit().putLong(key, value).commit();
+ }
+
+ /** Stores the value of a given key with type int. **/
+ public void putInt(String key, int value) {
+ mSharedPreferences.edit().putInt(key, value).commit();
+ }
+
+ /** Increments the value of a given key with type int. **/
+ public synchronized void incrementIntKey(String key, int defaultInitialValue) {
+ int oldValue = getInt(key, defaultInitialValue);
+ putInt(key, oldValue + 1);
+ }
+
+ /** Delete the preference file and cleanup all metrics storage. **/
+ public void deletePrefsFile() {
+ if (!mMetricsPrefsFile.delete()) {
+ Slog.w(TAG, "Failed to delete metrics prefs");
+ }
+ }
+ }
static class Injector {
protected final Context mContext;
+ protected final PreferencesManager mPrefs;
Injector(Context context) {
mContext = context;
+ mPrefs = new PreferencesManager(context);
}
public Context getContext() {
@@ -202,6 +288,43 @@
public void threadSleep(long millis) throws InterruptedException {
Thread.sleep(millis);
}
+
+ public int getUidFromPackageName(String packageName) {
+ try {
+ return mContext.getPackageManager().getPackageUidAsUser(packageName, USER_SYSTEM);
+ } catch (PackageManager.NameNotFoundException e) {
+ Slog.w(TAG, "Failed to find uid for " + packageName);
+ }
+ return -1;
+ }
+
+ public PreferencesManager getMetricsPrefs() {
+ return mPrefs;
+ }
+
+ public long getCurrentTimeMillis() {
+ return System.currentTimeMillis();
+ }
+
+ public void reportRebootEscrowPreparationMetrics(int uid,
+ @ResumeOnRebootActionsOnRequest int requestResult, int requestedClientCount) {
+ FrameworkStatsLog.write(FrameworkStatsLog.REBOOT_ESCROW_PREPARATION_REPORTED, uid,
+ requestResult, requestedClientCount);
+ }
+
+ public void reportRebootEscrowLskfCapturedMetrics(int uid, int requestedClientCount,
+ int requestedToLskfCapturedDurationInSeconds) {
+ FrameworkStatsLog.write(FrameworkStatsLog.REBOOT_ESCROW_LSKF_CAPTURE_REPORTED, uid,
+ requestedClientCount, requestedToLskfCapturedDurationInSeconds);
+ }
+
+ public void reportRebootEscrowRebootMetrics(int errorCode, int uid,
+ int preparedClientCount, int requestCount, boolean slotSwitch, boolean serverBased,
+ int lskfCapturedToRebootDurationInSeconds, int lskfCapturedCounts) {
+ FrameworkStatsLog.write(FrameworkStatsLog.REBOOT_ESCROW_REBOOT_REPORTED, errorCode,
+ uid, preparedClientCount, requestCount, slotSwitch, serverBased,
+ lskfCapturedToRebootDurationInSeconds, lskfCapturedCounts);
+ }
}
/**
@@ -361,12 +484,28 @@
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.RECOVERY)
!= PackageManager.PERMISSION_GRANTED
&& mContext.checkCallingOrSelfPermission(android.Manifest.permission.REBOOT)
- != PackageManager.PERMISSION_GRANTED) {
+ != PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Caller must have " + android.Manifest.permission.RECOVERY
+ " or " + android.Manifest.permission.REBOOT + " for resume on reboot.");
}
}
+ private void reportMetricsOnRequestLskf(String packageName, int requestResult) {
+ int uid = mInjector.getUidFromPackageName(packageName);
+ int pendingRequestCount;
+ synchronized (this) {
+ pendingRequestCount = mCallerPendingRequest.size();
+ }
+
+ // Save the timestamp and request count for new ror request
+ PreferencesManager prefs = mInjector.getMetricsPrefs();
+ prefs.putLong(packageName + REQUEST_LSKF_TIMESTAMP_PREF_SUFFIX,
+ mInjector.getCurrentTimeMillis());
+ prefs.incrementIntKey(packageName + REQUEST_LSKF_COUNT_PREF_SUFFIX, 0);
+
+ mInjector.reportRebootEscrowPreparationMetrics(uid, requestResult, pendingRequestCount);
+ }
+
@Override // Binder call
public boolean requestLskf(String packageName, IntentSender intentSender) {
enforcePermissionForResumeOnReboot();
@@ -378,6 +517,8 @@
@ResumeOnRebootActionsOnRequest int action = updateRoRPreparationStateOnNewRequest(
packageName, intentSender);
+ reportMetricsOnRequestLskf(packageName, action);
+
switch (action) {
case ROR_SKIP_PREPARATION_AND_NOTIFY:
// We consider the preparation done if someone else has prepared.
@@ -420,12 +561,42 @@
return needPreparation ? ROR_NEED_PREPARATION : ROR_SKIP_PREPARATION_NOT_NOTIFY;
}
+ private void reportMetricsOnPreparedForReboot() {
+ long currentTimestamp = mInjector.getCurrentTimeMillis();
+
+ List<String> preparedClients;
+ synchronized (this) {
+ preparedClients = new ArrayList<>(mCallerPreparedForReboot);
+ }
+
+ // Save the timestamp & lskf capture count for lskf capture
+ PreferencesManager prefs = mInjector.getMetricsPrefs();
+ prefs.putLong(LSKF_CAPTURED_TIMESTAMP_PREF, currentTimestamp);
+ prefs.incrementIntKey(LSKF_CAPTURED_COUNT_PREF, 0);
+
+ for (String packageName : preparedClients) {
+ int uid = mInjector.getUidFromPackageName(packageName);
+
+ int durationSeconds = -1;
+ long requestLskfTimestamp = prefs.getLong(
+ packageName + REQUEST_LSKF_TIMESTAMP_PREF_SUFFIX, -1);
+ if (requestLskfTimestamp != -1 && currentTimestamp > requestLskfTimestamp) {
+ durationSeconds = (int) (currentTimestamp - requestLskfTimestamp) / 1000;
+ }
+ Slog.i(TAG, String.format("Reporting lskf captured, lskf capture takes %d seconds for"
+ + " package %s", durationSeconds, packageName));
+ mInjector.reportRebootEscrowLskfCapturedMetrics(uid, preparedClients.size(),
+ durationSeconds);
+ }
+ }
+
@Override
public void onPreparedForReboot(boolean ready) {
if (!ready) {
return;
}
updateRoRPreparationStateOnPreparedForReboot();
+ reportMetricsOnPreparedForReboot();
}
private synchronized void updateRoRPreparationStateOnPreparedForReboot() {
@@ -462,6 +633,7 @@
Slog.w(TAG, "Missing packageName when clearing lskf.");
return false;
}
+ // TODO(179105110) Clear the RoR metrics for the given packageName.
@ResumeOnRebootActionsOnClear int action = updateRoRPreparationStateOnClear(packageName);
switch (action) {
@@ -548,24 +720,84 @@
return true;
}
- private boolean rebootWithLskfImpl(String packageName, String reason, boolean slotSwitch) {
+ private @ResumeOnRebootRebootErrorCode int armRebootEscrow(String packageName,
+ boolean slotSwitch) {
if (packageName == null) {
Slog.w(TAG, "Missing packageName when rebooting with lskf.");
- return false;
+ return REBOOT_ERROR_INVALID_PACKAGE_NAME;
}
if (!isLskfCaptured(packageName)) {
- return false;
+ return REBOOT_ERROR_LSKF_NOT_CAPTURED;
}
if (!verifySlotForNextBoot(slotSwitch)) {
+ return REBOOT_ERROR_SLOT_MISMATCH;
+ }
+
+ final long origId = Binder.clearCallingIdentity();
+ boolean result;
+ try {
+ result = mInjector.getLockSettingsService().armRebootEscrow();
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+
+ if (!result) {
+ Slog.w(TAG, "Failure to escrow key for reboot");
+ return REBOOT_ERROR_ARM_REBOOT_ESCROW_FAILURE;
+ }
+
+ return REBOOT_ERROR_NONE;
+ }
+
+ private boolean useServerBasedRoR() {
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_OTA,
+ "server_based_ror_enabled", false);
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
+ private void reportMetricsOnRebootWithLskf(String packageName, boolean slotSwitch,
+ @ResumeOnRebootRebootErrorCode int errorCode) {
+ int uid = mInjector.getUidFromPackageName(packageName);
+ boolean serverBased = useServerBasedRoR();
+ int preparedClientCount;
+ synchronized (this) {
+ preparedClientCount = mCallerPreparedForReboot.size();
+ }
+
+ long currentTimestamp = mInjector.getCurrentTimeMillis();
+ int durationSeconds = -1;
+ PreferencesManager prefs = mInjector.getMetricsPrefs();
+ long lskfCapturedTimestamp = prefs.getLong(LSKF_CAPTURED_TIMESTAMP_PREF, -1);
+ if (lskfCapturedTimestamp != -1 && currentTimestamp > lskfCapturedTimestamp) {
+ durationSeconds = (int) (currentTimestamp - lskfCapturedTimestamp) / 1000;
+ }
+
+ int requestCount = prefs.getInt(packageName + REQUEST_LSKF_COUNT_PREF_SUFFIX, -1);
+ int lskfCapturedCount = prefs.getInt(LSKF_CAPTURED_COUNT_PREF, -1);
+
+ Slog.i(TAG, String.format("Reporting reboot with lskf, package name %s, client count %d,"
+ + " request count %d, lskf captured count %d, duration since lskf captured"
+ + " %d seconds.", packageName, preparedClientCount, requestCount,
+ lskfCapturedCount, durationSeconds));
+ mInjector.reportRebootEscrowRebootMetrics(errorCode, uid, preparedClientCount,
+ requestCount, slotSwitch, serverBased, durationSeconds, lskfCapturedCount);
+ }
+
+ private boolean rebootWithLskfImpl(String packageName, String reason, boolean slotSwitch) {
+ @ResumeOnRebootRebootErrorCode int errorCode = armRebootEscrow(packageName, slotSwitch);
+ reportMetricsOnRebootWithLskf(packageName, slotSwitch, errorCode);
+
+ if (errorCode != REBOOT_ERROR_NONE) {
return false;
}
- // TODO(xunchang) write the vbmeta digest along with the escrowKey before reboot.
- if (!mInjector.getLockSettingsService().armRebootEscrow()) {
- Slog.w(TAG, "Failure to escrow key for reboot");
- return false;
- }
+ // Clear the metrics prefs after a successful RoR reboot.
+ mInjector.getMetricsPrefs().deletePrefsFile();
PowerManager pm = mInjector.getPowerManager();
pm.reboot(reason);
diff --git a/services/core/java/com/android/server/stats/OWNERS b/services/core/java/com/android/server/stats/OWNERS
index fc7fd22..174ad3a 100644
--- a/services/core/java/com/android/server/stats/OWNERS
+++ b/services/core/java/com/android/server/stats/OWNERS
@@ -1,7 +1,10 @@
jeffreyhuang@google.com
joeo@google.com
+jtnguyen@google.com
muhammadq@google.com
+rslawik@google.com
ruchirr@google.com
+sharaienko@google.com
singhtejinder@google.com
tsaichristine@google.com
yaochen@google.com
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java
index 3519465..85d2d39 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java
@@ -20,7 +20,7 @@
import android.app.AlarmManager;
import android.content.ContentResolver;
import android.content.Context;
-import android.net.ConnectivityManager;
+import android.content.pm.PackageManager;
import android.os.SystemProperties;
import android.provider.Settings;
@@ -52,9 +52,7 @@
}
private boolean deviceHasTelephonyNetwork() {
- // TODO b/150583524 Avoid the use of a deprecated API.
- return mContext.getSystemService(ConnectivityManager.class)
- .isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
+ return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
}
@Override
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index d858ae4..61bd5df 100755
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -2934,7 +2934,11 @@
values.put(TvContract.WatchedPrograms.COLUMN_INTERNAL_SESSION_TOKEN,
sessionToken.toString());
- mContentResolver.insert(TvContract.WatchedPrograms.CONTENT_URI, values);
+ try{
+ mContentResolver.insert(TvContract.WatchedPrograms.CONTENT_URI, values);
+ }catch(IllegalArgumentException ex){
+ Slog.w(TAG, "error in insert db for MSG_LOG_WATCH_START", ex);
+ }
args.recycle();
break;
}
@@ -2949,7 +2953,11 @@
values.put(TvContract.WatchedPrograms.COLUMN_INTERNAL_SESSION_TOKEN,
sessionToken.toString());
- mContentResolver.insert(TvContract.WatchedPrograms.CONTENT_URI, values);
+ try{
+ mContentResolver.insert(TvContract.WatchedPrograms.CONTENT_URI, values);
+ }catch(IllegalArgumentException ex){
+ Slog.w(TAG, "error in insert db for MSG_LOG_WATCH_END", ex);
+ }
args.recycle();
break;
}
diff --git a/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java b/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
index b2db9f5..8dcc547 100644
--- a/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
+++ b/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
@@ -23,7 +23,6 @@
import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkCapabilities;
-import android.net.NetworkCapabilities.NetCapability;
import android.net.NetworkRequest;
import android.net.TelephonyNetworkSpecifier;
import android.os.Handler;
@@ -115,33 +114,61 @@
getWifiNetworkRequest(), mHandler, mWifiBringupCallback);
updateSubIdsAndCellularRequests();
- // register Network-selection request used to decide selected underlying Network
+ // Register Network-selection request used to decide selected underlying Network. All
+ // underlying networks must be VCN managed in order to be used.
mConnectivityManager.requestBackgroundNetwork(
- getNetworkRequestBase().build(), mHandler, mRouteSelectionCallback);
+ getBaseNetworkRequest(true /* requireVcnManaged */).build(),
+ mHandler,
+ mRouteSelectionCallback);
}
private NetworkRequest getWifiNetworkRequest() {
- return getNetworkRequestBase().addTransportType(NetworkCapabilities.TRANSPORT_WIFI).build();
+ // Request exclusively VCN managed networks to ensure that we only ever keep carrier wifi
+ // alive.
+ return getBaseNetworkRequest(true /* requireVcnManaged */)
+ .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
+ .build();
}
private NetworkRequest getCellNetworkRequestForSubId(int subId) {
- return getNetworkRequestBase()
+ // Do not request NOT_VCN_MANAGED to ensure that the TelephonyNetworkFactory has a
+ // fulfillable request to bring up underlying cellular Networks even if the VCN is already
+ // connected.
+ return getBaseNetworkRequest(false /* requireVcnManaged */)
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
.setNetworkSpecifier(new TelephonyNetworkSpecifier(subId))
.build();
}
- private NetworkRequest.Builder getNetworkRequestBase() {
- NetworkRequest.Builder requestBase = new NetworkRequest.Builder();
- for (@NetCapability int capability : mRequiredUnderlyingNetworkCapabilities) {
+ /**
+ * Builds and returns a NetworkRequest builder common to all Underlying Network requests
+ *
+ * <p>A NetworkRequest may either (1) Require the presence of a capability by using
+ * addCapability(), (2) require the absence of a capability using unwanted capabilities, or (3)
+ * allow any state. Underlying networks are never desired to have the NOT_VCN_MANAGED
+ * capability, and only cases (2) and (3) are used.
+ *
+ * @param requireVcnManaged whether the underlying network is required to be VCN managed to
+ * match this request. If {@code true}, the NOT_VCN_MANAGED capability will be set as
+ * unwanted. Else, the NOT_VCN_MANAGED capability will be removed, and any state is
+ * acceptable.
+ */
+ private NetworkRequest.Builder getBaseNetworkRequest(boolean requireVcnManaged) {
+ NetworkRequest.Builder requestBase =
+ new NetworkRequest.Builder()
+ .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
+ .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
+ .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED);
+
+ for (int capability : mRequiredUnderlyingNetworkCapabilities) {
requestBase.addCapability(capability);
}
- return requestBase
- .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
- .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
- .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)
- .addUnwantedCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED);
+ if (requireVcnManaged) {
+ requestBase.addUnwantedCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED);
+ }
+
+ return requestBase;
}
/**
diff --git a/services/core/java/com/android/server/vcn/Vcn.java b/services/core/java/com/android/server/vcn/Vcn.java
index c55913e..89ed956 100644
--- a/services/core/java/com/android/server/vcn/Vcn.java
+++ b/services/core/java/com/android/server/vcn/Vcn.java
@@ -41,6 +41,7 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -110,6 +111,24 @@
@NonNull private final VcnNetworkRequestListener mRequestListener;
@NonNull private final VcnCallback mVcnCallback;
+ /**
+ * Map containing all VcnGatewayConnections and their VcnGatewayConnectionConfigs.
+ *
+ * <p>Due to potential for race conditions, VcnGatewayConnections MUST only be created and added
+ * to this map in {@link #handleNetworkRequested(NetworkRequest, int, int)}, when a VCN receives
+ * a NetworkRequest that matches a VcnGatewayConnectionConfig for this VCN's VcnConfig.
+ *
+ * <p>A VcnGatewayConnection instance MUST NEVER overwrite an existing instance - otherwise
+ * there is potential for a orphaned VcnGatewayConnection instance that does not get properly
+ * shut down.
+ *
+ * <p>Due to potential for race conditions, VcnGatewayConnections MUST only be removed from this
+ * map once they have finished tearing down, which is reported to this VCN via {@link
+ * VcnGatewayStatusCallback#onQuit()}. Once this is done, all NetworkRequests are retrieved from
+ * the NetworkProvider so that another VcnGatewayConnectionConfig can match the
+ * previously-matched request.
+ */
+ // TODO(b/182533200): remove the invariant on VcnGatewayConnection lifecycles
@NonNull
private final Map<VcnGatewayConnectionConfig, VcnGatewayConnection> mVcnGatewayConnections =
new HashMap<>();
@@ -191,6 +210,19 @@
return Collections.unmodifiableSet(new HashSet<>(mVcnGatewayConnections.values()));
}
+ /** Get current Configs and Gateways for testing purposes */
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ public Map<VcnGatewayConnectionConfig, VcnGatewayConnection>
+ getVcnGatewayConnectionConfigMap() {
+ return Collections.unmodifiableMap(new HashMap<>(mVcnGatewayConnections));
+ }
+
+ /** Set whether this Vcn is active for testing purposes */
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ public void setIsActive(boolean isActive) {
+ mIsActive.set(isActive);
+ }
+
private class VcnNetworkRequestListener implements VcnNetworkProvider.NetworkRequestListener {
@Override
public void onNetworkRequested(@NonNull NetworkRequest request, int score, int providerId) {
@@ -202,11 +234,6 @@
@Override
public void handleMessage(@NonNull Message msg) {
- // Ignore if this Vcn is not active and we're not receiving new configs
- if (!isActive() && msg.what != MSG_EVENT_CONFIG_UPDATED) {
- return;
- }
-
switch (msg.what) {
case MSG_EVENT_CONFIG_UPDATED:
handleConfigUpdated((VcnConfig) msg.obj);
@@ -237,9 +264,31 @@
mConfig = config;
- // TODO(b/181815405): Reevaluate active VcnGatewayConnection(s)
+ if (mIsActive.getAndSet(true)) {
+ // VCN is already active - teardown any GatewayConnections whose configs have been
+ // removed and get all current requests
+ for (final Entry<VcnGatewayConnectionConfig, VcnGatewayConnection> entry :
+ mVcnGatewayConnections.entrySet()) {
+ final VcnGatewayConnectionConfig gatewayConnectionConfig = entry.getKey();
+ final VcnGatewayConnection gatewayConnection = entry.getValue();
- if (!mIsActive.getAndSet(true)) {
+ // GatewayConnectionConfigs must match exactly (otherwise authentication or
+ // connection details may have changed).
+ if (!mConfig.getGatewayConnectionConfigs().contains(gatewayConnectionConfig)) {
+ if (gatewayConnection == null) {
+ Slog.wtf(
+ getLogTag(),
+ "Found gatewayConnectionConfig without GatewayConnection");
+ } else {
+ gatewayConnection.teardownAsynchronously();
+ }
+ }
+ }
+
+ // Trigger a re-evaluation of all NetworkRequests (to make sure any that can be
+ // satisfied start a new GatewayConnection)
+ mVcnContext.getVcnNetworkProvider().resendAllRequests(mRequestListener);
+ } else {
// If this VCN was not previously active, it is exiting Safe Mode. Re-register the
// request listener to get NetworkRequests again (and all cached requests).
mVcnContext.getVcnNetworkProvider().registerListener(mRequestListener);
@@ -259,13 +308,16 @@
private void handleEnterSafeMode() {
handleTeardown();
- mVcnGatewayConnections.clear();
-
mVcnCallback.onEnteredSafeMode();
}
private void handleNetworkRequested(
@NonNull NetworkRequest request, int score, int providerId) {
+ if (!isActive()) {
+ Slog.v(getLogTag(), "Received NetworkRequest while inactive. Ignore for now");
+ return;
+ }
+
if (score > getNetworkScore()) {
if (VDBG) {
Slog.v(
@@ -299,9 +351,7 @@
for (VcnGatewayConnectionConfig gatewayConnectionConfig :
mConfig.getGatewayConnectionConfigs()) {
if (isRequestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) {
- Slog.v(
- getLogTag(),
- "Bringing up new VcnGatewayConnection for request " + request.requestId);
+ Slog.v(getLogTag(), "Bringing up new VcnGatewayConnection for request " + request);
final VcnGatewayConnection vcnGatewayConnection =
mDeps.newVcnGatewayConnection(
@@ -320,8 +370,10 @@
mVcnGatewayConnections.remove(config);
// Trigger a re-evaluation of all NetworkRequests (to make sure any that can be satisfied
- // start a new GatewayConnection)
- mVcnContext.getVcnNetworkProvider().resendAllRequests(mRequestListener);
+ // start a new GatewayConnection), but only if the Vcn is still active
+ if (isActive()) {
+ mVcnContext.getVcnNetworkProvider().resendAllRequests(mRequestListener);
+ }
}
private void handleSubscriptionsChanged(@NonNull TelephonySubscriptionSnapshot snapshot) {
diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
index 15429f4..9589505 100644
--- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
+++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
@@ -20,6 +20,7 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.net.vcn.VcnManager.VCN_ERROR_CODE_CONFIG_ERROR;
@@ -41,7 +42,6 @@
import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkAgent;
-import android.net.NetworkAgent.ValidationStatus;
import android.net.NetworkAgentConfig;
import android.net.NetworkCapabilities;
import android.net.RouteInfo;
@@ -59,6 +59,7 @@
import android.net.ipsec.ike.exceptions.IkeException;
import android.net.ipsec.ike.exceptions.IkeInternalException;
import android.net.ipsec.ike.exceptions.IkeProtocolException;
+import android.net.vcn.VcnControlPlaneIkeConfig;
import android.net.vcn.VcnGatewayConnectionConfig;
import android.net.vcn.VcnTransportInfo;
import android.net.wifi.WifiInfo;
@@ -1348,7 +1349,7 @@
mIkeSession = null;
}
- mIkeSession = buildIkeSession();
+ mIkeSession = buildIkeSession(mUnderlying.network);
}
@Override
@@ -1440,17 +1441,16 @@
caps,
lp,
Vcn.getNetworkScore(),
- new NetworkAgentConfig(),
+ new NetworkAgentConfig.Builder().build(),
mVcnContext.getVcnNetworkProvider()) {
@Override
- public void unwanted() {
+ public void onNetworkUnwanted() {
Slog.d(TAG, "NetworkAgent was unwanted");
teardownAsynchronously();
}
@Override
- public void onValidationStatus(
- @ValidationStatus int status, @Nullable Uri redirectUri) {
+ public void onValidationStatus(int status, @Nullable Uri redirectUri) {
if (status == NetworkAgent.VALIDATION_STATUS_VALID) {
clearFailedAttemptCounterAndSafeModeAlarm();
}
@@ -1726,6 +1726,7 @@
final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder();
builder.addTransportType(TRANSPORT_CELLULAR);
+ builder.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
builder.addCapability(NET_CAPABILITY_NOT_CONGESTED);
builder.addCapability(NET_CAPABILITY_NOT_SUSPENDED);
@@ -1795,8 +1796,10 @@
lp.addDnsServer(addr);
}
- lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
- lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
+ lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null /*gateway*/,
+ null /*iface*/, RouteInfo.RTN_UNICAST));
+ lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null /*gateway*/,
+ null /*iface*/, RouteInfo.RTN_UNICAST));
lp.setMtu(gatewayConnectionConfig.getMaxMtu());
@@ -1939,23 +1942,29 @@
new EventDisconnectRequestedInfo(reason, shouldQuit));
}
- private IkeSessionParams buildIkeParams() {
- // TODO: Implement this once IkeSessionParams is persisted
- return null;
+ private IkeSessionParams buildIkeParams(@NonNull Network network) {
+ final VcnControlPlaneIkeConfig controlPlaneConfig =
+ (VcnControlPlaneIkeConfig) mConnectionConfig.getControlPlaneConfig();
+ final IkeSessionParams.Builder builder =
+ new IkeSessionParams.Builder(controlPlaneConfig.getIkeSessionParams());
+ builder.setConfiguredNetwork(network);
+
+ return builder.build();
}
private ChildSessionParams buildChildParams() {
- // TODO: Implement this once IkeSessionParams is persisted
- return null;
+ final VcnControlPlaneIkeConfig controlPlaneConfig =
+ (VcnControlPlaneIkeConfig) mConnectionConfig.getControlPlaneConfig();
+ return controlPlaneConfig.getChildSessionParams();
}
@VisibleForTesting(visibility = Visibility.PRIVATE)
- VcnIkeSession buildIkeSession() {
+ VcnIkeSession buildIkeSession(@NonNull Network network) {
final int token = ++mCurrentToken;
return mDeps.newIkeSession(
mVcnContext,
- buildIkeParams(),
+ buildIkeParams(network),
buildChildParams(),
new IkeSessionCallbackImpl(token),
new VcnChildSessionCallback(token));
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 7e6b7cd..e060171 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -110,6 +110,7 @@
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Binder;
+import android.os.Build;
import android.os.Bundle;
import android.os.Debug;
import android.os.Handler;
@@ -165,13 +166,13 @@
static final String TAG_TASKS = TAG + POSTFIX_TASKS;
/** How long we wait until giving up on the last activity telling us it is idle. */
- private static final int IDLE_TIMEOUT = 10 * 1000;
+ private static final int IDLE_TIMEOUT = 10 * 1000 * Build.HW_TIMEOUT_MULTIPLIER;
/** How long we can hold the sleep wake lock before giving up. */
- private static final int SLEEP_TIMEOUT = 5 * 1000;
+ private static final int SLEEP_TIMEOUT = 5 * 1000 * Build.HW_TIMEOUT_MULTIPLIER;
// How long we can hold the launch wake lock before giving up.
- private static final int LAUNCH_TIMEOUT = 10 * 1000;
+ private static final int LAUNCH_TIMEOUT = 10 * 1000 * Build.HW_TIMEOUT_MULTIPLIER;
/** How long we wait until giving up on the activity telling us it released the top state. */
private static final int TOP_RESUMED_STATE_LOSS_TIMEOUT = 500;
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 816a6a0..f55a983 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -312,9 +312,10 @@
private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
// How long we wait until we timeout on key dispatching.
- public static final int KEY_DISPATCHING_TIMEOUT_MS = 5 * 1000;
+ public static final int KEY_DISPATCHING_TIMEOUT_MS = 5 * 1000 * Build.HW_TIMEOUT_MULTIPLIER;
// How long we wait until we timeout on key dispatching during instrumentation.
- static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MS = 60 * 1000;
+ static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MS =
+ 60 * 1000 * Build.HW_TIMEOUT_MULTIPLIER;
// How long we permit background activity starts after an activity in the process
// started or finished.
static final long ACTIVITY_BG_START_GRACE_PERIOD_MS = 10 * 1000;
diff --git a/services/core/jni/com_android_server_SystemServer.cpp b/services/core/jni/com_android_server_SystemServer.cpp
index 729fa71..d18043f 100644
--- a/services/core/jni/com_android_server_SystemServer.cpp
+++ b/services/core/jni/com_android_server_SystemServer.cpp
@@ -100,16 +100,9 @@
}
static void android_server_SystemServer_fdtrackAbort(JNIEnv*, jobject) {
- raise(BIONIC_SIGNAL_FDTRACK);
-
- // Wait for a bit to allow fdtrack to dump backtraces to logcat.
- std::this_thread::sleep_for(5s);
-
- // Abort on a different thread to avoid ART dumping runtime stacks.
- std::thread([]() {
- LOG_ALWAYS_FATAL("b/140703823: aborting due to fd leak: check logs for fd "
- "backtraces");
- }).join();
+ sigval val;
+ val.sival_int = 1;
+ sigqueue(getpid(), BIONIC_SIGNAL_FDTRACK, val);
}
static jlong android_server_SystemServer_startIncrementalService(JNIEnv* env, jclass klass,
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 6badafa..736a6f6 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -15621,10 +15621,7 @@
Objects.requireNonNull(who, "ComponentName is null");
enforceDeviceOwner(who);
- String currentMode = mInjector.settingsGlobalGetString(PRIVATE_DNS_MODE);
- if (currentMode == null) {
- currentMode = ConnectivityManager.PRIVATE_DNS_DEFAULT_MODE_FALLBACK;
- }
+ final String currentMode = ConnectivityManager.getPrivateDnsMode(mContext);
switch (currentMode) {
case ConnectivityManager.PRIVATE_DNS_MODE_OFF:
return PRIVATE_DNS_MODE_OFF;
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index a6a99f23..46ec65d 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -108,6 +108,7 @@
import com.android.server.clipboard.ClipboardService;
import com.android.server.compat.PlatformCompat;
import com.android.server.compat.PlatformCompatNative;
+import com.android.server.connectivity.PacProxyService;
import com.android.server.contentcapture.ContentCaptureManagerInternal;
import com.android.server.coverage.CoverageService;
import com.android.server.devicepolicy.DevicePolicyManagerService;
@@ -331,8 +332,6 @@
private static final String UNCRYPT_PACKAGE_FILE = "/cache/recovery/uncrypt_file";
private static final String BLOCK_MAP_FILE = "/cache/recovery/block.map";
- private static final String GSI_RUNNING_PROP = "ro.gsid.image_running";
-
// maximum number of binder threads used for system_server
// will be higher than the system default
private static final int sMaxBinderThreads = 31;
@@ -1115,6 +1114,7 @@
ConsumerIrService consumerIr = null;
MmsServiceBroker mmsService = null;
HardwarePropertiesManagerService hardwarePropertiesService = null;
+ PacProxyService pacProxyService = null;
boolean disableSystemTextClassifier = SystemProperties.getBoolean(
"config.disable_systemtextclassifier", false);
@@ -1125,7 +1125,7 @@
false);
boolean enableLeftyService = SystemProperties.getBoolean("config.enable_lefty", false);
- boolean isEmulator = SystemProperties.get("ro.kernel.qemu").equals("1");
+ boolean isEmulator = SystemProperties.get("ro.boot.qemu").equals("1");
boolean isWatch = context.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_WATCH);
@@ -1441,8 +1441,7 @@
t.traceEnd();
final boolean hasPdb = !SystemProperties.get(PERSISTENT_DATA_BLOCK_PROP).equals("");
- final boolean hasGsi = SystemProperties.getInt(GSI_RUNNING_PROP, 0) > 0;
- if (hasPdb && !hasGsi) {
+ if (hasPdb) {
t.traceBegin("StartPersistentDataBlock");
mSystemServiceManager.startService(PersistentDataBlockService.class);
t.traceEnd();
@@ -1623,6 +1622,15 @@
t.traceEnd();
}
+ t.traceBegin("StartPacProxyService");
+ try {
+ pacProxyService = new PacProxyService(context);
+ ServiceManager.addService(Context.PAC_PROXY_SERVICE, pacProxyService);
+ } catch (Throwable e) {
+ reportWtf("starting PacProxyService", e);
+ }
+ t.traceEnd();
+
t.traceBegin("StartConnectivityService");
// This has to be called after NetworkManagementService, NetworkStatsService
// and NetworkPolicyManager because ConnectivityService needs to take these
diff --git a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
index a262939..29aedce 100644
--- a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
+++ b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
@@ -295,10 +295,30 @@
return;
}
- try {
- mIProfcollect.report();
- } catch (RemoteException e) {
- Log.e(LOG_TAG, e.getMessage());
- }
+ final boolean uploadReport =
+ DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PROFCOLLECT_NATIVE_BOOT,
+ "upload_report", false);
+
+ new Thread(() -> {
+ try {
+ String reportPath = mIProfcollect.report();
+ if (!uploadReport) {
+ return;
+ }
+ Intent uploadIntent =
+ new Intent("com.google.android.apps.betterbug.intent.action.UPLOAD_PROFILE")
+ .setPackage("com.google.android.apps.internal.betterbug")
+ .putExtra("EXTRA_DESTINATION", "PROFCOLLECT")
+ .putExtra("EXTRA_PACKAGE_NAME", getContext().getPackageName())
+ .putExtra("EXTRA_PROFILE_PATH", reportPath)
+ .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+ Context context = getContext();
+ if (context.getPackageManager().queryBroadcastReceivers(uploadIntent, 0) != null) {
+ context.sendBroadcast(uploadIntent);
+ }
+ } catch (RemoteException e) {
+ Log.e(LOG_TAG, e.getMessage());
+ }
+ }).start();
}
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java b/services/tests/mockingservicestests/src/com/android/server/pm/dex/DexManagerTests.java
similarity index 84%
rename from services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
rename to services/tests/mockingservicestests/src/com/android/server/pm/dex/DexManagerTests.java
index ee0a16a..2e0cadf 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/dex/DexManagerTests.java
@@ -11,7 +11,7 @@
* 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
+ * limitations under the License.
*/
package com.android.server.pm.dex;
@@ -28,28 +28,34 @@
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.os.BatteryManager;
import android.os.Build;
+import android.os.PowerManager;
import android.os.UserHandle;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.dx.mockito.inline.extended.ExtendedMockito;
+import com.android.dx.mockito.inline.extended.StaticMockitoSession;
import com.android.server.pm.Installer;
+import com.android.server.pm.PackageManagerService;
import dalvik.system.DelegateLastClassLoader;
import dalvik.system.PathClassLoader;
import dalvik.system.VMRuntime;
+import org.junit.After;
import org.junit.Before;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
import org.mockito.quality.Strictness;
import java.io.File;
@@ -69,9 +75,15 @@
DelegateLastClassLoader.class.getName();
private static final String UNSUPPORTED_CLASS_LOADER_NAME = "unsupported.class_loader";
- @Rule public MockitoRule mockito = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS);
+ private static final int TEST_BATTERY_LEVEL_CRITICAL = 10;
+ private static final int TEST_BATTERY_LEVEL_DEFAULT = 80;
+
+ public StaticMockitoSession mMockitoSession;
@Mock Installer mInstaller;
@Mock IPackageManager mPM;
+ @Mock BatteryManager mMockBatteryManager;
+ @Mock PowerManager mMockPowerManager;
+
private final Object mInstallLock = new Object();
private DexManager mDexManager;
@@ -117,7 +129,37 @@
mSystemServerJarUpdatedContext = new TestData("android", isa, mUser0,
DELEGATE_LAST_CLASS_LOADER_NAME);
- mDexManager = new DexManager(/*Context*/ null, mPM, /*PackageDexOptimizer*/ null,
+ // Initialize Static Mocking
+
+ mMockitoSession = ExtendedMockito.mockitoSession()
+ .initMocks(this)
+ .strictness(Strictness.LENIENT)
+ .startMocking();
+
+ // Mock....
+
+ mMockBatteryManager = ExtendedMockito.mock(BatteryManager.class);
+ mMockPowerManager = ExtendedMockito.mock(PowerManager.class);
+
+ setDefaultMockValues();
+
+ Resources mockResources = ExtendedMockito.mock(Resources.class);
+ ExtendedMockito.when(mockResources
+ .getInteger(com.android.internal.R.integer.config_criticalBatteryWarningLevel))
+ .thenReturn(15);
+
+ Context mockContext = ExtendedMockito.mock(Context.class);
+ ExtendedMockito.doReturn(mockResources)
+ .when(mockContext)
+ .getResources();
+ ExtendedMockito.doReturn(mMockBatteryManager)
+ .when(mockContext)
+ .getSystemService(BatteryManager.class);
+ ExtendedMockito.doReturn(mMockPowerManager)
+ .when(mockContext)
+ .getSystemService(PowerManager.class);
+
+ mDexManager = new DexManager(mockContext, mPM, /*PackageDexOptimizer*/ null,
mInstaller, mInstallLock);
// Foo and Bar are available to user0.
@@ -128,6 +170,25 @@
mDexManager.load(existingPackages);
}
+ @After
+ public void teardown() throws Exception {
+ mMockitoSession.finishMocking();
+ }
+
+ private void setDefaultMockValues() {
+ ExtendedMockito.doReturn(BatteryManager.BATTERY_STATUS_DISCHARGING)
+ .when(mMockBatteryManager)
+ .getIntProperty(BatteryManager.BATTERY_PROPERTY_STATUS);
+
+ ExtendedMockito.doReturn(TEST_BATTERY_LEVEL_DEFAULT)
+ .when(mMockBatteryManager)
+ .getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY);
+
+ ExtendedMockito.doReturn(PowerManager.THERMAL_STATUS_NONE)
+ .when(mMockPowerManager)
+ .getCurrentThermalStatus();
+ }
+
@Test
public void testNotifyPrimaryUse() {
// The main dex file and splits are re-loaded by the app.
@@ -633,6 +694,114 @@
assertNoDclInfo(mSystemServerJarInvalid);
}
+ @Test
+ public void testInstallScenarioToReasonDefault() {
+ assertEquals(
+ PackageManagerService.REASON_INSTALL,
+ mDexManager.getCompilationReasonForInstallScenario(
+ PackageManager.INSTALL_SCENARIO_DEFAULT));
+
+ assertEquals(
+ PackageManagerService.REASON_INSTALL_FAST,
+ mDexManager.getCompilationReasonForInstallScenario(
+ PackageManager.INSTALL_SCENARIO_FAST));
+
+ assertEquals(
+ PackageManagerService.REASON_INSTALL_BULK,
+ mDexManager.getCompilationReasonForInstallScenario(
+ PackageManager.INSTALL_SCENARIO_BULK));
+
+ assertEquals(
+ PackageManagerService.REASON_INSTALL_BULK_SECONDARY,
+ mDexManager.getCompilationReasonForInstallScenario(
+ PackageManager.INSTALL_SCENARIO_BULK_SECONDARY));
+ }
+
+ @Test
+ public void testInstallScenarioToReasonThermal() {
+ ExtendedMockito.doReturn(PowerManager.THERMAL_STATUS_SEVERE)
+ .when(mMockPowerManager)
+ .getCurrentThermalStatus();
+
+ assertEquals(
+ PackageManagerService.REASON_INSTALL,
+ mDexManager.getCompilationReasonForInstallScenario(
+ PackageManager.INSTALL_SCENARIO_DEFAULT));
+
+ assertEquals(
+ PackageManagerService.REASON_INSTALL_FAST,
+ mDexManager.getCompilationReasonForInstallScenario(
+ PackageManager.INSTALL_SCENARIO_FAST));
+
+ assertEquals(
+ PackageManagerService.REASON_INSTALL_BULK_DOWNGRADED,
+ mDexManager.getCompilationReasonForInstallScenario(
+ PackageManager.INSTALL_SCENARIO_BULK));
+
+ assertEquals(
+ PackageManagerService.REASON_INSTALL_BULK_SECONDARY_DOWNGRADED,
+ mDexManager.getCompilationReasonForInstallScenario(
+ PackageManager.INSTALL_SCENARIO_BULK_SECONDARY));
+ }
+
+ @Test
+ public void testInstallScenarioToReasonBatteryDischarging() {
+ ExtendedMockito.doReturn(TEST_BATTERY_LEVEL_CRITICAL)
+ .when(mMockBatteryManager)
+ .getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY);
+
+ assertEquals(
+ PackageManagerService.REASON_INSTALL,
+ mDexManager.getCompilationReasonForInstallScenario(
+ PackageManager.INSTALL_SCENARIO_DEFAULT));
+
+ assertEquals(
+ PackageManagerService.REASON_INSTALL_FAST,
+ mDexManager.getCompilationReasonForInstallScenario(
+ PackageManager.INSTALL_SCENARIO_FAST));
+
+ assertEquals(
+ PackageManagerService.REASON_INSTALL_BULK_DOWNGRADED,
+ mDexManager.getCompilationReasonForInstallScenario(
+ PackageManager.INSTALL_SCENARIO_BULK));
+
+ assertEquals(
+ PackageManagerService.REASON_INSTALL_BULK_SECONDARY_DOWNGRADED,
+ mDexManager.getCompilationReasonForInstallScenario(
+ PackageManager.INSTALL_SCENARIO_BULK_SECONDARY));
+ }
+
+ @Test
+ public void testInstallScenarioToReasonBatteryCharging() {
+ ExtendedMockito.doReturn(TEST_BATTERY_LEVEL_CRITICAL)
+ .when(mMockBatteryManager)
+ .getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY);
+
+ ExtendedMockito.doReturn(BatteryManager.BATTERY_STATUS_CHARGING)
+ .when(mMockBatteryManager)
+ .getIntProperty(BatteryManager.BATTERY_PROPERTY_STATUS);
+
+ assertEquals(
+ PackageManagerService.REASON_INSTALL,
+ mDexManager.getCompilationReasonForInstallScenario(
+ PackageManager.INSTALL_SCENARIO_DEFAULT));
+
+ assertEquals(
+ PackageManagerService.REASON_INSTALL_FAST,
+ mDexManager.getCompilationReasonForInstallScenario(
+ PackageManager.INSTALL_SCENARIO_FAST));
+
+ assertEquals(
+ PackageManagerService.REASON_INSTALL_BULK,
+ mDexManager.getCompilationReasonForInstallScenario(
+ PackageManager.INSTALL_SCENARIO_BULK));
+
+ assertEquals(
+ PackageManagerService.REASON_INSTALL_BULK_SECONDARY,
+ mDexManager.getCompilationReasonForInstallScenario(
+ PackageManager.INSTALL_SCENARIO_BULK_SECONDARY));
+ }
+
private void assertSecondaryUse(TestData testData, PackageUseInfo pui,
List<String> secondaries, boolean isUsedByOtherApps, int ownerUserId,
String[] expectedContexts) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/dex/OWNERS b/services/tests/mockingservicestests/src/com/android/server/pm/dex/OWNERS
new file mode 100644
index 0000000..5492dc8
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/dex/OWNERS
@@ -0,0 +1 @@
+include platform/art:/OWNERS
\ No newline at end of file
diff --git a/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/OWNERS b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/OWNERS
new file mode 100644
index 0000000..e95633a
--- /dev/null
+++ b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/app/admin/OWNERS
diff --git a/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest2/OWNERS b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest2/OWNERS
new file mode 100644
index 0000000..e95633a
--- /dev/null
+++ b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest2/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/app/admin/OWNERS
diff --git a/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest3/OWNERS b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest3/OWNERS
new file mode 100644
index 0000000..e95633a
--- /dev/null
+++ b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest3/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/app/admin/OWNERS
diff --git a/services/tests/servicestests/assets/OwnersTest/OWNERS b/services/tests/servicestests/assets/OwnersTest/OWNERS
new file mode 100644
index 0000000..e95633a
--- /dev/null
+++ b/services/tests/servicestests/assets/OwnersTest/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/app/admin/OWNERS
diff --git a/services/tests/servicestests/assets/PolicyVersionUpgraderTest/OWNERS b/services/tests/servicestests/assets/PolicyVersionUpgraderTest/OWNERS
new file mode 100644
index 0000000..e95633a
--- /dev/null
+++ b/services/tests/servicestests/assets/PolicyVersionUpgraderTest/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/app/admin/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java b/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java
index 07f6732..2f0d71a 100644
--- a/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java
@@ -18,6 +18,7 @@
import static android.content.pm.PackageManager.MATCH_ANY_USER;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.AdditionalAnswers.returnsArgAt;
import static org.mockito.ArgumentMatchers.any;
@@ -40,9 +41,11 @@
import android.net.Uri;
import android.os.RemoteException;
import android.os.UserManager;
+import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
+import com.android.server.LocalServices;
import com.android.server.SystemService;
import org.junit.Before;
@@ -55,15 +58,18 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.Executor;
/**
* Tests for {@link com.android.server.apphibernation.AppHibernationService}
*/
@SmallTest
+@Presubmit
public final class AppHibernationServiceTest {
private static final String PACKAGE_SCHEME = "package";
private static final String PACKAGE_NAME_1 = "package1";
private static final String PACKAGE_NAME_2 = "package2";
+ private static final String PACKAGE_NAME_3 = "package3";
private static final int USER_ID_1 = 1;
private static final int USER_ID_2 = 2;
@@ -91,6 +97,7 @@
MockitoAnnotations.initMocks(this);
doReturn(mContext).when(mContext).createContextAsUser(any(), anyInt());
+ LocalServices.removeServiceForTest(AppHibernationManagerInternal.class);
mAppHibernationService = new AppHibernationService(new MockInjector(mContext));
verify(mContext).registerReceiver(mReceiverCaptor.capture(), any());
@@ -103,13 +110,15 @@
List<PackageInfo> packages = new ArrayList<>();
packages.add(makePackageInfo(PACKAGE_NAME_1));
+ packages.add(makePackageInfo(PACKAGE_NAME_2));
+ packages.add(makePackageInfo(PACKAGE_NAME_3));
doReturn(new ParceledListSlice<>(packages)).when(mIPackageManager).getInstalledPackages(
intThat(arg -> (arg & MATCH_ANY_USER) != 0), anyInt());
mAppHibernationService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
UserInfo userInfo = addUser(USER_ID_1);
- mAppHibernationService.onUserUnlocking(new SystemService.TargetUser(userInfo));
doReturn(true).when(mUserManager).isUserUnlockingOrUnlocked(USER_ID_1);
+ mAppHibernationService.onUserUnlocking(new SystemService.TargetUser(userInfo));
mAppHibernationService.mIsServiceEnabled = true;
}
@@ -142,8 +151,8 @@
throws RemoteException {
// WHEN a new user is added and a package from the user is hibernated
UserInfo user2 = addUser(USER_ID_2);
- mAppHibernationService.onUserUnlocking(new SystemService.TargetUser(user2));
doReturn(true).when(mUserManager).isUserUnlockingOrUnlocked(USER_ID_2);
+ mAppHibernationService.onUserUnlocking(new SystemService.TargetUser(user2));
mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_1, USER_ID_2, true);
// THEN the new user's package is hibernated
@@ -175,6 +184,26 @@
assertTrue(mAppHibernationService.isHibernatingGlobally(PACKAGE_NAME_1));
}
+ @Test
+ public void testGetHibernatingPackagesForUser_returnsCorrectPackages() throws RemoteException {
+ // GIVEN an unlocked user with all packages installed
+ UserInfo userInfo =
+ addUser(USER_ID_2, new String[]{PACKAGE_NAME_1, PACKAGE_NAME_2, PACKAGE_NAME_3});
+ doReturn(true).when(mUserManager).isUserUnlockingOrUnlocked(USER_ID_2);
+ mAppHibernationService.onUserUnlocking(new SystemService.TargetUser(userInfo));
+
+ // WHEN packages are hibernated for the user
+ mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_1, USER_ID_2, true);
+ mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_2, USER_ID_2, true);
+
+ // THEN the hibernating packages returned matches
+ List<String> hibernatingPackages =
+ mAppHibernationService.getHibernatingPackagesForUser(USER_ID_2);
+ assertEquals(2, hibernatingPackages.size());
+ assertTrue(hibernatingPackages.contains(PACKAGE_NAME_1));
+ assertTrue(hibernatingPackages.contains(PACKAGE_NAME_2));
+ }
+
/**
* Add a mock user with one package.
*/
@@ -231,6 +260,12 @@
}
@Override
+ public Executor getBackgroundExecutor() {
+ // Just execute immediately in tests.
+ return r -> r.run();
+ }
+
+ @Override
public HibernationStateDiskStore<GlobalLevelState> getGlobalLevelDiskStore() {
return Mockito.mock(HibernationStateDiskStore.class);
}
diff --git a/services/tests/servicestests/src/com/android/server/apphibernation/HibernationStateDiskStoreTest.java b/services/tests/servicestests/src/com/android/server/apphibernation/HibernationStateDiskStoreTest.java
index 59f3c35..2237c84 100644
--- a/services/tests/servicestests/src/com/android/server/apphibernation/HibernationStateDiskStoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/apphibernation/HibernationStateDiskStoreTest.java
@@ -19,6 +19,7 @@
import static org.junit.Assert.assertEquals;
import android.os.FileUtils;
+import android.platform.test.annotations.Presubmit;
import android.util.proto.ProtoInputStream;
import android.util.proto.ProtoOutputStream;
@@ -48,6 +49,7 @@
@SmallTest
+@Presubmit
public class HibernationStateDiskStoreTest {
private static final String STATES_FILE_NAME = "states";
private final MockScheduledExecutorService mMockScheduledExecutorService =
diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java b/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java
index f00edcc..7bdc87e 100644
--- a/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java
+++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java
@@ -116,7 +116,12 @@
}
CompatConfigBuilder addOverridableChangeWithId(long id) {
- mChanges.add(new CompatChange(id, "", -1, -1, false, true, "", true));
+ mChanges.add(new CompatChange(id, "", -1, -1, true, false, "", true));
+ return this;
+ }
+
+ CompatConfigBuilder addEnabledSinceApexChangeWithId(int sdk, long id) {
+ mChanges.add(new CompatChange(id, "", -1, sdk, false, false, "", false));
return this;
}
diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
index 8b0e948..a866363 100644
--- a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
@@ -86,6 +86,7 @@
// Assume userdebug/eng non-final build
when(mBuildClassifier.isDebuggableBuild()).thenReturn(true);
when(mBuildClassifier.isFinalBuild()).thenReturn(false);
+ when(mBuildClassifier.platformTargetSdk()).thenReturn(30);
ChangeIdStateCache.disable();
when(mPackageManager.getApplicationInfo(anyString(), anyInt()))
.thenThrow(new NameNotFoundException());
@@ -259,6 +260,36 @@
}
@Test
+ public void testInstallerCanSetOverrides() throws Exception {
+ final long changeId = 1234L;
+ final int installerUid = 23;
+ CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+ .addOverridableChangeWithId(1234L)
+ .build();
+ ApplicationInfo applicationInfo = ApplicationInfoBuilder.create()
+ .withPackageName("com.some.package")
+ .build();
+ PackageManager packageManager = mock(PackageManager.class);
+ when(mContext.getPackageManager()).thenReturn(packageManager);
+ when(packageManager.getApplicationInfo(eq("com.some.package"), anyInt()))
+ .thenReturn(applicationInfo);
+
+ // Force the validator to prevent overriding the change by using a user build.
+ when(mBuildClassifier.isDebuggableBuild()).thenReturn(false);
+ when(mBuildClassifier.isFinalBuild()).thenReturn(true);
+
+ CompatibilityOverrideConfig config = new CompatibilityOverrideConfig(
+ Collections.singletonMap(1234L,
+ new PackageOverride.Builder()
+ .setMaxVersionCode(99L)
+ .setEnabled(true)
+ .build()));
+
+ compatConfig.addOverrides(config, "com.some.package");
+ assertThat(compatConfig.isChangeEnabled(1234L, applicationInfo)).isTrue();
+ }
+
+ @Test
public void testApplyDeferredOverridesAfterInstallingApp() throws Exception {
ApplicationInfo applicationInfo = ApplicationInfoBuilder.create()
.withPackageName("com.notinstalled.foo")
@@ -567,6 +598,34 @@
}
@Test
+ public void testReadApexConfig() throws IOException {
+ String configXml = "<config>"
+ + "<compat-change id=\"1234\" name=\"MY_CHANGE1\" enableAfterTargetSdk=\"2\" />"
+ + "<compat-change id=\"1235\" name=\"MY_CHANGE2\" disabled=\"true\" />"
+ + "<compat-change id=\"1236\" name=\"MY_CHANGE3\" />"
+ + "<compat-change id=\"1237\" name=\"MY_CHANGE4\" enableSinceTargetSdk=\"31\" />"
+ + "</config>";
+
+ File dir = createTempDir();
+ writeToFile(dir, "platform_compat_config.xml", configXml);
+ CompatConfig compatConfig = new CompatConfig(mBuildClassifier, mContext);
+ compatConfig.forceNonDebuggableFinalForTest(false);
+
+ compatConfig.initConfigFromLib(dir);
+
+ assertThat(compatConfig.isChangeEnabled(1234L,
+ ApplicationInfoBuilder.create().withTargetSdk(1).build())).isFalse();
+ assertThat(compatConfig.isChangeEnabled(1234L,
+ ApplicationInfoBuilder.create().withTargetSdk(3).build())).isTrue();
+ assertThat(compatConfig.isChangeEnabled(1235L,
+ ApplicationInfoBuilder.create().withTargetSdk(5).build())).isFalse();
+ assertThat(compatConfig.isChangeEnabled(1236L,
+ ApplicationInfoBuilder.create().withTargetSdk(1).build())).isTrue();
+ assertThat(compatConfig.isChangeEnabled(1237L,
+ ApplicationInfoBuilder.create().withTargetSdk(31).build())).isTrue();
+ }
+
+ @Test
public void testReadConfigMultipleFiles() throws IOException {
String configXml1 = "<config>"
+ "<compat-change id=\"1234\" name=\"MY_CHANGE1\" enableAfterTargetSdk=\"2\" />"
@@ -602,17 +661,26 @@
.addEnableSinceSdkChangeWithId(2, 2L)
.build();
compatConfig.forceNonDebuggableFinalForTest(true);
- compatConfig.initOverrides(overridesFile);
+ compatConfig.initOverrides(overridesFile, new File(""));
when(mPackageManager.getApplicationInfo(eq("foo.bar"), anyInt()))
.thenReturn(ApplicationInfoBuilder.create()
- .withPackageName("foo.bar")
- .debuggable()
- .build());
+ .withPackageName("foo.bar")
+ .debuggable()
+ .build());
when(mPackageManager.getApplicationInfo(eq("bar.baz"), anyInt()))
.thenThrow(new NameNotFoundException());
-
- compatConfig.addOverride(1L, "foo.bar", true);
- compatConfig.addOverride(2L, "bar.baz", false);
+ compatConfig.addOverrides(
+ new CompatibilityOverrideConfig(
+ Collections.singletonMap(
+ 1L,
+ new PackageOverride.Builder().setEnabled(true).build())),
+ "foo.bar");
+ compatConfig.addOverrides(
+ new CompatibilityOverrideConfig(
+ Collections.singletonMap(
+ 2L,
+ new PackageOverride.Builder().setEnabled(false).build())),
+ "bar.baz");
assertThat(readFile(overridesFile)).isEqualTo("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+ "<overrides>\n"
@@ -649,7 +717,7 @@
.addEnableSinceSdkChangeWithId(2, 2L)
.build();
compatConfig.forceNonDebuggableFinalForTest(true);
- compatConfig.initOverrides(overridesFile);
+ compatConfig.initOverrides(overridesFile, new File(""));
compatConfig.addOverrides(new CompatibilityOverrideConfig(Collections.singletonMap(1L,
new PackageOverride.Builder()
@@ -673,11 +741,11 @@
}
@Test
- public void testLoadOverridesRaw() throws Exception {
+ public void testInitOverridesRaw() throws Exception {
File tempDir = createTempDir();
File overridesFile = new File(tempDir, "overrides.xml");
// Change 1 is enabled for foo.bar (validated)
- // Change 2 is disabled for bar.baz (deferred)
+ // Change 2 is disabled for bar.baz (raw)
String xmlData = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+ "<overrides>\n"
+ " <change-overrides changeId=\"1\">\n"
@@ -709,7 +777,7 @@
.addEnableSinceSdkChangeWithId(2, 2L)
.build();
compatConfig.forceNonDebuggableFinalForTest(true);
- compatConfig.initOverrides(overridesFile);
+ compatConfig.initOverrides(overridesFile, new File(""));
ApplicationInfo applicationInfo = ApplicationInfoBuilder.create()
.withPackageName("foo.bar")
.withVersionCode(100L)
@@ -728,7 +796,7 @@
}
@Test
- public void testLoadOverridesDeferred() throws Exception {
+ public void testInitOverridesDeferred() throws Exception {
File tempDir = createTempDir();
File overridesFile = new File(tempDir, "overrides.xml");
// Change 1 is enabled for foo.bar (validated)
@@ -754,7 +822,7 @@
.addEnableSinceSdkChangeWithId(2, 2L)
.build();
compatConfig.forceNonDebuggableFinalForTest(true);
- compatConfig.initOverrides(overridesFile);
+ compatConfig.initOverrides(overridesFile, new File(""));
ApplicationInfo applicationInfo = ApplicationInfoBuilder.create()
.withPackageName("foo.bar")
.debuggable()
@@ -767,4 +835,115 @@
assertThat(compatConfig.isChangeEnabled(1L, applicationInfo)).isTrue();
assertThat(compatConfig.willChangeBeEnabled(2L, "bar.baz")).isFalse();
}
+
+ @Test
+ public void testInitOverridesWithStaticFile() throws Exception {
+ File tempDir = createTempDir();
+ File dynamicOverridesFile = new File(tempDir, "dynamic_overrides.xml");
+ File staticOverridesFile = new File(tempDir, "static_overrides.xml");
+ // Change 1 is enabled for foo.bar (raw)
+ // Change 2 is disabled for bar.baz (raw)
+ String dynamicXmlData = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+ + "<overrides>"
+ + "<change-overrides changeId=\"1\">"
+ + "<raw>"
+ + " <raw-override-value packageName=\"foo.bar\" "
+ + "minVersionCode=\"-9223372036854775808\" "
+ + "maxVersionCode=\"9223372036854775807\" enabled=\"true\">\n"
+ + " </raw-override-value>\n"
+ + "</raw>"
+ + "</change-overrides>"
+ + "<change-overrides changeId=\"2\">"
+ + "<raw>"
+ + " <raw-override-value packageName=\"bar.baz\" "
+ + "minVersionCode=\"-9223372036854775808\" "
+ + "maxVersionCode=\"9223372036854775807\" enabled=\"false\">\n"
+ + " </raw-override-value>\n"
+ + "</raw>"
+ + "</change-overrides>"
+ + "</overrides>";
+ writeToFile(tempDir, "dynamic_overrides.xml", dynamicXmlData);
+ // Change 2 is enabled for foo.bar and bar.baz (raw)
+ // Change 3 is enabled for bar.baz (raw)
+ String staticXmlData = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+ + "<overrides>"
+ + "<change-overrides changeId=\"2\">"
+ + "<raw>"
+ + " <raw-override-value packageName=\"foo.bar\" "
+ + "minVersionCode=\"-9223372036854775808\" "
+ + "maxVersionCode=\"9223372036854775807\" enabled=\"true\">\n"
+ + " </raw-override-value>\n"
+ + " <raw-override-value packageName=\"bar.baz\" "
+ + "minVersionCode=\"-9223372036854775808\" "
+ + "maxVersionCode=\"9223372036854775807\" enabled=\"true\">\n"
+ + " </raw-override-value>\n"
+ + "</raw>"
+ + "</change-overrides>"
+ + "<change-overrides changeId=\"3\">"
+ + "<raw>"
+ + " <raw-override-value packageName=\"bar.baz\" "
+ + "minVersionCode=\"-9223372036854775808\" "
+ + "maxVersionCode=\"9223372036854775807\" enabled=\"true\">\n"
+ + " </raw-override-value>\n"
+ + "</raw>"
+ + "</change-overrides>"
+ + "</overrides>";
+ writeToFile(tempDir, "static_overrides.xml", staticXmlData);
+ CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+ .addDisabledChangeWithId(1L)
+ .addDisabledChangeWithId(2L)
+ .addDisabledChangeWithId(3L)
+ .build();
+ compatConfig.forceNonDebuggableFinalForTest(true);
+ // Adding an override that will be cleared after initOverrides is called.
+ compatConfig.addOverride(1L, "bar.baz", true);
+ compatConfig.initOverrides(dynamicOverridesFile, staticOverridesFile);
+ when(mPackageManager.getApplicationInfo(eq("foo.bar"), anyInt()))
+ .thenThrow(new NameNotFoundException());
+ when(mPackageManager.getApplicationInfo(eq("bar.baz"), anyInt()))
+ .thenThrow(new NameNotFoundException());
+
+ assertThat(compatConfig.willChangeBeEnabled(1L, "foo.bar")).isTrue();
+ assertThat(compatConfig.willChangeBeEnabled(2L, "foo.bar")).isTrue();
+ assertThat(compatConfig.willChangeBeEnabled(2L, "bar.baz")).isFalse();
+ assertThat(compatConfig.willChangeBeEnabled(3L, "bar.baz")).isTrue();
+ assertThat(readFile(dynamicOverridesFile))
+ .isEqualTo("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+ + "<overrides>\n"
+ + " <change-overrides changeId=\"1\">\n"
+ + " <validated>\n"
+ + " </validated>\n"
+ + " <raw>\n"
+ + " <raw-override-value packageName=\"foo.bar\" "
+ + "minVersionCode=\"-9223372036854775808\" "
+ + "maxVersionCode=\"9223372036854775807\" enabled=\"true\">\n"
+ + " </raw-override-value>\n"
+ + " </raw>\n"
+ + " </change-overrides>\n"
+ + " <change-overrides changeId=\"2\">\n"
+ + " <validated>\n"
+ + " </validated>\n"
+ + " <raw>\n"
+ + " <raw-override-value packageName=\"foo.bar\" "
+ + "minVersionCode=\"-9223372036854775808\" "
+ + "maxVersionCode=\"9223372036854775807\" enabled=\"true\">\n"
+ + " </raw-override-value>\n"
+ + " <raw-override-value packageName=\"bar.baz\" "
+ + "minVersionCode=\"-9223372036854775808\" "
+ + "maxVersionCode=\"9223372036854775807\" enabled=\"false\">\n"
+ + " </raw-override-value>\n"
+ + " </raw>\n"
+ + " </change-overrides>\n"
+ + " <change-overrides changeId=\"3\">\n"
+ + " <validated>\n"
+ + " </validated>\n"
+ + " <raw>\n"
+ + " <raw-override-value packageName=\"bar.baz\" "
+ + "minVersionCode=\"-9223372036854775808\" "
+ + "maxVersionCode=\"9223372036854775807\" enabled=\"true\">\n"
+ + " </raw-override-value>\n"
+ + " </raw>\n"
+ + " </change-overrides>\n"
+ + "</overrides>\n");
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java b/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java
index 0fd6445..57fdcd3 100644
--- a/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java
@@ -22,6 +22,7 @@
import static com.android.internal.compat.OverrideAllowedState.DISABLED_NOT_DEBUGGABLE;
import static com.android.internal.compat.OverrideAllowedState.DISABLED_TARGET_SDK_TOO_HIGH;
import static com.android.internal.compat.OverrideAllowedState.LOGGING_ONLY_CHANGE;
+import static com.android.internal.compat.OverrideAllowedState.PLATFORM_TOO_OLD;
import static com.google.common.truth.Truth.assertThat;
@@ -52,6 +53,7 @@
private static final int TARGET_SDK = 10;
private static final int TARGET_SDK_BEFORE = 9;
private static final int TARGET_SDK_AFTER = 11;
+ private static final int PLATFORM_SDK_VERSION = 30;
@Mock
private PackageManager mPackageManager;
@@ -61,6 +63,7 @@
private AndroidBuildClassifier debuggableBuild() {
AndroidBuildClassifier buildClassifier = mock(AndroidBuildClassifier.class);
when(buildClassifier.isDebuggableBuild()).thenReturn(true);
+ when(buildClassifier.platformTargetSdk()).thenReturn(PLATFORM_SDK_VERSION);
return buildClassifier;
}
@@ -68,6 +71,7 @@
AndroidBuildClassifier buildClassifier = mock(AndroidBuildClassifier.class);
when(buildClassifier.isDebuggableBuild()).thenReturn(false);
when(buildClassifier.isFinalBuild()).thenReturn(false);
+ when(buildClassifier.platformTargetSdk()).thenReturn(PLATFORM_SDK_VERSION);
return buildClassifier;
}
@@ -75,6 +79,7 @@
AndroidBuildClassifier buildClassifier = mock(AndroidBuildClassifier.class);
when(buildClassifier.isDebuggableBuild()).thenReturn(false);
when(buildClassifier.isFinalBuild()).thenReturn(true);
+ when(buildClassifier.platformTargetSdk()).thenReturn(PLATFORM_SDK_VERSION);
return buildClassifier;
}
@@ -333,6 +338,26 @@
}
@Test
+ public void getOverrideAllowedState_targetSdkChangeGreaterThanOsVersion_rejectOverride()
+ throws Exception {
+ final AndroidBuildClassifier buildClassifier = finalBuild();
+ CompatConfig config = CompatConfigBuilder.create(finalBuild(), mContext)
+ .addEnabledSinceApexChangeWithId(PLATFORM_SDK_VERSION + 1, 1).build();
+ IOverrideValidator overrideValidator = config.getOverrideValidator();
+ when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(ApplicationInfoBuilder.create()
+ .withPackageName(PACKAGE_NAME)
+ .debuggable()
+ .build());
+
+ OverrideAllowedState stateTargetSdkLessChange =
+ overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME);
+ assertThat(stateTargetSdkLessChange).isEqualTo(
+ new OverrideAllowedState(PLATFORM_TOO_OLD, -1,
+ PLATFORM_SDK_VERSION));
+ }
+
+ @Test
public void getOverrideAllowedState_finalBuildEnabledChangeDebugApp_rejectOverride()
throws Exception {
CompatConfig config = CompatConfigBuilder.create(finalBuild(), mContext)
diff --git a/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java b/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java
index 799b067..a2664e5 100644
--- a/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java
+++ b/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java
@@ -78,11 +78,12 @@
when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
.thenThrow(new PackageManager.NameNotFoundException());
mCompatConfig = new CompatConfig(mBuildClassifier, mContext);
- mPlatformCompat = new PlatformCompat(mContext, mCompatConfig);
+ mPlatformCompat = new PlatformCompat(mContext, mCompatConfig, mBuildClassifier);
// Assume userdebug/eng non-final build
mCompatConfig.forceNonDebuggableFinalForTest(false);
when(mBuildClassifier.isDebuggableBuild()).thenReturn(true);
when(mBuildClassifier.isFinalBuild()).thenReturn(false);
+ when(mBuildClassifier.platformTargetSdk()).thenReturn(30);
LocalServices.removeServiceForTest(PackageManagerInternal.class);
LocalServices.addService(PackageManagerInternal.class, mPackageManagerInternal);
}
@@ -99,7 +100,7 @@
.addLoggingOnlyChangeWithId(7L)
.addOverridableChangeWithId(8L)
.build();
- mPlatformCompat = new PlatformCompat(mContext, mCompatConfig);
+ mPlatformCompat = new PlatformCompat(mContext, mCompatConfig, mBuildClassifier);
assertThat(mPlatformCompat.listAllChanges()).asList().containsExactly(
new CompatibilityChangeInfo(1L, "", -1, -1, false, false, "", false),
new CompatibilityChangeInfo(2L, "change2", -1, -1, true, false, "", false),
@@ -112,7 +113,7 @@
new CompatibilityChangeInfo(
6L, "", Build.VERSION_CODES.R, -1, false, false, "", false),
new CompatibilityChangeInfo(7L, "", -1, -1, false, true, "", false),
- new CompatibilityChangeInfo(8L, "", -1, -1, false, true, "", true));
+ new CompatibilityChangeInfo(8L, "", -1, -1, true, false, "", true));
}
@Test
@@ -125,8 +126,9 @@
.addEnableSinceSdkChangeWithId(Build.VERSION_CODES.Q, 5L)
.addEnableSinceSdkChangeWithId(Build.VERSION_CODES.R, 6L)
.addLoggingOnlyChangeWithId(7L)
+ .addEnableSinceSdkChangeWithId(31, 8L)
.build();
- mPlatformCompat = new PlatformCompat(mContext, mCompatConfig);
+ mPlatformCompat = new PlatformCompat(mContext, mCompatConfig, mBuildClassifier);
assertThat(mPlatformCompat.listUIChanges()).asList().containsExactly(
new CompatibilityChangeInfo(1L, "", -1, -1, false, false, "", false),
new CompatibilityChangeInfo(2L, "change2", -1, -1, true, false, "", false),
@@ -144,7 +146,7 @@
.addEnableAfterSdkChangeWithId(Build.VERSION_CODES.O, 3L)
.build();
mCompatConfig.forceNonDebuggableFinalForTest(true);
- mPlatformCompat = new PlatformCompat(mContext, mCompatConfig);
+ mPlatformCompat = new PlatformCompat(mContext, mCompatConfig, mBuildClassifier);
// Before adding overrides.
assertThat(mPlatformCompat.isChangeEnabledByPackageName(1, PACKAGE_NAME, 0)).isTrue();
diff --git a/services/tests/servicestests/src/com/android/server/content/OWNERS b/services/tests/servicestests/src/com/android/server/content/OWNERS
new file mode 100644
index 0000000..6264a142
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/content/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/content/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
index b51f4df..8c08226 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
@@ -21,11 +21,13 @@
import static android.content.pm.UserInfo.FLAG_PROFILE;
import static android.os.UserHandle.USER_SYSTEM;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.clearInvocations;
@@ -109,7 +111,12 @@
public interface MockableRebootEscrowInjected {
int getBootCount();
- void reportMetric(boolean success);
+ long getCurrentTimeMillis();
+
+ boolean forceServerBased();
+
+ void reportMetric(boolean success, int errorCode, int serviceType, int attemptCount,
+ int escrowDurationInSeconds, int vbmetaDigestStatus, int durationSinceBootComplete);
}
static class MockInjector extends RebootEscrowManager.Injector {
@@ -119,6 +126,7 @@
private final UserManager mUserManager;
private final MockableRebootEscrowInjected mInjected;
private final RebootEscrowKeyStoreManager mKeyStoreManager;
+ private final boolean mServerBased;
MockInjector(Context context, UserManager userManager,
IRebootEscrow rebootEscrow,
@@ -128,6 +136,7 @@
super(context, storage);
mRebootEscrow = rebootEscrow;
mServiceConnection = null;
+ mServerBased = false;
RebootEscrowProviderHalImpl.Injector halInjector =
new RebootEscrowProviderHalImpl.Injector() {
@Override
@@ -149,6 +158,7 @@
super(context, storage);
mServiceConnection = serviceConnection;
mRebootEscrow = null;
+ mServerBased = true;
RebootEscrowProviderServerBasedImpl.Injector injector =
new RebootEscrowProviderServerBasedImpl.Injector(serviceConnection);
mRebootEscrowProvider = new RebootEscrowProviderServerBasedImpl(storage, injector);
@@ -168,6 +178,14 @@
}
@Override
+ public boolean serverBasedResumeOnReboot() {
+ if (mInjected.forceServerBased()) {
+ return true;
+ }
+ return mServerBased;
+ }
+
+ @Override
public RebootEscrowProviderInterface getRebootEscrowProvider() {
return mRebootEscrowProvider;
}
@@ -195,8 +213,22 @@
}
@Override
- public void reportMetric(boolean success) {
- mInjected.reportMetric(success);
+ public String getVbmetaDigest(boolean other) {
+ return other ? "" : "fake digest";
+ }
+
+ @Override
+ public long getCurrentTimeMillis() {
+ return mInjected.getCurrentTimeMillis();
+ }
+
+ @Override
+ public void reportMetric(boolean success, int errorCode, int serviceType, int attemptCount,
+ int escrowDurationInSeconds, int vbmetaDigestStatus,
+ int durationSinceBootComplete) {
+
+ mInjected.reportMetric(success, errorCode, serviceType, attemptCount,
+ escrowDurationInSeconds, vbmetaDigestStatus, durationSinceBootComplete);
}
}
@@ -417,14 +449,21 @@
// pretend reboot happens here
when(mInjected.getBootCount()).thenReturn(1);
+ when(mInjected.getCurrentTimeMillis()).thenReturn(30000L);
+ mStorage.setLong(RebootEscrowManager.REBOOT_ESCROW_KEY_ARMED_TIMESTAMP, 10000L,
+ USER_SYSTEM);
ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class);
- doNothing().when(mInjected).reportMetric(metricsSuccessCaptor.capture());
+ doNothing().when(mInjected).reportMetric(metricsSuccessCaptor.capture(),
+ eq(0) /* error code */, eq(1) /* HAL based */, eq(1) /* attempt count */,
+ eq(20), eq(0) /* vbmeta status */, anyInt());
when(mRebootEscrow.retrieveKey()).thenAnswer(invocation -> keyByteCaptor.getValue());
mService.loadRebootEscrowDataIfAvailable(null);
verify(mRebootEscrow).retrieveKey();
assertTrue(metricsSuccessCaptor.getValue());
verify(mKeyStoreManager).clearKeyStoreEncryptionKey();
+ assertEquals(mStorage.getLong(RebootEscrowManager.REBOOT_ESCROW_KEY_ARMED_TIMESTAMP,
+ -1, USER_SYSTEM), -1);
}
@Test
@@ -451,7 +490,9 @@
// pretend reboot happens here
when(mInjected.getBootCount()).thenReturn(1);
ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class);
- doNothing().when(mInjected).reportMetric(metricsSuccessCaptor.capture());
+ doNothing().when(mInjected).reportMetric(metricsSuccessCaptor.capture(),
+ eq(0) /* error code */, eq(2) /* Server based */, eq(1) /* attempt count */,
+ anyInt(), eq(0) /* vbmeta status */, anyInt());
when(mServiceConnection.unwrap(any(), anyLong()))
.thenAnswer(invocation -> invocation.getArgument(0));
@@ -462,6 +503,84 @@
}
@Test
+ public void loadRebootEscrowDataIfAvailable_ServerBasedRemoteException_Failure()
+ throws Exception {
+ setServerBasedRebootEscrowProvider();
+
+ when(mInjected.getBootCount()).thenReturn(0);
+ RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
+ mService.setRebootEscrowListener(mockListener);
+ mService.prepareRebootEscrow();
+
+ clearInvocations(mServiceConnection);
+ mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN);
+ verify(mockListener).onPreparedForReboot(eq(true));
+ verify(mServiceConnection, never()).wrapBlob(any(), anyLong(), anyLong());
+
+ // Use x -> x for both wrap & unwrap functions.
+ when(mServiceConnection.wrapBlob(any(), anyLong(), anyLong()))
+ .thenAnswer(invocation -> invocation.getArgument(0));
+ assertTrue(mService.armRebootEscrowIfNeeded());
+ verify(mServiceConnection).wrapBlob(any(), anyLong(), anyLong());
+ assertTrue(mStorage.hasRebootEscrowServerBlob());
+
+ // pretend reboot happens here
+ when(mInjected.getBootCount()).thenReturn(1);
+ ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class);
+ ArgumentCaptor<Integer> metricsErrorCodeCaptor = ArgumentCaptor.forClass(Integer.class);
+ doNothing().when(mInjected).reportMetric(metricsSuccessCaptor.capture(),
+ metricsErrorCodeCaptor.capture(), eq(2) /* Server based */,
+ eq(1) /* attempt count */, anyInt(), eq(0) /* vbmeta status */, anyInt());
+
+ when(mServiceConnection.unwrap(any(), anyLong())).thenThrow(RemoteException.class);
+ mService.loadRebootEscrowDataIfAvailable(null);
+ verify(mServiceConnection).unwrap(any(), anyLong());
+ assertFalse(metricsSuccessCaptor.getValue());
+ assertEquals(Integer.valueOf(RebootEscrowManager.ERROR_LOAD_ESCROW_KEY),
+ metricsErrorCodeCaptor.getValue());
+ }
+
+ @Test
+ public void loadRebootEscrowDataIfAvailable_ServerBasedIoError_RetryFailure() throws Exception {
+ setServerBasedRebootEscrowProvider();
+
+ when(mInjected.getBootCount()).thenReturn(0);
+ RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
+ mService.setRebootEscrowListener(mockListener);
+ mService.prepareRebootEscrow();
+
+ clearInvocations(mServiceConnection);
+ mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN);
+ verify(mockListener).onPreparedForReboot(eq(true));
+ verify(mServiceConnection, never()).wrapBlob(any(), anyLong(), anyLong());
+
+ // Use x -> x for both wrap & unwrap functions.
+ when(mServiceConnection.wrapBlob(any(), anyLong(), anyLong()))
+ .thenAnswer(invocation -> invocation.getArgument(0));
+ assertTrue(mService.armRebootEscrowIfNeeded());
+ verify(mServiceConnection).wrapBlob(any(), anyLong(), anyLong());
+ assertTrue(mStorage.hasRebootEscrowServerBlob());
+
+ // pretend reboot happens here
+ when(mInjected.getBootCount()).thenReturn(1);
+ ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class);
+ ArgumentCaptor<Integer> metricsErrorCodeCaptor = ArgumentCaptor.forClass(Integer.class);
+ doNothing().when(mInjected).reportMetric(metricsSuccessCaptor.capture(),
+ metricsErrorCodeCaptor.capture(), eq(2) /* Server based */,
+ eq(2) /* attempt count */, anyInt(), eq(0) /* vbmeta status */, anyInt());
+ when(mServiceConnection.unwrap(any(), anyLong())).thenThrow(IOException.class);
+
+ HandlerThread thread = new HandlerThread("RebootEscrowManagerTest");
+ thread.start();
+ mService.loadRebootEscrowDataIfAvailable(new Handler(thread.getLooper()));
+ // Sleep 5s for the retry to complete
+ Thread.sleep(5 * 1000);
+ assertFalse(metricsSuccessCaptor.getValue());
+ assertEquals(Integer.valueOf(RebootEscrowManager.ERROR_RETRY_COUNT_EXHAUSTED),
+ metricsErrorCodeCaptor.getValue());
+ }
+
+ @Test
public void loadRebootEscrowDataIfAvailable_ServerBased_RetrySuccess() throws Exception {
setServerBasedRebootEscrowProvider();
@@ -485,7 +604,8 @@
// pretend reboot happens here
when(mInjected.getBootCount()).thenReturn(1);
ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class);
- doNothing().when(mInjected).reportMetric(metricsSuccessCaptor.capture());
+ doNothing().when(mInjected).reportMetric(metricsSuccessCaptor.capture(),
+ anyInt(), anyInt(), eq(2) /* attempt count */, anyInt(), anyInt(), anyInt());
when(mServiceConnection.unwrap(any(), anyLong()))
.thenThrow(new IOException())
@@ -528,7 +648,8 @@
mService.loadRebootEscrowDataIfAvailable(null);
verify(mRebootEscrow).retrieveKey();
- verify(mInjected, never()).reportMetric(anyBoolean());
+ verify(mInjected, never()).reportMetric(anyBoolean(), anyInt(), anyInt(), anyInt(),
+ anyInt(), anyInt(), anyInt());
}
@Test
@@ -554,7 +675,8 @@
when(mRebootEscrow.retrieveKey()).thenReturn(new byte[32]);
mService.loadRebootEscrowDataIfAvailable(null);
- verify(mInjected, never()).reportMetric(anyBoolean());
+ verify(mInjected, never()).reportMetric(anyBoolean(), anyInt(), anyInt(), anyInt(),
+ anyInt(), anyInt(), anyInt());
}
@Test
@@ -587,8 +709,14 @@
when(mInjected.getBootCount()).thenReturn(10);
when(mRebootEscrow.retrieveKey()).thenAnswer(invocation -> keyByteCaptor.getValue());
+ // Trigger a vbmeta digest mismatch
+ mStorage.setString(RebootEscrowManager.REBOOT_ESCROW_KEY_VBMETA_DIGEST,
+ "non sense value", USER_SYSTEM);
mService.loadRebootEscrowDataIfAvailable(null);
- verify(mInjected).reportMetric(eq(true));
+ verify(mInjected).reportMetric(eq(true), eq(0) /* error code */, eq(1) /* HAL based */,
+ eq(1) /* attempt count */, anyInt(), eq(2) /* vbmeta status */, anyInt());
+ assertEquals(mStorage.getString(RebootEscrowManager.REBOOT_ESCROW_KEY_VBMETA_DIGEST,
+ "", USER_SYSTEM), "");
}
@Test
@@ -615,10 +743,17 @@
when(mInjected.getBootCount()).thenReturn(1);
ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class);
- doNothing().when(mInjected).reportMetric(metricsSuccessCaptor.capture());
- when(mRebootEscrow.retrieveKey()).thenAnswer(invocation -> new byte[32]);
+ ArgumentCaptor<Integer> metricsErrorCodeCaptor = ArgumentCaptor.forClass(Integer.class);
+ // Return a null escrow key
+ doNothing().when(mInjected).reportMetric(metricsSuccessCaptor.capture(),
+ metricsErrorCodeCaptor.capture(), eq(1) /* HAL based */,
+ eq(1) /* attempt count */, anyInt(), anyInt(), anyInt());
+
+ when(mRebootEscrow.retrieveKey()).thenAnswer(invocation -> null);
mService.loadRebootEscrowDataIfAvailable(null);
verify(mRebootEscrow).retrieveKey();
assertFalse(metricsSuccessCaptor.getValue());
+ assertEquals(Integer.valueOf(RebootEscrowManager.ERROR_LOAD_ESCROW_KEY),
+ metricsErrorCodeCaptor.getValue());
}
}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java
index a38745f..d9af51f 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java
@@ -42,7 +42,6 @@
import android.content.Context;
import android.os.FileUtils;
-import android.security.keystore.AndroidKeyStoreSecretKey;
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties;
import android.security.keystore.recovery.KeyChainSnapshot;
@@ -109,7 +108,7 @@
private RecoverySnapshotStorage mRecoverySnapshotStorage;
private RecoverableKeyStoreDb mRecoverableKeyStoreDb;
private File mDatabaseFile;
- private AndroidKeyStoreSecretKey mWrappingKey;
+ private SecretKey mWrappingKey;
private PlatformEncryptionKey mEncryptKey;
private KeySyncTask mKeySyncTask;
@@ -848,7 +847,7 @@
return keyGenerator.generateKey();
}
- private AndroidKeyStoreSecretKey generateAndroidKeyStoreKey() throws Exception {
+ private SecretKey generateAndroidKeyStoreKey() throws Exception {
KeyGenerator keyGenerator = KeyGenerator.getInstance(
KEY_ALGORITHM,
ANDROID_KEY_STORE_PROVIDER);
@@ -857,7 +856,7 @@
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.build());
- return (AndroidKeyStoreSecretKey) keyGenerator.generateKey();
+ return keyGenerator.generateKey();
}
private static byte[] utf8Bytes(String s) {
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java
index 670bd81..fd4fe56 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java
@@ -34,7 +34,6 @@
import android.content.Context;
import android.os.RemoteException;
import android.security.GateKeeper;
-import android.security.keystore.AndroidKeyStoreSecretKey;
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties;
import android.security.keystore.KeyProtection;
@@ -61,6 +60,7 @@
import java.util.List;
import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -586,7 +586,7 @@
return (KeyProtection) mProtectionParameterCaptor.getValue();
}
- private AndroidKeyStoreSecretKey generateAndroidKeyStoreKey() throws Exception {
+ private SecretKey generateAndroidKeyStoreKey() throws Exception {
KeyGenerator keyGenerator = KeyGenerator.getInstance(
KEY_ALGORITHM,
ANDROID_KEY_STORE_PROVIDER);
@@ -595,7 +595,7 @@
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.build());
- return (AndroidKeyStoreSecretKey) keyGenerator.generateKey();
+ return keyGenerator.generateKey();
}
class PlatformKeyManagerTestable extends PlatformKeyManager {
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyGeneratorTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyGeneratorTest.java
index c295177..6413026 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyGeneratorTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyGeneratorTest.java
@@ -23,7 +23,6 @@
import static org.junit.Assert.assertNull;
import android.content.Context;
-import android.security.keystore.AndroidKeyStoreSecretKey;
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties;
@@ -45,6 +44,7 @@
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
@SmallTest
@@ -77,7 +77,7 @@
mDatabaseFile = context.getDatabasePath(DATABASE_FILE_NAME);
mRecoverableKeyStoreDb = RecoverableKeyStoreDb.newInstance(context);
- AndroidKeyStoreSecretKey platformKey = generatePlatformKey();
+ SecretKey platformKey = generatePlatformKey();
mPlatformKey = new PlatformEncryptionKey(TEST_GENERATION_ID, platformKey);
mDecryptKey = new PlatformDecryptionKey(TEST_GENERATION_ID, platformKey);
mRecoverableKeyGenerator = RecoverableKeyGenerator.newInstance(mRecoverableKeyStoreDb);
@@ -168,7 +168,7 @@
assertArrayEquals(rawMaterial, unwrappedMaterial);
}
- private AndroidKeyStoreSecretKey generatePlatformKey() throws Exception {
+ private SecretKey generatePlatformKey() throws Exception {
KeyGenerator keyGenerator = KeyGenerator.getInstance(
KEY_ALGORITHM,
ANDROID_KEY_STORE_PROVIDER);
@@ -177,7 +177,7 @@
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.build());
- return (AndroidKeyStoreSecretKey) keyGenerator.generateKey();
+ return keyGenerator.generateKey();
}
private static byte[] randomBytes(int n) {
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
index ac74470..f4e74ba 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
@@ -45,7 +45,6 @@
import android.os.Binder;
import android.os.ServiceSpecificException;
import android.os.UserHandle;
-import android.security.keystore.AndroidKeyStoreSecretKey;
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties;
import android.security.keystore.recovery.KeyChainProtectionParams;
@@ -1311,7 +1310,7 @@
mRecoverableKeyStoreDb.setShouldCreateSnapshot(userId, uid, false);
}
- private AndroidKeyStoreSecretKey generateAndroidKeyStoreKey() throws Exception {
+ private SecretKey generateAndroidKeyStoreKey() throws Exception {
KeyGenerator keyGenerator = KeyGenerator.getInstance(
KEY_ALGORITHM,
ANDROID_KEY_STORE_PROVIDER);
@@ -1320,6 +1319,6 @@
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.build());
- return (AndroidKeyStoreSecretKey) keyGenerator.generateKey();
+ return keyGenerator.generateKey();
}
}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/WrappedKeyTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/WrappedKeyTest.java
index 9813ab7..60052f7 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/WrappedKeyTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/WrappedKeyTest.java
@@ -21,7 +21,6 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-import android.security.keystore.AndroidKeyStoreSecretKey;
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties;
import android.util.Pair;
@@ -117,7 +116,7 @@
@Test
public void decryptWrappedKeys_decryptsWrappedKeys_nullMetadata() throws Exception {
String alias = "karlin";
- AndroidKeyStoreSecretKey platformKey = generateAndroidKeyStoreKey();
+ SecretKey platformKey = generateAndroidKeyStoreKey();
SecretKey appKey = generateKey();
WrappedKey wrappedKey = WrappedKey.fromSecretKey(
new PlatformEncryptionKey(GENERATION_ID, platformKey), appKey, NULL_METADATA);
@@ -136,7 +135,7 @@
@Test
public void decryptWrappedKeys_decryptsWrappedKeys_nonNullMetadata() throws Exception {
String alias = "karlin";
- AndroidKeyStoreSecretKey platformKey = generateAndroidKeyStoreKey();
+ SecretKey platformKey = generateAndroidKeyStoreKey();
SecretKey appKey = generateKey();
WrappedKey wrappedKey = WrappedKey.fromSecretKey(
new PlatformEncryptionKey(GENERATION_ID, platformKey), appKey, NON_NULL_METADATA);
@@ -155,7 +154,7 @@
@Test
public void decryptWrappedKeys_doesNotDieIfSomeKeysAreUnwrappable() throws Exception {
String alias = "karlin";
- AndroidKeyStoreSecretKey platformKey = generateAndroidKeyStoreKey();
+ SecretKey platformKey = generateAndroidKeyStoreKey();
SecretKey appKey = generateKey();
WrappedKey wrappedKey = WrappedKey.fromSecretKey(
new PlatformEncryptionKey(GENERATION_ID, platformKey), appKey, NULL_METADATA);
@@ -171,7 +170,7 @@
@Test
public void decryptWrappedKeys_throwsIfPlatformKeyGenerationIdDoesNotMatch() throws Exception {
- AndroidKeyStoreSecretKey platformKey = generateAndroidKeyStoreKey();
+ SecretKey platformKey = generateAndroidKeyStoreKey();
WrappedKey wrappedKey = WrappedKey.fromSecretKey(
new PlatformEncryptionKey(GENERATION_ID, platformKey), generateKey(),
/*metadata=*/ null);
@@ -197,7 +196,7 @@
return keyGenerator.generateKey();
}
- private AndroidKeyStoreSecretKey generateAndroidKeyStoreKey() throws Exception {
+ private SecretKey generateAndroidKeyStoreKey() throws Exception {
KeyGenerator keyGenerator = KeyGenerator.getInstance(
KEY_ALGORITHM,
ANDROID_KEY_STORE_PROVIDER);
@@ -207,6 +206,6 @@
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.build());
- return (AndroidKeyStoreSecretKey) keyGenerator.generateKey();
+ return keyGenerator.generateKey();
}
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/ArtStatsLogUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/dex/ArtStatsLogUtilsTest.java
new file mode 100644
index 0000000..13d75a7
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/ArtStatsLogUtilsTest.java
@@ -0,0 +1,292 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm.dex;
+
+import static org.mockito.Mockito.inOrder;
+
+import com.android.internal.art.ArtStatsLog;
+import com.android.server.pm.dex.ArtStatsLogUtils.ArtStatsLogger;
+
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.Mock;
+import org.mockito.InOrder;
+import org.mockito.MockitoAnnotations;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+/**
+ * Unit tests for {@link com.android.server.pm.dex.ArtStatsLogUtils}.
+ *
+ * Run with "atest ArtStatsLogUtilsTest".
+ */
+@RunWith(JUnit4.class)
+public final class ArtStatsLogUtilsTest {
+ private static final String TAG = ArtStatsLogUtilsTest.class.getSimpleName();
+ private static final String COMPILER_FILTER = "space-profile";
+ private static final String PROFILE_DEX_METADATA = "primary.prof";
+ private static final String VDEX_DEX_METADATA = "primary.vdex";
+ private static final byte[] DEX_CONTENT = "dexData".getBytes();
+ private static final int COMPILATION_REASON = 1;
+ private static final int RESULT_CODE = 222;
+ private static final int UID = 111;
+ private static final long COMPILE_TIME = 333L;
+ private static final long SESSION_ID = 444L;
+
+ @Mock
+ ArtStatsLogger mockLogger;
+
+ private static Path TEST_DIR;
+ private static Path DEX;
+ private static Path NON_DEX;
+
+ @BeforeClass
+ public static void setUpAll() throws IOException {
+ TEST_DIR = Files.createTempDirectory(null);
+ DEX = Files.createFile(TEST_DIR.resolve("classes.dex"));
+ NON_DEX = Files.createFile(TEST_DIR.resolve("test.dex"));
+ Files.write(DEX, DEX_CONTENT);
+ Files.write(NON_DEX, "empty".getBytes());
+ }
+
+ @AfterClass
+ public static void tearnDownAll() {
+ deleteSliently(DEX);
+ deleteSliently(NON_DEX);
+ deleteSliently(TEST_DIR);
+ }
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ @Test
+ public void testProfileAndVdexDexMetadata() throws IOException {
+ // Setup
+ Path dexMetadataPath = null;
+ Path apk = null;
+ try {
+ dexMetadataPath = createDexMetadata(PROFILE_DEX_METADATA, VDEX_DEX_METADATA);
+ apk = zipFiles(".apk", DEX, NON_DEX, dexMetadataPath);
+
+ // Act
+ ArtStatsLogUtils.writeStatsLog(
+ mockLogger,
+ SESSION_ID,
+ apk.toString(),
+ COMPILER_FILTER,
+ UID,
+ COMPILE_TIME,
+ dexMetadataPath.toString(),
+ COMPILATION_REASON,
+ RESULT_CODE);
+
+ // Assert
+ verifyWrites(ArtStatsLog.
+ ART_DATUM_REPORTED__DEX_METADATA_TYPE__ART_DEX_METADATA_TYPE_PROFILE_AND_VDEX);
+ } finally {
+ deleteSliently(dexMetadataPath);
+ deleteSliently(apk);
+ }
+ }
+
+ @Test
+ public void testProfileOnlyDexMetadata() throws IOException {
+ // Setup
+ Path dexMetadataPath = null;
+ Path apk = null;
+ try {
+ dexMetadataPath = createDexMetadata(PROFILE_DEX_METADATA);
+ apk = zipFiles(".apk", DEX, NON_DEX, dexMetadataPath);
+
+ // Act
+ ArtStatsLogUtils.writeStatsLog(
+ mockLogger,
+ SESSION_ID,
+ apk.toString(),
+ COMPILER_FILTER,
+ UID,
+ COMPILE_TIME,
+ dexMetadataPath.toString(),
+ COMPILATION_REASON,
+ RESULT_CODE);
+
+ // Assert
+ verifyWrites(ArtStatsLog.
+ ART_DATUM_REPORTED__DEX_METADATA_TYPE__ART_DEX_METADATA_TYPE_PROFILE);
+ } finally {
+ deleteSliently(dexMetadataPath);
+ deleteSliently(apk);
+ }
+ }
+
+ @Test
+ public void testVdexOnlyDexMetadata() throws IOException {
+ // Setup
+ Path dexMetadataPath = null;
+ Path apk = null;
+ try {
+ dexMetadataPath = createDexMetadata(VDEX_DEX_METADATA);
+ apk = zipFiles(".apk", DEX, NON_DEX, dexMetadataPath);
+
+ // Act
+ ArtStatsLogUtils.writeStatsLog(
+ mockLogger,
+ SESSION_ID,
+ apk.toString(),
+ COMPILER_FILTER,
+ UID,
+ COMPILE_TIME,
+ dexMetadataPath.toString(),
+ COMPILATION_REASON,
+ RESULT_CODE);
+
+ // Assert
+ verifyWrites(ArtStatsLog.
+ ART_DATUM_REPORTED__DEX_METADATA_TYPE__ART_DEX_METADATA_TYPE_VDEX);
+ } finally {
+ deleteSliently(dexMetadataPath);
+ deleteSliently(apk);
+ }
+ }
+
+ @Test
+ public void testNoneDexMetadata() throws IOException {
+ // Setup
+ Path apk = null;
+ try {
+ apk = zipFiles(".apk", DEX, NON_DEX);
+
+ // Act
+ ArtStatsLogUtils.writeStatsLog(
+ mockLogger,
+ SESSION_ID,
+ apk.toString(),
+ COMPILER_FILTER,
+ UID,
+ COMPILE_TIME,
+ /*dexMetadataPath=*/ null,
+ COMPILATION_REASON,
+ RESULT_CODE);
+
+ // Assert
+ verifyWrites(ArtStatsLog.
+ ART_DATUM_REPORTED__DEX_METADATA_TYPE__ART_DEX_METADATA_TYPE_NONE);
+ } finally {
+ deleteSliently(apk);
+ }
+ }
+
+ @Test
+ public void testUnKnownDexMetadata() throws IOException {
+ // Setup
+ Path dexMetadataPath = null;
+ Path apk = null;
+ try {
+ dexMetadataPath = createDexMetadata("unknown");
+ apk = zipFiles(".apk", DEX, NON_DEX, dexMetadataPath);
+
+ // Act
+ ArtStatsLogUtils.writeStatsLog(
+ mockLogger,
+ SESSION_ID,
+ apk.toString(),
+ COMPILER_FILTER,
+ UID,
+ COMPILE_TIME,
+ dexMetadataPath.toString(),
+ COMPILATION_REASON,
+ RESULT_CODE);
+
+ // Assert
+ verifyWrites(ArtStatsLog.
+ ART_DATUM_REPORTED__DEX_METADATA_TYPE__ART_DEX_METADATA_TYPE_UNKNOWN);
+ } finally {
+ deleteSliently(dexMetadataPath);
+ deleteSliently(apk);
+ }
+ }
+
+ private void verifyWrites(int dexMetadataType) {
+ InOrder inorder = inOrder(mockLogger);
+ inorder.verify(mockLogger).write(
+ SESSION_ID, UID,
+ COMPILATION_REASON,
+ COMPILER_FILTER,
+ ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_RESULT_CODE,
+ RESULT_CODE,
+ dexMetadataType);
+ inorder.verify(mockLogger).write(
+ SESSION_ID,
+ UID,
+ COMPILATION_REASON,
+ COMPILER_FILTER,
+ ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_TOTAL_TIME,
+ COMPILE_TIME,
+ dexMetadataType);
+ }
+
+ private Path zipFiles(String suffix, Path... files) throws IOException {
+ Path zipFile = Files.createTempFile(null, suffix);
+ try (final OutputStream os = Files.newOutputStream(zipFile)) {
+ try (final ZipOutputStream zos = new ZipOutputStream(os)) {
+ for (Path file : files) {
+ ZipEntry zipEntry = new ZipEntry(file.getFileName().toString());
+ zos.putNextEntry(zipEntry);
+ zos.write(Files.readAllBytes(file));
+ zos.closeEntry();
+ }
+ }
+ }
+ return zipFile;
+ }
+
+ private Path createDexMetadata(String... entryNames) throws IOException {
+ Path zipFile = Files.createTempFile(null, ".dm");
+ try (final OutputStream os = Files.newOutputStream(zipFile)) {
+ try (final ZipOutputStream zos = new ZipOutputStream(os)) {
+ for (String entryName : entryNames) {
+ ZipEntry zipEntry = new ZipEntry(entryName);
+ zos.putNextEntry(zipEntry);
+ zos.write(entryName.getBytes());
+ zos.closeEntry();
+ }
+ }
+ }
+ return zipFile;
+ }
+
+ private static void deleteSliently(Path file) {
+ if (file != null) {
+ try {
+ Files.deleteIfExists(file);
+ } catch (IOException e) {
+ // ignore
+ }
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java b/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java
index 9b8a2a8..7903a90 100644
--- a/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java
@@ -18,9 +18,11 @@
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
+import static org.mockito.AdditionalMatchers.not;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doNothing;
@@ -70,6 +72,8 @@
private FileWriter mUncryptUpdateFileWriter;
private LockSettingsInternal mLockSettingsInternal;
private IBootControl mIBootControl;
+ private RecoverySystemServiceTestable.IMetricsReporter mMetricsReporter;
+ private RecoverySystemService.PreferencesManager mSharedPreferences;
private static final String FAKE_OTA_PACKAGE_NAME = "fake.ota.package";
private static final String FAKE_OTHER_PACKAGE_NAME = "fake.other.package";
@@ -94,9 +98,12 @@
when(mIBootControl.getCurrentSlot()).thenReturn(0);
when(mIBootControl.getActiveBootSlot()).thenReturn(1);
+ mMetricsReporter = mock(RecoverySystemServiceTestable.IMetricsReporter.class);
+ mSharedPreferences = mock(RecoverySystemService.PreferencesManager.class);
+
mRecoverySystemService = new RecoverySystemServiceTestable(mContext, mSystemProperties,
powerManager, mUncryptUpdateFileWriter, mUncryptSocket, mLockSettingsInternal,
- mIBootControl);
+ mIBootControl, mMetricsReporter, mSharedPreferences);
}
@Test
@@ -227,12 +234,35 @@
}
@Test
+ public void requestLskf_reportMetrics() throws Exception {
+ IntentSender intentSender = mock(IntentSender.class);
+ assertThat(mRecoverySystemService.requestLskf(FAKE_OTA_PACKAGE_NAME, intentSender),
+ is(true));
+ verify(mMetricsReporter).reportRebootEscrowPreparationMetrics(
+ eq(1000), eq(0) /* need preparation */, eq(1) /* client count */);
+ verify(mSharedPreferences).putLong(eq(FAKE_OTA_PACKAGE_NAME
+ + RecoverySystemService.REQUEST_LSKF_TIMESTAMP_PREF_SUFFIX), eq(100_000L));
+ }
+
+
+ @Test
public void requestLskf_success() throws Exception {
IntentSender intentSender = mock(IntentSender.class);
assertThat(mRecoverySystemService.requestLskf(FAKE_OTA_PACKAGE_NAME, intentSender),
is(true));
+
+ when(mSharedPreferences.getLong(eq(FAKE_OTA_PACKAGE_NAME
+ + RecoverySystemService.REQUEST_LSKF_TIMESTAMP_PREF_SUFFIX), anyLong()))
+ .thenReturn(200_000L).thenReturn(5000L);
+ mRecoverySystemService.onPreparedForReboot(true);
+ verify(mMetricsReporter).reportRebootEscrowLskfCapturedMetrics(
+ eq(1000), eq(1) /* client count */,
+ eq(-1) /* invalid duration */);
+
mRecoverySystemService.onPreparedForReboot(true);
verify(intentSender).sendIntent(any(), anyInt(), any(), any(), any());
+ verify(mMetricsReporter).reportRebootEscrowLskfCapturedMetrics(
+ eq(1000), eq(1) /* client count */, eq(95) /* duration */);
}
@Test
@@ -255,6 +285,8 @@
assertThat(mRecoverySystemService.requestLskf(FAKE_OTA_PACKAGE_NAME, intentSender),
is(true));
verify(intentSender, never()).sendIntent(any(), anyInt(), any(), any(), any());
+ verify(mMetricsReporter, never()).reportRebootEscrowLskfCapturedMetrics(
+ anyInt(), anyInt(), anyInt());
}
@Test
@@ -334,9 +366,19 @@
public void rebootWithLskf_Success() throws Exception {
assertThat(mRecoverySystemService.requestLskf(FAKE_OTA_PACKAGE_NAME, null), is(true));
mRecoverySystemService.onPreparedForReboot(true);
+
+ when(mSharedPreferences.getInt(eq(FAKE_OTA_PACKAGE_NAME
+ + RecoverySystemService.REQUEST_LSKF_COUNT_PREF_SUFFIX), anyInt())).thenReturn(2);
+ when(mSharedPreferences.getInt(eq(RecoverySystemService.LSKF_CAPTURED_COUNT_PREF),
+ anyInt())).thenReturn(3);
+ when(mSharedPreferences.getLong(eq(RecoverySystemService.LSKF_CAPTURED_TIMESTAMP_PREF),
+ anyLong())).thenReturn(40_000L);
assertThat(mRecoverySystemService.rebootWithLskf(FAKE_OTA_PACKAGE_NAME, "ab-update", true),
is(true));
verify(mIPowerManager).reboot(anyBoolean(), eq("ab-update"), anyBoolean());
+ verify(mMetricsReporter).reportRebootEscrowRebootMetrics(eq(0), eq(1000),
+ eq(1) /* client count */, eq(2) /* request count */, eq(true) /* slot switch */,
+ anyBoolean(), eq(60) /* duration */, eq(3) /* lskf capture count */);
}
@@ -373,6 +415,26 @@
verify(mIPowerManager).reboot(anyBoolean(), eq("ab-update"), anyBoolean());
}
+ @Test
+ public void rebootWithLskf_multiClient_success_reportMetrics() throws Exception {
+ assertThat(mRecoverySystemService.requestLskf(FAKE_OTA_PACKAGE_NAME, null), is(true));
+ assertThat(mRecoverySystemService.requestLskf(FAKE_OTHER_PACKAGE_NAME, null), is(true));
+ mRecoverySystemService.onPreparedForReboot(true);
+
+ when(mSharedPreferences.getInt(eq(FAKE_OTA_PACKAGE_NAME
+ + RecoverySystemService.REQUEST_LSKF_COUNT_PREF_SUFFIX), anyInt())).thenReturn(2);
+ when(mSharedPreferences.getInt(eq(RecoverySystemService.LSKF_CAPTURED_COUNT_PREF),
+ anyInt())).thenReturn(1);
+ when(mSharedPreferences.getLong(eq(RecoverySystemService.LSKF_CAPTURED_TIMESTAMP_PREF),
+ anyLong())).thenReturn(60_000L);
+
+ assertThat(mRecoverySystemService.rebootWithLskf(FAKE_OTA_PACKAGE_NAME, "ab-update", true),
+ is(true));
+ verify(mIPowerManager).reboot(anyBoolean(), eq("ab-update"), anyBoolean());
+ verify(mMetricsReporter).reportRebootEscrowRebootMetrics(eq(0), eq(1000),
+ eq(2) /* client count */, eq(2) /* request count */, eq(true) /* slot switch */,
+ anyBoolean(), eq(40), eq(1) /* lskf capture count */);
+ }
@Test
public void rebootWithLskf_multiClient_ClientBSuccess() throws Exception {
@@ -380,16 +442,30 @@
mRecoverySystemService.onPreparedForReboot(true);
assertThat(mRecoverySystemService.requestLskf(FAKE_OTHER_PACKAGE_NAME, null), is(true));
+ when(mSharedPreferences.getInt(eq(FAKE_OTHER_PACKAGE_NAME
+ + RecoverySystemService.REQUEST_LSKF_COUNT_PREF_SUFFIX), anyInt())).thenReturn(2);
+ when(mSharedPreferences.getInt(eq(RecoverySystemService.LSKF_CAPTURED_COUNT_PREF),
+ anyInt())).thenReturn(1);
+ when(mSharedPreferences.getLong(eq(RecoverySystemService.LSKF_CAPTURED_TIMESTAMP_PREF),
+ anyLong())).thenReturn(60_000L);
+
assertThat(mRecoverySystemService.clearLskf(FAKE_OTA_PACKAGE_NAME), is(true));
assertThat(mRecoverySystemService.rebootWithLskf(FAKE_OTA_PACKAGE_NAME, null, true),
is(false));
verifyNoMoreInteractions(mIPowerManager);
+ verify(mMetricsReporter).reportRebootEscrowRebootMetrics(not(eq(0)), eq(1000),
+ eq(1) /* client count */, anyInt() /* request count */, eq(true) /* slot switch */,
+ anyBoolean(), eq(40), eq(1)/* lskf capture count */);
assertThat(mRecoverySystemService.requestLskf(FAKE_OTHER_PACKAGE_NAME, null), is(true));
assertThat(
mRecoverySystemService.rebootWithLskf(FAKE_OTHER_PACKAGE_NAME, "ab-update", true),
is(true));
verify(mIPowerManager).reboot(anyBoolean(), eq("ab-update"), anyBoolean());
+
+ verify(mMetricsReporter).reportRebootEscrowRebootMetrics((eq(0)), eq(2000),
+ eq(1) /* client count */, eq(2) /* request count */, eq(true) /* slot switch */,
+ anyBoolean(), eq(40), eq(1) /* lskf capture count */);
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTestable.java b/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTestable.java
index 0727e5a..27e953f 100644
--- a/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTestable.java
@@ -32,11 +32,14 @@
private final UncryptSocket mUncryptSocket;
private final LockSettingsInternal mLockSettingsInternal;
private final IBootControl mIBootControl;
+ private final IMetricsReporter mIMetricsReporter;
+ private final RecoverySystemService.PreferencesManager mSharedPreferences;
MockInjector(Context context, FakeSystemProperties systemProperties,
PowerManager powerManager, FileWriter uncryptPackageFileWriter,
UncryptSocket uncryptSocket, LockSettingsInternal lockSettingsInternal,
- IBootControl bootControl) {
+ IBootControl bootControl, IMetricsReporter metricsReporter,
+ RecoverySystemService.PreferencesManager preferences) {
super(context);
mSystemProperties = systemProperties;
mPowerManager = powerManager;
@@ -44,6 +47,8 @@
mUncryptSocket = uncryptSocket;
mLockSettingsInternal = lockSettingsInternal;
mIBootControl = bootControl;
+ mIMetricsReporter = metricsReporter;
+ mSharedPreferences = preferences;
}
@Override
@@ -94,14 +99,58 @@
public IBootControl getBootControl() {
return mIBootControl;
}
+ @Override
+ public int getUidFromPackageName(String packageName) {
+ if ("fake.ota.package".equals(packageName)) {
+ return 1000;
+ }
+ if ("fake.other.package".equals(packageName)) {
+ return 2000;
+ }
+ return 3000;
+ }
+
+ @Override
+ public void reportRebootEscrowPreparationMetrics(int uid, int requestResult,
+ int requestedClientCount) {
+ mIMetricsReporter.reportRebootEscrowPreparationMetrics(uid, requestResult,
+ requestedClientCount);
+ }
+
+ @Override
+ public void reportRebootEscrowLskfCapturedMetrics(int uid, int requestedClientCount,
+ int requestedToLskfCapturedDurationInSeconds) {
+ mIMetricsReporter.reportRebootEscrowLskfCapturedMetrics(uid, requestedClientCount,
+ requestedToLskfCapturedDurationInSeconds);
+ }
+
+ @Override
+ public void reportRebootEscrowRebootMetrics(int errorCode, int uid, int preparedClientCount,
+ int requestCount, boolean slotSwitch, boolean serverBased,
+ int lskfCapturedToRebootDurationInSeconds, int lskfCapturedCounts) {
+ mIMetricsReporter.reportRebootEscrowRebootMetrics(errorCode, uid, preparedClientCount,
+ requestCount, slotSwitch, serverBased, lskfCapturedToRebootDurationInSeconds,
+ lskfCapturedCounts);
+ }
+
+ @Override
+ public long getCurrentTimeMillis() {
+ return 100_000;
+ }
+
+ @Override
+ public RecoverySystemService.PreferencesManager getMetricsPrefs() {
+ return mSharedPreferences;
+ }
}
RecoverySystemServiceTestable(Context context, FakeSystemProperties systemProperties,
PowerManager powerManager, FileWriter uncryptPackageFileWriter,
UncryptSocket uncryptSocket, LockSettingsInternal lockSettingsInternal,
- IBootControl bootControl) {
+ IBootControl bootControl, IMetricsReporter metricsReporter,
+ RecoverySystemService.PreferencesManager preferences) {
super(new MockInjector(context, systemProperties, powerManager, uncryptPackageFileWriter,
- uncryptSocket, lockSettingsInternal, bootControl));
+ uncryptSocket, lockSettingsInternal, bootControl, metricsReporter, preferences));
}
public static class FakeSystemProperties {
@@ -131,4 +180,16 @@
return mCtlStart;
}
}
+
+ public interface IMetricsReporter {
+ void reportRebootEscrowPreparationMetrics(int uid, int requestResult,
+ int requestedClientCount);
+
+ void reportRebootEscrowLskfCapturedMetrics(int uid, int requestedClientCount,
+ int requestedToLskfCapturedDurationInSeconds);
+
+ void reportRebootEscrowRebootMetrics(int errorCode, int uid, int preparedClientCount,
+ int requestCount, boolean slotSwitch, boolean serverBased,
+ int lskfCapturedToRebootDurationInSeconds, int lskfCapturedCounts);
+ }
}
diff --git a/services/tests/servicestests/test-apps/SimpleServiceTestApp/OWNERS b/services/tests/servicestests/test-apps/SimpleServiceTestApp/OWNERS
new file mode 100644
index 0000000..72c0a9e
--- /dev/null
+++ b/services/tests/servicestests/test-apps/SimpleServiceTestApp/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/am/OWNERS
diff --git a/services/tests/servicestests/utils-mockito/com/android/server/testutils/OWNERS b/services/tests/servicestests/utils-mockito/com/android/server/testutils/OWNERS
new file mode 100644
index 0000000..d825dfd
--- /dev/null
+++ b/services/tests/servicestests/utils-mockito/com/android/server/testutils/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/pm/OWNERS
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 4259831..ee89e1c 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -833,10 +833,10 @@
@Test
public void testDefaultAssistant_overrideDefault() {
- final int userId = 0;
+ final int userId = mContext.getUserId();
final String testComponent = "package/class";
final List<UserInfo> userInfos = new ArrayList<>();
- userInfos.add(new UserInfo(0, "", 0));
+ userInfos.add(new UserInfo(userId, "", 0));
final ArraySet<ComponentName> validAssistants = new ArraySet<>();
validAssistants.add(ComponentName.unflattenFromString(testComponent));
when(mActivityManager.isLowRamDevice()).thenReturn(false);
@@ -2393,7 +2393,7 @@
.thenReturn(mTestNotificationChannel);
reset(mListeners);
- mBinderService.updateNotificationChannelForPackage(PKG, 0, mTestNotificationChannel);
+ mBinderService.updateNotificationChannelForPackage(PKG, mUid, mTestNotificationChannel);
verify(mListeners, times(1)).notifyNotificationChannelChanged(eq(PKG),
eq(Process.myUserHandle()), eq(mTestNotificationChannel),
eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED));
@@ -2929,7 +2929,7 @@
@Test
public void testSetListenerAccessForUser() throws Exception {
- UserHandle user = UserHandle.of(10);
+ UserHandle user = UserHandle.of(mContext.getUserId() + 10);
ComponentName c = ComponentName.unflattenFromString("package/Component");
mBinderService.setNotificationListenerAccessGrantedForUser(c, user.getIdentifier(), true);
@@ -2945,20 +2945,20 @@
@Test
public void testSetAssistantAccessForUser() throws Exception {
- UserHandle user = UserHandle.of(10);
- List<UserInfo> uis = new ArrayList<>();
UserInfo ui = new UserInfo();
- ui.id = 10;
+ ui.id = mContext.getUserId() + 10;
+ UserHandle user = UserHandle.of(ui.id);
+ List<UserInfo> uis = new ArrayList<>();
uis.add(ui);
ComponentName c = ComponentName.unflattenFromString("package/Component");
- when(mUm.getEnabledProfiles(10)).thenReturn(uis);
+ when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis);
mBinderService.setNotificationAssistantAccessGrantedForUser(c, user.getIdentifier(), true);
verify(mContext, times(1)).sendBroadcastAsUser(any(), eq(user), any());
verify(mAssistants, times(1)).setPackageOrComponentEnabled(
c.flattenToString(), user.getIdentifier(), true, true);
- verify(mAssistants).setUserSet(10, true);
+ verify(mAssistants).setUserSet(ui.id, true);
verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
c.flattenToString(), user.getIdentifier(), false, true);
verify(mListeners, never()).setPackageOrComponentEnabled(
@@ -2967,7 +2967,7 @@
@Test
public void testGetAssistantAllowedForUser() throws Exception {
- UserHandle user = UserHandle.of(10);
+ UserHandle user = UserHandle.of(mContext.getUserId() + 10);
try {
mBinderService.getAllowedNotificationAssistantForUser(user.getIdentifier());
} catch (IllegalStateException e) {
@@ -2987,12 +2987,12 @@
throw e;
}
}
- verify(mAssistants, times(1)).getAllowedComponents(0);
+ verify(mAssistants, times(1)).getAllowedComponents(mContext.getUserId());
}
@Test
public void testSetDndAccessForUser() throws Exception {
- UserHandle user = UserHandle.of(10);
+ UserHandle user = UserHandle.of(mContext.getUserId() + 10);
ComponentName c = ComponentName.unflattenFromString("package/Component");
mBinderService.setNotificationPolicyAccessGrantedForUser(
c.getPackageName(), user.getIdentifier(), true);
@@ -3012,9 +3012,9 @@
mBinderService.setNotificationListenerAccessGranted(c, true);
verify(mListeners, times(1)).setPackageOrComponentEnabled(
- c.flattenToString(), 0, true, true);
+ c.flattenToString(), mContext.getUserId(), true, true);
verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
- c.flattenToString(), 0, false, true);
+ c.flattenToString(), mContext.getUserId(), false, true);
verify(mAssistants, never()).setPackageOrComponentEnabled(
any(), anyInt(), anyBoolean(), anyBoolean());
}
@@ -3023,7 +3023,7 @@
public void testSetAssistantAccess() throws Exception {
List<UserInfo> uis = new ArrayList<>();
UserInfo ui = new UserInfo();
- ui.id = 0;
+ ui.id = mContext.getUserId();
uis.add(ui);
when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis);
ComponentName c = ComponentName.unflattenFromString("package/Component");
@@ -3031,9 +3031,9 @@
mBinderService.setNotificationAssistantAccessGranted(c, true);
verify(mAssistants, times(1)).setPackageOrComponentEnabled(
- c.flattenToString(), 0, true, true);
+ c.flattenToString(), ui.id, true, true);
verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
- c.flattenToString(), 0, false, true);
+ c.flattenToString(), ui.id, false, true);
verify(mListeners, never()).setPackageOrComponentEnabled(
any(), anyInt(), anyBoolean(), anyBoolean());
}
@@ -3042,10 +3042,10 @@
public void testSetAssistantAccess_multiProfile() throws Exception {
List<UserInfo> uis = new ArrayList<>();
UserInfo ui = new UserInfo();
- ui.id = 0;
+ ui.id = mContext.getUserId();
uis.add(ui);
UserInfo ui10 = new UserInfo();
- ui10.id = 10;
+ ui10.id = mContext.getUserId() + 10;
uis.add(ui10);
when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis);
ComponentName c = ComponentName.unflattenFromString("package/Component");
@@ -3053,13 +3053,13 @@
mBinderService.setNotificationAssistantAccessGranted(c, true);
verify(mAssistants, times(1)).setPackageOrComponentEnabled(
- c.flattenToString(), 0, true, true);
+ c.flattenToString(), ui.id, true, true);
verify(mAssistants, times(1)).setPackageOrComponentEnabled(
- c.flattenToString(), 10, true, true);
+ c.flattenToString(), ui10.id, true, true);
verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
- c.flattenToString(), 0, false, true);
+ c.flattenToString(), ui.id, false, true);
verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
- c.flattenToString(), 10, false, true);
+ c.flattenToString(), ui10.id, false, true);
verify(mListeners, never()).setPackageOrComponentEnabled(
any(), anyInt(), anyBoolean(), anyBoolean());
}
@@ -3072,16 +3072,16 @@
when(mAssistants.getAllowedComponents(anyInt())).thenReturn(componentList);
List<UserInfo> uis = new ArrayList<>();
UserInfo ui = new UserInfo();
- ui.id = 0;
+ ui.id = mContext.getUserId();
uis.add(ui);
when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis);
mBinderService.setNotificationAssistantAccessGranted(null, true);
verify(mAssistants, times(1)).setPackageOrComponentEnabled(
- c.flattenToString(), 0, true, false);
+ c.flattenToString(), ui.id, true, false);
verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
- c.flattenToString(), 0, false, false);
+ c.flattenToString(), ui.id, false, false);
verify(mListeners, never()).setPackageOrComponentEnabled(
any(), anyInt(), anyBoolean(), anyBoolean());
}
@@ -3090,21 +3090,21 @@
public void testSetAssistantAccessForUser_nullWithAllowedAssistant() throws Exception {
List<UserInfo> uis = new ArrayList<>();
UserInfo ui = new UserInfo();
- ui.id = 10;
+ ui.id = mContext.getUserId() + 10;
uis.add(ui);
UserHandle user = ui.getUserHandle();
ArrayList<ComponentName> componentList = new ArrayList<>();
ComponentName c = ComponentName.unflattenFromString("package/Component");
componentList.add(c);
when(mAssistants.getAllowedComponents(anyInt())).thenReturn(componentList);
- when(mUm.getEnabledProfiles(10)).thenReturn(uis);
+ when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis);
mBinderService.setNotificationAssistantAccessGrantedForUser(
null, user.getIdentifier(), true);
verify(mAssistants, times(1)).setPackageOrComponentEnabled(
c.flattenToString(), user.getIdentifier(), true, false);
- verify(mAssistants).setUserSet(10, true);
+ verify(mAssistants).setUserSet(ui.id, true);
verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
c.flattenToString(), user.getIdentifier(), false, false);
verify(mListeners, never()).setPackageOrComponentEnabled(
@@ -3116,10 +3116,10 @@
throws Exception {
List<UserInfo> uis = new ArrayList<>();
UserInfo ui = new UserInfo();
- ui.id = 0;
+ ui.id = mContext.getUserId();
uis.add(ui);
UserInfo ui10 = new UserInfo();
- ui10.id = 10;
+ ui10.id = mContext.getUserId() + 10;
uis.add(ui10);
UserHandle user = ui.getUserHandle();
ArrayList<ComponentName> componentList = new ArrayList<>();
@@ -3135,8 +3135,8 @@
c.flattenToString(), user.getIdentifier(), true, false);
verify(mAssistants, times(1)).setPackageOrComponentEnabled(
c.flattenToString(), ui10.id, true, false);
- verify(mAssistants).setUserSet(0, true);
- verify(mAssistants).setUserSet(10, true);
+ verify(mAssistants).setUserSet(ui.id, true);
+ verify(mAssistants).setUserSet(ui10.id, true);
verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
c.flattenToString(), user.getIdentifier(), false, false);
verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
@@ -3152,7 +3152,7 @@
mBinderService.setNotificationPolicyAccessGranted(c.getPackageName(), true);
verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
- c.getPackageName(), 0, true, true);
+ c.getPackageName(), mContext.getUserId(), true, true);
verify(mAssistants, never()).setPackageOrComponentEnabled(
any(), anyInt(), anyBoolean(), anyBoolean());
verify(mListeners, never()).setPackageOrComponentEnabled(
@@ -3179,7 +3179,7 @@
ComponentName c = ComponentName.unflattenFromString("package/Component");
List<UserInfo> uis = new ArrayList<>();
UserInfo ui = new UserInfo();
- ui.id = 0;
+ ui.id = mContext.getUserId();
uis.add(ui);
when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis);
@@ -3214,9 +3214,9 @@
mBinderService.setNotificationListenerAccessGranted(c, true);
verify(mListeners, times(1)).setPackageOrComponentEnabled(
- c.flattenToString(), 0, true, true);
+ c.flattenToString(), mContext.getUserId(), true, true);
verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
- c.flattenToString(), 0, false, true);
+ c.flattenToString(), mContext.getUserId(), false, true);
verify(mAssistants, never()).setPackageOrComponentEnabled(
any(), anyInt(), anyBoolean(), anyBoolean());
}
@@ -3228,7 +3228,7 @@
ComponentName c = ComponentName.unflattenFromString("package/Component");
List<UserInfo> uis = new ArrayList<>();
UserInfo ui = new UserInfo();
- ui.id = 0;
+ ui.id = mContext.getUserId();
uis.add(ui);
when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis);
@@ -3237,9 +3237,9 @@
verify(mListeners, never()).setPackageOrComponentEnabled(
anyString(), anyInt(), anyBoolean(), anyBoolean());
verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
- c.flattenToString(), 0, false, true);
+ c.flattenToString(), ui.id, false, true);
verify(mAssistants, times(1)).setPackageOrComponentEnabled(
- c.flattenToString(), 0, true, true);
+ c.flattenToString(), ui.id, true, true);
}
@Test
@@ -3253,7 +3253,7 @@
verify(mListeners, never()).setPackageOrComponentEnabled(
anyString(), anyInt(), anyBoolean(), anyBoolean());
verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
- c.getPackageName(), 0, true, true);
+ c.getPackageName(), mContext.getUserId(), true, true);
verify(mAssistants, never()).setPackageOrComponentEnabled(
any(), anyInt(), anyBoolean(), anyBoolean());
}
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 477592b..26cea2c 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -837,20 +837,31 @@
boolean prevHostConnected = mHostConnected;
UsbPort port = (UsbPort) args.arg1;
UsbPortStatus status = (UsbPortStatus) args.arg2;
- mHostConnected = status.getCurrentDataRole() == DATA_ROLE_HOST;
- mSourcePower = status.getCurrentPowerRole() == POWER_ROLE_SOURCE;
- mSinkPower = status.getCurrentPowerRole() == POWER_ROLE_SINK;
- mAudioAccessoryConnected = (status.getCurrentMode() == MODE_AUDIO_ACCESSORY);
+
+ if (status != null) {
+ mHostConnected = status.getCurrentDataRole() == DATA_ROLE_HOST;
+ mSourcePower = status.getCurrentPowerRole() == POWER_ROLE_SOURCE;
+ mSinkPower = status.getCurrentPowerRole() == POWER_ROLE_SINK;
+ mAudioAccessoryConnected = (status.getCurrentMode() == MODE_AUDIO_ACCESSORY);
+
+ // Ideally we want to see if PR_SWAP and DR_SWAP is supported.
+ // But, this should be suffice, since, all four combinations are only supported
+ // when PR_SWAP and DR_SWAP are supported.
+ mSupportsAllCombinations = status.isRoleCombinationSupported(
+ POWER_ROLE_SOURCE, DATA_ROLE_HOST)
+ && status.isRoleCombinationSupported(POWER_ROLE_SINK, DATA_ROLE_HOST)
+ && status.isRoleCombinationSupported(POWER_ROLE_SOURCE,
+ DATA_ROLE_DEVICE)
+ && status.isRoleCombinationSupported(POWER_ROLE_SINK, DATA_ROLE_DEVICE);
+ } else {
+ mHostConnected = false;
+ mSourcePower = false;
+ mSinkPower = false;
+ mAudioAccessoryConnected = false;
+ mSupportsAllCombinations = false;
+ }
+
mAudioAccessorySupported = port.isModeSupported(MODE_AUDIO_ACCESSORY);
- // Ideally we want to see if PR_SWAP and DR_SWAP is supported.
- // But, this should be suffice, since, all four combinations are only supported
- // when PR_SWAP and DR_SWAP are supported.
- mSupportsAllCombinations = status.isRoleCombinationSupported(
- POWER_ROLE_SOURCE, DATA_ROLE_HOST)
- && status.isRoleCombinationSupported(POWER_ROLE_SINK, DATA_ROLE_HOST)
- && status.isRoleCombinationSupported(POWER_ROLE_SOURCE,
- DATA_ROLE_DEVICE)
- && status.isRoleCombinationSupported(POWER_ROLE_SINK, DATA_ROLE_DEVICE);
args.recycle();
updateUsbNotification(false);
diff --git a/services/usb/java/com/android/server/usb/UsbPortManager.java b/services/usb/java/com/android/server/usb/UsbPortManager.java
index ec7d4bd..647a2a2 100644
--- a/services/usb/java/com/android/server/usb/UsbPortManager.java
+++ b/services/usb/java/com/android/server/usb/UsbPortManager.java
@@ -60,9 +60,9 @@
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
+import android.service.ServiceProtoEnums;
import android.service.usb.UsbPortInfoProto;
import android.service.usb.UsbPortManagerProto;
-import android.service.usb.UsbServiceProto;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Slog;
@@ -992,15 +992,15 @@
private static int convertContaminantDetectionStatusToProto(int contaminantDetectionStatus) {
switch (contaminantDetectionStatus) {
case UsbPortStatus.CONTAMINANT_DETECTION_NOT_SUPPORTED:
- return UsbServiceProto.CONTAMINANT_STATUS_NOT_SUPPORTED;
+ return ServiceProtoEnums.CONTAMINANT_STATUS_NOT_SUPPORTED;
case UsbPortStatus.CONTAMINANT_DETECTION_DISABLED:
- return UsbServiceProto.CONTAMINANT_STATUS_DISABLED;
+ return ServiceProtoEnums.CONTAMINANT_STATUS_DISABLED;
case UsbPortStatus.CONTAMINANT_DETECTION_NOT_DETECTED:
- return UsbServiceProto.CONTAMINANT_STATUS_NOT_DETECTED;
+ return ServiceProtoEnums.CONTAMINANT_STATUS_NOT_DETECTED;
case UsbPortStatus.CONTAMINANT_DETECTION_DETECTED:
- return UsbServiceProto.CONTAMINANT_STATUS_DETECTED;
+ return ServiceProtoEnums.CONTAMINANT_STATUS_DETECTED;
default:
- return UsbServiceProto.CONTAMINANT_STATUS_UNKNOWN;
+ return ServiceProtoEnums.CONTAMINANT_STATUS_UNKNOWN;
}
}
diff --git a/telecomm/java/android/telecom/Conference.java b/telecomm/java/android/telecom/Conference.java
index dc2fb94..f84dd7b 100644
--- a/telecomm/java/android/telecom/Conference.java
+++ b/telecomm/java/android/telecom/Conference.java
@@ -338,7 +338,7 @@
*
* @param videoState The video state in which to answer the connection.
*/
- public void onAnswer(int videoState) {}
+ public void onAnswer(@VideoProfile.VideoState int videoState) {}
/**
* Notifies this Conference, which is in {@code STATE_RINGING}, of
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index 580513c..d82205e 100755
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -20,6 +20,7 @@
import android.annotation.Nullable;
import android.annotation.SdkConstant;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.app.Service;
import android.content.ComponentName;
import android.content.Intent;
@@ -1887,6 +1888,7 @@
/** {@inheritDoc} */
@Override
public final IBinder onBind(Intent intent) {
+ onBindClient(intent);
return mBinder;
}
@@ -1897,6 +1899,13 @@
return super.onUnbind(intent);
}
+ /**
+ * Used for testing to let the test suite know when the connection service has been bound.
+ * @hide
+ */
+ @TestApi
+ public void onBindClient(@Nullable Intent intent) {
+ }
/**
* This can be used by telecom to either create a new outgoing conference call or attach
@@ -2544,9 +2553,9 @@
* @return The {@code Connection} object to satisfy this call, or {@code null} to
* not handle the call.
*/
- public final RemoteConnection createRemoteIncomingConnection(
- PhoneAccountHandle connectionManagerPhoneAccount,
- ConnectionRequest request) {
+ public final @Nullable RemoteConnection createRemoteIncomingConnection(
+ @NonNull PhoneAccountHandle connectionManagerPhoneAccount,
+ @NonNull ConnectionRequest request) {
return mRemoteConnectionManager.createRemoteConnection(
connectionManagerPhoneAccount, request, true);
}
@@ -2563,9 +2572,9 @@
* @return The {@code Connection} object to satisfy this call, or {@code null} to
* not handle the call.
*/
- public final RemoteConnection createRemoteOutgoingConnection(
- PhoneAccountHandle connectionManagerPhoneAccount,
- ConnectionRequest request) {
+ public final @Nullable RemoteConnection createRemoteOutgoingConnection(
+ @NonNull PhoneAccountHandle connectionManagerPhoneAccount,
+ @NonNull ConnectionRequest request) {
return mRemoteConnectionManager.createRemoteConnection(
connectionManagerPhoneAccount, request, false);
}
@@ -2805,12 +2814,14 @@
* @param connectionManagerPhoneAccount See description at
* {@link #onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}.
* @param request Details about the incoming conference call.
- * @return The {@code Conference} object to satisfy this call, or {@code null} to
- * not handle the call.
+ * @return The {@code Conference} object to satisfy this call. If the conference attempt is
+ * failed, the return value will be a result of an invocation of
+ * {@link Connection#createFailedConnection(DisconnectCause)}.
+ * Return {@code null} if the {@link ConnectionService} cannot handle the call.
*/
public @Nullable Conference onCreateIncomingConference(
- @Nullable PhoneAccountHandle connectionManagerPhoneAccount,
- @Nullable ConnectionRequest request) {
+ @NonNull PhoneAccountHandle connectionManagerPhoneAccount,
+ @NonNull ConnectionRequest request) {
return null;
}
@@ -2913,8 +2924,8 @@
* @param request The outgoing connection request.
*/
public void onCreateOutgoingConferenceFailed(
- @Nullable PhoneAccountHandle connectionManagerPhoneAccount,
- @Nullable ConnectionRequest request) {
+ @NonNull PhoneAccountHandle connectionManagerPhoneAccount,
+ @NonNull ConnectionRequest request) {
}
@@ -2978,12 +2989,14 @@
* a {@code PhoneAccount} registered by this {@code ConnectionService} to use for
* making the connection.
* @param request Details about the outgoing call.
- * @return The {@code Conference} object to satisfy this call, or the result of an invocation
- * of {@link Connection#createFailedConnection(DisconnectCause)} to not handle the call.
+ * @return The {@code Conference} object to satisfy this call. If the conference attempt is
+ * failed, the return value will be a result of an invocation of
+ * {@link Connection#createFailedConnection(DisconnectCause)}.
+ * Return {@code null} if the {@link ConnectionService} cannot handle the call.
*/
public @Nullable Conference onCreateOutgoingConference(
- @Nullable PhoneAccountHandle connectionManagerPhoneAccount,
- @Nullable ConnectionRequest request) {
+ @NonNull PhoneAccountHandle connectionManagerPhoneAccount,
+ @NonNull ConnectionRequest request) {
return null;
}
diff --git a/telephony/java/android/telephony/CarrierBandwidth.java b/telephony/java/android/telephony/CarrierBandwidth.java
index b153fef..9e1dee0 100644
--- a/telephony/java/android/telephony/CarrierBandwidth.java
+++ b/telephony/java/android/telephony/CarrierBandwidth.java
@@ -101,7 +101,7 @@
}
/**
- * Retrieves the upstream bandwidth for the primary network in Kbps. This always only refers to
+ * Retrieves the upstream bandwidth for the primary network in kbps. This always only refers to
* the estimated first hop transport bandwidth.
* This will be {@link #INVALID} if the network is not connected
*
@@ -112,7 +112,7 @@
}
/**
- * Retrieves the downstream bandwidth for the primary network in Kbps. This always only refers
+ * Retrieves the downstream bandwidth for the primary network in kbps. This always only refers
* to the estimated first hop transport bandwidth.
* This will be {@link #INVALID} if the network is not connected
*
@@ -123,7 +123,7 @@
}
/**
- * Retrieves the upstream bandwidth for the secondary network in Kbps. This always only refers
+ * Retrieves the upstream bandwidth for the secondary network in kbps. This always only refers
* to the estimated first hop transport bandwidth.
* <p/>
* This will be {@link #INVALID} if either are the case:
@@ -143,7 +143,7 @@
}
/**
- * Retrieves the downstream bandwidth for the secondary network in Kbps. This always only
+ * Retrieves the downstream bandwidth for the secondary network in kbps. This always only
* refers to the estimated first hop transport bandwidth.
* <p/>
* This will be {@link #INVALID} if either are the case:
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 9c9670c..0ba96a9 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -33,13 +33,15 @@
import android.service.carrier.CarrierService;
import android.telecom.TelecomManager;
import android.telephony.ims.ImsReasonInfo;
+import android.telephony.ims.ImsRegistrationAttributes;
import android.telephony.ims.ImsSsData;
+import android.telephony.ims.SipDelegateManager;
+import android.telephony.ims.feature.MmTelFeature;
+import android.telephony.ims.feature.RcsFeature;
import com.android.internal.telephony.ICarrierConfigLoader;
import com.android.telephony.Rlog;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
import java.util.concurrent.TimeUnit;
/**
@@ -106,31 +108,17 @@
*/
public static final int USSD_OVER_IMS_ONLY = 3;
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(prefix = { "CARRIER_NR_AVAILABILITY_" }, value = {
- CARRIER_NR_AVAILABILITY_NONE,
- CARRIER_NR_AVAILABILITY_NSA,
- CARRIER_NR_AVAILABILITY_SA,
- })
- public @interface DeviceNrCapability {}
-
- /**
- * Indicates CARRIER_NR_AVAILABILITY_NONE determine that the carrier does not enable 5G NR.
- */
- public static final int CARRIER_NR_AVAILABILITY_NONE = 0;
-
/**
* Indicates CARRIER_NR_AVAILABILITY_NSA determine that the carrier enable the non-standalone
* (NSA) mode of 5G NR.
*/
- public static final int CARRIER_NR_AVAILABILITY_NSA = 1 << 0;
+ public static final int CARRIER_NR_AVAILABILITY_NSA = 1;
/**
* Indicates CARRIER_NR_AVAILABILITY_SA determine that the carrier enable the standalone (SA)
* mode of 5G NR.
*/
- public static final int CARRIER_NR_AVAILABILITY_SA = 1 << 1;
+ public static final int CARRIER_NR_AVAILABILITY_SA = 2;
private final Context mContext;
@@ -1803,23 +1791,20 @@
"show_precise_failed_cause_bool";
/**
- * Bit-field integer to determine whether the carrier enable the non-standalone (NSA) mode of
- * 5G NR, standalone (SA) mode of 5G NR
+ * A list of carrier nr availability is used to determine whether the carrier enable the
+ * non-standalone (NSA) mode of 5G NR, standalone (SA) mode of 5G NR
*
- * <UL>
- * <LI>CARRIER_NR_AVAILABILITY_NONE: non-NR = 0 </LI>
- * <LI>CARRIER_NR_AVAILABILITY_NSA: NSA = 1 << 0</LI>
- * <LI>CARRIER_NR_AVAILABILITY_SA: SA = 1 << 1</LI>
- * </UL>
- * <p> The value of this key must be bitwise OR of
- * {@link #CARRIER_NR_AVAILABILITY_NONE}, {@link #CARRIER_NR_AVAILABILITY_NSA},
- * {@link #CARRIER_NR_AVAILABILITY_SA}.
+ * <p> The value of list is
+ * {@link #CARRIER_NR_AVAILABILITY_NSA}, or {@link #CARRIER_NR_AVAILABILITY_SA}.
*
- * <p> For example, if both NSA and SA are used, the value of key is 3 (1 << 0 | 1 << 1).
- * If the carrier doesn't support 5G NR, the value of key is 0 (non-NR).
- * If the key is invalid or not configured, a default value 3 (NSA|SA = 3) will apply.
+ * <p> For example, if both NSA and SA are used, the list value is {
+ * {@link #CARRIER_NR_AVAILABILITY_NSA},{@link #CARRIER_NR_AVAILABILITY_SA}}.
+ * If the carrier doesn't support 5G NR, the value is the empty array.
+ * If the key is invalid or not configured, the default value {
+ * {@link #CARRIER_NR_AVAILABILITY_NSA},{@link #CARRIER_NR_AVAILABILITY_SA}} will apply.
*/
- public static final String KEY_CARRIER_NR_AVAILABILITY_INT = "carrier_nr_availability_int";
+ public static final String KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY =
+ "carrier_nr_availabilities_int_array";
/**
* Boolean to decide whether LTE is enabled.
@@ -2894,6 +2879,18 @@
public static final String KEY_RTT_SUPPORTED_FOR_VT_BOOL = "rtt_supported_for_vt_bool";
/**
+ * Indicates if the carrier supports upgrading a call that was previously an RTT call to VT.
+ */
+ public static final String KEY_VT_UPGRADE_SUPPORTED_FOR_DOWNGRADED_RTT_CALL_BOOL =
+ "vt_upgrade_supported_for_downgraded_rtt_call";
+
+ /**
+ * Indicates if the carrier supports upgrading a call that was previously a VT call to RTT.
+ */
+ public static final String KEY_RTT_UPGRADE_SUPPORTED_FOR_DOWNGRADED_VT_CALL_BOOL =
+ "rtt_upgrade_supported_for_downgraded_vt_call";
+
+ /**
* Indicates if the carrier supports upgrading a voice call to an RTT call during the call.
*/
public static final String KEY_RTT_UPGRADE_SUPPORTED_BOOL = "rtt_upgrade_supported_bool";
@@ -3941,6 +3938,43 @@
KEY_PREFIX + "enable_presence_publish_bool";
/**
+ * Each string in this array contains a mapping between the service-id and version portion
+ * of the service-description element and the associated IMS feature tag(s) that are
+ * associated with each element (see RCC.07 Table 7).
+ * <p>
+ * Each string contains 3 parts, which define the mapping between service-description and
+ * feature tag(s) that must be present in the IMS REGISTER for the RCS service to be
+ * published as part of the RCS PUBLISH procedure:
+ * [service-id]|[version]|[desc]|[feature_tag];[feature_tag];...
+ * <ul>
+ * <li>[service-id]: the service-id element associated with the RCS capability.</li>
+ * <li>[version]: The version element associated with that service-id</li>
+ * <li>[desc]: The optional desecription element associated with that service-id</li>
+ * <li>[feature_tag];[feature_tag]: The list of all feature tags associated with this
+ * capability that MUST ALL be present in the IMS registration for this this
+ * capability to be published to the network.</li>
+ * </ul>
+ * <p>
+ * Features managed by the framework will be considered capable when the ImsService reports
+ * that those services are capable via the
+ * {@link MmTelFeature#notifyCapabilitiesStatusChanged(MmTelFeature.MmTelCapabilities)} or
+ * {@link RcsFeature#notifyCapabilitiesStatusChanged(RcsFeature.RcsImsCapabilities)} APIs.
+ * For RCS services not managed by the framework, the capability of these services are
+ * determined by looking at the feature tags associated with the IMS registration using the
+ * {@link ImsRegistrationAttributes} API and mapping them to the service-description map.
+ * <p>
+ * The framework contains a default value of this key, which is based off of RCC.07
+ * specification. Capabilities based of carrier extensions may be added to this list on a
+ * carrier-by-carrier basis as required in order to support additional services in the
+ * PUBLISH. If this list contains a service-id and version that overlaps with the default,
+ * it will override the framework default.
+ * @hide
+ */
+ @SystemApi
+ public static final String KEY_PUBLISH_SERVICE_DESC_FEATURE_TAG_MAP_OVERRIDE_STRING_ARRAY =
+ KEY_PREFIX + "publish_service_desc_feature_tag_map_override_string_array";
+
+ /**
* Flag indicating whether or not this carrier supports the exchange of phone numbers with
* the carrier's RCS presence server in order to retrieve the RCS capabilities of requested
* contacts used in the RCS User Capability Exchange (UCE) procedure. See RCC.71, section 3
@@ -3992,6 +4026,14 @@
public static final String KEY_NON_RCS_CAPABILITIES_CACHE_EXPIRATION_SEC_INT =
KEY_PREFIX + "non_rcs_capabilities_cache_expiration_sec_int";
+ /**
+ * Specifies the RCS feature tag allowed for the carrier.
+ *
+ * <p>The values refer to RCC.07 2.4.4.
+ */
+ public static final String KEY_RCS_FEATURE_TAG_ALLOWED_STRING_ARRAY =
+ KEY_PREFIX + "rcs_feature_tag_allowed_string_array";
+
private Ims() {}
private static PersistableBundle getDefaults() {
@@ -3999,10 +4041,33 @@
defaults.putInt(KEY_WIFI_OFF_DEFERRING_TIME_MILLIS_INT, 4000);
defaults.putBoolean(KEY_IMS_SINGLE_REGISTRATION_REQUIRED_BOOL, false);
defaults.putBoolean(KEY_ENABLE_PRESENCE_PUBLISH_BOOL, false);
+ defaults.putStringArray(KEY_PUBLISH_SERVICE_DESC_FEATURE_TAG_MAP_OVERRIDE_STRING_ARRAY,
+ new String[] {});
defaults.putBoolean(KEY_ENABLE_PRESENCE_CAPABILITY_EXCHANGE_BOOL, false);
defaults.putBoolean(KEY_RCS_BULK_CAPABILITY_EXCHANGE_BOOL, false);
defaults.putBoolean(KEY_ENABLE_PRESENCE_GROUP_SUBSCRIBE_BOOL, true);
defaults.putInt(KEY_NON_RCS_CAPABILITIES_CACHE_EXPIRATION_SEC_INT, 30 * 24 * 60 * 60);
+ defaults.putStringArray(KEY_RCS_FEATURE_TAG_ALLOWED_STRING_ARRAY, new String[]{
+ "+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gpp-service.ims.icsi.oma.cpm.msg\"",
+ "+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gpp-service.ims.icsi.oma.cpm.largemsg\"",
+ "+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gpp-service.ims.icsi.oma.cpm.deferred\"",
+ "+g.gsma.rcs.cpm.pager-large",
+ "+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gpp-service.ims.icsi.oma.cpm.session\"",
+ "+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gpp-service.ims.icsi.oma.cpm.session\"",
+ "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-application.ims.iari.rcs.fthttp\"",
+ "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-application.ims.iari.rcs.ftsms\"",
+ "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-service.ims.icsi.gsma.callcomposer\"",
+ "+g.gsma.callcomposer",
+ "+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gpp-service.ims.icsi.gsma.callunanswered\"",
+ "+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gpp-service.ims.icsi.gsma.sharedmap\"",
+ "+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gpp-service.ims.icsi.gsma.sharedsketch\"",
+ "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-application.ims.iari.rcs.geopush\"",
+ "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-application.ims.iari.rcs.geosms\"",
+ "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-application.ims.iari.rcs.chatbot\"",
+ "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-application.ims.iari.rcs.chatbot.sa\"",
+ "+g.gsma.rcs.botversion=\"#=1,#=2\"",
+ "+g.gsma.rcs.cpimext"});
+
return defaults;
}
}
@@ -4213,6 +4278,14 @@
public static final String KEY_STORE_SIM_PIN_FOR_UNATTENDED_REBOOT_BOOL =
"store_sim_pin_for_unattended_reboot_bool";
+ /**
+ * Determine whether "Enable 2G" toggle can be shown.
+ *
+ * Used to trade privacy/security against potentially reduced carrier coverage for some
+ * carriers.
+ */
+ public static final String KEY_HIDE_ENABLE_2G = "hide_enable_2g_bool";
+
/** The default value for every variable. */
private final static PersistableBundle sDefaults;
@@ -4575,6 +4648,8 @@
sDefaults.putBoolean(KEY_TTY_SUPPORTED_BOOL, true);
sDefaults.putBoolean(KEY_HIDE_TTY_HCO_VCO_WITH_RTT_BOOL, false);
sDefaults.putBoolean(KEY_RTT_SUPPORTED_WHILE_ROAMING_BOOL, false);
+ sDefaults.putBoolean(KEY_RTT_UPGRADE_SUPPORTED_FOR_DOWNGRADED_VT_CALL_BOOL, true);
+ sDefaults.putBoolean(KEY_VT_UPGRADE_SUPPORTED_FOR_DOWNGRADED_RTT_CALL_BOOL, true);
sDefaults.putBoolean(KEY_DISABLE_CHARGE_INDICATION_BOOL, false);
sDefaults.putBoolean(KEY_SUPPORT_NO_REPLY_TIMER_FOR_CFNRY_BOOL, true);
sDefaults.putStringArray(KEY_FEATURE_ACCESS_CODES_STRING_ARRAY, null);
@@ -4588,8 +4663,8 @@
sDefaults.putString(KEY_SHOW_CARRIER_DATA_ICON_PATTERN_STRING, "");
sDefaults.putBoolean(KEY_HIDE_LTE_PLUS_DATA_ICON_BOOL, true);
sDefaults.putInt(KEY_LTE_PLUS_THRESHOLD_BANDWIDTH_KHZ_INT, 20000);
- sDefaults.putInt(KEY_CARRIER_NR_AVAILABILITY_INT,
- CARRIER_NR_AVAILABILITY_NSA | CARRIER_NR_AVAILABILITY_SA);
+ sDefaults.putIntArray(KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY,
+ new int[]{CARRIER_NR_AVAILABILITY_NSA, CARRIER_NR_AVAILABILITY_SA});
sDefaults.putBoolean(KEY_LTE_ENABLED_BOOL, true);
sDefaults.putBoolean(KEY_SUPPORT_TDSCDMA_BOOL, false);
sDefaults.putStringArray(KEY_SUPPORT_TDSCDMA_ROAMING_NETWORKS_STRING_ARRAY, null);
@@ -4768,6 +4843,7 @@
sDefaults.putStringArray(KEY_ALLOWED_INITIAL_ATTACH_APN_TYPES_STRING_ARRAY,
new String[]{"ia", "default", "ims", "mms", "dun", "emergency"});
sDefaults.putBoolean(KEY_STORE_SIM_PIN_FOR_UNATTENDED_REBOOT_BOOL, true);
+ sDefaults.putBoolean(KEY_HIDE_ENABLE_2G, false);
}
/**
diff --git a/telephony/java/android/telephony/DataSpecificRegistrationInfo.java b/telephony/java/android/telephony/DataSpecificRegistrationInfo.java
index 597fe8f..957f683 100644
--- a/telephony/java/android/telephony/DataSpecificRegistrationInfo.java
+++ b/telephony/java/android/telephony/DataSpecificRegistrationInfo.java
@@ -68,22 +68,22 @@
public final boolean isEnDcAvailable;
/**
- * Provides network support info for LTE VoPS and LTE Emergency bearer support
+ * Provides network support info for VoPS and Emergency bearer support
*/
@Nullable
- private final LteVopsSupportInfo mLteVopsSupportInfo;
+ private final VopsSupportInfo mVopsSupportInfo;
/**
* @hide
*/
DataSpecificRegistrationInfo(
int maxDataCalls, boolean isDcNrRestricted, boolean isNrAvailable,
- boolean isEnDcAvailable, @Nullable LteVopsSupportInfo lteVops) {
+ boolean isEnDcAvailable, @Nullable VopsSupportInfo vops) {
this.maxDataCalls = maxDataCalls;
this.isDcNrRestricted = isDcNrRestricted;
this.isNrAvailable = isNrAvailable;
this.isEnDcAvailable = isEnDcAvailable;
- this.mLteVopsSupportInfo = lteVops;
+ this.mVopsSupportInfo = vops;
}
/**
@@ -97,7 +97,7 @@
isDcNrRestricted = dsri.isDcNrRestricted;
isNrAvailable = dsri.isNrAvailable;
isEnDcAvailable = dsri.isEnDcAvailable;
- mLteVopsSupportInfo = dsri.mLteVopsSupportInfo;
+ mVopsSupportInfo = dsri.mVopsSupportInfo;
}
private DataSpecificRegistrationInfo(/* @NonNull */ Parcel source) {
@@ -105,7 +105,7 @@
isDcNrRestricted = source.readBoolean();
isNrAvailable = source.readBoolean();
isEnDcAvailable = source.readBoolean();
- mLteVopsSupportInfo = LteVopsSupportInfo.CREATOR.createFromParcel(source);
+ mVopsSupportInfo = source.readParcelable(VopsSupportInfo.class.getClassLoader());
}
@Override
@@ -114,7 +114,7 @@
dest.writeBoolean(isDcNrRestricted);
dest.writeBoolean(isNrAvailable);
dest.writeBoolean(isEnDcAvailable);
- mLteVopsSupportInfo.writeToParcel(dest, flags);
+ dest.writeParcelable(mVopsSupportInfo, flags);
}
@Override
@@ -131,15 +131,15 @@
.append(" isDcNrRestricted = " + isDcNrRestricted)
.append(" isNrAvailable = " + isNrAvailable)
.append(" isEnDcAvailable = " + isEnDcAvailable)
- .append(" " + mLteVopsSupportInfo)
+ .append(" " + mVopsSupportInfo)
.append(" }")
.toString();
}
@Override
public int hashCode() {
- return Objects.hash(maxDataCalls, isDcNrRestricted, isNrAvailable, isEnDcAvailable,
- mLteVopsSupportInfo);
+ return Objects.hash(maxDataCalls, isDcNrRestricted, isNrAvailable,
+ isEnDcAvailable, mVopsSupportInfo);
}
@Override
@@ -153,7 +153,7 @@
&& this.isDcNrRestricted == other.isDcNrRestricted
&& this.isNrAvailable == other.isNrAvailable
&& this.isEnDcAvailable == other.isEnDcAvailable
- && Objects.equals(mLteVopsSupportInfo, other.mLteVopsSupportInfo);
+ && Objects.equals(mVopsSupportInfo, other.mVopsSupportInfo);
}
public static final @NonNull Parcelable.Creator<DataSpecificRegistrationInfo> CREATOR =
@@ -171,10 +171,26 @@
/**
* @return The LTE VOPS (Voice over Packet Switched) support information
+ *
+ * @deprecated use {@link #getVopsSupportInfo()}
*/
+ @Deprecated
@NonNull
public LteVopsSupportInfo getLteVopsSupportInfo() {
- return mLteVopsSupportInfo;
+ return mVopsSupportInfo instanceof LteVopsSupportInfo
+ ? (LteVopsSupportInfo) mVopsSupportInfo
+ : new LteVopsSupportInfo(LteVopsSupportInfo.LTE_STATUS_NOT_AVAILABLE,
+ LteVopsSupportInfo.LTE_STATUS_NOT_AVAILABLE);
}
+ /**
+ * @return The VOPS (Voice over Packet Switched) support information.
+ *
+ * The instance of {@link LTEVopsSupportInfo}, or {@link NrVopsSupportInfo},
+ * null if there is there is no VOPS support information available.
+ */
+ @Nullable
+ public VopsSupportInfo getVopsSupportInfo() {
+ return mVopsSupportInfo;
+ }
}
diff --git a/telephony/java/android/telephony/DataThrottlingRequest.java b/telephony/java/android/telephony/DataThrottlingRequest.java
index f50bb58..2827e8d 100644
--- a/telephony/java/android/telephony/DataThrottlingRequest.java
+++ b/telephony/java/android/telephony/DataThrottlingRequest.java
@@ -17,6 +17,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.RequiresFeature;
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -52,6 +53,9 @@
* @hide
*/
@SystemApi
+ @RequiresFeature(
+ enforcement = "android.telephony.TelephonyManager#isRadioInterfaceCapabilitySupported",
+ value = TelephonyManager.CAPABILITY_THERMAL_MITIGATION_DATA_THROTTLING)
public static final int DATA_THROTTLING_ACTION_THROTTLE_SECONDARY_CARRIER = 1;
/**
@@ -63,6 +67,9 @@
* @hide
*/
@SystemApi
+ @RequiresFeature(
+ enforcement = "android.telephony.TelephonyManager#isRadioInterfaceCapabilitySupported",
+ value = TelephonyManager.CAPABILITY_THERMAL_MITIGATION_DATA_THROTTLING)
public static final int DATA_THROTTLING_ACTION_THROTTLE_PRIMARY_CARRIER = 2;
/**
@@ -76,6 +83,9 @@
* @hide
*/
@SystemApi
+ @RequiresFeature(
+ enforcement = "android.telephony.TelephonyManager#isRadioInterfaceCapabilitySupported",
+ value = TelephonyManager.CAPABILITY_THERMAL_MITIGATION_DATA_THROTTLING)
public static final int DATA_THROTTLING_ACTION_HOLD = 3;
/**
diff --git a/packages/Connectivity/framework/src/android/net/IOnSetOemNetworkPreferenceListener.aidl b/telephony/java/android/telephony/LinkCapacityEstimate.aidl
similarity index 76%
copy from packages/Connectivity/framework/src/android/net/IOnSetOemNetworkPreferenceListener.aidl
copy to telephony/java/android/telephony/LinkCapacityEstimate.aidl
index 7979afc..286f33f 100644
--- a/packages/Connectivity/framework/src/android/net/IOnSetOemNetworkPreferenceListener.aidl
+++ b/telephony/java/android/telephony/LinkCapacityEstimate.aidl
@@ -1,12 +1,11 @@
-/**
- *
+/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * 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,
@@ -15,9 +14,6 @@
* limitations under the License.
*/
-package android.net;
+package android.telephony;
-/** @hide */
-oneway interface IOnSetOemNetworkPreferenceListener {
- void onComplete();
-}
+parcelable LinkCapacityEstimate;
\ No newline at end of file
diff --git a/telephony/java/android/telephony/LinkCapacityEstimate.java b/telephony/java/android/telephony/LinkCapacityEstimate.java
new file mode 100644
index 0000000..deeb809
--- /dev/null
+++ b/telephony/java/android/telephony/LinkCapacityEstimate.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+
+/**
+ * Link Capacity Estimate from the modem
+ * @hide
+ */
+@SystemApi
+public final class LinkCapacityEstimate implements Parcelable {
+ /** A value indicates that the capacity estimate is not available */
+ public static final int INVALID = -1;
+
+ /**
+ * LCE for the primary network
+ */
+ public static final int LCE_TYPE_PRIMARY = 0;
+
+ /**
+ * LCE for the secondary network
+ */
+ public static final int LCE_TYPE_SECONDARY = 1;
+
+ /**
+ * Combined LCE for primary network and secondary network reported by the legacy modem
+ */
+ public static final int LCE_TYPE_COMBINED = 2;
+
+ /** @hide */
+ @IntDef(prefix = { "LCE_TYPE_" }, value = {
+ LCE_TYPE_PRIMARY,
+ LCE_TYPE_SECONDARY,
+ LCE_TYPE_COMBINED,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface LceType {}
+
+ private final @LceType int mType;
+
+ /** Downlink capacity estimate in kbps */
+ private final int mDownlinkCapacityKbps;
+
+ /** Uplink capacity estimate in kbps */
+ private final int mUplinkCapacityKbps;
+
+ /**
+ * Constructor for link capacity estimate
+ */
+ public LinkCapacityEstimate(@LceType int type,
+ int downlinkCapacityKbps, int uplinkCapacityKbps) {
+ mDownlinkCapacityKbps = downlinkCapacityKbps;
+ mUplinkCapacityKbps = uplinkCapacityKbps;
+ mType = type;
+ }
+
+ /**
+ * @hide
+ */
+ public LinkCapacityEstimate(Parcel in) {
+ mDownlinkCapacityKbps = in.readInt();
+ mUplinkCapacityKbps = in.readInt();
+ mType = in.readInt();
+ }
+
+ /**
+ * Retrieves the type of LCE
+ * @return The type of link capacity estimate
+ */
+ public @LceType int getType() {
+ return mType;
+ }
+
+ /**
+ * Retrieves the downlink bandwidth in Kbps.
+ * This will be {@link #INVALID} if the network is not connected
+ * @return The estimated first hop downstream (network to device) bandwidth.
+ */
+ public int getDownlinkCapacityKbps() {
+ return mDownlinkCapacityKbps;
+ }
+
+ /**
+ * Retrieves the uplink bandwidth in Kbps.
+ * This will be {@link #INVALID} if the network is not connected
+ *
+ * @return The estimated first hop upstream (device to network) bandwidth.
+ */
+ public int getUplinkCapacityKbps() {
+ return mUplinkCapacityKbps;
+ }
+
+ @Override
+ public String toString() {
+ return new StringBuilder()
+ .append("{mType=")
+ .append(mType)
+ .append(", mDownlinkCapacityKbps=")
+ .append(mDownlinkCapacityKbps)
+ .append(", mUplinkCapacityKbps=")
+ .append(mUplinkCapacityKbps)
+ .append("}")
+ .toString();
+ }
+
+ /**
+ * {@link Parcelable#describeContents}
+ */
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * {@link Parcelable#writeToParcel}
+ * @hide
+ */
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mDownlinkCapacityKbps);
+ dest.writeInt(mUplinkCapacityKbps);
+ dest.writeInt(mType);
+ }
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (o == null || !(o instanceof LinkCapacityEstimate) || hashCode() != o.hashCode()) {
+ return false;
+ }
+
+ if (this == o) {
+ return true;
+ }
+
+ LinkCapacityEstimate that = (LinkCapacityEstimate) o;
+ return mDownlinkCapacityKbps == that.mDownlinkCapacityKbps
+ && mUplinkCapacityKbps == that.mUplinkCapacityKbps
+ && mType == that.mType;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mDownlinkCapacityKbps, mUplinkCapacityKbps, mType);
+ }
+
+ public static final
+ @android.annotation.NonNull Parcelable.Creator<LinkCapacityEstimate> CREATOR =
+ new Parcelable.Creator() {
+ public LinkCapacityEstimate createFromParcel(Parcel in) {
+ return new LinkCapacityEstimate(in);
+ }
+
+ public LinkCapacityEstimate[] newArray(int size) {
+ return new LinkCapacityEstimate[size];
+ }
+ };
+}
diff --git a/telephony/java/android/telephony/LteVopsSupportInfo.java b/telephony/java/android/telephony/LteVopsSupportInfo.java
index 83e41bf..87761e2 100644
--- a/telephony/java/android/telephony/LteVopsSupportInfo.java
+++ b/telephony/java/android/telephony/LteVopsSupportInfo.java
@@ -21,7 +21,7 @@
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.os.Parcel;
-import android.os.Parcelable;
+import android.telephony.AccessNetworkConstants.AccessNetworkType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -32,7 +32,7 @@
* @hide
*/
@SystemApi
-public final class LteVopsSupportInfo implements Parcelable {
+public final class LteVopsSupportInfo extends VopsSupportInfo {
/**@hide*/
@Retention(RetentionPolicy.SOURCE)
@@ -42,7 +42,10 @@
public @interface LteVopsStatus {}
/**
* Indicates information not available from modem.
+ *
+ * @deprecated as no instance will be created in this case
*/
+ @Deprecated
public static final int LTE_STATUS_NOT_AVAILABLE = 1;
/**
@@ -82,13 +85,38 @@
return mEmcBearerSupport;
}
+ /**
+ * Returns whether VoPS is supported by the network
+ */
+ @Override
+ public boolean isVopsSupported() {
+ return mVopsSupport == LTE_STATUS_SUPPORTED;
+ }
+
+ /**
+ * Returns whether emergency service is supported by the network
+ */
+ @Override
+ public boolean isEmergencyServiceSupported() {
+ return mEmcBearerSupport == LTE_STATUS_SUPPORTED;
+ }
+
+ /**
+ * Returns whether emergency service fallback is supported by the network
+ */
+ @Override
+ public boolean isEmergencyServiceFallbackSupported() {
+ return false;
+ }
+
@Override
public int describeContents() {
return 0;
}
@Override
- public void writeToParcel(Parcel out, int flags) {
+ public void writeToParcel(@NonNull Parcel out, int flags) {
+ super.writeToParcel(out, flags, AccessNetworkType.EUTRAN);
out.writeInt(mVopsSupport);
out.writeInt(mEmcBearerSupport);
}
@@ -124,6 +152,8 @@
new Creator<LteVopsSupportInfo>() {
@Override
public LteVopsSupportInfo createFromParcel(Parcel in) {
+ // Skip the type info.
+ in.readInt();
return new LteVopsSupportInfo(in);
}
@@ -133,6 +163,11 @@
}
};
+ /** @hide */
+ protected static LteVopsSupportInfo createFromParcelBody(Parcel in) {
+ return new LteVopsSupportInfo(in);
+ }
+
private LteVopsSupportInfo(Parcel in) {
mVopsSupport = in.readInt();
mEmcBearerSupport = in.readInt();
diff --git a/telephony/java/android/telephony/NetworkRegistrationInfo.java b/telephony/java/android/telephony/NetworkRegistrationInfo.java
index a78f813..5fb60d7 100644
--- a/telephony/java/android/telephony/NetworkRegistrationInfo.java
+++ b/telephony/java/android/telephony/NetworkRegistrationInfo.java
@@ -293,11 +293,12 @@
@Nullable CellIdentity cellIdentity, @Nullable String rplmn,
int maxDataCalls, boolean isDcNrRestricted,
boolean isNrAvailable, boolean isEndcAvailable,
- LteVopsSupportInfo lteVopsSupportInfo) {
+ @Nullable VopsSupportInfo vopsSupportInfo) {
this(domain, transportType, registrationState, accessNetworkTechnology, rejectCause,
emergencyOnly, availableServices, cellIdentity, rplmn);
mDataSpecificInfo = new DataSpecificRegistrationInfo(
- maxDataCalls, isDcNrRestricted, isNrAvailable, isEndcAvailable, lteVopsSupportInfo);
+ maxDataCalls, isDcNrRestricted, isNrAvailable,
+ isEndcAvailable, vopsSupportInfo);
updateNrState();
}
diff --git a/packages/Connectivity/framework/src/android/net/IOnSetOemNetworkPreferenceListener.aidl b/telephony/java/android/telephony/NrVopsSupportInfo.aidl
similarity index 69%
copy from packages/Connectivity/framework/src/android/net/IOnSetOemNetworkPreferenceListener.aidl
copy to telephony/java/android/telephony/NrVopsSupportInfo.aidl
index 7979afc..460a589 100644
--- a/packages/Connectivity/framework/src/android/net/IOnSetOemNetworkPreferenceListener.aidl
+++ b/telephony/java/android/telephony/NrVopsSupportInfo.aidl
@@ -1,12 +1,11 @@
-/**
- *
- * Copyright (C) 2021 The Android Open Source Project
+/*
+ * Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * 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,
@@ -15,9 +14,6 @@
* limitations under the License.
*/
-package android.net;
+package android.telephony;
-/** @hide */
-oneway interface IOnSetOemNetworkPreferenceListener {
- void onComplete();
-}
+parcelable NrVopsSupportInfo;
diff --git a/telephony/java/android/telephony/NrVopsSupportInfo.java b/telephony/java/android/telephony/NrVopsSupportInfo.java
new file mode 100644
index 0000000..155ee38
--- /dev/null
+++ b/telephony/java/android/telephony/NrVopsSupportInfo.java
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.telephony.AccessNetworkConstants.AccessNetworkType;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+
+/**
+ * Class stores information related to NR network VoPS support
+ * @hide
+ */
+@SystemApi
+public final class NrVopsSupportInfo extends VopsSupportInfo {
+
+ /**
+ * Indicates network does not support vops
+ */
+ public static final int NR_STATUS_VOPS_NOT_SUPPORTED = 0;
+
+ /**
+ * Indicates network supports vops over 3gpp access.
+ */
+ public static final int NR_STATUS_VOPS_3GPP_SUPPORTED = 1;
+
+ /**
+ * Indicates network supports vops over non 3gpp access
+ */
+ public static final int NR_STATUS_VOPS_NON_3GPP_SUPPORTED = 2;
+
+ /**@hide*/
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(
+ prefix = {"NR_STATUS_VOPS_"},
+ value = {
+ NR_STATUS_VOPS_NOT_SUPPORTED,
+ NR_STATUS_VOPS_3GPP_SUPPORTED,
+ NR_STATUS_VOPS_NON_3GPP_SUPPORTED
+ })
+ public @interface NrVopsStatus {}
+
+ /**
+ * Indicates network does not support emergency service
+ */
+ public static final int NR_STATUS_EMC_NOT_SUPPORTED = 0;
+
+ /**
+ * Indicates network supports emergency service in NR connected to 5GCN only
+ */
+ public static final int NR_STATUS_EMC_5GCN_ONLY = 1;
+
+ /**
+ * Indicates network supports emergency service in E-UTRA connected to 5GCN only
+ */
+ public static final int NR_STATUS_EMC_EUTRA_5GCN_ONLY = 2;
+
+ /**
+ * Indicates network supports emergency service in NR connected to 5GCN and
+ * E-UTRA connected to 5GCN
+ */
+ public static final int NR_STATUS_EMC_NR_EUTRA_5GCN = 3;
+
+ /**@hide*/
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(
+ prefix = {"NR_STATUS_EMC_"},
+ value = {
+ NR_STATUS_EMC_NOT_SUPPORTED,
+ NR_STATUS_EMC_5GCN_ONLY,
+ NR_STATUS_EMC_EUTRA_5GCN_ONLY,
+ NR_STATUS_EMC_NR_EUTRA_5GCN
+ })
+ public @interface NrEmcStatus {}
+
+ /**
+ * Indicates network does not support emergency service
+ */
+ public static final int NR_STATUS_EMF_NOT_SUPPORTED = 0;
+
+ /**
+ * Indicates network supports emergency service fallback in NR connected to 5GCN only
+ */
+ public static final int NR_STATUS_EMF_5GCN_ONLY = 1;
+
+ /**
+ * Indicates network supports emergency service fallback in E-UTRA connected to 5GCN only
+ */
+ public static final int NR_STATUS_EMF_EUTRA_5GCN_ONLY = 2;
+
+ /**
+ * Indicates network supports emergency service fallback in NR connected to 5GCN
+ * and E-UTRA connected to 5GCN
+ */
+ public static final int NR_STATUS_EMF_NR_EUTRA_5GCN = 3;
+
+ /**@hide*/
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(
+ prefix = {"NR_STATUS_EMF_"},
+ value = {
+ NR_STATUS_EMF_NOT_SUPPORTED,
+ NR_STATUS_EMF_5GCN_ONLY,
+ NR_STATUS_EMF_EUTRA_5GCN_ONLY,
+ NR_STATUS_EMF_NR_EUTRA_5GCN
+ })
+ public @interface NrEmfStatus {}
+
+ @NrVopsStatus
+ private final int mVopsSupport;
+ @NrEmcStatus
+ private final int mEmcSupport;
+ @NrEmfStatus
+ private final int mEmfSupport;
+
+ public NrVopsSupportInfo(@NrVopsStatus int vops, @NrEmcStatus int emc, @NrEmcStatus int emf) {
+ mVopsSupport = vops;
+ mEmcSupport = emc;
+ mEmfSupport = emf;
+ }
+
+ /**
+ * Provides the NR VoPS support capability as described in:
+ * 3GPP 24.501 EPS network feature support -> IMS VoPS
+ */
+ public @NrVopsStatus int getVopsSupport() {
+ return mVopsSupport;
+ }
+
+ /**
+ * Provides the NR Emergency bearer support capability as described in:
+ * 3GPP 24.501 EPS network feature support -> EMC, and
+ * 38.331 SIB1 : ims-EmergencySupport
+ */
+ public @NrEmcStatus int getEmcSupport() {
+ return mEmcSupport;
+ }
+
+ /**
+ * Provides the NR emergency service fallback support capability as
+ * described in 3GPP 24.501 EPS network feature support -> EMF
+ */
+ public @NrEmfStatus int getEmfSupport() {
+ return mEmfSupport;
+ }
+
+ /**
+ * Returns whether VoPS is supported by the network
+ */
+ @Override
+ public boolean isVopsSupported() {
+ return mVopsSupport != NR_STATUS_VOPS_NOT_SUPPORTED;
+ }
+
+ /**
+ * Returns whether emergency service is supported by the network
+ */
+ @Override
+ public boolean isEmergencyServiceSupported() {
+ return mEmcSupport != NR_STATUS_EMC_NOT_SUPPORTED;
+ }
+
+ /**
+ * Returns whether emergency service fallback is supported by the network
+ */
+ public boolean isEmergencyServiceFallbackSupported() {
+ return mEmfSupport != NR_STATUS_EMF_NOT_SUPPORTED;
+ }
+
+ /**
+ * Implement the Parcelable interface
+ */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel out, int flags) {
+ super.writeToParcel(out, flags, AccessNetworkType.NGRAN);
+ out.writeInt(mVopsSupport);
+ out.writeInt(mEmcSupport);
+ out.writeInt(mEmfSupport);
+ }
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (o == null || !(o instanceof NrVopsSupportInfo)) {
+ return false;
+ }
+ if (this == o) return true;
+ NrVopsSupportInfo other = (NrVopsSupportInfo) o;
+ return mVopsSupport == other.mVopsSupport
+ && mEmcSupport == other.mEmcSupport
+ && mEmfSupport == other.mEmfSupport;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mVopsSupport, mEmcSupport, mEmfSupport);
+ }
+
+ /**
+ * @return string representation.
+ */
+ @NonNull
+ @Override
+ public String toString() {
+ return ("NrVopsSupportInfo : "
+ + " mVopsSupport = " + mVopsSupport
+ + " mEmcSupport = " + mEmcSupport
+ + " mEmfSupport = " + mEmfSupport);
+ }
+
+ public static final @android.annotation.NonNull Creator<NrVopsSupportInfo> CREATOR =
+ new Creator<NrVopsSupportInfo>() {
+ @Override
+ public NrVopsSupportInfo createFromParcel(Parcel in) {
+ // Skip the type info.
+ in.readInt();
+ return new NrVopsSupportInfo(in);
+ }
+
+ @Override
+ public NrVopsSupportInfo[] newArray(int size) {
+ return new NrVopsSupportInfo[size];
+ }
+ };
+
+ /** @hide */
+ protected static NrVopsSupportInfo createFromParcelBody(Parcel in) {
+ return new NrVopsSupportInfo(in);
+ }
+
+ private NrVopsSupportInfo(Parcel in) {
+ mVopsSupport = in.readInt();
+ mEmcSupport = in.readInt();
+ mEmfSupport = in.readInt();
+ }
+}
diff --git a/telephony/java/android/telephony/PhysicalChannelConfig.java b/telephony/java/android/telephony/PhysicalChannelConfig.java
index dfe269c..1c9cd94 100644
--- a/telephony/java/android/telephony/PhysicalChannelConfig.java
+++ b/telephony/java/android/telephony/PhysicalChannelConfig.java
@@ -292,6 +292,14 @@
}
/**
+ * Return a copy of this PhysicalChannelConfig object but redact all the location info.
+ * @hide
+ */
+ public PhysicalChannelConfig createLocationInfoSanitizedCopy() {
+ return new Builder(this).setPhysicalCellId(PHYSICAL_CELL_ID_UNKNOWN).build();
+ }
+
+ /**
* @return String representation of the connection status
* @hide
*/
@@ -540,6 +548,23 @@
mBand = BAND_UNKNOWN;
}
+ /**
+ * Builder object constructed from existing PhysicalChannelConfig object.
+ * @hide
+ */
+ public Builder(PhysicalChannelConfig config) {
+ mNetworkType = config.getNetworkType();
+ mFrequencyRange = config.getFrequencyRange();
+ mDownlinkChannelNumber = config.getDownlinkChannelNumber();
+ mUplinkChannelNumber = config.getUplinkChannelNumber();
+ mCellBandwidthDownlinkKhz = config.getCellBandwidthDownlinkKhz();
+ mCellBandwidthUplinkKhz = config.getCellBandwidthUplinkKhz();
+ mCellConnectionStatus = config.getConnectionStatus();
+ mContextIds = Arrays.copyOf(config.getContextIds(), config.getContextIds().length);
+ mPhysicalCellId = config.getPhysicalCellId();
+ mBand = config.getBand();
+ }
+
public PhysicalChannelConfig build() {
return new PhysicalChannelConfig(this);
}
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index f110dae..2d06062 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -564,6 +564,7 @@
* @hide
*/
@UnsupportedAppUsage
+ @TestApi
public int getDataRegState() {
return mDataRegState;
}
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index b958bff..ce5a8cc 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -2127,7 +2127,7 @@
ret = iccISms.getSmsCapacityOnIccForSubscriber(getSubscriptionId());
}
} catch (RemoteException ex) {
- throw new RuntimeException(ex);
+ Log.e(TAG, "getSmsCapacityOnIcc() RemoteException", ex);
}
return ret;
}
diff --git a/telephony/java/android/telephony/SmsMessage.java b/telephony/java/android/telephony/SmsMessage.java
index cfb29f1..5a12865 100644
--- a/telephony/java/android/telephony/SmsMessage.java
+++ b/telephony/java/android/telephony/SmsMessage.java
@@ -300,9 +300,12 @@
* @param data Message data.
* @param isCdma Indicates weather the type of the SMS is CDMA.
* @return An SmsMessage representing the message.
+ *
+ * @hide
*/
+ @SystemApi
@Nullable
- public static SmsMessage createSmsSubmitPdu(@NonNull byte[] data, boolean isCdma) {
+ public static SmsMessage createFromNativeSmsSubmitPdu(@NonNull byte[] data, boolean isCdma) {
SmsMessageBase wrappedMessage;
if (isCdma) {
@@ -318,23 +321,6 @@
}
/**
- * Create an SmsMessage from a native SMS-Submit PDU, specified by Bluetooth Message Access
- * Profile Specification v1.4.2 5.8.
- * This is used by Bluetooth MAP profile to decode message when sending non UTF-8 SMS messages.
- *
- * @param data Message data.
- * @param isCdma Indicates weather the type of the SMS is CDMA.
- * @return An SmsMessage representing the message.
- *
- * @hide
- */
- @SystemApi
- @Nullable
- public static SmsMessage createFromNativeSmsSubmitPdu(@NonNull byte[] data, boolean isCdma) {
- return null;
- }
-
- /**
* Get the TP-Layer-Length for the given SMS-SUBMIT PDU Basically, the
* length in bytes (not hex chars) less the SMSC header
*
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index e3853fa..7c39cf0 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -129,6 +129,8 @@
import java.util.UUID;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
/**
* Provides access to information about the telephony services on
@@ -3116,6 +3118,10 @@
return NETWORK_TYPE_BITMASK_LTE_CA;
case NETWORK_TYPE_NR:
return NETWORK_TYPE_BITMASK_NR;
+ case NETWORK_TYPE_IWLAN:
+ return NETWORK_TYPE_BITMASK_IWLAN;
+ case NETWORK_TYPE_IDEN:
+ return (1 << (NETWORK_TYPE_IDEN - 1));
default:
return NETWORK_TYPE_BITMASK_UNKNOWN;
}
@@ -8224,7 +8230,8 @@
@IntDef({
ALLOWED_NETWORK_TYPES_REASON_USER,
ALLOWED_NETWORK_TYPES_REASON_POWER,
- ALLOWED_NETWORK_TYPES_REASON_CARRIER
+ ALLOWED_NETWORK_TYPES_REASON_CARRIER,
+ ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G
})
@Retention(RetentionPolicy.SOURCE)
public @interface AllowedNetworkTypesReason {
@@ -8261,21 +8268,36 @@
public static final int ALLOWED_NETWORK_TYPES_REASON_CARRIER = 2;
/**
- * Set the allowed network types of the device and
- * provide the reason triggering the allowed network change.
+ * To indicate allowed network type change is requested by the user via the 2G toggle.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G = 3;
+
+ /**
+ * Set the allowed network types of the device and provide the reason triggering the allowed
+ * network change.
* This can be called for following reasons
* <ol>
* <li>Allowed network types control by USER {@link #ALLOWED_NETWORK_TYPES_REASON_USER}
* <li>Allowed network types control by power manager
* {@link #ALLOWED_NETWORK_TYPES_REASON_POWER}
* <li>Allowed network types control by carrier {@link #ALLOWED_NETWORK_TYPES_REASON_CARRIER}
+ * <li>Allowed network types control by the user-controlled "Allow 2G" toggle
+ * {@link #ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G}
* </ol>
* This API will result in allowing an intersection of allowed network types for all reasons,
* including the configuration done through other reasons.
+ *
+ * The functionality of this API with the parameter
+ * {@link #ALLOWED_NETWORK_TYPES_REASON_CARRIER} is the same as the API
+ * {@link TelephonyManager#setAllowedNetworkTypes}. Use this API instead of
+ * {@link TelephonyManager#setAllowedNetworkTypes}.
* <p>
* If {@link android.telephony.TelephonyManager#isRadioInterfaceCapabilitySupported}
* ({@link TelephonyManager#CAPABILITY_ALLOWED_NETWORK_TYPES_USED}) returns true, then
- * setAllowedNetworkTypesBitmap is used on the radio interface. Otherwise,
+ * setAllowedNetworkTypesBitmap is used on the radio interface. Otherwise,
* setPreferredNetworkTypesBitmap is used instead.
*
* @param reason the reason the allowed network type change is taking place
@@ -8315,21 +8337,17 @@
* {@link #getAllowedNetworkTypesForReason} returns allowed network type for a
* specific reason.
*
- * <p>Requires Permission:
- * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE}
- * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
- *
* @param reason the reason the allowed network type change is taking place
* @return the allowed network type bitmask
* @throws IllegalStateException if the Telephony process is not currently available.
* @throws IllegalArgumentException if invalid AllowedNetworkTypesReason is passed.
* @hide
*/
- @SystemApi
@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
@RequiresFeature(
enforcement = "android.telephony.TelephonyManager#isRadioInterfaceCapabilitySupported",
value = TelephonyManager.CAPABILITY_ALLOWED_NETWORK_TYPES_USED)
+ @SystemApi
public @NetworkTypeBitMask long getAllowedNetworkTypesForReason(
@AllowedNetworkTypesReason int reason) {
if (!isValidAllowedNetworkTypesReason(reason)) {
@@ -8358,6 +8376,7 @@
case TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER:
case TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_POWER:
case TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_CARRIER:
+ case TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G:
return true;
}
return false;
@@ -8373,6 +8392,25 @@
}
/**
+ * Returns a string representation of the allowed network types{@link NetworkTypeBitMask}.
+ *
+ * @param networkTypeBitmask The bitmask of allowed network types.
+ * @return the name of the allowed network types
+ * @hide
+ */
+ public static String convertNetworkTypeBitmaskToString(
+ @NetworkTypeBitMask long networkTypeBitmask) {
+ String networkTypeName = IntStream.rangeClosed(NETWORK_TYPE_GPRS, NETWORK_TYPE_NR)
+ .filter(x -> {
+ return (networkTypeBitmask & getBitMaskForNetworkType(x))
+ == getBitMaskForNetworkType(x);
+ })
+ .mapToObj(x -> getNetworkTypeName(x))
+ .collect(Collectors.joining("|"));
+ return TextUtils.isEmpty(networkTypeName) ? "UNKNOWN" : networkTypeName;
+ }
+
+ /**
* Set the preferred network type to global mode which includes LTE, CDMA, EvDo and GSM/WCDMA.
*
* <p>Requires that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
@@ -11859,12 +11897,6 @@
* "Data capable" means that this device supports packet-switched
* data connections over the telephony network.
* <p>
- * Note: the meaning of this flag is subtly different from the
- * PackageManager.FEATURE_TELEPHONY system feature, which is available
- * on any device with a telephony radio, even if the device is
- * voice-only.
- *
- * @hide
*/
public boolean isDataCapable() {
if (mContext == null) return true;
@@ -12079,6 +12111,7 @@
NETWORK_TYPE_BITMASK_LTE,
NETWORK_TYPE_BITMASK_LTE_CA,
NETWORK_TYPE_BITMASK_NR,
+ NETWORK_TYPE_BITMASK_IWLAN
})
public @interface NetworkTypeBitMask {}
@@ -13981,33 +14014,6 @@
}
/**
- * Get carrier bandwidth. In case of Dual connected network this will report
- * bandwidth per primary and secondary network.
- * @return CarrierBandwidth with bandwidth of both primary and secondary carrier.
- * @throws IllegalStateException if the Telephony process is not currently available.
- * @hide
- */
- @SystemApi
- @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
- @NonNull
- public CarrierBandwidth getCarrierBandwidth() {
- try {
- ITelephony service = getITelephony();
- if (service != null) {
- return service.getCarrierBandwidth(getSubId());
- } else {
- throw new IllegalStateException("telephony service is null.");
- }
- } catch (RemoteException ex) {
- Log.e(TAG, "getCarrierBandwidth RemoteException", ex);
- ex.rethrowFromSystemServer();
- }
-
- //Should not reach. Adding return statement to make compiler happy
- return null;
- }
-
- /**
* Called when userActivity is signalled in the power manager.
* This should only be called from system Uid.
* @hide
@@ -14111,6 +14117,10 @@
/**
* Enable/Disable E-UTRA-NR Dual Connectivity.
*
+ * This api is supported only if
+ * {@link android.telephony.TelephonyManager#isRadioInterfaceCapabilitySupported}
+ * ({@link TelephonyManager#CAPABILITY_NR_DUAL_CONNECTIVITY_CONFIGURATION_AVAILABLE})
+ * returns true.
* @param nrDualConnectivityState expected NR dual connectivity state
* This can be passed following states
* <ol>
@@ -14120,12 +14130,14 @@
* {@link #NR_DUAL_CONNECTIVITY_DISABLE_IMMEDIATE}
* </ol>
* @return operation result.
- * <p>Requires Permission:
- * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
* @throws IllegalStateException if the Telephony process is not currently available.
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ @RequiresFeature(
+ enforcement = "android.telephony.TelephonyManager#isRadioInterfaceCapabilitySupported",
+ value = TelephonyManager.CAPABILITY_NR_DUAL_CONNECTIVITY_CONFIGURATION_AVAILABLE)
public @EnableNrDualConnectivityResult int setNrDualConnectivityState(
@NrDualConnectivityState int nrDualConnectivityState) {
try {
@@ -14145,15 +14157,21 @@
/**
* Is E-UTRA-NR Dual Connectivity enabled.
+ * This api is supported only if
+ * {@link android.telephony.TelephonyManager#isRadioInterfaceCapabilitySupported}
+ * ({@link TelephonyManager#CAPABILITY_NR_DUAL_CONNECTIVITY_CONFIGURATION_AVAILABLE})
+ * returns true.
* @return true if dual connectivity is enabled else false. Enabled state does not mean dual
* connectivity is active. It means the device is allowed to connect to both primary and
* secondary cell.
- * <p>Requires Permission:
- * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE}
* @throws IllegalStateException if the Telephony process is not currently available.
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ @RequiresFeature(
+ enforcement = "android.telephony.TelephonyManager#isRadioInterfaceCapabilitySupported",
+ value = TelephonyManager.CAPABILITY_NR_DUAL_CONNECTIVITY_CONFIGURATION_AVAILABLE)
public boolean isNrDualConnectivityEnabled() {
try {
ITelephony telephony = getITelephony();
@@ -14405,11 +14423,34 @@
public static final String CAPABILITY_ALLOWED_NETWORK_TYPES_USED =
"CAPABILITY_ALLOWED_NETWORK_TYPES_USED";
+ /**
+ * Indicates whether {@link #setNrDualConnectivityState()} and
+ * {@link #isNrDualConnectivityEnabled()} ()} are available. See comments
+ * on respective methods for more information.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String CAPABILITY_NR_DUAL_CONNECTIVITY_CONFIGURATION_AVAILABLE =
+ "CAPABILITY_NR_DUAL_CONNECTIVITY_CONFIGURATION_AVAILABLE";
+
+ /**
+ * Indicates whether a data throttling request sent with {@link #sendThermalMitigationRequest}
+ * is supported. See comments on {@link #sendThermalMitigationRequest} for more information.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String CAPABILITY_THERMAL_MITIGATION_DATA_THROTTLING =
+ "CAPABILITY_THERMAL_MITIGATION_DATA_THROTTLING";
+
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@StringDef(prefix = "CAPABILITY_", value = {
CAPABILITY_SECONDARY_LINK_BANDWIDTH_VISIBLE,
CAPABILITY_ALLOWED_NETWORK_TYPES_USED,
+ CAPABILITY_NR_DUAL_CONNECTIVITY_CONFIGURATION_AVAILABLE,
+ CAPABILITY_THERMAL_MITIGATION_DATA_THROTTLING,
})
public @interface RadioInterfaceCapability {}
@@ -14519,11 +14560,29 @@
* and can be used at any time during data throttling to hold onto the current level of data
* throttling.
*
+ * <p> If {@link android.telephony.TelephonyManager#isRadioInterfaceCapabilitySupported}({@link
+ * #CAPABILITY_THERMAL_MITIGATION_DATA_THROTTLING}) returns false, then sending a {@link
+ * DataThrottlingRequest#DATA_THROTTLING_ACTION_HOLD}, {@link
+ * DataThrottlingRequest#DATA_THROTTLING_ACTION_THROTTLE_SECONDARY_CARRIER}, or {@link
+ * DataThrottlingRequest#DATA_THROTTLING_ACTION_THROTTLE_PRIMARY_CARRIER} will result in {@link
+ * IllegalArgumentException} being thrown. However, on devices that do not
+ * support data throttling, {@link
+ * DataThrottlingRequest#DATA_THROTTLING_ACTION_NO_DATA_THROTTLING} can still be requested in
+ * order to undo the mitigations above it (i.e {@link
+ * ThermalMitigationRequest#THERMAL_MITIGATION_ACTION_VOICE_ONLY} and/or {@link
+ * ThermalMitigationRequest#THERMAL_MITIGATION_ACTION_RADIO_OFF}). </p>
+ *
+ * <p> In addition to the {@link Manifest.permission#MODIFY_PHONE_STATE} permission, callers of
+ * this API must also be listed in the device configuration as an authorized app in
+ * {@code packages/services/Telephony/res/values/config.xml} under the
+ * {@code thermal_mitigation_allowlisted_packages} key. </p>
+ *
* @param thermalMitigationRequest Thermal mitigation request. See {@link
* ThermalMitigationRequest} for details.
*
* @throws IllegalStateException if the Telephony process is not currently available.
- * @throws IllegalArgumentException if the thermalMitigationRequest had invalid parameters.
+ * @throws IllegalArgumentException if the thermalMitigationRequest had invalid parameters or
+ * if the device's modem does not support data throttling.
*
* @hide
*/
@@ -14535,7 +14594,8 @@
try {
ITelephony telephony = getITelephony();
if (telephony != null) {
- return telephony.sendThermalMitigationRequest(getSubId(), thermalMitigationRequest);
+ return telephony.sendThermalMitigationRequest(getSubId(), thermalMitigationRequest,
+ getOpPackageName());
}
throw new IllegalStateException("telephony service is null.");
} catch (RemoteException ex) {
@@ -14577,6 +14637,11 @@
*/
public void registerTelephonyCallback(@NonNull @CallbackExecutor Executor executor,
@NonNull TelephonyCallback callback) {
+
+ if (mContext == null) {
+ throw new IllegalStateException("telephony service is null.");
+ }
+
if (executor == null || callback == null) {
throw new IllegalArgumentException("TelephonyCallback and executor must be non-null");
}
@@ -14721,13 +14786,17 @@
* </ul>
* @param appType icc application type, like {@link #APPTYPE_USIM} or {@link
* #APPTYPE_ISIM} or {@link#APPTYPE_UNKNOWN}
- * @param nafId Network Application Function(NAF) fully qualified domain name and
- * the selected GBA mode. It shall contain two parts delimited by "@" sign. The first
- * part is the constant string "3GPP-bootstrapping" (GBA_ME),
- * "3GPP-bootstrapping-uicc" (GBA_ U), or "3GPP-bootstrapping-digest" (GBA_Digest),
- * and the latter part shall be the FQDN of the NAF (e.g.
- * "3GPP-bootstrapping@naf1.operator.com" or "3GPP-bootstrapping-uicc@naf1.operator.com",
- * or "3GPP-bootstrapping-digest@naf1.operator.com").
+ * @param nafId A URI to specify Network Application Function(NAF) fully qualified domain
+ * name (FQDN) and the selected GBA mode. The authority of the URI must contain two parts
+ * delimited by "@" sign. The first part is the constant string "3GPP-bootstrapping" (GBA_ME),
+ * "3GPP-bootstrapping-uicc" (GBA_ U), or "3GPP-bootstrapping-digest" (GBA_Digest).
+ * The second part shall be the FQDN of the NAF. The scheme of the URI is not actually used
+ * for the authentication, which may be set the same as the resource that the application is
+ * going to access. For example, the nafId can be
+ * "https://3GPP-bootstrapping@naf1.operator.com",
+ * "https://3GPP-bootstrapping-uicc@naf1.operator.com",
+ * "https://3GPP-bootstrapping-digest@naf1.operator.com",
+ * "ftps://3GPP-bootstrapping-digest@naf1.operator.com".
* @param securityProtocol Security protocol identifier between UE and NAF. See
* 3GPP TS 33.220 Annex H. Application can use
* {@link UaSecurityProtocolIdentifier#createDefaultUaSpId},
@@ -14899,7 +14968,9 @@
public static final int PREPARE_UNATTENDED_REBOOT_PIN_REQUIRED = 1;
/**
- * The unattended reboot was not prepared due to generic error.
+ * The unattended reboot was not prepared due to a non-recoverable error. After this error,
+ * the client that manages the unattended reboot should not try to invoke the API again
+ * until the next power cycle.
* @hide
*/
@SystemApi
diff --git a/packages/Connectivity/framework/src/android/net/IOnSetOemNetworkPreferenceListener.aidl b/telephony/java/android/telephony/VopsSupportInfo.aidl
similarity index 69%
copy from packages/Connectivity/framework/src/android/net/IOnSetOemNetworkPreferenceListener.aidl
copy to telephony/java/android/telephony/VopsSupportInfo.aidl
index 7979afc..31c608f 100644
--- a/packages/Connectivity/framework/src/android/net/IOnSetOemNetworkPreferenceListener.aidl
+++ b/telephony/java/android/telephony/VopsSupportInfo.aidl
@@ -1,12 +1,11 @@
-/**
- *
- * Copyright (C) 2021 The Android Open Source Project
+/*
+ * Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * 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,
@@ -15,9 +14,6 @@
* limitations under the License.
*/
-package android.net;
+package android.telephony;
-/** @hide */
-oneway interface IOnSetOemNetworkPreferenceListener {
- void onComplete();
-}
+parcelable VopsSupportInfo;
diff --git a/telephony/java/android/telephony/VopsSupportInfo.java b/telephony/java/android/telephony/VopsSupportInfo.java
new file mode 100644
index 0000000..f89bfa9
--- /dev/null
+++ b/telephony/java/android/telephony/VopsSupportInfo.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony;
+
+import android.annotation.NonNull;
+import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.telephony.AccessNetworkConstants.AccessNetworkType;
+
+/**
+ * Abstract base class for the information related to network VoPS support.
+ * This is the base class for XxVopsSupportInfo which represent VoPS support
+ * information for specific network access techonology.
+ * @hide
+ */
+@SuppressLint("ParcelNotFinal")
+@SystemApi
+public abstract class VopsSupportInfo implements Parcelable {
+
+ /**
+ * @hide
+ */
+ public VopsSupportInfo() {}
+
+ /**
+ * Returns whether VoPS is supported by the network
+ */
+ public abstract boolean isVopsSupported();
+
+ /**
+ * Returns whether emergency service is supported by the network
+ */
+ public abstract boolean isEmergencyServiceSupported();
+
+ /**
+ * Returns whether emergency service fallback is supported by the network
+ */
+ public abstract boolean isEmergencyServiceFallbackSupported();
+
+ /**
+ * Implement the Parcelable interface
+ */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /** Implement the Parcelable interface */
+ @Override
+ public abstract void writeToParcel(@NonNull Parcel dest, int flags);
+
+ /**
+ * Used by child classes for parceling.
+ *
+ * @hide
+ */
+ protected void writeToParcel(@NonNull Parcel dest, int flags, int type) {
+ dest.writeInt(type);
+ }
+
+ /** Implement the Parcelable interface */
+ public static final @android.annotation.NonNull Creator<VopsSupportInfo> CREATOR =
+ new Creator<VopsSupportInfo>() {
+ @Override
+ public VopsSupportInfo createFromParcel(Parcel in) {
+ int type = in.readInt();
+ switch (type) {
+ case AccessNetworkType.EUTRAN:
+ return LteVopsSupportInfo.createFromParcelBody(in);
+ case AccessNetworkType.NGRAN:
+ return NrVopsSupportInfo.createFromParcelBody(in);
+ default: throw new RuntimeException("Bad VopsSupportInfo Parcel");
+ }
+ }
+
+ @Override
+ public VopsSupportInfo[] newArray(int size) {
+ return new VopsSupportInfo[size];
+ }
+ };
+
+ @Override
+ public abstract int hashCode();
+
+ @Override
+ public abstract boolean equals(Object o);
+}
diff --git a/telephony/java/android/telephony/data/DataServiceCallback.java b/telephony/java/android/telephony/data/DataServiceCallback.java
index ca1f861..363e47a 100644
--- a/telephony/java/android/telephony/data/DataServiceCallback.java
+++ b/telephony/java/android/telephony/data/DataServiceCallback.java
@@ -254,15 +254,15 @@
}
/**
- * The APN is throttled for the duration specified in
- * {@link DataCallResponse#getRetryDurationMillis}. Calling this method unthrottles that
- * APN.
+ * Unthrottles the APN on the current transport. There is no matching "APN throttle" method.
+ * Instead, the APN is throttled for the time specified in
+ * {@link DataCallResponse#getRetryDurationMillis}.
* <p/>
* see: {@link DataCallResponse#getRetryDurationMillis}
*
* @param apn Access Point Name defined by the carrier.
*/
- public void onApnUnthrottled(@NonNull String apn) {
+ public void onApnUnthrottled(final @NonNull String apn) {
if (mCallback != null) {
try {
if (DBG) Rlog.d(TAG, "onApnUnthrottled");
diff --git a/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.java b/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.java
index 041edc0..9bc7a5c 100644
--- a/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.java
+++ b/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.java
@@ -53,7 +53,7 @@
*
* @return the qci of the session
*/
- public int getQci() {
+ public int getQosIdentifier() {
return mQci;
}
@@ -66,7 +66,7 @@
*
* @return the guaranteed bit rate in kbps
*/
- public long getGuaranteedUplinkBitRate() {
+ public long getGuaranteedUplinkBitRateKbps() {
return mGuaranteedUplinkBitRate;
}
@@ -79,7 +79,7 @@
*
* @return the guaranteed bit rate in kbps
*/
- public long getGuaranteedDownlinkBitRate() {
+ public long getGuaranteedDownlinkBitRateKbps() {
return mGuaranteedDownlinkBitRate;
}
@@ -92,7 +92,7 @@
*
* @return the max uplink bit rate in kbps
*/
- public long getMaxUplinkBitRate() {
+ public long getMaxUplinkBitRateKbps() {
return mMaxUplinkBitRate;
}
@@ -105,7 +105,7 @@
*
* @return the max downlink bit rate in kbps
*/
- public long getMaxDownlinkBitRate() {
+ public long getMaxDownlinkBitRateKbps() {
return mMaxDownlinkBitRate;
}
@@ -184,16 +184,6 @@
mRemoteAddresses = Collections.unmodifiableList(remoteAddresses);
}
- /**
- * Creates attributes based off of a parcel
- * @param in the parcel
- * @return the attributes
- */
- @NonNull
- public static EpsBearerQosSessionAttributes create(@NonNull final Parcel in) {
- return new EpsBearerQosSessionAttributes(in);
- }
-
@Override
public int describeContents() {
return 0;
diff --git a/telephony/java/android/telephony/data/NrQos.java b/telephony/java/android/telephony/data/NrQos.java
index 2011eed..fe124ac 100644
--- a/telephony/java/android/telephony/data/NrQos.java
+++ b/telephony/java/android/telephony/data/NrQos.java
@@ -50,6 +50,18 @@
return new NrQos(in);
}
+ public int get5Qi() {
+ return fiveQi;
+ }
+
+ public int getQfi() {
+ return qosFlowId;
+ }
+
+ public int getAveragingWindow() {
+ return averagingWindowMs;
+ }
+
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
super.writeToParcel(Qos.QOS_TYPE_NR, dest, flags);
diff --git a/packages/Connectivity/framework/src/android/net/IOnSetOemNetworkPreferenceListener.aidl b/telephony/java/android/telephony/data/NrQosSessionAttributes.aidl
similarity index 76%
copy from packages/Connectivity/framework/src/android/net/IOnSetOemNetworkPreferenceListener.aidl
copy to telephony/java/android/telephony/data/NrQosSessionAttributes.aidl
index 7979afc..fd3bbb0 100644
--- a/packages/Connectivity/framework/src/android/net/IOnSetOemNetworkPreferenceListener.aidl
+++ b/telephony/java/android/telephony/data/NrQosSessionAttributes.aidl
@@ -1,12 +1,11 @@
-/**
- *
+/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * 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,
@@ -15,9 +14,6 @@
* limitations under the License.
*/
-package android.net;
+ package android.telephony.data;
-/** @hide */
-oneway interface IOnSetOemNetworkPreferenceListener {
- void onComplete();
-}
+ parcelable NrQosSessionAttributes;
diff --git a/telephony/java/android/telephony/data/NrQosSessionAttributes.java b/telephony/java/android/telephony/data/NrQosSessionAttributes.java
new file mode 100644
index 0000000..4c37687
--- /dev/null
+++ b/telephony/java/android/telephony/data/NrQosSessionAttributes.java
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.data;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.net.QosSessionAttributes;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.UnknownHostException;
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Provides Qos attributes of an NR bearer.
+ *
+ * {@hide}
+ */
+@SystemApi
+public final class NrQosSessionAttributes implements Parcelable, QosSessionAttributes {
+ private static final String TAG = NrQosSessionAttributes.class.getSimpleName();
+ private final int m5Qi;
+ private final @IntRange(from=1, to=63) int mQfi;
+ private final long mMaxUplinkBitRate;
+ private final long mMaxDownlinkBitRate;
+ private final long mGuaranteedUplinkBitRate;
+ private final long mGuaranteedDownlinkBitRate;
+ private final long mAveragingWindow;
+ @NonNull private final List<InetSocketAddress> mRemoteAddresses;
+
+ /**
+ * 5G QOS Identifier (5QI), see 3GPP TS 24.501 and 23.501.
+ * The allowed values are standard values(1-9, 65-68, 69-70, 75, 79-80, 82-85)
+ * defined in the spec and operator specific values in the range 128-254.
+ *
+ * @return the 5QI of the QOS flow
+ */
+ public int getQosIdentifier() {
+ return m5Qi;
+ }
+
+ /**
+ * QOS flow identifier of the QOS flow description in the
+ * range of 1 to 63. see 3GPP TS 24.501 and 23.501.
+ *
+ * @return the QOS flow identifier of the session
+ */
+ public @IntRange(from=1, to=63) int getQosFlowIdentifier() {
+ return mQfi;
+ }
+
+ /**
+ * Minimum bit rate in kbps that is guaranteed to be provided by the network on the uplink.
+ *
+ * see 3GPP TS 24.501 section 6.2.5
+ *
+ * Note: The Qos Session may be shared with OTHER applications besides yours.
+ *
+ * @return the guaranteed bit rate in kbps
+ */
+ public long getGuaranteedUplinkBitRateKbps() {
+ return mGuaranteedUplinkBitRate;
+ }
+
+ /**
+ * Minimum bit rate in kbps that is guaranteed to be provided by the network on the downlink.
+ *
+ * see 3GPP TS 24.501 section 6.2.5
+ *
+ * Note: The Qos Session may be shared with OTHER applications besides yours.
+ *
+ * @return the guaranteed bit rate in kbps
+ */
+ public long getGuaranteedDownlinkBitRateKbps() {
+ return mGuaranteedDownlinkBitRate;
+ }
+
+ /**
+ * The maximum uplink kbps that the network will accept.
+ *
+ * see 3GPP TS 24.501 section 6.2.5
+ *
+ * Note: The Qos Session may be shared with OTHER applications besides yours.
+ *
+ * @return the max uplink bit rate in kbps
+ */
+ public long getMaxUplinkBitRateKbps() {
+ return mMaxUplinkBitRate;
+ }
+
+ /**
+ * The maximum downlink kbps that the network can provide.
+ *
+ * see 3GPP TS 24.501 section 6.2.5
+ *
+ * Note: The Qos Session may be shared with OTHER applications besides yours.
+ *
+ * @return the max downlink bit rate in kbps
+ */
+ public long getMaxDownlinkBitRateKbps() {
+ return mMaxDownlinkBitRate;
+ }
+
+ /**
+ * The duration in milliseconds over which the maximum bit rates and guaranteed bit rates
+ * are calculated
+ *
+ * see 3GPP TS 24.501 section 6.2.5
+ *
+ * @return the averaging window duration in milliseconds
+ */
+ @NonNull
+ public Duration getBitRateWindowDuration() {
+ return Duration.ofMillis(mAveragingWindow);
+ }
+
+ /**
+ * List of remote addresses associated with the Qos Session. The given uplink bit rates apply
+ * to this given list of remote addresses.
+ *
+ * Note: In the event that the list is empty, it is assumed that the uplink bit rates apply to
+ * all remote addresses that are not contained in a different set of attributes.
+ *
+ * @return list of remote socket addresses that the attributes apply to
+ */
+ @NonNull
+ public List<InetSocketAddress> getRemoteAddresses() {
+ return mRemoteAddresses;
+ }
+
+ /**
+ * ..ctor for attributes
+ *
+ * @param fiveQi 5G quality class indicator
+ * @param qfi QOS flow identifier
+ * @param maxDownlinkBitRate the max downlink bit rate in kbps
+ * @param maxUplinkBitRate the max uplink bit rate in kbps
+ * @param guaranteedDownlinkBitRate the guaranteed downlink bit rate in kbps
+ * @param guaranteedUplinkBitRate the guaranteed uplink bit rate in kbps
+ * @param averagingWindow the averaging window duration in milliseconds
+ * @param remoteAddresses the remote addresses that the uplink bit rates apply to
+ *
+ * @hide
+ */
+ public NrQosSessionAttributes(final int fiveQi, final int qfi,
+ final long maxDownlinkBitRate, final long maxUplinkBitRate,
+ final long guaranteedDownlinkBitRate, final long guaranteedUplinkBitRate,
+ final long averagingWindow, @NonNull final List<InetSocketAddress> remoteAddresses) {
+ Objects.requireNonNull(remoteAddresses, "remoteAddress must be non-null");
+ m5Qi = fiveQi;
+ mQfi = qfi;
+ mMaxDownlinkBitRate = maxDownlinkBitRate;
+ mMaxUplinkBitRate = maxUplinkBitRate;
+ mGuaranteedDownlinkBitRate = guaranteedDownlinkBitRate;
+ mGuaranteedUplinkBitRate = guaranteedUplinkBitRate;
+ mAveragingWindow = averagingWindow;
+
+ final List<InetSocketAddress> remoteAddressesTemp = copySocketAddresses(remoteAddresses);
+ mRemoteAddresses = Collections.unmodifiableList(remoteAddressesTemp);
+ }
+
+ private static List<InetSocketAddress> copySocketAddresses(
+ @NonNull final List<InetSocketAddress> remoteAddresses) {
+ final List<InetSocketAddress> remoteAddressesTemp = new ArrayList<>();
+ for (final InetSocketAddress socketAddress : remoteAddresses) {
+ if (socketAddress != null && socketAddress.getAddress() != null) {
+ remoteAddressesTemp.add(socketAddress);
+ }
+ }
+ return remoteAddressesTemp;
+ }
+
+ private NrQosSessionAttributes(@NonNull final Parcel in) {
+ m5Qi = in.readInt();
+ mQfi = in.readInt();
+ mMaxDownlinkBitRate = in.readLong();
+ mMaxUplinkBitRate = in.readLong();
+ mGuaranteedDownlinkBitRate = in.readLong();
+ mGuaranteedUplinkBitRate = in.readLong();
+ mAveragingWindow = in.readLong();
+
+ final int size = in.readInt();
+ final List<InetSocketAddress> remoteAddresses = new ArrayList<>(size);
+ for (int i = 0; i < size; i++) {
+ final byte[] addressBytes = in.createByteArray();
+ final int port = in.readInt();
+ try {
+ remoteAddresses.add(
+ new InetSocketAddress(InetAddress.getByAddress(addressBytes), port));
+ } catch (final UnknownHostException e) {
+ // Impossible case since its filtered out the null values in the ..ctor
+ Log.e(TAG, "unable to unparcel remote address at index: " + i, e);
+ }
+ }
+ mRemoteAddresses = Collections.unmodifiableList(remoteAddresses);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull final Parcel dest, final int flags) {
+ dest.writeInt(m5Qi);
+ dest.writeInt(mQfi);
+ dest.writeLong(mMaxDownlinkBitRate);
+ dest.writeLong(mMaxUplinkBitRate);
+ dest.writeLong(mGuaranteedDownlinkBitRate);
+ dest.writeLong(mGuaranteedUplinkBitRate);
+ dest.writeLong(mAveragingWindow);
+
+ final int size = mRemoteAddresses.size();
+ dest.writeInt(size);
+ for (int i = 0; i < size; i++) {
+ final InetSocketAddress address = mRemoteAddresses.get(i);
+ dest.writeByteArray(address.getAddress().getAddress());
+ dest.writeInt(address.getPort());
+ }
+ }
+
+ @NonNull
+ public static final Creator<NrQosSessionAttributes> CREATOR =
+ new Creator<NrQosSessionAttributes>() {
+ @NonNull
+ @Override
+ public NrQosSessionAttributes createFromParcel(@NonNull final Parcel in) {
+ return new NrQosSessionAttributes(in);
+ }
+
+ @NonNull
+ @Override
+ public NrQosSessionAttributes[] newArray(final int size) {
+ return new NrQosSessionAttributes[size];
+ }
+ };
+}
diff --git a/telephony/java/android/telephony/data/SliceInfo.java b/telephony/java/android/telephony/data/SliceInfo.java
index 51857a7..609d111 100644
--- a/telephony/java/android/telephony/data/SliceInfo.java
+++ b/telephony/java/android/telephony/data/SliceInfo.java
@@ -29,7 +29,12 @@
import java.util.Objects;
/**
- * Represents a S-NSSAI as defined in 3GPP TS 24.501.
+ * Represents a S-NSSAI as defined in 3GPP TS 24.501, which represents a network slice.
+ *
+ * There are 2 main fields that define a slice, SliceServiceType and SliceDifferentiator.
+ * SliceServiceType defines the type of service provided by the slice, and SliceDifferentiator is
+ * used to differentiate between multiple slices of the same type. If the devices is not on HPLMN,
+ * the mappedHplmn versions of these 2 fields indicate the corresponding values in HPLMN.
*
* @hide
*/
diff --git a/telephony/java/android/telephony/ims/ProvisioningManager.java b/telephony/java/android/telephony/ims/ProvisioningManager.java
index aa9145b..1e80ab7 100644
--- a/telephony/java/android/telephony/ims/ProvisioningManager.java
+++ b/telephony/java/android/telephony/ims/ProvisioningManager.java
@@ -993,6 +993,16 @@
}
}
+ @Override
+ public void onPreProvisioningReceived(byte[] configXml) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() -> mLocalCallback.onPreProvisioningReceived(configXml));
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
private void setExecutor(Executor executor) {
mExecutor = executor;
}
@@ -1005,7 +1015,7 @@
* due to various triggers defined in GSMA RCC.14 for ACS(auto configuration
* server) or other operator defined triggers. If RCS provisioning is already
* completed at the time of callback registration, then this method shall be
- * invoked with the current configuration
+ * invoked with the current configuration.
* @param configXml The RCS configuration XML received by OTA. It is defined
* by GSMA RCC.07.
*/
@@ -1038,6 +1048,20 @@
*/
public void onRemoved() {}
+ /**
+ * Some carriers using ACS (auto configuration server) may send a carrier-specific
+ * pre-provisioning configuration XML if the user has not been provisioned for RCS
+ * services yet. When this provisioning XML is received, the framework will move
+ * into a "not provisioned" state for RCS. In order for provisioning to proceed,
+ * the application must parse this configuration XML and perform the carrier specific
+ * opt-in flow for RCS services. If the user accepts, {@link #triggerRcsReconfiguration}
+ * must be called in order for the device to move out of this state and try to fetch
+ * the RCS provisioning information.
+ *
+ * @param configXml the pre-provisioning config in carrier specified format.
+ */
+ public void onPreProvisioningReceived(@NonNull byte[] configXml) {}
+
/**@hide*/
public final IRcsConfigCallback getBinder() {
return mBinder;
diff --git a/telephony/java/android/telephony/ims/RcsContactPresenceTuple.java b/telephony/java/android/telephony/ims/RcsContactPresenceTuple.java
index 5eb75e7..9c28c36 100644
--- a/telephony/java/android/telephony/ims/RcsContactPresenceTuple.java
+++ b/telephony/java/android/telephony/ims/RcsContactPresenceTuple.java
@@ -21,11 +21,16 @@
import android.annotation.StringDef;
import android.annotation.SystemApi;
import android.net.Uri;
+import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
+import android.text.TextUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.time.Instant;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -38,6 +43,17 @@
@SystemApi
public final class RcsContactPresenceTuple implements Parcelable {
+ private static final String LOG_TAG = "RcsContactPresenceTuple";
+
+ /**
+ * The service ID used to indicate that service discovery via presence is available.
+ * <p>
+ * See RCC.07 v5.0 specification for more information.
+ * @hide
+ */
+ public static final String SERVICE_ID_PRESENCE =
+ "org.3gpp.urn:urn-7:3gpp-application.ims.iari.rcse.dp";
+
/**
* The service ID used to indicate that MMTEL service is available.
* <p>
@@ -329,6 +345,13 @@
public @NonNull @DuplexMode List<String> getUnsupportedDuplexModes() {
return Collections.unmodifiableList(mUnsupportedDuplexModeList);
}
+
+ @Override
+ public String toString() {
+ return "servCaps{" + "a=" + mIsAudioCapable + ", v=" + mIsVideoCapable
+ + ", supported=" + mSupportedDuplexModeList + ", unsupported="
+ + mUnsupportedDuplexModeList + '}';
+ }
}
/**
@@ -353,7 +376,8 @@
}
/**
- * The optional SIP Contact URI associated with the PIDF tuple element.
+ * The optional SIP Contact URI associated with the PIDF tuple element if the network
+ * expects the user to use the URI instead of the contact URI to contact it.
*/
public @NonNull Builder setContactUri(@NonNull Uri contactUri) {
mPresenceTuple.mContactUri = contactUri;
@@ -365,7 +389,7 @@
* Per RFC3863 section 4.1.7, the timestamp is formatted as an IMPP datetime format
* string per RFC3339.
*/
- public @NonNull Builder setTimestamp(@NonNull String timestamp) {
+ public @NonNull Builder setTime(@NonNull Instant timestamp) {
mPresenceTuple.mTimestamp = timestamp;
return this;
}
@@ -397,7 +421,7 @@
}
private Uri mContactUri;
- private String mTimestamp;
+ private Instant mTimestamp;
private @BasicStatus String mStatus;
// The service information in the service-description element.
@@ -416,7 +440,7 @@
private RcsContactPresenceTuple(Parcel in) {
mContactUri = in.readParcelable(Uri.class.getClassLoader());
- mTimestamp = in.readString();
+ mTimestamp = convertStringFormatTimeToInstant(in.readString());
mStatus = in.readString();
mServiceId = in.readString();
mServiceVersion = in.readString();
@@ -427,7 +451,7 @@
@Override
public void writeToParcel(@NonNull Parcel out, int flags) {
out.writeParcelable(mContactUri, flags);
- out.writeString(mTimestamp);
+ out.writeString(convertInstantToStringFormat(mTimestamp));
out.writeString(mStatus);
out.writeString(mServiceId);
out.writeString(mServiceVersion);
@@ -453,6 +477,26 @@
}
};
+ // Convert the Instant to the string format
+ private String convertInstantToStringFormat(Instant instant) {
+ if (instant == null) {
+ return "";
+ }
+ return instant.toString();
+ }
+
+ // Convert the time string format to Instant
+ private @Nullable Instant convertStringFormatTimeToInstant(String timestamp) {
+ if (TextUtils.isEmpty(timestamp)) {
+ return null;
+ }
+ try {
+ return DateTimeFormatter.ISO_OFFSET_DATE_TIME.parse(timestamp, Instant::from);
+ } catch (DateTimeParseException e) {
+ return null;
+ }
+ }
+
/** @return the status of the tuple element. */
public @NonNull @BasicStatus String getStatus() {
return mStatus;
@@ -474,7 +518,7 @@
}
/** @return the timestamp element contained in the tuple if it exists */
- public @Nullable String getTimestamp() {
+ public @Nullable Instant getTime() {
return mTimestamp;
}
@@ -487,4 +531,36 @@
public @Nullable ServiceCapabilities getServiceCapabilities() {
return mServiceCapabilities;
}
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder("{");
+ if (Build.IS_ENG) {
+ builder.append("u=");
+ builder.append(mContactUri);
+ } else {
+ builder.append("u=");
+ builder.append(mContactUri != null ? "XXX" : "null");
+ }
+ builder.append(", id=");
+ builder.append(mServiceId);
+ builder.append(", v=");
+ builder.append(mServiceVersion);
+ builder.append(", s=");
+ builder.append(mStatus);
+ if (mTimestamp != null) {
+ builder.append(", timestamp=");
+ builder.append(mTimestamp);
+ }
+ if (mServiceDescription != null) {
+ builder.append(", servDesc=");
+ builder.append(mServiceDescription);
+ }
+ if (mServiceCapabilities != null) {
+ builder.append(", servCaps=");
+ builder.append(mServiceCapabilities);
+ }
+ builder.append("}");
+ return builder.toString();
+ }
}
diff --git a/telephony/java/android/telephony/ims/RcsContactUceCapability.java b/telephony/java/android/telephony/ims/RcsContactUceCapability.java
index fe85502..a133ead 100644
--- a/telephony/java/android/telephony/ims/RcsContactUceCapability.java
+++ b/telephony/java/android/telephony/ims/RcsContactUceCapability.java
@@ -21,6 +21,7 @@
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.net.Uri;
+import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
@@ -28,7 +29,9 @@
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
/**
* Contains the User Capability Exchange capabilities corresponding to a contact's URI.
@@ -109,7 +112,6 @@
/**
* Builder to help construct {@link RcsContactUceCapability} instances when capabilities were
* queried through SIP OPTIONS.
- * @hide
*/
public static final class OptionsBuilder {
@@ -150,7 +152,7 @@
* @param tags the list of the supported feature tags
* @return this OptionBuilder
*/
- public @NonNull OptionsBuilder addFeatureTags(@NonNull List<String> tags) {
+ public @NonNull OptionsBuilder addFeatureTags(@NonNull Set<String> tags) {
mCapabilities.mFeatureTags.addAll(tags);
return this;
}
@@ -219,7 +221,7 @@
private @CapabilityMechanism int mCapabilityMechanism;
private @RequestResult int mRequestResult;
- private final List<String> mFeatureTags = new ArrayList<>();
+ private final Set<String> mFeatureTags = new HashSet<>();
private final List<RcsContactPresenceTuple> mPresenceTuples = new ArrayList<>();
private RcsContactUceCapability(@NonNull Uri contactUri, @CapabilityMechanism int mechanism,
@@ -234,7 +236,9 @@
mCapabilityMechanism = in.readInt();
mSourceType = in.readInt();
mRequestResult = in.readInt();
- in.readStringList(mFeatureTags);
+ List<String> featureTagList = new ArrayList<>();
+ in.readStringList(featureTagList);
+ mFeatureTags.addAll(featureTagList);
in.readParcelableList(mPresenceTuples, RcsContactPresenceTuple.class.getClassLoader());
}
@@ -244,7 +248,7 @@
out.writeInt(mCapabilityMechanism);
out.writeInt(mSourceType);
out.writeInt(mRequestResult);
- out.writeStringList(mFeatureTags);
+ out.writeStringList(new ArrayList<>(mFeatureTags));
out.writeParcelableList(mPresenceTuples, flags);
}
@@ -284,7 +288,20 @@
if (mCapabilityMechanism != CAPABILITY_MECHANISM_OPTIONS) {
return Collections.emptyList();
}
- return Collections.unmodifiableList(mFeatureTags);
+ return Collections.unmodifiableList(new ArrayList<>(mFeatureTags));
+ }
+
+ /**
+ * @return The feature tags present in the OPTIONS response from the network.
+ * <p>
+ * Note: this is only populated if {@link #getCapabilityMechanism} is
+ * {@link RcsContactUceCapability#CAPABILITY_MECHANISM_OPTIONS}
+ */
+ public @NonNull Set<String> getFeatureTags() {
+ if (mCapabilityMechanism != CAPABILITY_MECHANISM_OPTIONS) {
+ return Collections.emptySet();
+ }
+ return Collections.unmodifiableSet(mFeatureTags);
}
/**
@@ -339,9 +356,45 @@
}
/**
+ * Retrieve the contact URI requested by the applications.
* @return the URI representing the contact associated with the capabilities.
*/
public @NonNull Uri getContactUri() {
return mContactUri;
}
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder("RcsContactUceCapability");
+ if (mCapabilityMechanism == CAPABILITY_MECHANISM_PRESENCE) {
+ builder.append("(presence) {");
+ } else if (mCapabilityMechanism == CAPABILITY_MECHANISM_OPTIONS) {
+ builder.append("(options) {");
+ } else {
+ builder.append("(?) {");
+ }
+ if (Build.IS_ENG) {
+ builder.append("uri=");
+ builder.append(mContactUri);
+ } else {
+ builder.append("uri (isNull)=");
+ builder.append(mContactUri != null ? "XXX" : "null");
+ }
+ builder.append(", sourceType=");
+ builder.append(mSourceType);
+ builder.append(", requestResult=");
+ builder.append(mRequestResult);
+
+ if (mCapabilityMechanism == CAPABILITY_MECHANISM_PRESENCE) {
+ builder.append(", presenceTuples={");
+ builder.append(mPresenceTuples);
+ builder.append("}");
+ } else if (mCapabilityMechanism == CAPABILITY_MECHANISM_OPTIONS) {
+ builder.append(", featureTags={");
+ builder.append(mFeatureTags);
+ builder.append("}");
+ }
+
+ return builder.toString();
+ }
}
diff --git a/telephony/java/android/telephony/ims/RcsUceAdapter.java b/telephony/java/android/telephony/ims/RcsUceAdapter.java
index ce8bd7d..dd91026 100644
--- a/telephony/java/android/telephony/ims/RcsUceAdapter.java
+++ b/telephony/java/android/telephony/ims/RcsUceAdapter.java
@@ -36,6 +36,8 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -430,7 +432,8 @@
/**
* The pending request has completed successfully due to all requested contacts information
- * being delivered.
+ * being delivered. The callback {@link #onCapabilitiesReceived(List)}
+ * for each contacts is required to be called before {@link #onComplete} is called.
*/
void onComplete();
@@ -486,7 +489,7 @@
@SystemApi
@RequiresPermission(allOf = {Manifest.permission.ACCESS_RCS_USER_CAPABILITY_EXCHANGE,
Manifest.permission.READ_CONTACTS})
- public void requestCapabilities(@NonNull List<Uri> contactNumbers,
+ public void requestCapabilities(@NonNull Collection<Uri> contactNumbers,
@NonNull @CallbackExecutor Executor executor,
@NonNull CapabilitiesCallback c) throws ImsException {
if (c == null) {
@@ -538,7 +541,7 @@
try {
imsRcsController.requestCapabilities(mSubId, mContext.getOpPackageName(),
- mContext.getAttributionTag(), contactNumbers, internalCallback);
+ mContext.getAttributionTag(), new ArrayList(contactNumbers), internalCallback);
} catch (ServiceSpecificException e) {
throw new ImsException(e.toString(), e.errorCode);
} catch (RemoteException e) {
@@ -569,6 +572,10 @@
* {@link CapabilitiesCallback} is called.
* @param c A one-time callback for when the request for capabilities completes or there is
* an error processing the request.
+ * @throws ImsException if the subscription associated with this instance of
+ * {@link RcsUceAdapter} is valid, but the ImsService associated with the subscription is not
+ * available. This can happen if the ImsService has crashed, for example, or if the subscription
+ * becomes inactive. See {@link ImsException#getCode()} for more information on the error codes.
* @hide
*/
@SystemApi
diff --git a/telephony/java/android/telephony/ims/aidl/CapabilityExchangeAidlWrapper.java b/telephony/java/android/telephony/ims/aidl/CapabilityExchangeAidlWrapper.java
index a217d13..c3d7325 100644
--- a/telephony/java/android/telephony/ims/aidl/CapabilityExchangeAidlWrapper.java
+++ b/telephony/java/android/telephony/ims/aidl/CapabilityExchangeAidlWrapper.java
@@ -26,7 +26,8 @@
import android.telephony.ims.stub.CapabilityExchangeEventListener;
import android.util.Log;
-import java.util.List;
+import java.util.ArrayList;
+import java.util.Set;
/**
* The ICapabilityExchangeEventListener wrapper class to store the listener which is registered by
@@ -84,7 +85,7 @@
* request to the framework.
*/
public void onRemoteCapabilityRequest(@NonNull Uri contactUri,
- @NonNull List<String> remoteCapabilities, @NonNull OptionsRequestCallback callback)
+ @NonNull Set<String> remoteCapabilities, @NonNull OptionsRequestCallback callback)
throws ImsException {
ICapabilityExchangeEventListener listener = mListenerBinder;
if (listener == null) {
@@ -114,7 +115,8 @@
};
try {
- listener.onRemoteCapabilityRequest(contactUri, remoteCapabilities, internalCallback);
+ listener.onRemoteCapabilityRequest(contactUri, new ArrayList<>(remoteCapabilities),
+ internalCallback);
} catch (RemoteException e) {
Log.w(LOG_TAG, "Remote capability request exception: " + e);
throw new ImsException("Remote is not available",
diff --git a/telephony/java/android/telephony/ims/aidl/IRcsConfigCallback.aidl b/telephony/java/android/telephony/ims/aidl/IRcsConfigCallback.aidl
index 5a8973e..d0853d1 100644
--- a/telephony/java/android/telephony/ims/aidl/IRcsConfigCallback.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IRcsConfigCallback.aidl
@@ -25,5 +25,6 @@
void onAutoConfigurationErrorReceived(int errorCode, String errorString);
void onConfigurationReset();
void onRemoved();
+ void onPreProvisioningReceived(in byte[] config);
}
diff --git a/telephony/java/android/telephony/ims/feature/RcsFeature.java b/telephony/java/android/telephony/ims/feature/RcsFeature.java
index 85703f8..6315b24 100644
--- a/telephony/java/android/telephony/ims/feature/RcsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/RcsFeature.java
@@ -47,6 +47,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.HashSet;
import java.util.List;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletableFuture;
@@ -145,8 +146,8 @@
throws RemoteException {
OptionsResponseCallback callbackWrapper = new RcsOptionsResponseAidlWrapper(callback);
executeMethodAsync(() -> mReference.getCapabilityExchangeImplBaseInternal()
- .sendOptionsCapabilityRequest(contactUri, myCapabilities, callbackWrapper),
- "sendOptionsCapabilityRequest");
+ .sendOptionsCapabilityRequest(contactUri, new HashSet<>(myCapabilities),
+ callbackWrapper), "sendOptionsCapabilityRequest");
}
// Call the methods with a clean calling identity on the executor and wait indefinitely for
diff --git a/telephony/java/android/telephony/ims/stub/CapabilityExchangeEventListener.java b/telephony/java/android/telephony/ims/stub/CapabilityExchangeEventListener.java
index 6295548..a3be8da 100644
--- a/telephony/java/android/telephony/ims/stub/CapabilityExchangeEventListener.java
+++ b/telephony/java/android/telephony/ims/stub/CapabilityExchangeEventListener.java
@@ -26,7 +26,7 @@
import android.telephony.ims.feature.ImsFeature;
import android.telephony.ims.feature.RcsFeature;
-import java.util.List;
+import java.util.Set;
/**
* The interface that is used by the framework to listen to events from the vendor RCS stack
@@ -98,7 +98,8 @@
* {@link OptionsRequestCallback#onRespondToCapabilityRequestWithError}.
* @param contactUri The URI associated with the remote contact that is
* requesting capabilities.
- * @param remoteCapabilities The remote contact's capability information.
+ * @param remoteCapabilities The remote contact's capability information. The capability
+ * information is in the format defined in RCC.07 section 2.6.1.3.
* @param callback The callback of this request which is sent from the remote user.
* @throws ImsException If this {@link RcsCapabilityExchangeImplBase} instance is not
* currently connected to the framework. This can happen if the {@link RcsFeature} is not
@@ -107,6 +108,6 @@
* cases when the Telephony stack has crashed.
*/
void onRemoteCapabilityRequest(@NonNull Uri contactUri,
- @NonNull List<String> remoteCapabilities,
+ @NonNull Set<String> remoteCapabilities,
@NonNull OptionsRequestCallback callback) throws ImsException;
}
diff --git a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
index 34984e0..4dcb7f5 100644
--- a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
@@ -542,11 +542,34 @@
}
mRcsCallbacks.broadcastAction(c -> {
try {
- //TODO compressed by default?
c.onAutoConfigurationErrorReceived(errorCode, errorString);
} catch (RemoteException e) {
Log.w(TAG, "dead binder in notifyAutoConfigurationErrorReceived, skipping.");
}
});
}
+
+ /**
+ * Notifies application that pre-provisioning config is received.
+ *
+ * <p>Some carriers using ACS (auto configuration server) may send a carrier-specific
+ * pre-provisioning configuration XML if the user has not been provisioned for RCS
+ * services yet. When such provisioning XML is received, ACS client must call this
+ * method to notify the application with the XML.
+ *
+ * @param configXml the pre-provisioning config in carrier specified format.
+ */
+ public final void notifyPreProvisioningReceived(@NonNull byte[] configXml) {
+ // can be null in testing
+ if (mRcsCallbacks == null) {
+ return;
+ }
+ mRcsCallbacks.broadcastAction(c -> {
+ try {
+ c.onPreProvisioningReceived(configXml);
+ } catch (RemoteException e) {
+ Log.w(TAG, "dead binder in notifyPreProvisioningReceived, skipping.");
+ }
+ });
+ }
}
diff --git a/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java
index 908869b..25b9446 100644
--- a/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java
@@ -31,7 +31,9 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.Collection;
import java.util.List;
+import java.util.Set;
import java.util.concurrent.Executor;
/**
@@ -241,7 +243,7 @@
/**
* Notify the framework of the response to the SUBSCRIBE request from
- * {@link #subscribeForCapabilities(List, SubscribeResponseCallback)}.
+ * {@link #subscribeForCapabilities(Collection, SubscribeResponseCallback)}.
* <p>
* If the carrier network responds to the SUBSCRIBE request with a 2XX response, then the
* framework will expect the IMS stack to call {@link #onNotifyCapabilitiesUpdate},
@@ -266,7 +268,7 @@
/**
* Notify the framework of the response to the SUBSCRIBE request from
- * {@link #subscribeForCapabilities(List, SubscribeResponseCallback)} that also
+ * {@link #subscribeForCapabilities(Collection, SubscribeResponseCallback)} that also
* includes a reason provided in the “reason” header. See RFC3326 for more
* information.
*
@@ -385,13 +387,13 @@
* {@link SubscribeResponseCallback#onTerminated(String, long)} must be called for the
* framework to finish listening for NOTIFY responses.
*
- * @param uris A {@link List} of the {@link Uri}s that the framework is requesting the UCE
- * capabilities for.
+ * @param uris A {@link Collection} of the {@link Uri}s that the framework is requesting the
+ * UCE capabilities for.
* @param cb The callback of the subscribe request.
*/
// executor used is defined in the constructor.
@SuppressLint("ExecutorRegistration")
- public void subscribeForCapabilities(@NonNull List<Uri> uris,
+ public void subscribeForCapabilities(@NonNull Collection<Uri> uris,
@NonNull SubscribeResponseCallback cb) {
// Stub - to be implemented by service
Log.w(LOG_TAG, "subscribeForCapabilities called with no implementation.");
@@ -432,6 +434,7 @@
* @param contactUri The URI of the remote user that we wish to get the capabilities of.
* @param myCapabilities The capabilities of this device to send to the remote user.
* @param callback The callback of this request which is sent from the remote user.
+ * @hide
*/
// executor used is defined in the constructor.
@SuppressLint("ExecutorRegistration")
@@ -445,4 +448,27 @@
// Do not do anything, this is a stub implementation.
}
}
+
+ /**
+ * Push one's own capabilities to a remote user via the SIP OPTIONS presence exchange mechanism
+ * in order to receive the capabilities of the remote user in response.
+ * <p>
+ * The implementer must use {@link OptionsResponseCallback} to send the response of
+ * this query from the network back to the framework.
+ * @param contactUri The URI of the remote user that we wish to get the capabilities of.
+ * @param myCapabilities The capabilities of this device to send to the remote user.
+ * @param callback The callback of this request which is sent from the remote user.
+ */
+ // executor used is defined in the constructor.
+ @SuppressLint("ExecutorRegistration")
+ public void sendOptionsCapabilityRequest(@NonNull Uri contactUri,
+ @NonNull Set<String> myCapabilities, @NonNull OptionsResponseCallback callback) {
+ // Stub - to be implemented by service
+ Log.w(LOG_TAG, "sendOptionsCapabilityRequest called with no implementation.");
+ try {
+ callback.onCommandError(COMMAND_CODE_NOT_SUPPORTED);
+ } catch (ImsException e) {
+ // Do not do anything, this is a stub implementation.
+ }
+ }
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index f74484b..97078c3 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -31,7 +31,6 @@
import android.telecom.PhoneAccount;
import android.telecom.PhoneAccountHandle;
import android.telephony.CallForwardingInfo;
-import android.telephony.CarrierBandwidth;
import android.telephony.CarrierRestrictionRules;
import android.telephony.CellIdentity;
import android.telephony.CellInfo;
@@ -54,6 +53,7 @@
import android.telephony.VisualVoicemailSmsFilterSettings;
import android.telephony.emergency.EmergencyNumber;
import android.telephony.ims.RcsClientConfiguration;
+import android.telephony.ims.RcsContactUceCapability;
import android.telephony.ims.aidl.IImsCapabilityCallback;
import android.telephony.ims.aidl.IImsConfig;
import android.telephony.ims.aidl.IImsConfigCallback;
@@ -2219,12 +2219,6 @@
boolean isNrDualConnectivityEnabled(int subId);
/**
- * Get carrier bandwidth per primary and secondary carrier
- * @return CarrierBandwidth with bandwidth of both primary and secondary carrier.
- */
- CarrierBandwidth getCarrierBandwidth(int subId);
-
- /**
* Checks whether the device supports the given capability on the radio interface.
*
* @param capability the name of the capability
@@ -2237,10 +2231,12 @@
*
* @param subId the id of the subscription
* @param thermalMitigationRequest holds the parameters necessary for the request.
+ * @param callingPackage the package name of the calling package.
* @throws InvalidThermalMitigationRequestException if the parametes are invalid.
*/
int sendThermalMitigationRequest(int subId,
- in ThermalMitigationRequest thermalMitigationRequest);
+ in ThermalMitigationRequest thermalMitigationRequest,
+ String callingPackage);
/**
* Get the Generic Bootstrapping Architecture authentication keys
@@ -2331,6 +2327,16 @@
boolean getCarrierSingleRegistrationEnabled(int subId);
/**
+ * Overrides the ims feature validation result
+ */
+ boolean setImsFeatureValidationOverride(int subId, String enabled);
+
+ /**
+ * Gets the ims feature validation override value
+ */
+ boolean getImsFeatureValidationOverride(int subId);
+
+ /**
* Return the mobile provisioning url that is used to launch a browser to allow users to manage
* their mobile plan.
*/
@@ -2357,6 +2363,41 @@
void setDeviceUceEnabled(boolean isEnabled);
/**
+ * Add feature tags to the IMS registration being tracked by UCE and potentially
+ * generate a new PUBLISH to the network.
+ * Note: This is designed for a SHELL command only.
+ */
+ RcsContactUceCapability addUceRegistrationOverrideShell(int subId, in List<String> featureTags);
+
+ /**
+ * Remove feature tags from the IMS registration being tracked by UCE and potentially
+ * generate a new PUBLISH to the network.
+ * Note: This is designed for a SHELL command only.
+ */
+ RcsContactUceCapability removeUceRegistrationOverrideShell(int subId,
+ in List<String> featureTags);
+
+ /**
+ * Clear overridden feature tags in the IMS registration being tracked by UCE and potentially
+ * generate a new PUBLISH to the network.
+ * Note: This is designed for a SHELL command only.
+ */
+ RcsContactUceCapability clearUceRegistrationOverrideShell(int subId);
+
+ /**
+ * Get the latest RcsContactUceCapability structure that is used in SIP PUBLISH procedures.
+ * Note: This is designed for a SHELL command only.
+ */
+ RcsContactUceCapability getLatestRcsContactUceCapabilityShell(int subId);
+
+ /**
+ * Returns the last PIDF XML sent to the network during the last PUBLISH or "none" if the
+ * device does not have an active PUBLISH.
+ * Note: This is designed for a SHELL command only.
+ */
+ String getLastUcePidfXmlShell(int subId);
+
+ /**
* Set a SignalStrengthUpdateRequest to receive notification when Signal Strength breach the
* specified thresholds.
*/
diff --git a/tests/net/Android.bp b/tests/net/Android.bp
index 8122495..e1a424f 100644
--- a/tests/net/Android.bp
+++ b/tests/net/Android.bp
@@ -70,7 +70,7 @@
"mockito-target-minus-junit4",
"net-tests-utils",
"platform-test-annotations",
- "service-connectivity",
+ "service-connectivity-pre-jarjar",
"services.core",
"services.net",
],
@@ -79,6 +79,7 @@
"android.test.runner",
"android.test.base",
"android.test.mock",
+ "ServiceConnectivityResources",
],
jni_libs: [
"libservice-connectivity",
diff --git a/tests/net/TEST_MAPPING b/tests/net/TEST_MAPPING
index 89fc6ea..d659688 100644
--- a/tests/net/TEST_MAPPING
+++ b/tests/net/TEST_MAPPING
@@ -9,6 +9,23 @@
"name": "FrameworksNetDeflakeTest"
}
],
+ "auto-postsubmit": [
+ // Test tag for automotive targets. These are only running in postsubmit so as to harden the
+ // automotive targets to avoid introducing additional test flake and build time. The plan for
+ // presubmit testing for auto is to augment the existing tests to cover auto use cases as well.
+ // Additionally, this tag is used in targeted test suites to limit resource usage on the test
+ // infra during the hardening phase.
+ // TODO: this tag to be removed once the above is no longer an issue.
+ {
+ "name": "FrameworksNetTests"
+ },
+ {
+ "name": "FrameworksNetIntegrationTests"
+ },
+ {
+ "name": "FrameworksNetDeflakeTest"
+ }
+ ],
"imports": [
{
"path": "cts/tests/tests/net"
diff --git a/tests/net/common/java/android/net/IpPrefixTest.java b/tests/net/common/java/android/net/IpPrefixTest.java
index 9c0fc7c..50ecb42 100644
--- a/tests/net/common/java/android/net/IpPrefixTest.java
+++ b/tests/net/common/java/android/net/IpPrefixTest.java
@@ -113,6 +113,15 @@
p = new IpPrefix("f00:::/32");
fail("Expected IllegalArgumentException: invalid IPv6 address");
} catch (IllegalArgumentException expected) { }
+
+ p = new IpPrefix("/64");
+ assertEquals("::/64", p.toString());
+
+ p = new IpPrefix("/128");
+ assertEquals("::1/128", p.toString());
+
+ p = new IpPrefix("[2001:db8::123]/64");
+ assertEquals("2001:db8::/64", p.toString());
}
@Test
diff --git a/tests/net/common/java/android/net/LinkAddressTest.java b/tests/net/common/java/android/net/LinkAddressTest.java
index 1eaf30c..2cf3cf9 100644
--- a/tests/net/common/java/android/net/LinkAddressTest.java
+++ b/tests/net/common/java/android/net/LinkAddressTest.java
@@ -53,6 +53,7 @@
import org.junit.runner.RunWith;
import java.net.Inet4Address;
+import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InterfaceAddress;
import java.net.NetworkInterface;
@@ -117,6 +118,20 @@
assertEquals(456, address.getScope());
assertTrue(address.isIpv4());
+ address = new LinkAddress("/64", 1 /* flags */, 2 /* scope */);
+ assertEquals(Inet6Address.LOOPBACK, address.getAddress());
+ assertEquals(64, address.getPrefixLength());
+ assertEquals(1, address.getFlags());
+ assertEquals(2, address.getScope());
+ assertTrue(address.isIpv6());
+
+ address = new LinkAddress("[2001:db8::123]/64", 3 /* flags */, 4 /* scope */);
+ assertEquals(InetAddresses.parseNumericAddress("2001:db8::123"), address.getAddress());
+ assertEquals(64, address.getPrefixLength());
+ assertEquals(3, address.getFlags());
+ assertEquals(4, address.getScope());
+ assertTrue(address.isIpv6());
+
// InterfaceAddress doesn't have a constructor. Fetch some from an interface.
List<InterfaceAddress> addrs = NetworkInterface.getByName("lo").getInterfaceAddresses();
diff --git a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
index 5d0e016..1f50e31 100644
--- a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
@@ -28,12 +28,16 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PAID;
import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE;
import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY;
import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_WIFI_P2P;
+import static android.net.NetworkCapabilities.REDACT_FOR_ACCESS_FINE_LOCATION;
+import static android.net.NetworkCapabilities.REDACT_FOR_LOCAL_MAC_ADDRESS;
+import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS;
import static android.net.NetworkCapabilities.RESTRICTED_CAPABILITIES;
import static android.net.NetworkCapabilities.SIGNAL_STRENGTH_UNSPECIFIED;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
@@ -44,9 +48,12 @@
import static android.net.NetworkCapabilities.UNRESTRICTED_CAPABILITIES;
import static android.os.Process.INVALID_UID;
+import static com.android.modules.utils.build.SdkLevel.isAtLeastR;
+import static com.android.modules.utils.build.SdkLevel.isAtLeastS;
+import static com.android.testutils.MiscAsserts.assertEmpty;
+import static com.android.testutils.MiscAsserts.assertThrows;
import static com.android.testutils.ParcelUtils.assertParcelSane;
import static com.android.testutils.ParcelUtils.assertParcelingIsLossless;
-import static com.android.testutils.ParcelUtils.parcelingRoundTrip;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
@@ -57,17 +64,17 @@
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeTrue;
-import android.net.wifi.WifiInfo;
import android.net.wifi.aware.DiscoverySession;
import android.net.wifi.aware.PeerHandle;
import android.net.wifi.aware.WifiAwareNetworkSpecifier;
import android.os.Build;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.ArraySet;
+import android.util.Range;
import androidx.test.runner.AndroidJUnit4;
-import com.android.modules.utils.build.SdkLevel;
+import com.android.testutils.CompatUtil;
import com.android.testutils.DevSdkIgnoreRule;
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
@@ -84,6 +91,9 @@
public class NetworkCapabilitiesTest {
private static final String TEST_SSID = "TEST_SSID";
private static final String DIFFERENT_TEST_SSID = "DIFFERENT_TEST_SSID";
+ private static final int TEST_SUBID1 = 1;
+ private static final int TEST_SUBID2 = 2;
+ private static final int TEST_SUBID3 = 3;
@Rule
public DevSdkIgnoreRule mDevSdkIgnoreRule = new DevSdkIgnoreRule();
@@ -91,14 +101,6 @@
private DiscoverySession mDiscoverySession = Mockito.mock(DiscoverySession.class);
private PeerHandle mPeerHandle = Mockito.mock(PeerHandle.class);
- private boolean isAtLeastR() {
- return SdkLevel.isAtLeastR();
- }
-
- private boolean isAtLeastS() {
- return SdkLevel.isAtLeastS();
- }
-
@Test
public void testMaybeMarkCapabilitiesRestricted() {
// verify EIMS is restricted
@@ -211,7 +213,7 @@
nc1 = new NetworkCapabilities().addTransportType(TRANSPORT_WIFI);
nc2 = new NetworkCapabilities()
.addTransportType(TRANSPORT_WIFI)
- .setNetworkSpecifier(new StringNetworkSpecifier("specs"));
+ .setNetworkSpecifier(CompatUtil.makeEthernetNetworkSpecifier("eth42"));
assertNotEquals("", nc1.describeImmutableDifferences(nc2));
assertEquals("", nc1.describeImmutableDifferences(nc1));
}
@@ -240,70 +242,94 @@
@Test
public void testSetUids() {
final NetworkCapabilities netCap = new NetworkCapabilities();
- final Set<UidRange> uids = new ArraySet<>();
- uids.add(new UidRange(50, 100));
- uids.add(new UidRange(3000, 4000));
- netCap.setUids(uids);
- assertTrue(netCap.appliesToUid(50));
- assertTrue(netCap.appliesToUid(80));
- assertTrue(netCap.appliesToUid(100));
+ // Null uids match all UIDs
+ netCap.setUids(null);
+ assertTrue(netCap.appliesToUid(10));
+ assertTrue(netCap.appliesToUid(200));
assertTrue(netCap.appliesToUid(3000));
- assertTrue(netCap.appliesToUid(3001));
- assertFalse(netCap.appliesToUid(10));
- assertFalse(netCap.appliesToUid(25));
- assertFalse(netCap.appliesToUid(49));
- assertFalse(netCap.appliesToUid(101));
- assertFalse(netCap.appliesToUid(2000));
- assertFalse(netCap.appliesToUid(100000));
-
+ assertTrue(netCap.appliesToUid(10010));
assertTrue(netCap.appliesToUidRange(new UidRange(50, 100)));
assertTrue(netCap.appliesToUidRange(new UidRange(70, 72)));
assertTrue(netCap.appliesToUidRange(new UidRange(3500, 3912)));
- assertFalse(netCap.appliesToUidRange(new UidRange(1, 100)));
- assertFalse(netCap.appliesToUidRange(new UidRange(49, 100)));
- assertFalse(netCap.appliesToUidRange(new UidRange(1, 10)));
- assertFalse(netCap.appliesToUidRange(new UidRange(60, 101)));
- assertFalse(netCap.appliesToUidRange(new UidRange(60, 3400)));
-
- NetworkCapabilities netCap2 = new NetworkCapabilities();
- // A new netcap object has null UIDs, so anything will satisfy it.
- assertTrue(netCap2.satisfiedByUids(netCap));
- // Still not equal though.
- assertFalse(netCap2.equalsUids(netCap));
- netCap2.setUids(uids);
- assertTrue(netCap2.satisfiedByUids(netCap));
- assertTrue(netCap.equalsUids(netCap2));
- assertTrue(netCap2.equalsUids(netCap));
-
- uids.add(new UidRange(600, 700));
- netCap2.setUids(uids);
- assertFalse(netCap2.satisfiedByUids(netCap));
- assertFalse(netCap.appliesToUid(650));
- assertTrue(netCap2.appliesToUid(650));
- netCap.combineCapabilities(netCap2);
- assertTrue(netCap2.satisfiedByUids(netCap));
- assertTrue(netCap.appliesToUid(650));
- assertFalse(netCap.appliesToUid(500));
-
- assertTrue(new NetworkCapabilities().satisfiedByUids(netCap));
- netCap.combineCapabilities(new NetworkCapabilities());
- assertTrue(netCap.appliesToUid(500));
assertTrue(netCap.appliesToUidRange(new UidRange(1, 100000)));
- assertFalse(netCap2.appliesToUid(500));
- assertFalse(netCap2.appliesToUidRange(new UidRange(1, 100000)));
- assertTrue(new NetworkCapabilities().satisfiedByUids(netCap));
+
+ if (isAtLeastS()) {
+ final Set<Range<Integer>> uids = new ArraySet<>();
+ uids.add(uidRange(50, 100));
+ uids.add(uidRange(3000, 4000));
+ netCap.setUids(uids);
+ assertTrue(netCap.appliesToUid(50));
+ assertTrue(netCap.appliesToUid(80));
+ assertTrue(netCap.appliesToUid(100));
+ assertTrue(netCap.appliesToUid(3000));
+ assertTrue(netCap.appliesToUid(3001));
+ assertFalse(netCap.appliesToUid(10));
+ assertFalse(netCap.appliesToUid(25));
+ assertFalse(netCap.appliesToUid(49));
+ assertFalse(netCap.appliesToUid(101));
+ assertFalse(netCap.appliesToUid(2000));
+ assertFalse(netCap.appliesToUid(100000));
+
+ assertTrue(netCap.appliesToUidRange(new UidRange(50, 100)));
+ assertTrue(netCap.appliesToUidRange(new UidRange(70, 72)));
+ assertTrue(netCap.appliesToUidRange(new UidRange(3500, 3912)));
+ assertFalse(netCap.appliesToUidRange(new UidRange(1, 100)));
+ assertFalse(netCap.appliesToUidRange(new UidRange(49, 100)));
+ assertFalse(netCap.appliesToUidRange(new UidRange(1, 10)));
+ assertFalse(netCap.appliesToUidRange(new UidRange(60, 101)));
+ assertFalse(netCap.appliesToUidRange(new UidRange(60, 3400)));
+
+ NetworkCapabilities netCap2 = new NetworkCapabilities();
+ // A new netcap object has null UIDs, so anything will satisfy it.
+ assertTrue(netCap2.satisfiedByUids(netCap));
+ // Still not equal though.
+ assertFalse(netCap2.equalsUids(netCap));
+ netCap2.setUids(uids);
+ assertTrue(netCap2.satisfiedByUids(netCap));
+ assertTrue(netCap.equalsUids(netCap2));
+ assertTrue(netCap2.equalsUids(netCap));
+
+ uids.add(uidRange(600, 700));
+ netCap2.setUids(uids);
+ assertFalse(netCap2.satisfiedByUids(netCap));
+ assertFalse(netCap.appliesToUid(650));
+ assertTrue(netCap2.appliesToUid(650));
+ netCap.combineCapabilities(netCap2);
+ assertTrue(netCap2.satisfiedByUids(netCap));
+ assertTrue(netCap.appliesToUid(650));
+ assertFalse(netCap.appliesToUid(500));
+
+ assertTrue(new NetworkCapabilities().satisfiedByUids(netCap));
+ netCap.combineCapabilities(new NetworkCapabilities());
+ assertTrue(netCap.appliesToUid(500));
+ assertTrue(netCap.appliesToUidRange(new UidRange(1, 100000)));
+ assertFalse(netCap2.appliesToUid(500));
+ assertFalse(netCap2.appliesToUidRange(new UidRange(1, 100000)));
+ assertTrue(new NetworkCapabilities().satisfiedByUids(netCap));
+
+ // Null uids satisfies everything.
+ netCap.setUids(null);
+ assertTrue(netCap2.satisfiedByUids(netCap));
+ assertTrue(netCap.satisfiedByUids(netCap2));
+ netCap2.setUids(null);
+ assertTrue(netCap2.satisfiedByUids(netCap));
+ assertTrue(netCap.satisfiedByUids(netCap2));
+ }
}
@Test
public void testParcelNetworkCapabilities() {
- final Set<UidRange> uids = new ArraySet<>();
- uids.add(new UidRange(50, 100));
- uids.add(new UidRange(3000, 4000));
+ final Set<Range<Integer>> uids = new ArraySet<>();
+ uids.add(uidRange(50, 100));
+ uids.add(uidRange(3000, 4000));
final NetworkCapabilities netCap = new NetworkCapabilities()
.addCapability(NET_CAPABILITY_INTERNET)
- .setUids(uids)
.addCapability(NET_CAPABILITY_EIMS)
.addCapability(NET_CAPABILITY_NOT_METERED);
+ if (isAtLeastS()) {
+ netCap.setSubIds(Set.of(TEST_SUBID1, TEST_SUBID2));
+ netCap.setUids(uids);
+ }
if (isAtLeastR()) {
netCap.setOwnerUid(123);
netCap.setAdministratorUids(new int[] {5, 11});
@@ -328,58 +354,9 @@
testParcelSane(netCap);
}
- private NetworkCapabilities createNetworkCapabilitiesWithWifiInfo() {
- // uses a real WifiInfo to test parceling of sensitive data.
- final WifiInfo wifiInfo = new WifiInfo.Builder()
- .setSsid("sssid1234".getBytes())
- .setBssid("00:11:22:33:44:55")
- .build();
- return new NetworkCapabilities()
- .addCapability(NET_CAPABILITY_INTERNET)
- .addCapability(NET_CAPABILITY_EIMS)
- .addCapability(NET_CAPABILITY_NOT_METERED)
- .setSSID(TEST_SSID)
- .setTransportInfo(wifiInfo)
- .setRequestorPackageName("com.android.test")
- .setRequestorUid(9304);
- }
-
- @Test
- public void testParcelNetworkCapabilitiesWithLocationSensitiveFields() {
- assumeTrue(isAtLeastS());
-
- final NetworkCapabilities netCap = createNetworkCapabilitiesWithWifiInfo();
- final NetworkCapabilities netCapWithLocationSensitiveFields =
- new NetworkCapabilities(netCap, true);
-
- assertParcelingIsLossless(netCapWithLocationSensitiveFields);
- testParcelSane(netCapWithLocationSensitiveFields);
-
- assertEquals(netCapWithLocationSensitiveFields,
- parcelingRoundTrip(netCapWithLocationSensitiveFields));
- }
-
- @Test
- public void testParcelNetworkCapabilitiesWithoutLocationSensitiveFields() {
- assumeTrue(isAtLeastS());
-
- final NetworkCapabilities netCap = createNetworkCapabilitiesWithWifiInfo();
- final NetworkCapabilities netCapWithoutLocationSensitiveFields =
- new NetworkCapabilities(netCap, false);
-
- final NetworkCapabilities sanitizedNetCap =
- new NetworkCapabilities(netCapWithoutLocationSensitiveFields);
- final WifiInfo sanitizedWifiInfo = new WifiInfo.Builder()
- .setSsid(new byte[0])
- .setBssid(WifiInfo.DEFAULT_MAC_ADDRESS)
- .build();
- sanitizedNetCap.setTransportInfo(sanitizedWifiInfo);
- assertEquals(sanitizedNetCap, parcelingRoundTrip(netCapWithoutLocationSensitiveFields));
- }
-
private void testParcelSane(NetworkCapabilities cap) {
if (isAtLeastS()) {
- assertParcelSane(cap, 16);
+ assertParcelSane(cap, 17);
} else if (isAtLeastR()) {
assertParcelSane(cap, 15);
} else {
@@ -387,6 +364,45 @@
}
}
+ private static NetworkCapabilities createNetworkCapabilitiesWithTransportInfo() {
+ return new NetworkCapabilities()
+ .addCapability(NET_CAPABILITY_INTERNET)
+ .addCapability(NET_CAPABILITY_EIMS)
+ .addCapability(NET_CAPABILITY_NOT_METERED)
+ .setSSID(TEST_SSID)
+ .setTransportInfo(new TestTransportInfo())
+ .setRequestorPackageName("com.android.test")
+ .setRequestorUid(9304);
+ }
+
+ @Test
+ public void testNetworkCapabilitiesCopyWithNoRedactions() {
+ assumeTrue(isAtLeastS());
+
+ final NetworkCapabilities netCap = createNetworkCapabilitiesWithTransportInfo();
+ final NetworkCapabilities netCapWithNoRedactions =
+ new NetworkCapabilities(netCap, NetworkCapabilities.REDACT_NONE);
+ TestTransportInfo testTransportInfo =
+ (TestTransportInfo) netCapWithNoRedactions.getTransportInfo();
+ assertFalse(testTransportInfo.locationRedacted);
+ assertFalse(testTransportInfo.localMacAddressRedacted);
+ assertFalse(testTransportInfo.settingsRedacted);
+ }
+
+ @Test
+ public void testNetworkCapabilitiesCopyWithoutLocationSensitiveFields() {
+ assumeTrue(isAtLeastS());
+
+ final NetworkCapabilities netCap = createNetworkCapabilitiesWithTransportInfo();
+ final NetworkCapabilities netCapWithNoRedactions =
+ new NetworkCapabilities(netCap, REDACT_FOR_ACCESS_FINE_LOCATION);
+ TestTransportInfo testTransportInfo =
+ (TestTransportInfo) netCapWithNoRedactions.getTransportInfo();
+ assertTrue(testTransportInfo.locationRedacted);
+ assertFalse(testTransportInfo.localMacAddressRedacted);
+ assertFalse(testTransportInfo.settingsRedacted);
+ }
+
@Test
public void testOemPaid() {
NetworkCapabilities nc = new NetworkCapabilities();
@@ -516,11 +532,22 @@
assertFalse(nc1.equalsNetCapabilities(nc2));
nc2.addUnwantedCapability(NET_CAPABILITY_INTERNET);
assertTrue(nc1.equalsNetCapabilities(nc2));
+ if (isAtLeastS()) {
+ // Remove a required capability doesn't affect unwanted capabilities.
+ // This is a behaviour change from S.
+ nc1.removeCapability(NET_CAPABILITY_INTERNET);
+ assertTrue(nc1.equalsNetCapabilities(nc2));
- nc1.removeCapability(NET_CAPABILITY_INTERNET);
- assertFalse(nc1.equalsNetCapabilities(nc2));
- nc2.removeCapability(NET_CAPABILITY_INTERNET);
- assertTrue(nc1.equalsNetCapabilities(nc2));
+ nc1.removeUnwantedCapability(NET_CAPABILITY_INTERNET);
+ assertFalse(nc1.equalsNetCapabilities(nc2));
+ nc2.removeUnwantedCapability(NET_CAPABILITY_INTERNET);
+ assertTrue(nc1.equalsNetCapabilities(nc2));
+ } else {
+ nc1.removeCapability(NET_CAPABILITY_INTERNET);
+ assertFalse(nc1.equalsNetCapabilities(nc2));
+ nc2.removeCapability(NET_CAPABILITY_INTERNET);
+ assertTrue(nc1.equalsNetCapabilities(nc2));
+ }
}
@Test
@@ -538,12 +565,16 @@
assertFalse(nc1.satisfiedByNetworkCapabilities(nc2));
}
- private ArraySet<UidRange> uidRange(int from, int to) {
- final ArraySet<UidRange> range = new ArraySet<>(1);
- range.add(new UidRange(from, to));
+ private ArraySet<Range<Integer>> uidRanges(int from, int to) {
+ final ArraySet<Range<Integer>> range = new ArraySet<>(1);
+ range.add(uidRange(from, to));
return range;
}
+ private Range<Integer> uidRange(int from, int to) {
+ return new Range<Integer>(from, to);
+ }
+
@Test @IgnoreUpTo(Build.VERSION_CODES.Q)
public void testSetAdministratorUids() {
NetworkCapabilities nc =
@@ -577,11 +608,21 @@
// This will effectively move NOT_ROAMING capability from required to unwanted for nc1.
nc1.addUnwantedCapability(NET_CAPABILITY_NOT_ROAMING);
- nc2.combineCapabilities(nc1);
- // We will get this capability in both requested and unwanted lists thus this request
- // will never be satisfied.
- assertTrue(nc2.hasCapability(NET_CAPABILITY_NOT_ROAMING));
- assertTrue(nc2.hasUnwantedCapability(NET_CAPABILITY_NOT_ROAMING));
+ if (isAtLeastS()) {
+ // From S, it is not allowed to have the same capability in both wanted and
+ // unwanted list.
+ assertThrows(IllegalArgumentException.class, () -> nc2.combineCapabilities(nc1));
+ // Remove unwanted capability to continue other tests.
+ nc1.removeUnwantedCapability(NET_CAPABILITY_NOT_ROAMING);
+ } else {
+ nc2.combineCapabilities(nc1);
+ // We will get this capability in both requested and unwanted lists thus this request
+ // will never be satisfied.
+ assertTrue(nc2.hasCapability(NET_CAPABILITY_NOT_ROAMING));
+ assertTrue(nc2.hasUnwantedCapability(NET_CAPABILITY_NOT_ROAMING));
+ // For R or below, remove unwanted capability via removeCapability.
+ nc1.removeCapability(NET_CAPABILITY_NOT_ROAMING);
+ }
nc1.setSSID(TEST_SSID);
nc2.combineCapabilities(nc1);
@@ -599,20 +640,34 @@
} catch (IllegalStateException expected) {}
nc1.setSSID(TEST_SSID);
- nc1.setUids(uidRange(10, 13));
- assertNotEquals(nc1, nc2);
- nc2.combineCapabilities(nc1); // Everything + 10~13 is still everything.
- assertNotEquals(nc1, nc2);
- nc1.combineCapabilities(nc2); // 10~13 + everything is everything.
- assertEquals(nc1, nc2);
- nc1.setUids(uidRange(10, 13));
- nc2.setUids(uidRange(20, 23));
- assertNotEquals(nc1, nc2);
- nc1.combineCapabilities(nc2);
- assertTrue(nc1.appliesToUid(12));
- assertFalse(nc2.appliesToUid(12));
- assertTrue(nc1.appliesToUid(22));
- assertTrue(nc2.appliesToUid(22));
+ if (isAtLeastS()) {
+ nc1.setUids(uidRanges(10, 13));
+ assertNotEquals(nc1, nc2);
+ nc2.combineCapabilities(nc1); // Everything + 10~13 is still everything.
+ assertNotEquals(nc1, nc2);
+ nc1.combineCapabilities(nc2); // 10~13 + everything is everything.
+ assertEquals(nc1, nc2);
+ nc1.setUids(uidRanges(10, 13));
+ nc2.setUids(uidRanges(20, 23));
+ assertNotEquals(nc1, nc2);
+ nc1.combineCapabilities(nc2);
+ assertTrue(nc1.appliesToUid(12));
+ assertFalse(nc2.appliesToUid(12));
+ assertTrue(nc1.appliesToUid(22));
+ assertTrue(nc2.appliesToUid(22));
+
+ // Verify the subscription id list can be combined only when they are equal.
+ nc1.setSubIds(Set.of(TEST_SUBID1, TEST_SUBID2));
+ nc2.setSubIds(Set.of(TEST_SUBID2));
+ assertThrows(IllegalStateException.class, () -> nc2.combineCapabilities(nc1));
+
+ nc2.setSubIds(Set.of());
+ assertThrows(IllegalStateException.class, () -> nc2.combineCapabilities(nc1));
+
+ nc2.setSubIds(Set.of(TEST_SUBID2, TEST_SUBID1));
+ nc2.combineCapabilities(nc1);
+ assertEquals(Set.of(TEST_SUBID2, TEST_SUBID1), nc2.getSubIds());
+ }
}
@Test @IgnoreUpTo(Build.VERSION_CODES.Q)
@@ -671,7 +726,7 @@
NetworkCapabilities nc1 = new NetworkCapabilities();
nc1.addTransportType(TRANSPORT_CELLULAR).addTransportType(TRANSPORT_WIFI);
try {
- nc1.setNetworkSpecifier(new StringNetworkSpecifier("specs"));
+ nc1.setNetworkSpecifier(CompatUtil.makeEthernetNetworkSpecifier("eth0"));
fail("Cannot set NetworkSpecifier on a NetworkCapability with multiple transports!");
} catch (IllegalStateException expected) {
// empty
@@ -680,7 +735,7 @@
// Sequence 2: Transport + NetworkSpecifier + Transport
NetworkCapabilities nc2 = new NetworkCapabilities();
nc2.addTransportType(TRANSPORT_CELLULAR).setNetworkSpecifier(
- new StringNetworkSpecifier("specs"));
+ CompatUtil.makeEthernetNetworkSpecifier("testtap3"));
try {
nc2.addTransportType(TRANSPORT_WIFI);
fail("Cannot set a second TransportType of a network which has a NetworkSpecifier!");
@@ -757,10 +812,31 @@
if (isAtLeastR()) {
assertTrue(DIFFERENT_TEST_SSID.equals(nc2.getSsid()));
}
-
- nc1.setUids(uidRange(10, 13));
+ if (isAtLeastS()) {
+ nc1.setUids(uidRanges(10, 13));
+ } else {
+ nc1.setUids(null);
+ }
nc2.set(nc1); // Overwrites, as opposed to combineCapabilities
assertEquals(nc1, nc2);
+
+ if (isAtLeastS()) {
+ assertThrows(NullPointerException.class, () -> nc1.setSubIds(null));
+ nc1.setSubIds(Set.of());
+ nc2.set(nc1);
+ assertEquals(nc1, nc2);
+
+ nc1.setSubIds(Set.of(TEST_SUBID1));
+ nc2.set(nc1);
+ assertEquals(nc1, nc2);
+
+ nc2.setSubIds(Set.of(TEST_SUBID2, TEST_SUBID1));
+ nc2.set(nc1);
+ assertEquals(nc1, nc2);
+
+ nc2.setSubIds(Set.of(TEST_SUBID3, TEST_SUBID2));
+ assertNotEquals(nc1, nc2);
+ }
}
@Test
@@ -841,6 +917,50 @@
} catch (NullPointerException expected) { }
}
+ private static NetworkCapabilities capsWithSubIds(Integer ... subIds) {
+ // Since the NetworkRequest would put NOT_VCN_MANAGED capabilities in general, for
+ // every NetworkCapabilities that simulates networks needs to add it too in order to
+ // satisfy these requests.
+ final NetworkCapabilities nc = new NetworkCapabilities.Builder()
+ .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
+ .setSubIds(new ArraySet<>(subIds)).build();
+ assertEquals(new ArraySet<>(subIds), nc.getSubIds());
+ return nc;
+ }
+
+ @Test @IgnoreUpTo(Build.VERSION_CODES.R)
+ public void testSubIds() throws Exception {
+ final NetworkCapabilities ncWithoutId = capsWithSubIds();
+ final NetworkCapabilities ncWithId = capsWithSubIds(TEST_SUBID1);
+ final NetworkCapabilities ncWithOtherIds = capsWithSubIds(TEST_SUBID1, TEST_SUBID3);
+ final NetworkCapabilities ncWithoutRequestedIds = capsWithSubIds(TEST_SUBID3);
+
+ final NetworkRequest requestWithoutId = new NetworkRequest.Builder().build();
+ assertEmpty(requestWithoutId.networkCapabilities.getSubIds());
+ final NetworkRequest requestWithIds = new NetworkRequest.Builder()
+ .setSubIds(Set.of(TEST_SUBID1, TEST_SUBID2)).build();
+ assertEquals(Set.of(TEST_SUBID1, TEST_SUBID2),
+ requestWithIds.networkCapabilities.getSubIds());
+
+ assertFalse(requestWithIds.canBeSatisfiedBy(ncWithoutId));
+ assertTrue(requestWithIds.canBeSatisfiedBy(ncWithOtherIds));
+ assertFalse(requestWithIds.canBeSatisfiedBy(ncWithoutRequestedIds));
+ assertTrue(requestWithIds.canBeSatisfiedBy(ncWithId));
+ assertTrue(requestWithoutId.canBeSatisfiedBy(ncWithoutId));
+ assertTrue(requestWithoutId.canBeSatisfiedBy(ncWithId));
+ }
+
+ @Test @IgnoreUpTo(Build.VERSION_CODES.R)
+ public void testEqualsSubIds() throws Exception {
+ assertEquals(capsWithSubIds(), capsWithSubIds());
+ assertNotEquals(capsWithSubIds(), capsWithSubIds(TEST_SUBID1));
+ assertEquals(capsWithSubIds(TEST_SUBID1), capsWithSubIds(TEST_SUBID1));
+ assertNotEquals(capsWithSubIds(TEST_SUBID1), capsWithSubIds(TEST_SUBID2));
+ assertNotEquals(capsWithSubIds(TEST_SUBID1), capsWithSubIds(TEST_SUBID2, TEST_SUBID1));
+ assertEquals(capsWithSubIds(TEST_SUBID1, TEST_SUBID2),
+ capsWithSubIds(TEST_SUBID2, TEST_SUBID1));
+ }
+
@Test
public void testLinkBandwidthKbps() {
final NetworkCapabilities nc = new NetworkCapabilities();
@@ -955,18 +1075,42 @@
} catch (IllegalArgumentException e) { }
}
- private class TestTransportInfo implements TransportInfo {
+ /**
+ * Test TransportInfo to verify redaction mechanism.
+ */
+ private static class TestTransportInfo implements TransportInfo {
+ public final boolean locationRedacted;
+ public final boolean localMacAddressRedacted;
+ public final boolean settingsRedacted;
+
TestTransportInfo() {
+ locationRedacted = false;
+ localMacAddressRedacted = false;
+ settingsRedacted = false;
+ }
+
+ TestTransportInfo(boolean locationRedacted,
+ boolean localMacAddressRedacted,
+ boolean settingsRedacted) {
+ this.locationRedacted = locationRedacted;
+ this.localMacAddressRedacted =
+ localMacAddressRedacted;
+ this.settingsRedacted = settingsRedacted;
}
@Override
- public TransportInfo makeCopy(boolean parcelLocationSensitiveFields) {
- return this;
+ public TransportInfo makeCopy(@NetworkCapabilities.RedactionType long redactions) {
+ return new TestTransportInfo(
+ (redactions & NetworkCapabilities.REDACT_FOR_ACCESS_FINE_LOCATION) != 0,
+ (redactions & REDACT_FOR_LOCAL_MAC_ADDRESS) != 0,
+ (redactions & REDACT_FOR_NETWORK_SETTINGS) != 0
+ );
}
@Override
- public boolean hasLocationSensitiveFields() {
- return false;
+ public @NetworkCapabilities.RedactionType long getApplicableRedactions() {
+ return REDACT_FOR_ACCESS_FINE_LOCATION | REDACT_FOR_LOCAL_MAC_ADDRESS
+ | REDACT_FOR_NETWORK_SETTINGS;
}
}
@@ -977,7 +1121,7 @@
final int requestUid = 10100;
final int[] administratorUids = {ownerUid, 10001};
final TelephonyNetworkSpecifier specifier = new TelephonyNetworkSpecifier(1);
- final TestTransportInfo transportInfo = new TestTransportInfo();
+ final TransportInfo transportInfo = new TransportInfo() {};
final String ssid = "TEST_SSID";
final String packageName = "com.google.test.networkcapabilities";
final NetworkCapabilities nc = new NetworkCapabilities.Builder()
@@ -1021,5 +1165,11 @@
fail("Should not set null into NetworkCapabilities.Builder");
} catch (NullPointerException expected) { }
assertEquals(nc, new NetworkCapabilities.Builder(nc).build());
+
+ if (isAtLeastS()) {
+ final NetworkCapabilities nc2 = new NetworkCapabilities.Builder()
+ .setSubIds(Set.of(TEST_SUBID1)).build();
+ assertEquals(Set.of(TEST_SUBID1), nc2.getSubIds());
+ }
}
}
diff --git a/tests/net/common/java/android/net/NetworkProviderTest.kt b/tests/net/common/java/android/net/NetworkProviderTest.kt
index bcc9072..340e6f9 100644
--- a/tests/net/common/java/android/net/NetworkProviderTest.kt
+++ b/tests/net/common/java/android/net/NetworkProviderTest.kt
@@ -27,6 +27,7 @@
import android.os.Looper
import androidx.test.InstrumentationRegistry
import com.android.net.module.util.ArrayTrackRecord
+import com.android.testutils.CompatUtil
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
import com.android.testutils.DevSdkIgnoreRunner
import com.android.testutils.isDevSdkInRange
@@ -102,7 +103,8 @@
mCm.registerNetworkProvider(provider)
assertNotEquals(provider.getProviderId(), NetworkProvider.ID_NONE)
- val specifier = StringNetworkSpecifier(UUID.randomUUID().toString())
+ val specifier = CompatUtil.makeTestNetworkSpecifier(
+ UUID.randomUUID().toString())
val nr: NetworkRequest = NetworkRequest.Builder()
.addTransportType(TRANSPORT_TEST)
.setNetworkSpecifier(specifier)
@@ -183,7 +185,8 @@
mCm.registerNetworkProvider(provider)
- val specifier = StringNetworkSpecifier(UUID.randomUUID().toString())
+ val specifier = CompatUtil.makeTestNetworkSpecifier(
+ UUID.randomUUID().toString())
val nr: NetworkRequest = NetworkRequest.Builder()
.addTransportType(TRANSPORT_TEST)
.setNetworkSpecifier(specifier)
diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt b/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
index 2a2dc56..b6e4274 100644
--- a/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
+++ b/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
@@ -44,12 +44,10 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import com.android.server.ConnectivityService
-import com.android.server.LocalServices
import com.android.server.NetworkAgentWrapper
import com.android.server.TestNetIdManager
import com.android.server.connectivity.MockableSystemProperties
import com.android.server.connectivity.ProxyTracker
-import com.android.server.net.NetworkPolicyManagerInternal
import com.android.testutils.TestableNetworkCallback
import org.junit.After
import org.junit.Before
@@ -75,7 +73,7 @@
import kotlin.test.fail
const val SERVICE_BIND_TIMEOUT_MS = 5_000L
-const val TEST_TIMEOUT_MS = 1_000L
+const val TEST_TIMEOUT_MS = 10_000L
/**
* Test that exercises an instrumented version of ConnectivityService against an instrumented
@@ -162,10 +160,6 @@
networkStackClient.init()
networkStackClient.start()
- LocalServices.removeServiceForTest(NetworkPolicyManagerInternal::class.java)
- LocalServices.addService(NetworkPolicyManagerInternal::class.java,
- mock(NetworkPolicyManagerInternal::class.java))
-
service = TestConnectivityService(makeDependencies())
cm = ConnectivityManager(context, service)
context.addMockSystemService(Context.CONNECTIVITY_SERVICE, cm)
diff --git a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
index e1da3d0..e2d43cb 100644
--- a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
+++ b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
@@ -44,11 +44,11 @@
import android.net.NetworkSpecifier;
import android.net.QosFilter;
import android.net.SocketKeepalive;
-import android.net.UidRange;
import android.os.ConditionVariable;
import android.os.HandlerThread;
import android.os.Message;
import android.util.Log;
+import android.util.Range;
import com.android.net.module.util.ArrayTrackRecord;
import com.android.server.connectivity.ConnectivityConstants;
@@ -64,6 +64,7 @@
private final HandlerThread mHandlerThread;
private final Context mContext;
private final String mLogTag;
+ private final NetworkAgentConfig mNetworkAgentConfig;
private final ConditionVariable mDisconnected = new ConditionVariable();
private final ConditionVariable mPreventReconnectReceived = new ConditionVariable();
@@ -115,13 +116,19 @@
mHandlerThread = new HandlerThread(mLogTag);
mHandlerThread.start();
- mNetworkAgent = makeNetworkAgent(linkProperties, type, typeName);
+ // extraInfo is set to "" by default in NetworkAgentConfig.
+ final String extraInfo = (transport == TRANSPORT_CELLULAR) ? "internet.apn" : "";
+ mNetworkAgentConfig = new NetworkAgentConfig.Builder()
+ .setLegacyType(type)
+ .setLegacyTypeName(typeName)
+ .setLegacyExtraInfo(extraInfo)
+ .build();
+ mNetworkAgent = makeNetworkAgent(linkProperties, mNetworkAgentConfig);
}
protected InstrumentedNetworkAgent makeNetworkAgent(LinkProperties linkProperties,
- final int type, final String typeName)
- throws Exception {
- return new InstrumentedNetworkAgent(this, linkProperties, type, typeName);
+ final NetworkAgentConfig nac) throws Exception {
+ return new InstrumentedNetworkAgent(this, linkProperties, nac);
}
public static class InstrumentedNetworkAgent extends NetworkAgent {
@@ -129,11 +136,9 @@
private static final String PROVIDER_NAME = "InstrumentedNetworkAgentProvider";
public InstrumentedNetworkAgent(NetworkAgentWrapper wrapper, LinkProperties lp,
- final int type, final String typeName) {
+ NetworkAgentConfig nac) {
super(wrapper.mContext, wrapper.mHandlerThread.getLooper(), wrapper.mLogTag,
- wrapper.mNetworkCapabilities, lp, wrapper.mScore,
- new NetworkAgentConfig.Builder()
- .setLegacyType(type).setLegacyTypeName(typeName).build(),
+ wrapper.mNetworkCapabilities, lp, wrapper.mScore, nac,
new NetworkProvider(wrapper.mContext, wrapper.mHandlerThread.getLooper(),
PROVIDER_NAME));
mWrapper = wrapper;
@@ -217,7 +222,7 @@
mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
}
- public void setUids(Set<UidRange> uids) {
+ public void setUids(Set<Range<Integer>> uids) {
mNetworkCapabilities.setUids(uids);
mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
}
@@ -301,6 +306,14 @@
return mNetworkCapabilities;
}
+ public int getLegacyType() {
+ return mNetworkAgentConfig.getLegacyType();
+ }
+
+ public String getExtraInfo() {
+ return mNetworkAgentConfig.getLegacyExtraInfo();
+ }
+
public @NonNull ArrayTrackRecord<CallbackType>.ReadHead getCallbackHistory() {
return mCallbackHistory;
}
diff --git a/tests/net/java/android/net/ConnectivityManagerTest.java b/tests/net/java/android/net/ConnectivityManagerTest.java
index 6a09b02..6cbdd25 100644
--- a/tests/net/java/android/net/ConnectivityManagerTest.java
+++ b/tests/net/java/android/net/ConnectivityManagerTest.java
@@ -41,10 +41,10 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyBoolean;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -64,6 +64,7 @@
import android.os.Looper;
import android.os.Message;
import android.os.Messenger;
+import android.os.Process;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -219,8 +220,8 @@
ArgumentCaptor<Messenger> captor = ArgumentCaptor.forClass(Messenger.class);
// register callback
- when(mService.requestNetwork(any(), anyInt(), captor.capture(), anyInt(), any(), anyInt(),
- any(), nullable(String.class))).thenReturn(request);
+ when(mService.requestNetwork(anyInt(), any(), anyInt(), captor.capture(), anyInt(), any(),
+ anyInt(), anyInt(), any(), nullable(String.class))).thenReturn(request);
manager.requestNetwork(request, callback, handler);
// callback triggers
@@ -247,8 +248,8 @@
ArgumentCaptor<Messenger> captor = ArgumentCaptor.forClass(Messenger.class);
// register callback
- when(mService.requestNetwork(any(), anyInt(), captor.capture(), anyInt(), any(), anyInt(),
- any(), nullable(String.class))).thenReturn(req1);
+ when(mService.requestNetwork(anyInt(), any(), anyInt(), captor.capture(), anyInt(), any(),
+ anyInt(), anyInt(), any(), nullable(String.class))).thenReturn(req1);
manager.requestNetwork(req1, callback, handler);
// callback triggers
@@ -265,8 +266,8 @@
verify(callback, timeout(100).times(0)).onLosing(any(), anyInt());
// callback can be registered again
- when(mService.requestNetwork(any(), anyInt(), captor.capture(), anyInt(), any(), anyInt(),
- any(), nullable(String.class))).thenReturn(req2);
+ when(mService.requestNetwork(anyInt(), any(), anyInt(), captor.capture(), anyInt(), any(),
+ anyInt(), anyInt(), any(), nullable(String.class))).thenReturn(req2);
manager.requestNetwork(req2, callback, handler);
// callback triggers
@@ -289,8 +290,8 @@
info.targetSdkVersion = VERSION_CODES.N_MR1 + 1;
when(mCtx.getApplicationInfo()).thenReturn(info);
- when(mService.requestNetwork(any(), anyInt(), any(), anyInt(), any(), anyInt(), any(),
- nullable(String.class))).thenReturn(request);
+ when(mService.requestNetwork(anyInt(), any(), anyInt(), any(), anyInt(), any(), anyInt(),
+ anyInt(), any(), nullable(String.class))).thenReturn(request);
Handler handler = new Handler(Looper.getMainLooper());
manager.requestNetwork(request, callback, handler);
@@ -357,35 +358,41 @@
final NetworkCallback callback = new ConnectivityManager.NetworkCallback();
manager.requestNetwork(request, callback);
- verify(mService).requestNetwork(eq(request.networkCapabilities),
- eq(REQUEST.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE),
+ verify(mService).requestNetwork(eq(Process.INVALID_UID), eq(request.networkCapabilities),
+ eq(REQUEST.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(),
eq(testPkgName), eq(testAttributionTag));
reset(mService);
// Verify that register network callback does not calls requestNetwork at all.
manager.registerNetworkCallback(request, callback);
- verify(mService, never()).requestNetwork(any(), anyInt(), any(), anyInt(), any(),
- anyInt(), any(), any());
- verify(mService).listenForNetwork(eq(request.networkCapabilities), any(), any(),
- eq(testPkgName), eq(testAttributionTag));
- reset(mService);
-
- manager.registerDefaultNetworkCallback(callback);
- verify(mService).requestNetwork(eq(null),
- eq(TRACK_DEFAULT.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE),
- eq(testPkgName), eq(testAttributionTag));
- reset(mService);
-
- manager.requestBackgroundNetwork(request, null, callback);
- verify(mService).requestNetwork(eq(request.networkCapabilities),
- eq(BACKGROUND_REQUEST.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE),
+ verify(mService, never()).requestNetwork(anyInt(), any(), anyInt(), any(), anyInt(), any(),
+ anyInt(), anyInt(), any(), any());
+ verify(mService).listenForNetwork(eq(request.networkCapabilities), any(), any(), anyInt(),
eq(testPkgName), eq(testAttributionTag));
reset(mService);
Handler handler = new Handler(ConnectivityThread.getInstanceLooper());
+
+ manager.registerDefaultNetworkCallback(callback);
+ verify(mService).requestNetwork(eq(Process.INVALID_UID), eq(null),
+ eq(TRACK_DEFAULT.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(),
+ eq(testPkgName), eq(testAttributionTag));
+ reset(mService);
+
+ manager.registerDefaultNetworkCallbackAsUid(42, callback, handler);
+ verify(mService).requestNetwork(eq(42), eq(null),
+ eq(TRACK_DEFAULT.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(),
+ eq(testPkgName), eq(testAttributionTag));
+
+ manager.requestBackgroundNetwork(request, handler, callback);
+ verify(mService).requestNetwork(eq(Process.INVALID_UID), eq(request.networkCapabilities),
+ eq(BACKGROUND_REQUEST.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(),
+ eq(testPkgName), eq(testAttributionTag));
+ reset(mService);
+
manager.registerSystemDefaultNetworkCallback(callback, handler);
- verify(mService).requestNetwork(eq(null),
- eq(TRACK_SYSTEM_DEFAULT.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE),
+ verify(mService).requestNetwork(eq(Process.INVALID_UID), eq(null),
+ eq(TRACK_SYSTEM_DEFAULT.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(),
eq(testPkgName), eq(testAttributionTag));
reset(mService);
}
diff --git a/tests/net/java/android/net/VpnTransportInfoTest.java b/tests/net/java/android/net/VpnTransportInfoTest.java
index d04c87b..b7a42ec 100644
--- a/tests/net/java/android/net/VpnTransportInfoTest.java
+++ b/tests/net/java/android/net/VpnTransportInfoTest.java
@@ -42,7 +42,13 @@
VpnTransportInfo v1 = new VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM);
VpnTransportInfo v2 = new VpnTransportInfo(VpnManager.TYPE_VPN_SERVICE);
VpnTransportInfo v3 = new VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM);
+ VpnTransportInfo v4 = new VpnTransportInfo(VpnManager.TYPE_VPN_LEGACY);
+ VpnTransportInfo v5 = new VpnTransportInfo(VpnManager.TYPE_VPN_OEM);
+
assertNotEquals(v1, v2);
+ assertNotEquals(v3, v4);
+ assertNotEquals(v4, v5);
+
assertEquals(v1, v3);
assertEquals(v1.hashCode(), v3.hashCode());
}
diff --git a/tests/net/java/android/net/util/KeepaliveUtilsTest.kt b/tests/net/java/android/net/util/KeepaliveUtilsTest.kt
index 8ea226d..b62bdbc 100644
--- a/tests/net/java/android/net/util/KeepaliveUtilsTest.kt
+++ b/tests/net/java/android/net/util/KeepaliveUtilsTest.kt
@@ -18,6 +18,7 @@
import android.content.Context
import android.content.res.Resources
+import android.net.ConnectivityResources
import android.net.NetworkCapabilities
import android.net.NetworkCapabilities.MAX_TRANSPORT
import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
@@ -26,13 +27,15 @@
import android.net.NetworkCapabilities.TRANSPORT_WIFI
import androidx.test.filters.SmallTest
import com.android.internal.R
+import org.junit.After
import org.junit.Assert.assertArrayEquals
import org.junit.Assert.assertEquals
import org.junit.Assert.fail
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
-import org.mockito.ArgumentMatchers
+import org.mockito.ArgumentMatchers.eq
+import org.mockito.Mockito.any
import org.mockito.Mockito.doReturn
import org.mockito.Mockito.mock
@@ -47,21 +50,33 @@
class KeepaliveUtilsTest {
// Prepare mocked context with given resource strings.
- private fun getMockedContextWithStringArrayRes(id: Int, res: Array<out String?>?): Context {
+ private fun getMockedContextWithStringArrayRes(
+ id: Int,
+ name: String,
+ res: Array<out String?>?
+ ): Context {
val mockRes = mock(Resources::class.java)
- doReturn(res).`when`(mockRes).getStringArray(ArgumentMatchers.eq(id))
+ doReturn(res).`when`(mockRes).getStringArray(eq(id))
+ doReturn(id).`when`(mockRes).getIdentifier(eq(name), any(), any())
return mock(Context::class.java).apply {
doReturn(mockRes).`when`(this).getResources()
+ ConnectivityResources.setResourcesContextForTest(this)
}
}
+ @After
+ fun tearDown() {
+ ConnectivityResources.setResourcesContextForTest(null)
+ }
+
@Test
fun testGetSupportedKeepalives() {
fun assertRunWithException(res: Array<out String?>?) {
try {
val mockContext = getMockedContextWithStringArrayRes(
- R.array.config_networkSupportedKeepaliveCount, res)
+ R.array.config_networkSupportedKeepaliveCount,
+ "config_networkSupportedKeepaliveCount", res)
KeepaliveUtils.getSupportedKeepalives(mockContext)
fail("Expected KeepaliveDeviceConfigurationException")
} catch (expected: KeepaliveUtils.KeepaliveDeviceConfigurationException) {
@@ -89,7 +104,8 @@
val expectedValidRes = intArrayOf(3, 0, 0, 0, 4, 0, 0, 0)
val mockContext = getMockedContextWithStringArrayRes(
- R.array.config_networkSupportedKeepaliveCount, validRes)
+ R.array.config_networkSupportedKeepaliveCount,
+ "config_networkSupportedKeepaliveCount", validRes)
val actual = KeepaliveUtils.getSupportedKeepalives(mockContext)
assertArrayEquals(expectedValidRes, actual)
}
diff --git a/tests/net/java/android/net/util/MultinetworkPolicyTrackerTest.kt b/tests/net/java/android/net/util/MultinetworkPolicyTrackerTest.kt
index c1315f6..25aa626 100644
--- a/tests/net/java/android/net/util/MultinetworkPolicyTrackerTest.kt
+++ b/tests/net/java/android/net/util/MultinetworkPolicyTrackerTest.kt
@@ -21,18 +21,20 @@
import android.net.ConnectivityManager.MULTIPATH_PREFERENCE_HANDOVER
import android.net.ConnectivityManager.MULTIPATH_PREFERENCE_PERFORMANCE
import android.net.ConnectivityManager.MULTIPATH_PREFERENCE_RELIABILITY
+import android.net.ConnectivityResources
+import android.net.ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI
+import android.net.ConnectivitySettingsManager.NETWORK_METERED_MULTIPATH_PREFERENCE
import android.net.util.MultinetworkPolicyTracker.ActiveDataSubscriptionIdListener
import android.provider.Settings
-import android.provider.Settings.Global.NETWORK_AVOID_BAD_WIFI
-import android.provider.Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE
import android.telephony.SubscriptionInfo
import android.telephony.SubscriptionManager
import android.telephony.TelephonyManager
import android.test.mock.MockContentResolver
import androidx.test.filters.SmallTest
import androidx.test.runner.AndroidJUnit4
-import com.android.internal.R
+import com.android.connectivity.resources.R
import com.android.internal.util.test.FakeSettingsProvider
+import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
@@ -41,6 +43,7 @@
import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.argThat
+import org.mockito.ArgumentMatchers.eq
import org.mockito.Mockito.any
import org.mockito.Mockito.doReturn
import org.mockito.Mockito.mock
@@ -57,6 +60,8 @@
@SmallTest
class MultinetworkPolicyTrackerTest {
private val resources = mock(Resources::class.java).also {
+ doReturn(R.integer.config_networkAvoidBadWifi).`when`(it).getIdentifier(
+ eq("config_networkAvoidBadWifi"), eq("integer"), any())
doReturn(0).`when`(it).getInteger(R.integer.config_networkAvoidBadWifi)
}
private val telephonyManager = mock(TelephonyManager::class.java)
@@ -75,6 +80,7 @@
doReturn(resources).`when`(it).resources
doReturn(it).`when`(it).createConfigurationContext(any())
Settings.Global.putString(resolver, NETWORK_AVOID_BAD_WIFI, "1")
+ ConnectivityResources.setResourcesContextForTest(it)
}
private val tracker = MultinetworkPolicyTracker(context, null /* handler */)
@@ -85,6 +91,11 @@
assertEquals(preference, tracker.meteredMultipathPreference)
}
+ @After
+ fun tearDown() {
+ ConnectivityResources.setResourcesContextForTest(null)
+ }
+
@Test
fun testUpdateMeteredMultipathPreference() {
assertMultipathPreference(MULTIPATH_PREFERENCE_HANDOVER)
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index a643bc8..10b2f1e 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -23,23 +23,31 @@
import static android.content.Intent.ACTION_USER_REMOVED;
import static android.content.Intent.ACTION_USER_UNLOCKED;
import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
+import static android.content.pm.PackageManager.FEATURE_WIFI;
+import static android.content.pm.PackageManager.FEATURE_WIFI_DIRECT;
import static android.content.pm.PackageManager.GET_PERMISSIONS;
import static android.content.pm.PackageManager.MATCH_ANY_USER;
import static android.content.pm.PackageManager.PERMISSION_DENIED;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.net.ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN;
+import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_DATA_SAVER;
+import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_USER_RESTRICTED;
+import static android.net.ConnectivityManager.BLOCKED_REASON_BATTERY_SAVER;
+import static android.net.ConnectivityManager.BLOCKED_REASON_NONE;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.EXTRA_NETWORK_INFO;
import static android.net.ConnectivityManager.EXTRA_NETWORK_TYPE;
-import static android.net.ConnectivityManager.NETID_UNSET;
import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF;
import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
+import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_DEFAULT;
+import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE;
import static android.net.ConnectivityManager.TYPE_ETHERNET;
import static android.net.ConnectivityManager.TYPE_MOBILE;
import static android.net.ConnectivityManager.TYPE_MOBILE_FOTA;
import static android.net.ConnectivityManager.TYPE_MOBILE_MMS;
import static android.net.ConnectivityManager.TYPE_MOBILE_SUPL;
+import static android.net.ConnectivityManager.TYPE_PROXY;
import static android.net.ConnectivityManager.TYPE_VPN;
import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_DNS;
@@ -77,15 +85,15 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_WIFI_P2P;
import static android.net.NetworkCapabilities.NET_CAPABILITY_XCAP;
+import static android.net.NetworkCapabilities.REDACT_FOR_ACCESS_FINE_LOCATION;
+import static android.net.NetworkCapabilities.REDACT_FOR_LOCAL_MAC_ADDRESS;
+import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS;
+import static android.net.NetworkCapabilities.REDACT_NONE;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
import static android.net.NetworkCapabilities.TRANSPORT_VPN;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE;
-import static android.net.NetworkPolicyManager.RULE_ALLOW_METERED;
-import static android.net.NetworkPolicyManager.RULE_NONE;
-import static android.net.NetworkPolicyManager.RULE_REJECT_ALL;
-import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID;
import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK;
import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY;
@@ -174,6 +182,8 @@
import android.net.ConnectivityManager.PacketKeepalive;
import android.net.ConnectivityManager.PacketKeepaliveCallback;
import android.net.ConnectivityManager.TooManyRequestsException;
+import android.net.ConnectivityResources;
+import android.net.ConnectivitySettingsManager;
import android.net.ConnectivityThread;
import android.net.DataStallReportParcelable;
import android.net.EthernetManager;
@@ -182,8 +192,7 @@
import android.net.INetd;
import android.net.INetworkMonitor;
import android.net.INetworkMonitorCallbacks;
-import android.net.INetworkPolicyListener;
-import android.net.IOnSetOemNetworkPreferenceListener;
+import android.net.IOnCompleteListener;
import android.net.IQosCallback;
import android.net.InetAddresses;
import android.net.InterfaceConfigurationParcel;
@@ -201,7 +210,9 @@
import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
import android.net.NetworkPolicyManager;
+import android.net.NetworkPolicyManager.NetworkPolicyCallback;
import android.net.NetworkRequest;
+import android.net.NetworkScore;
import android.net.NetworkSpecifier;
import android.net.NetworkStack;
import android.net.NetworkStackClient;
@@ -229,7 +240,6 @@
import android.net.shared.NetworkMonitorUtils;
import android.net.shared.PrivateDnsConfig;
import android.net.util.MultinetworkPolicyTracker;
-import android.net.wifi.WifiInfo;
import android.os.BadParcelableException;
import android.os.Binder;
import android.os.Build;
@@ -255,18 +265,20 @@
import android.system.Os;
import android.telephony.TelephonyManager;
import android.telephony.data.EpsBearerQosSessionAttributes;
+import android.telephony.data.NrQosSessionAttributes;
import android.test.mock.MockContentResolver;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log;
import android.util.Pair;
+import android.util.Range;
import android.util.SparseArray;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
-import com.android.internal.app.IBatteryStats;
+import com.android.connectivity.resources.R;
import com.android.internal.net.VpnConfig;
import com.android.internal.net.VpnProfile;
import com.android.internal.util.ArrayUtils;
@@ -285,7 +297,6 @@
import com.android.server.connectivity.Vpn;
import com.android.server.connectivity.VpnProfileStore;
import com.android.server.net.NetworkPinner;
-import com.android.server.net.NetworkPolicyManagerInternal;
import com.android.testutils.ExceptionUtils;
import com.android.testutils.HandlerUtils;
import com.android.testutils.RecorderCallback.CallbackEntry;
@@ -377,6 +388,11 @@
// Set a non-zero value to verify the flow to set tcp init rwnd value.
private static final int TEST_TCP_INIT_RWND = 60;
+ // Used for testing the per-work-profile default network.
+ private static final int TEST_APP_ID = 103;
+ private static final int TEST_WORK_PROFILE_USER_ID = 2;
+ private static final int TEST_WORK_PROFILE_APP_UID =
+ UserHandle.getUid(TEST_WORK_PROFILE_USER_ID, TEST_APP_ID);
private static final String CLAT_PREFIX = "v4-";
private static final String MOBILE_IFNAME = "test_rmnet_data0";
private static final String WIFI_IFNAME = "test_wlan0";
@@ -411,7 +427,7 @@
private TestNetworkAgentWrapper mEthernetNetworkAgent;
private MockVpn mMockVpn;
private Context mContext;
- private INetworkPolicyListener mPolicyListener;
+ private NetworkPolicyCallback mPolicyCallback;
private WrappedMultinetworkPolicyTracker mPolicyTracker;
private HandlerThread mAlarmManagerThread;
private TestNetIdManager mNetIdManager;
@@ -420,15 +436,14 @@
private VpnManagerService mVpnManagerService;
private TestNetworkCallback mDefaultNetworkCallback;
private TestNetworkCallback mSystemDefaultNetworkCallback;
+ private TestNetworkCallback mProfileDefaultNetworkCallback;
// State variables required to emulate NetworkPolicyManagerService behaviour.
- private int mUidRules = RULE_NONE;
- private boolean mRestrictBackground = false;
+ private int mBlockedReasons = BLOCKED_REASON_NONE;
@Mock DeviceIdleInternal mDeviceIdleInternal;
@Mock INetworkManagementService mNetworkManagementService;
@Mock NetworkStatsManager mStatsManager;
- @Mock IBatteryStats mBatteryStatsService;
@Mock IDnsResolver mMockDnsResolver;
@Mock INetd mMockNetd;
@Mock NetworkStackClient mNetworkStack;
@@ -446,6 +461,7 @@
@Mock NetworkPolicyManager mNetworkPolicyManager;
@Mock VpnProfileStore mVpnProfileStore;
@Mock SystemConfigManager mSystemConfigManager;
+ @Mock Resources mResources;
private ArgumentCaptor<ResolverParamsParcel> mResolverParamsParcelCaptor =
ArgumentCaptor.forClass(ResolverParamsParcel.class);
@@ -473,7 +489,7 @@
private class MockContext extends BroadcastInterceptingContext {
private final MockContentResolver mContentResolver;
- @Spy private Resources mResources;
+ @Spy private Resources mInternalResources;
private final LinkedBlockingQueue<Intent> mStartedActivities = new LinkedBlockingQueue<>();
// Map of permission name -> PermissionManager.Permission_{GRANTED|DENIED} constant
@@ -482,21 +498,15 @@
MockContext(Context base, ContentProvider settingsProvider) {
super(base);
- mResources = spy(base.getResources());
- when(mResources.getStringArray(com.android.internal.R.array.networkAttributes)).
- thenReturn(new String[] {
+ mInternalResources = spy(base.getResources());
+ when(mInternalResources.getStringArray(com.android.internal.R.array.networkAttributes))
+ .thenReturn(new String[] {
"wifi,1,1,1,-1,true",
"mobile,0,0,0,-1,true",
"mobile_mms,2,0,2,60000,true",
"mobile_supl,3,0,2,60000,true",
});
- when(mResources.getStringArray(
- com.android.internal.R.array.config_wakeonlan_supported_interfaces))
- .thenReturn(new String[]{
- WIFI_WOL_IFNAME,
- });
-
mContentResolver = new MockContentResolver();
mContentResolver.addProvider(Settings.AUTHORITY, settingsProvider);
}
@@ -547,13 +557,26 @@
return super.getSystemService(name);
}
+ final HashMap<UserHandle, UserManager> mUserManagers = new HashMap<>();
@Override
public Context createContextAsUser(UserHandle user, int flags) {
final Context asUser = mock(Context.class, AdditionalAnswers.delegatesTo(this));
doReturn(user).when(asUser).getUser();
+ doAnswer((inv) -> {
+ final UserManager um = mUserManagers.computeIfAbsent(user,
+ u -> mock(UserManager.class, AdditionalAnswers.delegatesTo(mUserManager)));
+ return um;
+ }).when(asUser).getSystemService(Context.USER_SERVICE);
return asUser;
}
+ public void setWorkProfile(@NonNull final UserHandle userHandle, boolean value) {
+ // This relies on all contexts for a given user returning the same UM mock
+ final UserManager umMock = createContextAsUser(userHandle, 0 /* flags */)
+ .getSystemService(UserManager.class);
+ doReturn(value).when(umMock).isManagedProfile();
+ }
+
@Override
public ContentResolver getContentResolver() {
return mContentResolver;
@@ -561,7 +584,7 @@
@Override
public Resources getResources() {
- return mResources;
+ return mInternalResources;
}
@Override
@@ -720,7 +743,7 @@
@Override
protected InstrumentedNetworkAgent makeNetworkAgent(LinkProperties linkProperties,
- final int type, final String typeName) throws Exception {
+ NetworkAgentConfig nac) throws Exception {
mNetworkMonitor = mock(INetworkMonitor.class);
final Answer validateAnswer = inv -> {
@@ -739,8 +762,8 @@
any() /* name */,
nmCbCaptor.capture());
- final InstrumentedNetworkAgent na = new InstrumentedNetworkAgent(this, linkProperties,
- type, typeName) {
+ final InstrumentedNetworkAgent na =
+ new InstrumentedNetworkAgent(this, linkProperties, nac) {
@Override
public void networkStatus(int status, String redirectUrl) {
mRedirectUrl = redirectUrl;
@@ -1084,6 +1107,10 @@
public void triggerUnfulfillable(NetworkRequest r) {
super.releaseRequestAsUnfulfillableByAnyFactory(r);
}
+
+ public void assertNoRequestChanged() {
+ assertNull(mRequestHistory.poll(0, r -> true));
+ }
}
private Set<UidRange> uidRangesForUids(int... uids) {
@@ -1135,7 +1162,7 @@
}
public void setUids(Set<UidRange> uids) {
- mNetworkCapabilities.setUids(uids);
+ mNetworkCapabilities.setUids(UidRange.toIntRanges(uids));
if (mAgentRegistered) {
mMockNetworkAgent.setNetworkCapabilities(mNetworkCapabilities, true);
}
@@ -1151,11 +1178,6 @@
}
@Override
- public int getNetId() {
- return (mMockNetworkAgent == null) ? NETID_UNSET : mMockNetworkAgent.getNetwork().netId;
- }
-
- @Override
public int getActiveVpnType() {
return mVpnType;
}
@@ -1179,10 +1201,10 @@
mNetworkCapabilities);
mMockNetworkAgent.waitForIdle(TIMEOUT_MS);
- verify(mMockNetd, times(1)).networkAddUidRanges(eq(mMockVpn.getNetId()),
+ verify(mMockNetd, times(1)).networkAddUidRanges(eq(mMockVpn.getNetwork().getNetId()),
eq(toUidRangeStableParcels(uids)));
verify(mMockNetd, never())
- .networkRemoveUidRanges(eq(mMockVpn.getNetId()), any());
+ .networkRemoveUidRanges(eq(mMockVpn.getNetwork().getNetId()), any());
mAgentRegistered = true;
updateState(NetworkInfo.DetailedState.CONNECTED, "registerAgent");
mNetworkCapabilities.set(mMockNetworkAgent.getNetworkCapabilities());
@@ -1351,28 +1373,13 @@
}
private void mockUidNetworkingBlocked() {
- doAnswer(i -> mContext.getSystemService(NetworkPolicyManager.class)
- .checkUidNetworkingBlocked(i.getArgument(0) /* uid */, mUidRules,
- i.getArgument(1) /* metered */, mRestrictBackground)
+ doAnswer(i -> NetworkPolicyManager.isUidBlocked(mBlockedReasons, i.getArgument(1))
).when(mNetworkPolicyManager).isUidNetworkingBlocked(anyInt(), anyBoolean());
-
- doAnswer(inv -> mContext.getSystemService(NetworkPolicyManager.class)
- .checkUidNetworkingBlocked(inv.getArgument(0) /* uid */,
- inv.getArgument(1) /* uidRules */,
- inv.getArgument(2) /* isNetworkMetered */,
- inv.getArgument(3) /* isBackgroundRestricted */)
- ).when(mNetworkPolicyManager).checkUidNetworkingBlocked(
- anyInt(), anyInt(), anyBoolean(), anyBoolean());
}
- private void setUidRulesChanged(int uidRules) throws RemoteException {
- mUidRules = uidRules;
- mPolicyListener.onUidRulesChanged(Process.myUid(), mUidRules);
- }
-
- private void setRestrictBackgroundChanged(boolean restrictBackground) throws RemoteException {
- mRestrictBackground = restrictBackground;
- mPolicyListener.onRestrictBackgroundChanged(mRestrictBackground);
+ private void setBlockedReasonChanged(int blockedReasons) {
+ mBlockedReasons = blockedReasons;
+ mPolicyCallback.onUidBlockedReasonChanged(Process.myUid(), blockedReasons);
}
private Nat464Xlat getNat464Xlat(NetworkAgentWrapper mna) {
@@ -1409,18 +1416,56 @@
fail("ConditionVariable was blocked for more than " + TIMEOUT_MS + "ms");
}
- private void registerNetworkCallbackAsUid(NetworkRequest request, NetworkCallback callback,
- int uid) {
+ private <T> T doAsUid(final int uid, @NonNull final Supplier<T> what) {
when(mDeps.getCallingUid()).thenReturn(uid);
try {
- mCm.registerNetworkCallback(request, callback);
- waitForIdle();
+ return what.get();
} finally {
returnRealCallingUid();
}
}
+ private void doAsUid(final int uid, @NonNull final Runnable what) {
+ doAsUid(uid, () -> {
+ what.run(); return Void.TYPE;
+ });
+ }
+
+ private void registerNetworkCallbackAsUid(NetworkRequest request, NetworkCallback callback,
+ int uid) {
+ doAsUid(uid, () -> {
+ mCm.registerNetworkCallback(request, callback);
+ });
+ }
+
+ private void registerDefaultNetworkCallbackAsUid(@NonNull final NetworkCallback callback,
+ final int uid) {
+ doAsUid(uid, () -> {
+ mCm.registerDefaultNetworkCallback(callback);
+ waitForIdle();
+ });
+ }
+
+ private interface ExceptionalRunnable {
+ void run() throws Exception;
+ }
+
+ private void withPermission(String permission, ExceptionalRunnable r) throws Exception {
+ if (mServiceContext.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED) {
+ r.run();
+ return;
+ }
+ try {
+ mServiceContext.setPermission(permission, PERMISSION_GRANTED);
+ r.run();
+ } finally {
+ mServiceContext.setPermission(permission, PERMISSION_DENIED);
+ }
+ }
+
private static final int PRIMARY_USER = 0;
+ private static final UidRange PRIMARY_UIDRANGE =
+ UidRange.createForUser(UserHandle.of(PRIMARY_USER));
private static final int APP1_UID = UserHandle.getUid(PRIMARY_USER, 10100);
private static final int APP2_UID = UserHandle.getUid(PRIMARY_USER, 10101);
private static final int VPN_UID = UserHandle.getUid(PRIMARY_USER, 10043);
@@ -1456,6 +1501,8 @@
applicationInfo.targetSdkVersion = Build.VERSION_CODES.Q;
when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), any()))
.thenReturn(applicationInfo);
+ when(mPackageManager.getTargetSdkVersion(anyString()))
+ .thenReturn(applicationInfo.targetSdkVersion);
when(mSystemConfigManager.getSystemPermissionUids(anyString())).thenReturn(new int[0]);
// InstrumentationTestRunner prepares a looper, but AndroidJUnitRunner does not.
@@ -1464,14 +1511,14 @@
Looper.prepare();
}
mockDefaultPackages();
+ mockHasSystemFeature(FEATURE_WIFI, true);
+ mockHasSystemFeature(FEATURE_WIFI_DIRECT, true);
+ doReturn(true).when(mTelephonyManager).isDataCapable();
FakeSettingsProvider.clearSettingsProvider();
mServiceContext = new MockContext(InstrumentationRegistry.getContext(),
new FakeSettingsProvider());
mServiceContext.setUseRegisteredHandlers(true);
- LocalServices.removeServiceForTest(NetworkPolicyManagerInternal.class);
- LocalServices.addService(
- NetworkPolicyManagerInternal.class, mock(NetworkPolicyManagerInternal.class));
mAlarmManagerThread = new HandlerThread("TestAlarmManager");
mAlarmManagerThread.start();
@@ -1490,10 +1537,11 @@
mService.mNascentDelayMs = TEST_NASCENT_DELAY_MS;
verify(mDeps).makeMultinetworkPolicyTracker(any(), any(), any());
- final ArgumentCaptor<INetworkPolicyListener> policyListenerCaptor =
- ArgumentCaptor.forClass(INetworkPolicyListener.class);
- verify(mNetworkPolicyManager).registerListener(policyListenerCaptor.capture());
- mPolicyListener = policyListenerCaptor.getValue();
+ final ArgumentCaptor<NetworkPolicyCallback> policyCallbackCaptor =
+ ArgumentCaptor.forClass(NetworkPolicyCallback.class);
+ verify(mNetworkPolicyManager).registerNetworkPolicyCallback(any(),
+ policyCallbackCaptor.capture());
+ mPolicyCallback = policyCallbackCaptor.getValue();
// Create local CM before sending system ready so that we can answer
// getSystemService() correctly.
@@ -1506,7 +1554,7 @@
mQosCallbackTracker = mock(QosCallbackTracker.class);
// Ensure that the default setting for Captive Portals is used for most tests
- setCaptivePortalMode(Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT);
+ setCaptivePortalMode(ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE_PROMPT);
setAlwaysOnNetworks(false);
setPrivateDnsSettings(PRIVATE_DNS_MODE_OFF, "ignored.example.com");
}
@@ -1516,23 +1564,47 @@
}
private ConnectivityService.Dependencies makeDependencies() {
- doReturn(TEST_TCP_INIT_RWND).when(mSystemProperties)
- .getInt("net.tcp.default_init_rwnd", 0);
doReturn(false).when(mSystemProperties).getBoolean("ro.radio.noril", false);
- doNothing().when(mSystemProperties).setTcpInitRwnd(anyInt());
final ConnectivityService.Dependencies deps = mock(ConnectivityService.Dependencies.class);
doReturn(mCsHandlerThread).when(deps).makeHandlerThread();
doReturn(mNetIdManager).when(deps).makeNetIdManager();
doReturn(mNetworkStack).when(deps).getNetworkStack();
doReturn(mSystemProperties).when(deps).getSystemProperties();
doReturn(mock(ProxyTracker.class)).when(deps).makeProxyTracker(any(), any());
- doReturn(true).when(deps).queryUserAccess(anyInt(), anyInt());
- doReturn(mBatteryStatsService).when(deps).getBatteryStatsService();
+ doReturn(true).when(deps).queryUserAccess(anyInt(), any(), any());
doAnswer(inv -> {
mPolicyTracker = new WrappedMultinetworkPolicyTracker(
inv.getArgument(0), inv.getArgument(1), inv.getArgument(2));
return mPolicyTracker;
}).when(deps).makeMultinetworkPolicyTracker(any(), any(), any());
+ doReturn(true).when(deps).getCellular464XlatEnabled();
+
+ doReturn(60000).when(mResources).getInteger(
+ com.android.connectivity.resources.R.integer.config_networkTransitionTimeout);
+ doReturn("").when(mResources).getString(
+ com.android.connectivity.resources.R.string.config_networkCaptivePortalServerUrl);
+ doReturn(new String[]{ WIFI_WOL_IFNAME }).when(mResources).getStringArray(
+ com.android.connectivity.resources.R.array.config_wakeonlan_supported_interfaces);
+ doReturn(new String[] { "0,1", "1,3" }).when(mResources).getStringArray(
+ com.android.connectivity.resources.R.array.config_networkSupportedKeepaliveCount);
+ doReturn(com.android.connectivity.resources.R.array.config_networkSupportedKeepaliveCount)
+ .when(mResources).getIdentifier(eq("config_networkSupportedKeepaliveCount"),
+ eq("array"), any());
+ doReturn(com.android.connectivity.resources.R.array.network_switch_type_name)
+ .when(mResources).getIdentifier(eq("network_switch_type_name"),
+ eq("array"), any());
+
+ // We don't test the actual notification value strings, so just return an empty array.
+ // It doesn't matter what the values are as long as it's not null.
+ doReturn(new String[0]).when(mResources).getStringArray(R.array.network_switch_type_name);
+
+ final ConnectivityResources connRes = mock(ConnectivityResources.class);
+ doReturn(mResources).when(connRes).get();
+ doReturn(connRes).when(deps).getResources(any());
+
+ final Context mockResContext = mock(Context.class);
+ doReturn(mResources).when(mockResContext).getResources();
+ ConnectivityResources.setResourcesContextForTest(mockResContext);
return deps;
}
@@ -1566,6 +1638,7 @@
@After
public void tearDown() throws Exception {
unregisterDefaultNetworkCallbacks();
+ maybeTearDownEnterpriseNetwork();
setAlwaysOnNetworks(false);
if (mCellNetworkAgent != null) {
mCellNetworkAgent.disconnect();
@@ -1588,6 +1661,7 @@
waitForIdle();
FakeSettingsProvider.clearSettingsProvider();
+ ConnectivityResources.setResourcesContextForTest(null);
mCsHandlerThread.quitSafely();
mAlarmManagerThread.quitSafely();
@@ -1743,11 +1817,29 @@
return expected;
}
+ private boolean extraInfoInBroadcastHasExpectedNullness(NetworkInfo ni) {
+ final DetailedState state = ni.getDetailedState();
+ if (state == DetailedState.CONNECTED && ni.getExtraInfo() == null) return false;
+ // Expect a null extraInfo if the network is CONNECTING, because a CONNECTIVITY_ACTION
+ // broadcast with a state of CONNECTING only happens due to legacy VPN lockdown, which also
+ // nulls out extraInfo.
+ if (state == DetailedState.CONNECTING && ni.getExtraInfo() != null) return false;
+ // Can't make any assertions about DISCONNECTED broadcasts. When a network actually
+ // disconnects, disconnectAndDestroyNetwork sets its state to DISCONNECTED and its extraInfo
+ // to null. But if the DISCONNECTED broadcast is just simulated by LegacyTypeTracker due to
+ // a network switch, extraInfo will likely be populated.
+ // This is likely a bug in CS, but likely not one we can fix without impacting apps.
+ return true;
+ }
+
private ExpectedBroadcast expectConnectivityAction(int type, NetworkInfo.DetailedState state) {
- return registerConnectivityBroadcastThat(1, intent ->
- type == intent.getIntExtra(EXTRA_NETWORK_TYPE, -1) && state.equals(
- ((NetworkInfo) intent.getParcelableExtra(EXTRA_NETWORK_INFO))
- .getDetailedState()));
+ return registerConnectivityBroadcastThat(1, intent -> {
+ final int actualType = intent.getIntExtra(EXTRA_NETWORK_TYPE, -1);
+ final NetworkInfo ni = intent.getParcelableExtra(EXTRA_NETWORK_INFO);
+ return type == actualType
+ && state == ni.getDetailedState()
+ && extraInfoInBroadcastHasExpectedNullness(ni);
+ });
}
@Test
@@ -1758,7 +1850,8 @@
assertTrue(mCm.isNetworkSupported(TYPE_WIFI));
assertTrue(mCm.isNetworkSupported(TYPE_MOBILE));
assertTrue(mCm.isNetworkSupported(TYPE_MOBILE_MMS));
- assertFalse(mCm.isNetworkSupported(TYPE_MOBILE_FOTA));
+ assertTrue(mCm.isNetworkSupported(TYPE_MOBILE_FOTA));
+ assertFalse(mCm.isNetworkSupported(TYPE_PROXY));
// Check that TYPE_ETHERNET is supported. Unlike the asserts above, which only validate our
// mocks, this assert exercises the ConnectivityService code path that ensures that
@@ -3331,7 +3424,7 @@
.addCapability(NET_CAPABILITY_VALIDATED).build();
mCm.registerNetworkCallback(validatedRequest, validatedCallback);
- setCaptivePortalMode(Settings.Global.CAPTIVE_PORTAL_MODE_AVOID);
+ setCaptivePortalMode(ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE_AVOID);
// Bring up a network with a captive portal.
// Expect it to fail to connect and not result in any callbacks.
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
@@ -3732,9 +3825,10 @@
NetworkCapabilities networkCapabilities = new NetworkCapabilities();
networkCapabilities.addTransportType(TRANSPORT_WIFI)
.setNetworkSpecifier(new MatchAllNetworkSpecifier());
- mService.requestNetwork(networkCapabilities, NetworkRequest.Type.REQUEST.ordinal(),
- null, 0, null, ConnectivityManager.TYPE_WIFI, mContext.getPackageName(),
- getAttributionTag());
+ mService.requestNetwork(Process.INVALID_UID, networkCapabilities,
+ NetworkRequest.Type.REQUEST.ordinal(), null, 0, null,
+ ConnectivityManager.TYPE_WIFI, NetworkCallback.FLAG_NONE,
+ mContext.getPackageName(), getAttributionTag());
});
class NonParcelableSpecifier extends NetworkSpecifier {
@@ -3962,7 +4056,7 @@
}
@Test
- public void testRegisterSystemDefaultCallbackRequiresNetworkSettings() throws Exception {
+ public void testRegisterPrivilegedDefaultCallbacksRequireNetworkSettings() throws Exception {
mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(false /* validated */);
@@ -3971,30 +4065,38 @@
assertThrows(SecurityException.class,
() -> mCm.registerSystemDefaultNetworkCallback(callback, handler));
callback.assertNoCallback();
+ assertThrows(SecurityException.class,
+ () -> mCm.registerDefaultNetworkCallbackAsUid(APP1_UID, callback, handler));
+ callback.assertNoCallback();
mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS,
PERMISSION_GRANTED);
mCm.registerSystemDefaultNetworkCallback(callback, handler);
callback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
mCm.unregisterNetworkCallback(callback);
+
+ mCm.registerDefaultNetworkCallbackAsUid(APP1_UID, callback, handler);
+ callback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
+ mCm.unregisterNetworkCallback(callback);
}
private void setCaptivePortalMode(int mode) {
ContentResolver cr = mServiceContext.getContentResolver();
- Settings.Global.putInt(cr, Settings.Global.CAPTIVE_PORTAL_MODE, mode);
+ Settings.Global.putInt(cr, ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE, mode);
}
private void setAlwaysOnNetworks(boolean enable) {
ContentResolver cr = mServiceContext.getContentResolver();
- Settings.Global.putInt(cr, Settings.Global.MOBILE_DATA_ALWAYS_ON, enable ? 1 : 0);
+ Settings.Global.putInt(cr, ConnectivitySettingsManager.MOBILE_DATA_ALWAYS_ON,
+ enable ? 1 : 0);
mService.updateAlwaysOnNetworks();
waitForIdle();
}
private void setPrivateDnsSettings(String mode, String specifier) {
final ContentResolver cr = mServiceContext.getContentResolver();
- Settings.Global.putString(cr, Settings.Global.PRIVATE_DNS_MODE, mode);
- Settings.Global.putString(cr, Settings.Global.PRIVATE_DNS_SPECIFIER, specifier);
+ Settings.Global.putString(cr, ConnectivitySettingsManager.PRIVATE_DNS_MODE, mode);
+ Settings.Global.putString(cr, ConnectivitySettingsManager.PRIVATE_DNS_SPECIFIER, specifier);
mService.updatePrivateDnsSettings();
waitForIdle();
}
@@ -4011,7 +4113,8 @@
grantUsingBackgroundNetworksPermissionForUid(Binder.getCallingUid());
final TestNetworkCallback cellBgCallback = new TestNetworkCallback();
mCm.requestBackgroundNetwork(new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_CELLULAR).build(), null, cellBgCallback);
+ .addTransportType(TRANSPORT_CELLULAR).build(),
+ mCsHandlerThread.getThreadHandler(), cellBgCallback);
// Make callbacks for monitoring.
final NetworkRequest request = new NetworkRequest.Builder().build();
@@ -4231,7 +4334,7 @@
@Test
public void testAvoidBadWifiSetting() throws Exception {
final ContentResolver cr = mServiceContext.getContentResolver();
- final String settingName = Settings.Global.NETWORK_AVOID_BAD_WIFI;
+ final String settingName = ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI;
mPolicyTracker.mConfigRestrictsAvoidBadWifi = false;
String[] values = new String[] {null, "0", "1"};
@@ -4265,6 +4368,7 @@
assertTrue(mPolicyTracker.shouldNotifyWifiUnvalidated());
}
+ @Ignore("Refactoring in progress b/178071397")
@Test
public void testAvoidBadWifi() throws Exception {
final ContentResolver cr = mServiceContext.getContentResolver();
@@ -4288,7 +4392,7 @@
TestNetworkCallback validatedWifiCallback = new TestNetworkCallback();
mCm.registerNetworkCallback(validatedWifiRequest, validatedWifiCallback);
- Settings.Global.putInt(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, 0);
+ Settings.Global.putInt(cr, ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI, 0);
mPolicyTracker.reevaluate();
// Bring up validated cell.
@@ -4356,7 +4460,7 @@
validatedWifiCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
// Simulate the user selecting "switch" and checking the don't ask again checkbox.
- Settings.Global.putInt(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, 1);
+ Settings.Global.putInt(cr, ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI, 1);
mPolicyTracker.reevaluate();
// We now switch to cell.
@@ -4369,11 +4473,11 @@
// Simulate the user turning the cellular fallback setting off and then on.
// We switch to wifi and then to cell.
- Settings.Global.putString(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, null);
+ Settings.Global.putString(cr, ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI, null);
mPolicyTracker.reevaluate();
defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
assertEquals(mCm.getActiveNetwork(), wifiNetwork);
- Settings.Global.putInt(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, 1);
+ Settings.Global.putInt(cr, ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI, 1);
mPolicyTracker.reevaluate();
defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
assertEquals(mCm.getActiveNetwork(), cellNetwork);
@@ -4392,7 +4496,7 @@
@Test
public void testMeteredMultipathPreferenceSetting() throws Exception {
final ContentResolver cr = mServiceContext.getContentResolver();
- final String settingName = Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE;
+ final String settingName = ConnectivitySettingsManager.NETWORK_METERED_MULTIPATH_PREFERENCE;
for (int config : Arrays.asList(0, 3, 2)) {
for (String setting: Arrays.asList(null, "0", "2", "1")) {
@@ -6868,7 +6972,7 @@
final int uid = Process.myUid();
NetworkCapabilities nc = mCm.getNetworkCapabilities(mMockVpn.getNetwork());
assertNotNull("nc=" + nc, nc.getUids());
- assertEquals(nc.getUids(), uidRangesForUids(uid));
+ assertEquals(nc.getUids(), UidRange.toIntRanges(uidRangesForUids(uid)));
assertVpnTransportInfo(nc, VpnManager.TYPE_VPN_SERVICE);
// Set an underlying network and expect to see the VPN transports change.
@@ -6893,10 +6997,13 @@
// Expect that the VPN UID ranges contain both |uid| and the UID range for the newly-added
// restricted user.
+ final UidRange rRange = UidRange.createForUser(UserHandle.of(RESTRICTED_USER));
+ final Range<Integer> restrictUidRange = new Range<Integer>(rRange.start, rRange.stop);
+ final Range<Integer> singleUidRange = new Range<Integer>(uid, uid);
callback.expectCapabilitiesThat(mMockVpn, (caps)
-> caps.getUids().size() == 2
- && caps.getUids().contains(new UidRange(uid, uid))
- && caps.getUids().contains(createUidRange(RESTRICTED_USER))
+ && caps.getUids().contains(singleUidRange)
+ && caps.getUids().contains(restrictUidRange)
&& caps.hasTransport(TRANSPORT_VPN)
&& caps.hasTransport(TRANSPORT_WIFI));
@@ -6905,8 +7012,8 @@
callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
callback.expectCapabilitiesThat(mMockVpn, (caps)
-> caps.getUids().size() == 2
- && caps.getUids().contains(new UidRange(uid, uid))
- && caps.getUids().contains(createUidRange(RESTRICTED_USER))
+ && caps.getUids().contains(singleUidRange)
+ && caps.getUids().contains(restrictUidRange)
&& caps.hasTransport(TRANSPORT_VPN)
&& !caps.hasTransport(TRANSPORT_WIFI));
@@ -6920,7 +7027,7 @@
// change made just before that (i.e., loss of TRANSPORT_WIFI) is preserved.
callback.expectCapabilitiesThat(mMockVpn, (caps)
-> caps.getUids().size() == 1
- && caps.getUids().contains(new UidRange(uid, uid))
+ && caps.getUids().contains(singleUidRange)
&& caps.hasTransport(TRANSPORT_VPN)
&& !caps.hasTransport(TRANSPORT_WIFI));
}
@@ -7170,6 +7277,20 @@
mMockVpn.disconnect();
}
+ private class DetailedBlockedStatusCallback extends TestNetworkCallback {
+ public void expectAvailableThenValidatedCallbacks(HasNetwork n, int blockedStatus) {
+ super.expectAvailableThenValidatedCallbacks(n.getNetwork(), blockedStatus, TIMEOUT_MS);
+ }
+ public void expectBlockedStatusCallback(HasNetwork n, int blockedStatus) {
+ // This doesn't work:
+ // super.expectBlockedStatusCallback(blockedStatus, n.getNetwork());
+ super.expectBlockedStatusCallback(blockedStatus, n.getNetwork(), TIMEOUT_MS);
+ }
+ public void onBlockedStatusChanged(Network network, int blockedReasons) {
+ getHistory().add(new CallbackEntry.BlockedStatusInt(network, blockedReasons));
+ }
+ }
+
@Test
public void testNetworkBlockedStatus() throws Exception {
final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
@@ -7177,81 +7298,116 @@
.addTransportType(TRANSPORT_CELLULAR)
.build();
mCm.registerNetworkCallback(cellRequest, cellNetworkCallback);
+ final DetailedBlockedStatusCallback detailedCallback = new DetailedBlockedStatusCallback();
+ mCm.registerNetworkCallback(cellRequest, detailedCallback);
+
mockUidNetworkingBlocked();
mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(true);
cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+ detailedCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent,
+ BLOCKED_REASON_NONE);
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
+ assertExtraInfoFromCmPresent(mCellNetworkAgent);
- setUidRulesChanged(RULE_REJECT_ALL);
+ setBlockedReasonChanged(BLOCKED_REASON_BATTERY_SAVER);
cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
+ detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent,
+ BLOCKED_REASON_BATTERY_SAVER);
assertNull(mCm.getActiveNetwork());
assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
+ assertExtraInfoFromCmBlocked(mCellNetworkAgent);
- // ConnectivityService should cache it not to invoke the callback again.
- setUidRulesChanged(RULE_REJECT_METERED);
- cellNetworkCallback.assertNoCallback();
+ // If blocked state does not change but blocked reason does, the boolean callback is called.
+ // TODO: investigate de-duplicating.
+ setBlockedReasonChanged(BLOCKED_METERED_REASON_USER_RESTRICTED);
+ cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
+ detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent,
+ BLOCKED_METERED_REASON_USER_RESTRICTED);
- setUidRulesChanged(RULE_NONE);
+ setBlockedReasonChanged(BLOCKED_REASON_NONE);
cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
+ detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent, BLOCKED_REASON_NONE);
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
+ assertExtraInfoFromCmPresent(mCellNetworkAgent);
- setUidRulesChanged(RULE_REJECT_METERED);
+ setBlockedReasonChanged(BLOCKED_METERED_REASON_DATA_SAVER);
cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
+ detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent,
+ BLOCKED_METERED_REASON_DATA_SAVER);
assertNull(mCm.getActiveNetwork());
assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
+ assertExtraInfoFromCmBlocked(mCellNetworkAgent);
// Restrict the network based on UID rule and NOT_METERED capability change.
mCellNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
cellNetworkCallback.expectCapabilitiesWith(NET_CAPABILITY_NOT_METERED, mCellNetworkAgent);
cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
+ detailedCallback.expectCapabilitiesWith(NET_CAPABILITY_NOT_METERED, mCellNetworkAgent);
+ detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent, BLOCKED_REASON_NONE);
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
+ assertExtraInfoFromCmPresent(mCellNetworkAgent);
mCellNetworkAgent.removeCapability(NET_CAPABILITY_NOT_METERED);
cellNetworkCallback.expectCapabilitiesWithout(NET_CAPABILITY_NOT_METERED,
mCellNetworkAgent);
cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
+ detailedCallback.expectCapabilitiesWithout(NET_CAPABILITY_NOT_METERED,
+ mCellNetworkAgent);
+ detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent,
+ BLOCKED_METERED_REASON_DATA_SAVER);
assertNull(mCm.getActiveNetwork());
assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
+ assertExtraInfoFromCmBlocked(mCellNetworkAgent);
- setUidRulesChanged(RULE_ALLOW_METERED);
+ setBlockedReasonChanged(BLOCKED_REASON_NONE);
cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
+ detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent, BLOCKED_REASON_NONE);
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
+ assertExtraInfoFromCmPresent(mCellNetworkAgent);
- setUidRulesChanged(RULE_NONE);
+ setBlockedReasonChanged(BLOCKED_REASON_NONE);
cellNetworkCallback.assertNoCallback();
+ detailedCallback.assertNoCallback();
// Restrict background data. Networking is not blocked because the network is unmetered.
- setRestrictBackgroundChanged(true);
+ setBlockedReasonChanged(BLOCKED_METERED_REASON_DATA_SAVER);
cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
+ detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent,
+ BLOCKED_METERED_REASON_DATA_SAVER);
assertNull(mCm.getActiveNetwork());
assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
- setRestrictBackgroundChanged(true);
+ assertExtraInfoFromCmBlocked(mCellNetworkAgent);
+ setBlockedReasonChanged(BLOCKED_METERED_REASON_DATA_SAVER);
cellNetworkCallback.assertNoCallback();
- setUidRulesChanged(RULE_ALLOW_METERED);
+ setBlockedReasonChanged(BLOCKED_REASON_NONE);
cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
+ detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent, BLOCKED_REASON_NONE);
assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
+ assertExtraInfoFromCmPresent(mCellNetworkAgent);
- setRestrictBackgroundChanged(false);
+ setBlockedReasonChanged(BLOCKED_REASON_NONE);
cellNetworkCallback.assertNoCallback();
+ detailedCallback.assertNoCallback();
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
+ assertExtraInfoFromCmPresent(mCellNetworkAgent);
mCm.unregisterNetworkCallback(cellNetworkCallback);
}
@@ -7263,9 +7419,9 @@
mockUidNetworkingBlocked();
// No Networkcallbacks invoked before any network is active.
- setUidRulesChanged(RULE_REJECT_ALL);
- setUidRulesChanged(RULE_NONE);
- setUidRulesChanged(RULE_REJECT_METERED);
+ setBlockedReasonChanged(BLOCKED_REASON_BATTERY_SAVER);
+ setBlockedReasonChanged(BLOCKED_REASON_NONE);
+ setBlockedReasonChanged(BLOCKED_METERED_REASON_DATA_SAVER);
defaultCallback.assertNoCallback();
mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
@@ -7290,8 +7446,8 @@
defaultCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
// Verify there's no Networkcallbacks invoked after data saver on/off.
- setRestrictBackgroundChanged(true);
- setRestrictBackgroundChanged(false);
+ setBlockedReasonChanged(BLOCKED_METERED_REASON_DATA_SAVER);
+ setBlockedReasonChanged(BLOCKED_REASON_NONE);
defaultCallback.assertNoCallback();
mCellNetworkAgent.disconnect();
@@ -7310,6 +7466,15 @@
assertNotNull(ni);
assertEquals(type, ni.getType());
assertEquals(ConnectivityManager.getNetworkTypeName(type), state, ni.getDetailedState());
+ if (state == DetailedState.CONNECTED || state == DetailedState.SUSPENDED) {
+ assertNotNull(ni.getExtraInfo());
+ } else {
+ // Technically speaking, a network that's in CONNECTING state will generally have a
+ // non-null extraInfo. This doesn't actually happen in this test because it never calls
+ // a legacy API while a network is connecting. When a network is in CONNECTING state
+ // because of legacy lockdown VPN, its extraInfo is always null.
+ assertNull(ni.getExtraInfo());
+ }
}
private void assertActiveNetworkInfo(int type, DetailedState state) {
@@ -7319,6 +7484,26 @@
checkNetworkInfo(mCm.getNetworkInfo(type), type, state);
}
+ private void assertExtraInfoFromCm(TestNetworkAgentWrapper network, boolean present) {
+ final NetworkInfo niForNetwork = mCm.getNetworkInfo(network.getNetwork());
+ final NetworkInfo niForType = mCm.getNetworkInfo(network.getLegacyType());
+ if (present) {
+ assertEquals(network.getExtraInfo(), niForNetwork.getExtraInfo());
+ assertEquals(network.getExtraInfo(), niForType.getExtraInfo());
+ } else {
+ assertNull(niForNetwork.getExtraInfo());
+ assertNull(niForType.getExtraInfo());
+ }
+ }
+
+ private void assertExtraInfoFromCmBlocked(TestNetworkAgentWrapper network) {
+ assertExtraInfoFromCm(network, false);
+ }
+
+ private void assertExtraInfoFromCmPresent(TestNetworkAgentWrapper network) {
+ assertExtraInfoFromCm(network, true);
+ }
+
// Checks that each of the |agents| receive a blocked status change callback with the specified
// |blocked| value, in any order. This is needed because when an event affects multiple
// networks, ConnectivityService does not guarantee the order in which callbacks are fired.
@@ -7361,6 +7546,13 @@
final NetworkRequest vpnUidRequest = new NetworkRequest.Builder().build();
registerNetworkCallbackAsUid(vpnUidRequest, vpnUidCallback, VPN_UID);
+ final TestNetworkCallback vpnUidDefaultCallback = new TestNetworkCallback();
+ registerDefaultNetworkCallbackAsUid(vpnUidDefaultCallback, VPN_UID);
+
+ final TestNetworkCallback vpnDefaultCallbackAsUid = new TestNetworkCallback();
+ mCm.registerDefaultNetworkCallbackAsUid(VPN_UID, vpnDefaultCallbackAsUid,
+ new Handler(ConnectivityThread.getInstanceLooper()));
+
final int uid = Process.myUid();
final int userId = UserHandle.getUserId(uid);
final ArrayList<String> allowList = new ArrayList<>();
@@ -7379,6 +7571,8 @@
callback.expectAvailableCallbacksUnvalidatedAndBlocked(mWiFiNetworkAgent);
defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mWiFiNetworkAgent);
vpnUidCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+ vpnUidDefaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+ vpnDefaultCallbackAsUid.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID));
assertNull(mCm.getActiveNetwork());
assertActiveNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED);
@@ -7391,6 +7585,8 @@
callback.expectBlockedStatusCallback(false, mWiFiNetworkAgent);
defaultCallback.expectBlockedStatusCallback(false, mWiFiNetworkAgent);
vpnUidCallback.assertNoCallback();
+ vpnUidDefaultCallback.assertNoCallback();
+ vpnDefaultCallbackAsUid.assertNoCallback();
expectNetworkRejectNonSecureVpn(inOrder, false, firstHalf, secondHalf);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID));
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
@@ -7405,6 +7601,8 @@
callback.assertNoCallback();
defaultCallback.assertNoCallback();
vpnUidCallback.assertNoCallback();
+ vpnUidDefaultCallback.assertNoCallback();
+ vpnDefaultCallbackAsUid.assertNoCallback();
// The following requires that the UID of this test package is greater than VPN_UID. This
// is always true in practice because a plain AOSP build with no apps installed has almost
@@ -7425,6 +7623,8 @@
callback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
defaultCallback.assertNoCallback();
vpnUidCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
+ vpnUidDefaultCallback.assertNoCallback();
+ vpnDefaultCallbackAsUid.assertNoCallback();
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID));
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
@@ -7445,6 +7645,8 @@
defaultCallback.expectBlockedStatusCallback(true, mWiFiNetworkAgent);
assertBlockedCallbackInAnyOrder(callback, true, mWiFiNetworkAgent, mCellNetworkAgent);
vpnUidCallback.assertNoCallback();
+ vpnUidDefaultCallback.assertNoCallback();
+ vpnDefaultCallbackAsUid.assertNoCallback();
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID));
assertNull(mCm.getActiveNetwork());
assertActiveNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED);
@@ -7456,6 +7658,8 @@
defaultCallback.expectBlockedStatusCallback(false, mWiFiNetworkAgent);
assertBlockedCallbackInAnyOrder(callback, false, mWiFiNetworkAgent, mCellNetworkAgent);
vpnUidCallback.assertNoCallback();
+ vpnUidDefaultCallback.assertNoCallback();
+ vpnDefaultCallbackAsUid.assertNoCallback();
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID));
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
@@ -7470,6 +7674,8 @@
callback.assertNoCallback();
defaultCallback.assertNoCallback();
vpnUidCallback.assertNoCallback();
+ vpnUidDefaultCallback.assertNoCallback();
+ vpnDefaultCallbackAsUid.assertNoCallback();
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID));
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
@@ -7481,6 +7687,8 @@
callback.assertNoCallback();
defaultCallback.assertNoCallback();
vpnUidCallback.assertNoCallback();
+ vpnUidDefaultCallback.assertNoCallback();
+ vpnDefaultCallbackAsUid.assertNoCallback();
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID));
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
@@ -7493,6 +7701,8 @@
defaultCallback.expectBlockedStatusCallback(true, mWiFiNetworkAgent);
assertBlockedCallbackInAnyOrder(callback, true, mWiFiNetworkAgent, mCellNetworkAgent);
vpnUidCallback.assertNoCallback();
+ vpnUidDefaultCallback.assertNoCallback();
+ vpnDefaultCallbackAsUid.assertNoCallback();
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID));
assertNull(mCm.getActiveNetwork());
assertActiveNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED);
@@ -7503,6 +7713,8 @@
assertUidRangesUpdatedForMyUid(true);
defaultCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
vpnUidCallback.assertNoCallback(); // vpnUidCallback has NOT_VPN capability.
+ vpnUidDefaultCallback.assertNoCallback(); // VPN does not apply to VPN_UID
+ vpnDefaultCallbackAsUid.assertNoCallback();
assertEquals(mMockVpn.getNetwork(), mCm.getActiveNetwork());
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID));
assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
@@ -7513,11 +7725,16 @@
mMockVpn.disconnect();
defaultCallback.expectCallback(CallbackEntry.LOST, mMockVpn);
defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mWiFiNetworkAgent);
+ vpnUidCallback.assertNoCallback();
+ vpnUidDefaultCallback.assertNoCallback();
+ vpnDefaultCallbackAsUid.assertNoCallback();
assertNull(mCm.getActiveNetwork());
mCm.unregisterNetworkCallback(callback);
mCm.unregisterNetworkCallback(defaultCallback);
mCm.unregisterNetworkCallback(vpnUidCallback);
+ mCm.unregisterNetworkCallback(vpnUidDefaultCallback);
+ mCm.unregisterNetworkCallback(vpnDefaultCallbackAsUid);
}
private void setupLegacyLockdownVpn() {
@@ -7539,7 +7756,7 @@
assertNotNull(underlying);
mMockVpn.setVpnType(VpnManager.TYPE_VPN_LEGACY);
// The legacy lockdown VPN only supports userId 0.
- final Set<UidRange> ranges = Collections.singleton(createUidRange(PRIMARY_USER));
+ final Set<UidRange> ranges = Collections.singleton(PRIMARY_UIDRANGE);
mMockVpn.registerAgent(ranges);
mMockVpn.setUnderlyingNetworks(new Network[]{underlying});
mMockVpn.connect(true);
@@ -7633,6 +7850,7 @@
assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
assertNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED);
assertNetworkInfo(TYPE_VPN, DetailedState.BLOCKED);
+ assertExtraInfoFromCmBlocked(mCellNetworkAgent);
// TODO: it would be nice if we could simply rely on the production code here, and have
// LockdownVpnTracker start the VPN, have the VPN code register its NetworkAgent with
@@ -7661,6 +7879,7 @@
assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
assertNetworkInfo(TYPE_WIFI, DetailedState.DISCONNECTED);
assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED);
+ assertExtraInfoFromCmPresent(mCellNetworkAgent);
assertTrue(vpnNc.hasTransport(TRANSPORT_VPN));
assertTrue(vpnNc.hasTransport(TRANSPORT_CELLULAR));
assertFalse(vpnNc.hasTransport(TRANSPORT_WIFI));
@@ -7703,6 +7922,7 @@
assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
assertNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED);
assertNetworkInfo(TYPE_VPN, DetailedState.BLOCKED);
+ assertExtraInfoFromCmBlocked(mWiFiNetworkAgent);
// The VPN comes up again on wifi.
b1 = expectConnectivityAction(TYPE_VPN, DetailedState.CONNECTED);
@@ -7717,6 +7937,7 @@
assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED);
assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED);
+ assertExtraInfoFromCmPresent(mWiFiNetworkAgent);
vpnNc = mCm.getNetworkCapabilities(mMockVpn.getNetwork());
assertTrue(vpnNc.hasTransport(TRANSPORT_VPN));
assertTrue(vpnNc.hasTransport(TRANSPORT_WIFI));
@@ -7733,6 +7954,7 @@
assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED);
assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED);
+ assertExtraInfoFromCmPresent(mWiFiNetworkAgent);
b1 = expectConnectivityAction(TYPE_WIFI, DetailedState.DISCONNECTED);
mWiFiNetworkAgent.disconnect();
@@ -7812,7 +8034,6 @@
verify(mDeps).reportNetworkInterfaceForTransports(mServiceContext,
cellLp.getInterfaceName(),
new int[] { TRANSPORT_CELLULAR });
- reset(mBatteryStatsService);
final LinkProperties wifiLp = new LinkProperties();
wifiLp.setInterfaceName("wifi0");
@@ -7822,7 +8043,6 @@
verify(mDeps).reportNetworkInterfaceForTransports(mServiceContext,
wifiLp.getInterfaceName(),
new int[] { TRANSPORT_WIFI });
- reset(mBatteryStatsService);
mCellNetworkAgent.disconnect();
mWiFiNetworkAgent.disconnect();
@@ -7905,7 +8125,6 @@
mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp);
reset(mMockDnsResolver);
reset(mMockNetd);
- reset(mBatteryStatsService);
// Connect with ipv6 link properties. Expect prefix discovery to be started.
mCellNetworkAgent.connect(true);
@@ -7925,7 +8144,6 @@
// Switching default network updates TCP buffer sizes.
verifyTcpBufferSizeChange(ConnectivityService.DEFAULT_TCP_BUFFER_SIZES);
- verify(mSystemProperties, times(1)).setTcpInitRwnd(eq(TEST_TCP_INIT_RWND));
// Add an IPv4 address. Expect prefix discovery to be stopped. Netd doesn't tell us that
// the NAT64 prefix was removed because one was never discovered.
cellLp.addLinkAddress(myIpv4);
@@ -8268,6 +8486,45 @@
}
@Test
+ public void testWith464XlatDisable() throws Exception {
+ doReturn(false).when(mDeps).getCellular464XlatEnabled();
+
+ final TestNetworkCallback callback = new TestNetworkCallback();
+ final TestNetworkCallback defaultCallback = new TestNetworkCallback();
+ final NetworkRequest networkRequest = new NetworkRequest.Builder()
+ .addCapability(NET_CAPABILITY_INTERNET)
+ .build();
+ mCm.registerNetworkCallback(networkRequest, callback);
+ mCm.registerDefaultNetworkCallback(defaultCallback);
+
+ // Bring up validated cell.
+ final LinkProperties cellLp = new LinkProperties();
+ cellLp.setInterfaceName(MOBILE_IFNAME);
+ cellLp.addLinkAddress(new LinkAddress("2001:db8:1::1/64"));
+ cellLp.addRoute(new RouteInfo(new IpPrefix("::/0"), null, MOBILE_IFNAME));
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+
+ mCellNetworkAgent.sendLinkProperties(cellLp);
+ mCellNetworkAgent.connect(true);
+ callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+ defaultCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+ final int cellNetId = mCellNetworkAgent.getNetwork().netId;
+ waitForIdle();
+
+ verify(mMockDnsResolver, never()).startPrefix64Discovery(cellNetId);
+ Nat464Xlat clat = getNat464Xlat(mCellNetworkAgent);
+ assertTrue("Nat464Xlat was not IDLE", !clat.isStarted());
+
+ // This cannot happen because prefix discovery cannot succeed if it is never started.
+ mService.mResolverUnsolEventCallback.onNat64PrefixEvent(
+ makeNat64PrefixEvent(cellNetId, PREFIX_OPERATION_ADDED, "64:ff9b::", 96));
+
+ // ... but still, check that even if it did, clatd would not be started.
+ verify(mMockNetd, never()).clatdStart(anyString(), anyString());
+ assertTrue("Nat464Xlat was not IDLE", !clat.isStarted());
+ }
+
+ @Test
public void testDataActivityTracking() throws Exception {
final TestNetworkCallback networkCallback = new TestNetworkCallback();
final NetworkRequest networkRequest = new NetworkRequest.Builder()
@@ -8372,14 +8629,12 @@
mCellNetworkAgent.connect(false);
networkCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
verifyTcpBufferSizeChange(ConnectivityService.DEFAULT_TCP_BUFFER_SIZES);
- verify(mSystemProperties, times(1)).setTcpInitRwnd(eq(TEST_TCP_INIT_RWND));
// Change link Properties should have updated tcp buffer size.
LinkProperties lp = new LinkProperties();
lp.setTcpBufferSizes(testTcpBufferSizes);
mCellNetworkAgent.sendLinkProperties(lp);
networkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
verifyTcpBufferSizeChange(testTcpBufferSizes);
- verify(mSystemProperties, times(2)).setTcpInitRwnd(eq(TEST_TCP_INIT_RWND));
// Clean up.
mCellNetworkAgent.disconnect();
networkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
@@ -8463,7 +8718,7 @@
lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE));
// The uid range needs to cover the test app so the network is visible to it.
- final Set<UidRange> vpnRange = Collections.singleton(createUidRange(PRIMARY_USER));
+ final Set<UidRange> vpnRange = Collections.singleton(PRIMARY_UIDRANGE);
mMockVpn.establish(lp, VPN_UID, vpnRange);
assertVpnUidRangesUpdated(true, vpnRange, VPN_UID);
@@ -8491,7 +8746,7 @@
lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
// The uid range needs to cover the test app so the network is visible to it.
- final Set<UidRange> vpnRange = Collections.singleton(createUidRange(PRIMARY_USER));
+ final Set<UidRange> vpnRange = Collections.singleton(PRIMARY_UIDRANGE);
mMockVpn.establish(lp, Process.SYSTEM_UID, vpnRange);
assertVpnUidRangesUpdated(true, vpnRange, Process.SYSTEM_UID);
@@ -8507,7 +8762,7 @@
lp.addRoute(new RouteInfo(new IpPrefix("192.0.2.0/24"), null, "tun0"));
lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE));
// The uid range needs to cover the test app so the network is visible to it.
- final Set<UidRange> vpnRange = Collections.singleton(createUidRange(PRIMARY_USER));
+ final Set<UidRange> vpnRange = Collections.singleton(PRIMARY_UIDRANGE);
mMockVpn.establish(lp, Process.SYSTEM_UID, vpnRange);
assertVpnUidRangesUpdated(true, vpnRange, Process.SYSTEM_UID);
@@ -8522,7 +8777,7 @@
lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
// The uid range needs to cover the test app so the network is visible to it.
- final Set<UidRange> vpnRange = Collections.singleton(createUidRange(PRIMARY_USER));
+ final Set<UidRange> vpnRange = Collections.singleton(PRIMARY_UIDRANGE);
mMockVpn.establish(lp, VPN_UID, vpnRange);
assertVpnUidRangesUpdated(true, vpnRange, VPN_UID);
@@ -8574,7 +8829,7 @@
lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), RTN_UNREACHABLE));
lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
// The uid range needs to cover the test app so the network is visible to it.
- final UidRange vpnRange = createUidRange(PRIMARY_USER);
+ final UidRange vpnRange = PRIMARY_UIDRANGE;
final Set<UidRange> vpnRanges = Collections.singleton(vpnRange);
mMockVpn.establish(lp, VPN_UID, vpnRanges);
assertVpnUidRangesUpdated(true, vpnRanges, VPN_UID);
@@ -8659,6 +8914,7 @@
applicationInfo.targetSdkVersion = targetSdk;
when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), any()))
.thenReturn(applicationInfo);
+ when(mPackageManager.getTargetSdkVersion(any())).thenReturn(targetSdk);
when(mLocationManager.isLocationEnabledForUser(any())).thenReturn(locationToggle);
@@ -8673,107 +8929,372 @@
}
}
- private int getOwnerUidNetCapsForCallerPermission(int ownerUid, int callerUid) {
+ private int getOwnerUidNetCapsPermission(int ownerUid, int callerUid,
+ boolean includeLocationSensitiveInfo) {
final NetworkCapabilities netCap = new NetworkCapabilities().setOwnerUid(ownerUid);
return mService.createWithLocationInfoSanitizedIfNecessaryWhenParceled(
- netCap, callerUid, mContext.getPackageName(), getAttributionTag()).getOwnerUid();
+ netCap, includeLocationSensitiveInfo, Process.myUid(), callerUid,
+ mContext.getPackageName(), getAttributionTag())
+ .getOwnerUid();
}
- private void verifyWifiInfoCopyNetCapsForCallerPermission(
- int callerUid, boolean shouldMakeCopyWithLocationSensitiveFieldsParcelable) {
- final WifiInfo wifiInfo = mock(WifiInfo.class);
- when(wifiInfo.hasLocationSensitiveFields()).thenReturn(true);
- final NetworkCapabilities netCap = new NetworkCapabilities().setTransportInfo(wifiInfo);
+ private void verifyTransportInfoCopyNetCapsPermission(
+ int callerUid, boolean includeLocationSensitiveInfo,
+ boolean shouldMakeCopyWithLocationSensitiveFieldsParcelable) {
+ final TransportInfo transportInfo = mock(TransportInfo.class);
+ when(transportInfo.getApplicableRedactions()).thenReturn(REDACT_FOR_ACCESS_FINE_LOCATION);
+ final NetworkCapabilities netCap =
+ new NetworkCapabilities().setTransportInfo(transportInfo);
mService.createWithLocationInfoSanitizedIfNecessaryWhenParceled(
- netCap, callerUid, mContext.getPackageName(), getAttributionTag());
- verify(wifiInfo).makeCopy(eq(shouldMakeCopyWithLocationSensitiveFieldsParcelable));
+ netCap, includeLocationSensitiveInfo, Process.myPid(), callerUid,
+ mContext.getPackageName(), getAttributionTag());
+ if (shouldMakeCopyWithLocationSensitiveFieldsParcelable) {
+ verify(transportInfo).makeCopy(REDACT_NONE);
+ } else {
+ verify(transportInfo).makeCopy(REDACT_FOR_ACCESS_FINE_LOCATION);
+ }
+ }
+
+ private void verifyOwnerUidAndTransportInfoNetCapsPermission(
+ boolean shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag,
+ boolean shouldInclLocationSensitiveOwnerUidWithIncludeFlag,
+ boolean shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag,
+ boolean shouldInclLocationSensitiveTransportInfoWithIncludeFlag) {
+ final int myUid = Process.myUid();
+
+ final int expectedOwnerUidWithoutIncludeFlag =
+ shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag
+ ? Process.myUid() : INVALID_UID;
+ assertEquals(expectedOwnerUidWithoutIncludeFlag, getOwnerUidNetCapsPermission(
+ myUid, myUid, false /* includeLocationSensitiveInfo */));
+
+ final int expectedOwnerUidWithIncludeFlag =
+ shouldInclLocationSensitiveOwnerUidWithIncludeFlag ? myUid : INVALID_UID;
+ assertEquals(expectedOwnerUidWithIncludeFlag, getOwnerUidNetCapsPermission(
+ myUid, myUid, true /* includeLocationSensitiveInfo */));
+
+ verifyTransportInfoCopyNetCapsPermission(myUid,
+ false, /* includeLocationSensitiveInfo */
+ shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag);
+
+ verifyTransportInfoCopyNetCapsPermission(myUid,
+ true, /* includeLocationSensitiveInfo */
+ shouldInclLocationSensitiveTransportInfoWithIncludeFlag);
+
}
@Test
- public void testCreateForCallerWithLocationInfoSanitizedWithFineLocationAfterQ()
+ public void testCreateWithLocationInfoSanitizedWithFineLocationAfterQ()
throws Exception {
setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION);
- final int myUid = Process.myUid();
- assertEquals(myUid, getOwnerUidNetCapsForCallerPermission(myUid, myUid));
-
- verifyWifiInfoCopyNetCapsForCallerPermission(myUid,
- true /* shouldMakeCopyWithLocationSensitiveFieldsParcelable */);
+ verifyOwnerUidAndTransportInfoNetCapsPermission(
+ // Ensure that we include owner uid even if the request asks to remove it since the
+ // app has necessary permissions and targetSdk < S.
+ true, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
+ true, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
+ false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
+ // Ensure that we remove location info if the request asks to remove it even if the
+ // app has necessary permissions.
+ true /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
+ );
}
@Test
- public void testCreateForCallerWithLocationInfoSanitizedWithCoarseLocationPreQ()
+ public void testCreateWithLocationInfoSanitizedWithFineLocationPreSWithAndWithoutCallbackFlag()
+ throws Exception {
+ setupLocationPermissions(Build.VERSION_CODES.R, true, AppOpsManager.OPSTR_FINE_LOCATION,
+ Manifest.permission.ACCESS_FINE_LOCATION);
+
+ verifyOwnerUidAndTransportInfoNetCapsPermission(
+ // Ensure that we include owner uid even if the request asks to remove it since the
+ // app has necessary permissions and targetSdk < S.
+ true, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
+ true, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
+ false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
+ // Ensure that we remove location info if the request asks to remove it even if the
+ // app has necessary permissions.
+ true /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
+ );
+ }
+
+ @Test
+ public void
+ testCreateWithLocationInfoSanitizedWithFineLocationAfterSWithAndWithoutCallbackFlag()
+ throws Exception {
+ setupLocationPermissions(Build.VERSION_CODES.S, true, AppOpsManager.OPSTR_FINE_LOCATION,
+ Manifest.permission.ACCESS_FINE_LOCATION);
+
+ verifyOwnerUidAndTransportInfoNetCapsPermission(
+ // Ensure that we owner UID if the request asks us to remove it even if the app
+ // has necessary permissions since targetSdk >= S.
+ false, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
+ true, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
+ false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
+ // Ensure that we remove location info if the request asks to remove it even if the
+ // app has necessary permissions.
+ true /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
+ );
+ }
+
+ @Test
+ public void testCreateWithLocationInfoSanitizedWithCoarseLocationPreQ()
throws Exception {
setupLocationPermissions(Build.VERSION_CODES.P, true, AppOpsManager.OPSTR_COARSE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION);
- final int myUid = Process.myUid();
- assertEquals(myUid, getOwnerUidNetCapsForCallerPermission(myUid, myUid));
-
- verifyWifiInfoCopyNetCapsForCallerPermission(myUid,
- true /* shouldMakeCopyWithLocationSensitiveFieldsParcelable */);
+ verifyOwnerUidAndTransportInfoNetCapsPermission(
+ // Ensure that we owner UID if the request asks us to remove it even if the app
+ // has necessary permissions since targetSdk >= S.
+ true, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
+ true, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
+ false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
+ // Ensure that we remove location info if the request asks to remove it even if the
+ // app has necessary permissions.
+ true /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
+ );
}
@Test
- public void testCreateForCallerWithLocationInfoSanitizedLocationOff() throws Exception {
+ public void testCreateWithLocationInfoSanitizedLocationOff() throws Exception {
// Test that even with fine location permission, and UIDs matching, the UID is sanitized.
setupLocationPermissions(Build.VERSION_CODES.Q, false, AppOpsManager.OPSTR_FINE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION);
- final int myUid = Process.myUid();
- assertEquals(Process.INVALID_UID, getOwnerUidNetCapsForCallerPermission(myUid, myUid));
-
- verifyWifiInfoCopyNetCapsForCallerPermission(myUid,
- false/* shouldMakeCopyWithLocationSensitiveFieldsParcelable */);
+ verifyOwnerUidAndTransportInfoNetCapsPermission(
+ false, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
+ false, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
+ false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
+ false /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
+ );
}
@Test
- public void testCreateForCallerWithLocationInfoSanitizedWrongUid() throws Exception {
+ public void testCreateWithLocationInfoSanitizedWrongUid() throws Exception {
// Test that even with fine location permission, not being the owner leads to sanitization.
setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION);
final int myUid = Process.myUid();
- assertEquals(Process.INVALID_UID, getOwnerUidNetCapsForCallerPermission(myUid + 1, myUid));
-
- verifyWifiInfoCopyNetCapsForCallerPermission(myUid,
- true /* shouldMakeCopyWithLocationSensitiveFieldsParcelable */);
+ assertEquals(Process.INVALID_UID,
+ getOwnerUidNetCapsPermission(myUid + 1, myUid,
+ true /* includeLocationSensitiveInfo */));
}
@Test
- public void testCreateForCallerWithLocationInfoSanitizedWithCoarseLocationAfterQ()
+ public void testCreateWithLocationInfoSanitizedWithCoarseLocationAfterQ()
throws Exception {
// Test that not having fine location permission leads to sanitization.
setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_COARSE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION);
- // Test that without the location permission, the owner field is sanitized.
- final int myUid = Process.myUid();
- assertEquals(Process.INVALID_UID, getOwnerUidNetCapsForCallerPermission(myUid, myUid));
-
- verifyWifiInfoCopyNetCapsForCallerPermission(myUid,
- false/* shouldMakeCopyWithLocationSensitiveFieldsParcelable */);
+ verifyOwnerUidAndTransportInfoNetCapsPermission(
+ false, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
+ false, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
+ false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
+ false /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
+ );
}
@Test
- public void testCreateForCallerWithLocationInfoSanitizedWithoutLocationPermission()
+ public void testCreateWithLocationInfoSanitizedWithoutLocationPermission()
throws Exception {
+ // Test that not having fine location permission leads to sanitization.
setupLocationPermissions(Build.VERSION_CODES.Q, true, null /* op */, null /* perm */);
- // Test that without the location permission, the owner field is sanitized.
- final int myUid = Process.myUid();
- assertEquals(Process.INVALID_UID, getOwnerUidNetCapsForCallerPermission(myUid, myUid));
+ verifyOwnerUidAndTransportInfoNetCapsPermission(
+ false, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
+ false, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
+ false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
+ false /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
+ );
+ }
- verifyWifiInfoCopyNetCapsForCallerPermission(myUid,
- false/* shouldMakeCopyWithLocationSensitiveFieldsParcelable */);
+ @Test
+ public void testCreateForCallerWithLocalMacAddressSanitizedWithLocalMacAddressPermission()
+ throws Exception {
+ mServiceContext.setPermission(Manifest.permission.LOCAL_MAC_ADDRESS, PERMISSION_GRANTED);
+
+ final TransportInfo transportInfo = mock(TransportInfo.class);
+ when(transportInfo.getApplicableRedactions())
+ .thenReturn(REDACT_FOR_ACCESS_FINE_LOCATION | REDACT_FOR_LOCAL_MAC_ADDRESS);
+ final NetworkCapabilities netCap =
+ new NetworkCapabilities().setTransportInfo(transportInfo);
+
+ mService.createWithLocationInfoSanitizedIfNecessaryWhenParceled(
+ netCap, false /* includeLocationSensitiveInfoInTransportInfo */,
+ Process.myPid(), Process.myUid(),
+ mContext.getPackageName(), getAttributionTag());
+ // don't redact MAC_ADDRESS fields, only location sensitive fields.
+ verify(transportInfo).makeCopy(REDACT_FOR_ACCESS_FINE_LOCATION);
+ }
+
+ @Test
+ public void testCreateForCallerWithLocalMacAddressSanitizedWithoutLocalMacAddressPermission()
+ throws Exception {
+ mServiceContext.setPermission(Manifest.permission.LOCAL_MAC_ADDRESS, PERMISSION_DENIED);
+
+ final TransportInfo transportInfo = mock(TransportInfo.class);
+ when(transportInfo.getApplicableRedactions())
+ .thenReturn(REDACT_FOR_ACCESS_FINE_LOCATION | REDACT_FOR_LOCAL_MAC_ADDRESS);
+ final NetworkCapabilities netCap =
+ new NetworkCapabilities().setTransportInfo(transportInfo);
+
+ mService.createWithLocationInfoSanitizedIfNecessaryWhenParceled(
+ netCap, false /* includeLocationSensitiveInfoInTransportInfo */,
+ Process.myPid(), Process.myUid(),
+ mContext.getPackageName(), getAttributionTag());
+ // redact both MAC_ADDRESS & location sensitive fields.
+ verify(transportInfo).makeCopy(REDACT_FOR_ACCESS_FINE_LOCATION
+ | REDACT_FOR_LOCAL_MAC_ADDRESS);
+ }
+
+ @Test
+ public void testCreateForCallerWithLocalMacAddressSanitizedWithSettingsPermission()
+ throws Exception {
+ mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS, PERMISSION_GRANTED);
+
+ final TransportInfo transportInfo = mock(TransportInfo.class);
+ when(transportInfo.getApplicableRedactions())
+ .thenReturn(REDACT_FOR_ACCESS_FINE_LOCATION | REDACT_FOR_NETWORK_SETTINGS);
+ final NetworkCapabilities netCap =
+ new NetworkCapabilities().setTransportInfo(transportInfo);
+
+ mService.createWithLocationInfoSanitizedIfNecessaryWhenParceled(
+ netCap, false /* includeLocationSensitiveInfoInTransportInfo */,
+ Process.myPid(), Process.myUid(),
+ mContext.getPackageName(), getAttributionTag());
+ // don't redact NETWORK_SETTINGS fields, only location sensitive fields.
+ verify(transportInfo).makeCopy(REDACT_FOR_ACCESS_FINE_LOCATION);
+ }
+
+ @Test
+ public void testCreateForCallerWithLocalMacAddressSanitizedWithoutSettingsPermission()
+ throws Exception {
+ mServiceContext.setPermission(Manifest.permission.LOCAL_MAC_ADDRESS, PERMISSION_DENIED);
+
+ final TransportInfo transportInfo = mock(TransportInfo.class);
+ when(transportInfo.getApplicableRedactions())
+ .thenReturn(REDACT_FOR_ACCESS_FINE_LOCATION | REDACT_FOR_NETWORK_SETTINGS);
+ final NetworkCapabilities netCap =
+ new NetworkCapabilities().setTransportInfo(transportInfo);
+
+ mService.createWithLocationInfoSanitizedIfNecessaryWhenParceled(
+ netCap, false /* includeLocationSensitiveInfoInTransportInfo */,
+ Process.myPid(), Process.myUid(),
+ mContext.getPackageName(), getAttributionTag());
+ // redact both NETWORK_SETTINGS & location sensitive fields.
+ verify(transportInfo).makeCopy(
+ REDACT_FOR_ACCESS_FINE_LOCATION | REDACT_FOR_NETWORK_SETTINGS);
+ }
+
+ /**
+ * Test TransportInfo to verify redaction mechanism.
+ */
+ private static class TestTransportInfo implements TransportInfo {
+ public final boolean locationRedacted;
+ public final boolean localMacAddressRedacted;
+ public final boolean settingsRedacted;
+
+ TestTransportInfo() {
+ locationRedacted = false;
+ localMacAddressRedacted = false;
+ settingsRedacted = false;
+ }
+
+ TestTransportInfo(boolean locationRedacted, boolean localMacAddressRedacted,
+ boolean settingsRedacted) {
+ this.locationRedacted = locationRedacted;
+ this.localMacAddressRedacted =
+ localMacAddressRedacted;
+ this.settingsRedacted = settingsRedacted;
+ }
+
+ @Override
+ public TransportInfo makeCopy(@NetworkCapabilities.RedactionType long redactions) {
+ return new TestTransportInfo(
+ (redactions & REDACT_FOR_ACCESS_FINE_LOCATION) != 0,
+ (redactions & REDACT_FOR_LOCAL_MAC_ADDRESS) != 0,
+ (redactions & REDACT_FOR_NETWORK_SETTINGS) != 0
+ );
+ }
+
+ @Override
+ public @NetworkCapabilities.RedactionType long getApplicableRedactions() {
+ return REDACT_FOR_ACCESS_FINE_LOCATION | REDACT_FOR_LOCAL_MAC_ADDRESS
+ | REDACT_FOR_NETWORK_SETTINGS;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof TestTransportInfo)) return false;
+ TestTransportInfo that = (TestTransportInfo) other;
+ return that.locationRedacted == this.locationRedacted
+ && that.localMacAddressRedacted == this.localMacAddressRedacted
+ && that.settingsRedacted == this.settingsRedacted;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(locationRedacted, localMacAddressRedacted, settingsRedacted);
+ }
+ }
+
+ private void verifyNetworkCallbackLocationDataInclusionUsingTransportInfoAndOwnerUidInNetCaps(
+ @NonNull TestNetworkCallback wifiNetworkCallback, int actualOwnerUid,
+ @NonNull TransportInfo actualTransportInfo, int expectedOwnerUid,
+ @NonNull TransportInfo expectedTransportInfo) throws Exception {
+ when(mPackageManager.getTargetSdkVersion(anyString())).thenReturn(Build.VERSION_CODES.S);
+ final NetworkCapabilities ncTemplate =
+ new NetworkCapabilities()
+ .addTransportType(TRANSPORT_WIFI)
+ .setOwnerUid(actualOwnerUid);
+
+ final NetworkRequest wifiRequest = new NetworkRequest.Builder()
+ .addTransportType(TRANSPORT_WIFI).build();
+ mCm.registerNetworkCallback(wifiRequest, wifiNetworkCallback);
+
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, new LinkProperties(),
+ ncTemplate);
+ mWiFiNetworkAgent.connect(false);
+
+ wifiNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+
+ // Send network capabilities update with TransportInfo to trigger capabilities changed
+ // callback.
+ mWiFiNetworkAgent.setNetworkCapabilities(
+ ncTemplate.setTransportInfo(actualTransportInfo), true);
+
+ wifiNetworkCallback.expectCapabilitiesThat(mWiFiNetworkAgent,
+ nc -> Objects.equals(expectedOwnerUid, nc.getOwnerUid())
+ && Objects.equals(expectedTransportInfo, nc.getTransportInfo()));
+
+ }
+
+ @Test
+ public void testVerifyLocationDataIsNotIncludedWhenInclFlagNotSet() throws Exception {
+ final TestNetworkCallback wifiNetworkCallack = new TestNetworkCallback();
+ final int ownerUid = Process.myUid();
+ final TransportInfo transportInfo = new TestTransportInfo();
+ // Even though the test uid holds privileged permissions, mask location fields since
+ // the callback did not explicitly opt-in to get location data.
+ final TransportInfo sanitizedTransportInfo = new TestTransportInfo(
+ true, /* locationRedacted */
+ true, /* localMacAddressRedacted */
+ true /* settingsRedacted */
+ );
+ // Should not expect location data since the callback does not set the flag for including
+ // location data.
+ verifyNetworkCallbackLocationDataInclusionUsingTransportInfoAndOwnerUidInNetCaps(
+ wifiNetworkCallack, ownerUid, transportInfo, INVALID_UID, sanitizedTransportInfo);
}
private void setupConnectionOwnerUid(int vpnOwnerUid, @VpnManager.VpnType int vpnType)
throws Exception {
- final Set<UidRange> vpnRange = Collections.singleton(createUidRange(PRIMARY_USER));
+ final Set<UidRange> vpnRange = Collections.singleton(PRIMARY_UIDRANGE);
mMockVpn.setVpnType(vpnType);
mMockVpn.establish(new LinkProperties(), vpnOwnerUid, vpnRange);
assertVpnUidRangesUpdated(true, vpnRange, vpnOwnerUid);
@@ -8972,8 +9493,9 @@
ConnectivityManager.getNetworkTypeName(TYPE_MOBILE),
TelephonyManager.getNetworkTypeName(TelephonyManager.NETWORK_TYPE_LTE));
return new NetworkAgentInfo(null, new Network(NET_ID), info, new LinkProperties(),
- nc, 0, mServiceContext, null, new NetworkAgentConfig(), mService, null, null, 0,
- INVALID_UID, mQosCallbackTracker);
+ nc, new NetworkScore.Builder().setLegacyInt(0).build(),
+ mServiceContext, null, new NetworkAgentConfig(), mService, null, null, 0,
+ INVALID_UID, mQosCallbackTracker, new ConnectivityService.Dependencies());
}
@Test
@@ -9314,10 +9836,12 @@
assertContainsExactly(exemptUidCaptor.getValue(), Process.VPN_UID, exemptUid);
if (add) {
- inOrder.verify(mMockNetd, times(1)).networkAddUidRanges(eq(mMockVpn.getNetId()),
+ inOrder.verify(mMockNetd, times(1))
+ .networkAddUidRanges(eq(mMockVpn.getNetwork().getNetId()),
eq(toUidRangeStableParcels(vpnRanges)));
} else {
- inOrder.verify(mMockNetd, times(1)).networkRemoveUidRanges(eq(mMockVpn.getNetId()),
+ inOrder.verify(mMockNetd, times(1))
+ .networkRemoveUidRanges(eq(mMockVpn.getNetwork().getNetId()),
eq(toUidRangeStableParcels(vpnRanges)));
}
@@ -9332,7 +9856,7 @@
lp.setInterfaceName("tun0");
lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
- final UidRange vpnRange = createUidRange(PRIMARY_USER);
+ final UidRange vpnRange = PRIMARY_UIDRANGE;
Set<UidRange> vpnRanges = Collections.singleton(vpnRange);
mMockVpn.establish(lp, VPN_UID, vpnRanges);
assertVpnUidRangesUpdated(true, vpnRanges, VPN_UID);
@@ -9358,9 +9882,9 @@
for (int reqTypeInt : invalidReqTypeInts) {
assertThrows("Expect throws for invalid request type " + reqTypeInt,
IllegalArgumentException.class,
- () -> mService.requestNetwork(nc, reqTypeInt, null, 0, null,
- ConnectivityManager.TYPE_NONE, mContext.getPackageName(),
- getAttributionTag())
+ () -> mService.requestNetwork(Process.INVALID_UID, nc, reqTypeInt, null, 0,
+ null, ConnectivityManager.TYPE_NONE, NetworkCallback.FLAG_NONE,
+ mContext.getPackageName(), getAttributionTag())
);
}
}
@@ -9478,7 +10002,7 @@
&& session.getSessionType() == QosSession.TYPE_EPS_BEARER), eq(attributes));
mQosCallbackMockHelper.mAgentWrapper.getNetworkAgent()
- .sendQosSessionLost(qosCallbackId, sessionId);
+ .sendQosSessionLost(qosCallbackId, sessionId, QosSession.TYPE_EPS_BEARER);
waitForIdle();
verify(mQosCallbackMockHelper.mCallback).onQosSessionLost(argThat(session ->
session.getSessionId() == sessionId
@@ -9486,6 +10010,36 @@
}
@Test
+ public void testNrQosCallbackAvailableAndLost() throws Exception {
+ mQosCallbackMockHelper = new QosCallbackMockHelper();
+ final int sessionId = 10;
+ final int qosCallbackId = 1;
+
+ when(mQosCallbackMockHelper.mFilter.validate())
+ .thenReturn(QosCallbackException.EX_TYPE_FILTER_NONE);
+ mQosCallbackMockHelper.registerQosCallback(
+ mQosCallbackMockHelper.mFilter, mQosCallbackMockHelper.mCallback);
+ waitForIdle();
+
+ final NrQosSessionAttributes attributes = new NrQosSessionAttributes(
+ 1, 2, 3, 4, 5, 6, 7, new ArrayList<>());
+ mQosCallbackMockHelper.mAgentWrapper.getNetworkAgent()
+ .sendQosSessionAvailable(qosCallbackId, sessionId, attributes);
+ waitForIdle();
+
+ verify(mQosCallbackMockHelper.mCallback).onNrQosSessionAvailable(argThat(session ->
+ session.getSessionId() == sessionId
+ && session.getSessionType() == QosSession.TYPE_NR_BEARER), eq(attributes));
+
+ mQosCallbackMockHelper.mAgentWrapper.getNetworkAgent()
+ .sendQosSessionLost(qosCallbackId, sessionId, QosSession.TYPE_NR_BEARER);
+ waitForIdle();
+ verify(mQosCallbackMockHelper.mCallback).onQosSessionLost(argThat(session ->
+ session.getSessionId() == sessionId
+ && session.getSessionType() == QosSession.TYPE_NR_BEARER));
+ }
+
+ @Test
public void testQosCallbackTooManyRequests() throws Exception {
mQosCallbackMockHelper = new QosCallbackMockHelper();
@@ -9530,7 +10084,7 @@
.thenReturn(hasFeature);
}
- private UidRange getNriFirstUidRange(
+ private Range<Integer> getNriFirstUidRange(
@NonNull final ConnectivityService.NetworkRequestInfo nri) {
return nri.mRequests.get(0).networkCapabilities.getUids().iterator().next();
}
@@ -9713,11 +10267,11 @@
pref));
// Sort by uid to access nris by index
- nris.sort(Comparator.comparingInt(nri -> getNriFirstUidRange(nri).start));
- assertEquals(TEST_PACKAGE_UID, getNriFirstUidRange(nris.get(0)).start);
- assertEquals(TEST_PACKAGE_UID, getNriFirstUidRange(nris.get(0)).stop);
- assertEquals(testPackageNameUid2, getNriFirstUidRange(nris.get(1)).start);
- assertEquals(testPackageNameUid2, getNriFirstUidRange(nris.get(1)).stop);
+ nris.sort(Comparator.comparingInt(nri -> getNriFirstUidRange(nri).getLower()));
+ assertEquals(TEST_PACKAGE_UID, (int) getNriFirstUidRange(nris.get(0)).getLower());
+ assertEquals(TEST_PACKAGE_UID, (int) getNriFirstUidRange(nris.get(0)).getUpper());
+ assertEquals(testPackageNameUid2, (int) getNriFirstUidRange(nris.get(1)).getLower());
+ assertEquals(testPackageNameUid2, (int) getNriFirstUidRange(nris.get(1)).getUpper());
}
@Test
@@ -9747,17 +10301,17 @@
// UIDs for all users and all managed packages should be present.
// Two users each with two packages.
final int expectedUidSize = 2;
- final List<UidRange> uids =
+ final List<Range<Integer>> uids =
new ArrayList<>(nris.get(0).mRequests.get(0).networkCapabilities.getUids());
assertEquals(expectedUidSize, uids.size());
// Sort by uid to access nris by index
- uids.sort(Comparator.comparingInt(uid -> uid.start));
+ uids.sort(Comparator.comparingInt(uid -> uid.getLower()));
final int secondUserTestPackageUid = UserHandle.getUid(secondUser, TEST_PACKAGE_UID);
- assertEquals(TEST_PACKAGE_UID, uids.get(0).start);
- assertEquals(TEST_PACKAGE_UID, uids.get(0).stop);
- assertEquals(secondUserTestPackageUid, uids.get(1).start);
- assertEquals(secondUserTestPackageUid, uids.get(1).stop);
+ assertEquals(TEST_PACKAGE_UID, (int) uids.get(0).getLower());
+ assertEquals(TEST_PACKAGE_UID, (int) uids.get(0).getUpper());
+ assertEquals(secondUserTestPackageUid, (int) uids.get(1).getLower());
+ assertEquals(secondUserTestPackageUid, (int) uids.get(1).getUpper());
}
@Test
@@ -9924,9 +10478,13 @@
Manifest.permission.NETWORK_SETTINGS, PERMISSION_GRANTED);
mSystemDefaultNetworkCallback = new TestNetworkCallback();
mDefaultNetworkCallback = new TestNetworkCallback();
+ mProfileDefaultNetworkCallback = new TestNetworkCallback();
mCm.registerSystemDefaultNetworkCallback(mSystemDefaultNetworkCallback,
new Handler(ConnectivityThread.getInstanceLooper()));
mCm.registerDefaultNetworkCallback(mDefaultNetworkCallback);
+ registerDefaultNetworkCallbackAsUid(mProfileDefaultNetworkCallback,
+ TEST_WORK_PROFILE_APP_UID);
+ // TODO: test using ConnectivityManager#registerDefaultNetworkCallbackAsUid as well.
mServiceContext.setPermission(
Manifest.permission.NETWORK_SETTINGS, PERMISSION_DENIED);
}
@@ -9938,12 +10496,15 @@
if (null != mSystemDefaultNetworkCallback) {
mCm.unregisterNetworkCallback(mSystemDefaultNetworkCallback);
}
+ if (null != mProfileDefaultNetworkCallback) {
+ mCm.unregisterNetworkCallback(mProfileDefaultNetworkCallback);
+ }
}
private void setupMultipleDefaultNetworksForOemNetworkPreferenceNotCurrentUidTest(
@OemNetworkPreferences.OemNetworkPreference final int networkPrefToSetup)
throws Exception {
- final int testPackageNameUid = 123;
+ final int testPackageNameUid = TEST_PACKAGE_UID;
final String testPackageName = "per.app.defaults.package";
setupMultipleDefaultNetworksForOemNetworkPreferenceTest(
networkPrefToSetup, testPackageNameUid, testPackageName);
@@ -9993,7 +10554,7 @@
oemPrefListener.expectOnComplete();
}
- private static class TestOemListenerCallback implements IOnSetOemNetworkPreferenceListener {
+ private static class TestOemListenerCallback implements IOnCompleteListener {
final CompletableFuture<Object> mDone = new CompletableFuture<>();
@Override
@@ -10079,6 +10640,11 @@
mCm.registerDefaultNetworkCallback(defaultNetworkCallback);
defaultNetworkCallback.assertNoCallback();
+ final TestNetworkCallback otherUidDefaultCallback = new TestNetworkCallback();
+ withPermission(Manifest.permission.NETWORK_SETTINGS, () ->
+ mCm.registerDefaultNetworkCallbackAsUid(TEST_PACKAGE_UID, otherUidDefaultCallback,
+ new Handler(ConnectivityThread.getInstanceLooper())));
+
// Setup the test process to use networkPref for their default network.
setupMultipleDefaultNetworksForOemNetworkPreferenceCurrentUidTest(networkPref);
@@ -10089,19 +10655,22 @@
null,
mEthernetNetworkAgent.getNetwork());
- // At this point with a restricted network used, the available callback should trigger
+ // At this point with a restricted network used, the available callback should trigger.
defaultNetworkCallback.expectAvailableThenValidatedCallbacks(mEthernetNetworkAgent);
assertEquals(defaultNetworkCallback.getLastAvailableNetwork(),
mEthernetNetworkAgent.getNetwork());
+ otherUidDefaultCallback.assertNoCallback();
// Now bring down the default network which should trigger a LOST callback.
setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, false);
// At this point, with no network is available, the lost callback should trigger
defaultNetworkCallback.expectCallback(CallbackEntry.LOST, mEthernetNetworkAgent);
+ otherUidDefaultCallback.assertNoCallback();
// Confirm we can unregister without issues.
mCm.unregisterNetworkCallback(defaultNetworkCallback);
+ mCm.unregisterNetworkCallback(otherUidDefaultCallback);
}
@Test
@@ -10119,6 +10688,11 @@
mCm.registerDefaultNetworkCallback(defaultNetworkCallback);
defaultNetworkCallback.assertNoCallback();
+ final TestNetworkCallback otherUidDefaultCallback = new TestNetworkCallback();
+ withPermission(Manifest.permission.NETWORK_SETTINGS, () ->
+ mCm.registerDefaultNetworkCallbackAsUid(TEST_PACKAGE_UID, otherUidDefaultCallback,
+ new Handler(ConnectivityThread.getInstanceLooper())));
+
// Bring up ethernet with OEM_PAID. This will satisfy NET_CAPABILITY_OEM_PAID.
// The active nai for the default is null at this point as this is a restricted network.
setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, true);
@@ -10130,15 +10704,19 @@
defaultNetworkCallback.expectAvailableThenValidatedCallbacks(mEthernetNetworkAgent);
assertEquals(defaultNetworkCallback.getLastAvailableNetwork(),
mEthernetNetworkAgent.getNetwork());
+ otherUidDefaultCallback.assertNoCallback();
// Now bring down the default network which should trigger a LOST callback.
setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, false);
+ otherUidDefaultCallback.assertNoCallback();
// At this point, with no network is available, the lost callback should trigger
defaultNetworkCallback.expectCallback(CallbackEntry.LOST, mEthernetNetworkAgent);
+ otherUidDefaultCallback.assertNoCallback();
// Confirm we can unregister without issues.
mCm.unregisterNetworkCallback(defaultNetworkCallback);
+ mCm.unregisterNetworkCallback(otherUidDefaultCallback);
}
@Test
@@ -10152,6 +10730,11 @@
mCm.registerDefaultNetworkCallback(defaultNetworkCallback);
defaultNetworkCallback.assertNoCallback();
+ final TestNetworkCallback otherUidDefaultCallback = new TestNetworkCallback();
+ withPermission(Manifest.permission.NETWORK_SETTINGS, () ->
+ mCm.registerDefaultNetworkCallbackAsUid(TEST_PACKAGE_UID, otherUidDefaultCallback,
+ new Handler(ConnectivityThread.getInstanceLooper())));
+
// Setup a process different than the test process to use the default network. This means
// that the defaultNetworkCallback won't be tracked by the per-app policy.
setupMultipleDefaultNetworksForOemNetworkPreferenceNotCurrentUidTest(networkPref);
@@ -10167,6 +10750,9 @@
defaultNetworkCallback.assertNoCallback();
assertDefaultNetworkCapabilities(userId /* no networks */);
+ // The other UID does have access, and gets a callback.
+ otherUidDefaultCallback.expectAvailableThenValidatedCallbacks(mEthernetNetworkAgent);
+
// Bring up unrestricted cellular. This should now satisfy the default network.
setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true);
verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
@@ -10174,25 +10760,31 @@
mEthernetNetworkAgent.getNetwork());
// At this point with an unrestricted network used, the available callback should trigger
+ // The other UID is unaffected and remains on the paid network.
defaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
assertEquals(defaultNetworkCallback.getLastAvailableNetwork(),
mCellNetworkAgent.getNetwork());
assertDefaultNetworkCapabilities(userId, mCellNetworkAgent);
+ otherUidDefaultCallback.assertNoCallback();
// Now bring down the per-app network.
setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, false);
- // Since the callback didn't use the per-app network, no callback should fire.
+ // Since the callback didn't use the per-app network, only the other UID gets a callback.
+ // Because the preference specifies no fallback, it does not switch to cellular.
defaultNetworkCallback.assertNoCallback();
+ otherUidDefaultCallback.expectCallback(CallbackEntry.LOST, mEthernetNetworkAgent);
// Now bring down the default network.
setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, false);
// As this callback was tracking the default, this should now trigger.
defaultNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
+ otherUidDefaultCallback.assertNoCallback();
// Confirm we can unregister without issues.
mCm.unregisterNetworkCallback(defaultNetworkCallback);
+ mCm.unregisterNetworkCallback(otherUidDefaultCallback);
}
/**
@@ -10930,4 +11522,495 @@
verifyNoNetwork();
mCm.unregisterNetworkCallback(cellCb);
}
+
+ // Cannot be part of MockNetworkFactory since it requires method of the test.
+ private void expectNoRequestChanged(@NonNull MockNetworkFactory factory) {
+ waitForIdle();
+ factory.assertNoRequestChanged();
+ }
+
+ @Test
+ public void testRegisterBestMatchingNetworkCallback_noIssueToFactory() throws Exception {
+ // Prepare mock mms factory.
+ final HandlerThread handlerThread = new HandlerThread("MockCellularFactory");
+ handlerThread.start();
+ NetworkCapabilities filter = new NetworkCapabilities()
+ .addTransportType(TRANSPORT_CELLULAR)
+ .addCapability(NET_CAPABILITY_MMS);
+ final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(),
+ mServiceContext, "testFactory", filter, mCsHandlerThread);
+ testFactory.setScoreFilter(40);
+
+ try {
+ // Register the factory and expect it will see default request, because all requests
+ // are sent to all factories.
+ testFactory.register();
+ testFactory.expectRequestAdd();
+ testFactory.assertRequestCountEquals(1);
+ // The factory won't try to start the network since the default request doesn't
+ // match the filter (no INTERNET capability).
+ assertFalse(testFactory.getMyStartRequested());
+
+ // Register callback for listening best matching network. Verify that the request won't
+ // be sent to factory.
+ final TestNetworkCallback bestMatchingCb = new TestNetworkCallback();
+ mCm.registerBestMatchingNetworkCallback(
+ new NetworkRequest.Builder().addCapability(NET_CAPABILITY_MMS).build(),
+ bestMatchingCb, mCsHandlerThread.getThreadHandler());
+ bestMatchingCb.assertNoCallback();
+ expectNoRequestChanged(testFactory);
+ testFactory.assertRequestCountEquals(1);
+ assertFalse(testFactory.getMyStartRequested());
+
+ // Fire a normal mms request, verify the factory will only see the request.
+ final TestNetworkCallback mmsNetworkCallback = new TestNetworkCallback();
+ final NetworkRequest mmsRequest = new NetworkRequest.Builder()
+ .addCapability(NET_CAPABILITY_MMS).build();
+ mCm.requestNetwork(mmsRequest, mmsNetworkCallback);
+ testFactory.expectRequestAdd();
+ testFactory.assertRequestCountEquals(2);
+ assertTrue(testFactory.getMyStartRequested());
+
+ // Unregister best matching callback, verify factory see no change.
+ mCm.unregisterNetworkCallback(bestMatchingCb);
+ expectNoRequestChanged(testFactory);
+ testFactory.assertRequestCountEquals(2);
+ assertTrue(testFactory.getMyStartRequested());
+ } finally {
+ testFactory.terminate();
+ }
+ }
+
+ @Test
+ public void testRegisterBestMatchingNetworkCallback_trackBestNetwork() throws Exception {
+ final TestNetworkCallback bestMatchingCb = new TestNetworkCallback();
+ mCm.registerBestMatchingNetworkCallback(
+ new NetworkRequest.Builder().addCapability(NET_CAPABILITY_TRUSTED).build(),
+ bestMatchingCb, mCsHandlerThread.getThreadHandler());
+
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+ mCellNetworkAgent.connect(true);
+ bestMatchingCb.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+ mWiFiNetworkAgent.connect(true);
+ bestMatchingCb.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
+
+ // Change something on cellular to trigger capabilities changed, since the callback
+ // only cares about the best network, verify it received nothing from cellular.
+ mCellNetworkAgent.addCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED);
+ bestMatchingCb.assertNoCallback();
+
+ // Make cellular the best network again, verify the callback now tracks cellular.
+ mWiFiNetworkAgent.adjustScore(-50);
+ bestMatchingCb.expectAvailableCallbacksValidated(mCellNetworkAgent);
+
+ // Make cellular temporary non-trusted, which will not satisfying the request.
+ // Verify the callback switch from/to the other network accordingly.
+ mCellNetworkAgent.removeCapability(NET_CAPABILITY_TRUSTED);
+ bestMatchingCb.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
+ mCellNetworkAgent.addCapability(NET_CAPABILITY_TRUSTED);
+ bestMatchingCb.expectAvailableDoubleValidatedCallbacks(mCellNetworkAgent);
+
+ // Verify the callback doesn't care about wifi disconnect.
+ mWiFiNetworkAgent.disconnect();
+ bestMatchingCb.assertNoCallback();
+ mCellNetworkAgent.disconnect();
+ bestMatchingCb.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
+ }
+
+ private UidRangeParcel[] uidRangeFor(final UserHandle handle) {
+ UidRange range = UidRange.createForUser(handle);
+ return new UidRangeParcel[] { new UidRangeParcel(range.start, range.stop) };
+ }
+
+ private static class TestOnCompleteListener implements Runnable {
+ final class OnComplete {}
+ final ArrayTrackRecord<OnComplete>.ReadHead mHistory =
+ new ArrayTrackRecord<OnComplete>().newReadHead();
+
+ @Override
+ public void run() {
+ mHistory.add(new OnComplete());
+ }
+
+ public void expectOnComplete() {
+ assertNotNull(mHistory.poll(TIMEOUT_MS, it -> true));
+ }
+ }
+
+ private TestNetworkAgentWrapper makeEnterpriseNetworkAgent() throws Exception {
+ final NetworkCapabilities workNc = new NetworkCapabilities();
+ workNc.addCapability(NET_CAPABILITY_ENTERPRISE);
+ workNc.removeCapability(NET_CAPABILITY_NOT_RESTRICTED);
+ return new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, new LinkProperties(), workNc);
+ }
+
+ private TestNetworkCallback mEnterpriseCallback;
+ private UserHandle setupEnterpriseNetwork() {
+ final UserHandle userHandle = UserHandle.of(TEST_WORK_PROFILE_USER_ID);
+ mServiceContext.setWorkProfile(userHandle, true);
+
+ // File a request to avoid the enterprise network being disconnected as soon as the default
+ // request goes away – it would make impossible to test that networkRemoveUidRanges
+ // is called, as the network would disconnect first for lack of a request.
+ mEnterpriseCallback = new TestNetworkCallback();
+ final NetworkRequest keepUpRequest = new NetworkRequest.Builder()
+ .addCapability(NET_CAPABILITY_ENTERPRISE)
+ .build();
+ mCm.requestNetwork(keepUpRequest, mEnterpriseCallback);
+ return userHandle;
+ }
+
+ private void maybeTearDownEnterpriseNetwork() {
+ if (null != mEnterpriseCallback) {
+ mCm.unregisterNetworkCallback(mEnterpriseCallback);
+ }
+ }
+
+ /**
+ * Make sure per-profile networking preference behaves as expected when the enterprise network
+ * goes up and down while the preference is active. Make sure they behave as expected whether
+ * there is a general default network or not.
+ */
+ @Test
+ public void testPreferenceForUserNetworkUpDown() throws Exception {
+ final InOrder inOrder = inOrder(mMockNetd);
+ final UserHandle testHandle = setupEnterpriseNetwork();
+ registerDefaultNetworkCallbacks();
+
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+ mCellNetworkAgent.connect(true);
+
+ mSystemDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+ mDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+ mProfileDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+ inOrder.verify(mMockNetd).networkCreatePhysical(mCellNetworkAgent.getNetwork().netId,
+ INetd.PERMISSION_NONE);
+
+ final TestOnCompleteListener listener = new TestOnCompleteListener();
+ mCm.setProfileNetworkPreference(testHandle, PROFILE_NETWORK_PREFERENCE_ENTERPRISE,
+ r -> r.run(), listener);
+ listener.expectOnComplete();
+
+ // Setting a network preference for this user will create a new set of routing rules for
+ // the UID range that corresponds to this user, so as to define the default network
+ // for these apps separately. This is true because the multi-layer request relevant to
+ // this UID range contains a TRACK_DEFAULT, so the range will be moved through UID-specific
+ // rules to the correct network – in this case the system default network. The case where
+ // the default network for the profile happens to be the same as the system default
+ // is not handled specially, the rules are always active as long as a preference is set.
+ inOrder.verify(mMockNetd).networkAddUidRanges(mCellNetworkAgent.getNetwork().netId,
+ uidRangeFor(testHandle));
+
+ // The enterprise network is not ready yet.
+ assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback,
+ mProfileDefaultNetworkCallback);
+
+ final TestNetworkAgentWrapper workAgent = makeEnterpriseNetworkAgent();
+ workAgent.connect(false);
+
+ mProfileDefaultNetworkCallback.expectAvailableCallbacksUnvalidated(workAgent);
+ mSystemDefaultNetworkCallback.assertNoCallback();
+ mDefaultNetworkCallback.assertNoCallback();
+ inOrder.verify(mMockNetd).networkCreatePhysical(workAgent.getNetwork().netId,
+ INetd.PERMISSION_SYSTEM);
+ inOrder.verify(mMockNetd).networkAddUidRanges(workAgent.getNetwork().netId,
+ uidRangeFor(testHandle));
+ inOrder.verify(mMockNetd).networkRemoveUidRanges(mCellNetworkAgent.getNetwork().netId,
+ uidRangeFor(testHandle));
+
+ // Make sure changes to the work agent send callbacks to the app in the work profile, but
+ // not to the other apps.
+ workAgent.setNetworkValid(true /* isStrictMode */);
+ workAgent.mNetworkMonitor.forceReevaluation(Process.myUid());
+ mProfileDefaultNetworkCallback.expectCapabilitiesThat(workAgent,
+ nc -> nc.hasCapability(NET_CAPABILITY_VALIDATED)
+ && nc.hasCapability(NET_CAPABILITY_ENTERPRISE));
+ assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback);
+
+ workAgent.addCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED);
+ mProfileDefaultNetworkCallback.expectCapabilitiesThat(workAgent, nc ->
+ nc.hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED));
+ assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback);
+
+ // Conversely, change a capability on the system-wide default network and make sure
+ // that only the apps outside of the work profile receive the callbacks.
+ mCellNetworkAgent.addCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED);
+ mSystemDefaultNetworkCallback.expectCapabilitiesThat(mCellNetworkAgent, nc ->
+ nc.hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED));
+ mDefaultNetworkCallback.expectCapabilitiesThat(mCellNetworkAgent, nc ->
+ nc.hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED));
+ mProfileDefaultNetworkCallback.assertNoCallback();
+
+ // Disconnect and reconnect the system-wide default network and make sure that the
+ // apps on this network see the appropriate callbacks, and the app on the work profile
+ // doesn't because it continues to use the enterprise network.
+ mCellNetworkAgent.disconnect();
+ mSystemDefaultNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
+ mDefaultNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
+ mProfileDefaultNetworkCallback.assertNoCallback();
+ inOrder.verify(mMockNetd).networkDestroy(mCellNetworkAgent.getNetwork().netId);
+
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+ mCellNetworkAgent.connect(true);
+ mSystemDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+ mDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+ mProfileDefaultNetworkCallback.assertNoCallback();
+ inOrder.verify(mMockNetd).networkCreatePhysical(mCellNetworkAgent.getNetwork().netId,
+ INetd.PERMISSION_NONE);
+
+ // When the agent disconnects, test that the app on the work profile falls back to the
+ // default network.
+ workAgent.disconnect();
+ mProfileDefaultNetworkCallback.expectCallback(CallbackEntry.LOST, workAgent);
+ mProfileDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
+ assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback);
+ inOrder.verify(mMockNetd).networkAddUidRanges(mCellNetworkAgent.getNetwork().netId,
+ uidRangeFor(testHandle));
+ inOrder.verify(mMockNetd).networkDestroy(workAgent.getNetwork().netId);
+
+ mCellNetworkAgent.disconnect();
+ mSystemDefaultNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
+ mDefaultNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
+ mProfileDefaultNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
+
+ // Waiting for the handler to be idle before checking for networkDestroy is necessary
+ // here because ConnectivityService calls onLost before the network is fully torn down.
+ waitForIdle();
+ inOrder.verify(mMockNetd).networkDestroy(mCellNetworkAgent.getNetwork().netId);
+
+ // If the control comes here, callbacks seem to behave correctly in the presence of
+ // a default network when the enterprise network goes up and down. Now, make sure they
+ // also behave correctly in the absence of a system-wide default network.
+ final TestNetworkAgentWrapper workAgent2 = makeEnterpriseNetworkAgent();
+ workAgent2.connect(false);
+
+ mProfileDefaultNetworkCallback.expectAvailableCallbacksUnvalidated(workAgent2);
+ assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback);
+ inOrder.verify(mMockNetd).networkCreatePhysical(workAgent2.getNetwork().netId,
+ INetd.PERMISSION_SYSTEM);
+ inOrder.verify(mMockNetd).networkAddUidRanges(workAgent2.getNetwork().netId,
+ uidRangeFor(testHandle));
+
+ workAgent2.setNetworkValid(true /* isStrictMode */);
+ workAgent2.mNetworkMonitor.forceReevaluation(Process.myUid());
+ mProfileDefaultNetworkCallback.expectCapabilitiesThat(workAgent2,
+ nc -> nc.hasCapability(NET_CAPABILITY_ENTERPRISE)
+ && !nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
+ assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback);
+ inOrder.verify(mMockNetd, never()).networkAddUidRanges(anyInt(), any());
+
+ // When the agent disconnects, test that the app on the work profile falls back to the
+ // default network.
+ workAgent2.disconnect();
+ mProfileDefaultNetworkCallback.expectCallback(CallbackEntry.LOST, workAgent2);
+ assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback);
+ inOrder.verify(mMockNetd).networkDestroy(workAgent2.getNetwork().netId);
+
+ assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback,
+ mProfileDefaultNetworkCallback);
+
+ // Callbacks will be unregistered by tearDown()
+ }
+
+ /**
+ * Test that, in a given networking context, calling setPreferenceForUser to set per-profile
+ * defaults on then off works as expected.
+ */
+ @Test
+ public void testSetPreferenceForUserOnOff() throws Exception {
+ final InOrder inOrder = inOrder(mMockNetd);
+ final UserHandle testHandle = setupEnterpriseNetwork();
+
+ // Connect both a regular cell agent and an enterprise network first.
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+ mCellNetworkAgent.connect(true);
+
+ final TestNetworkAgentWrapper workAgent = makeEnterpriseNetworkAgent();
+ workAgent.connect(true);
+
+ final TestOnCompleteListener listener = new TestOnCompleteListener();
+ mCm.setProfileNetworkPreference(testHandle, PROFILE_NETWORK_PREFERENCE_ENTERPRISE,
+ r -> r.run(), listener);
+ listener.expectOnComplete();
+ inOrder.verify(mMockNetd).networkCreatePhysical(mCellNetworkAgent.getNetwork().netId,
+ INetd.PERMISSION_NONE);
+ inOrder.verify(mMockNetd).networkAddUidRanges(workAgent.getNetwork().netId,
+ uidRangeFor(testHandle));
+
+ registerDefaultNetworkCallbacks();
+
+ mSystemDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
+ mDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
+ mProfileDefaultNetworkCallback.expectAvailableCallbacksValidated(workAgent);
+
+ mCm.setProfileNetworkPreference(testHandle, PROFILE_NETWORK_PREFERENCE_DEFAULT,
+ r -> r.run(), listener);
+ listener.expectOnComplete();
+
+ mProfileDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
+ assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback);
+ inOrder.verify(mMockNetd).networkRemoveUidRanges(workAgent.getNetwork().netId,
+ uidRangeFor(testHandle));
+
+ workAgent.disconnect();
+ mCellNetworkAgent.disconnect();
+
+ // Callbacks will be unregistered by tearDown()
+ }
+
+ /**
+ * Test per-profile default networks for two different profiles concurrently.
+ */
+ @Test
+ public void testSetPreferenceForTwoProfiles() throws Exception {
+ final InOrder inOrder = inOrder(mMockNetd);
+ final UserHandle testHandle2 = setupEnterpriseNetwork();
+ final UserHandle testHandle4 = UserHandle.of(TEST_WORK_PROFILE_USER_ID + 2);
+ mServiceContext.setWorkProfile(testHandle4, true);
+ registerDefaultNetworkCallbacks();
+
+ final TestNetworkCallback app4Cb = new TestNetworkCallback();
+ final int testWorkProfileAppUid4 =
+ UserHandle.getUid(testHandle4.getIdentifier(), TEST_APP_ID);
+ registerDefaultNetworkCallbackAsUid(app4Cb, testWorkProfileAppUid4);
+
+ // Connect both a regular cell agent and an enterprise network first.
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+ mCellNetworkAgent.connect(true);
+
+ final TestNetworkAgentWrapper workAgent = makeEnterpriseNetworkAgent();
+ workAgent.connect(true);
+
+ mSystemDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+ mDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+ mProfileDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+ app4Cb.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+ inOrder.verify(mMockNetd).networkCreatePhysical(mCellNetworkAgent.getNetwork().netId,
+ INetd.PERMISSION_NONE);
+ inOrder.verify(mMockNetd).networkCreatePhysical(workAgent.getNetwork().netId,
+ INetd.PERMISSION_SYSTEM);
+
+ final TestOnCompleteListener listener = new TestOnCompleteListener();
+ mCm.setProfileNetworkPreference(testHandle2, PROFILE_NETWORK_PREFERENCE_ENTERPRISE,
+ r -> r.run(), listener);
+ listener.expectOnComplete();
+ inOrder.verify(mMockNetd).networkAddUidRanges(workAgent.getNetwork().netId,
+ uidRangeFor(testHandle2));
+
+ mProfileDefaultNetworkCallback.expectAvailableCallbacksValidated(workAgent);
+ assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback,
+ app4Cb);
+
+ mCm.setProfileNetworkPreference(testHandle4, PROFILE_NETWORK_PREFERENCE_ENTERPRISE,
+ r -> r.run(), listener);
+ listener.expectOnComplete();
+ inOrder.verify(mMockNetd).networkAddUidRanges(workAgent.getNetwork().netId,
+ uidRangeFor(testHandle4));
+
+ app4Cb.expectAvailableCallbacksValidated(workAgent);
+ assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback,
+ mProfileDefaultNetworkCallback);
+
+ mCm.setProfileNetworkPreference(testHandle2, PROFILE_NETWORK_PREFERENCE_DEFAULT,
+ r -> r.run(), listener);
+ listener.expectOnComplete();
+ inOrder.verify(mMockNetd).networkRemoveUidRanges(workAgent.getNetwork().netId,
+ uidRangeFor(testHandle2));
+
+ mProfileDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
+ assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback,
+ app4Cb);
+
+ workAgent.disconnect();
+ mCellNetworkAgent.disconnect();
+
+ mCm.unregisterNetworkCallback(app4Cb);
+ // Other callbacks will be unregistered by tearDown()
+ }
+
+ @Test
+ public void testProfilePreferenceRemovedUponUserRemoved() throws Exception {
+ final InOrder inOrder = inOrder(mMockNetd);
+ final UserHandle testHandle = setupEnterpriseNetwork();
+
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+ mCellNetworkAgent.connect(true);
+
+ final TestOnCompleteListener listener = new TestOnCompleteListener();
+ mCm.setProfileNetworkPreference(testHandle, PROFILE_NETWORK_PREFERENCE_ENTERPRISE,
+ r -> r.run(), listener);
+ listener.expectOnComplete();
+ inOrder.verify(mMockNetd).networkCreatePhysical(mCellNetworkAgent.getNetwork().netId,
+ INetd.PERMISSION_NONE);
+ inOrder.verify(mMockNetd).networkAddUidRanges(mCellNetworkAgent.getNetwork().netId,
+ uidRangeFor(testHandle));
+
+ final Intent removedIntent = new Intent(ACTION_USER_REMOVED);
+ removedIntent.putExtra(Intent.EXTRA_USER, testHandle);
+ processBroadcast(removedIntent);
+
+ inOrder.verify(mMockNetd).networkRemoveUidRanges(mCellNetworkAgent.getNetwork().netId,
+ uidRangeFor(testHandle));
+ }
+
+ /**
+ * Make sure that OEM preference and per-profile preference can't be used at the same
+ * time and throw ISE if tried
+ */
+ @Test
+ public void testOemPreferenceAndProfilePreferenceExclusive() throws Exception {
+ final UserHandle testHandle = UserHandle.of(TEST_WORK_PROFILE_USER_ID);
+ mServiceContext.setWorkProfile(testHandle, true);
+ final TestOnCompleteListener listener = new TestOnCompleteListener();
+
+ setupMultipleDefaultNetworksForOemNetworkPreferenceNotCurrentUidTest(
+ OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY);
+ assertThrows("Should not be able to set per-profile pref while OEM prefs present",
+ IllegalStateException.class, () ->
+ mCm.setProfileNetworkPreference(testHandle,
+ PROFILE_NETWORK_PREFERENCE_ENTERPRISE,
+ r -> r.run(), listener));
+
+ // Empty the OEM prefs
+ final TestOemListenerCallback oemPrefListener = new TestOemListenerCallback();
+ final OemNetworkPreferences emptyOemPref = new OemNetworkPreferences.Builder().build();
+ mService.setOemNetworkPreference(emptyOemPref, oemPrefListener);
+ oemPrefListener.expectOnComplete();
+
+ mCm.setProfileNetworkPreference(testHandle, PROFILE_NETWORK_PREFERENCE_ENTERPRISE,
+ r -> r.run(), listener);
+ listener.expectOnComplete();
+ assertThrows("Should not be able to set OEM prefs while per-profile pref is on",
+ IllegalStateException.class , () ->
+ mService.setOemNetworkPreference(emptyOemPref, oemPrefListener));
+ }
+
+ /**
+ * Make sure wrong preferences for per-profile default networking are rejected.
+ */
+ @Test
+ public void testProfileNetworkPrefWrongPreference() throws Exception {
+ final UserHandle testHandle = UserHandle.of(TEST_WORK_PROFILE_USER_ID);
+ mServiceContext.setWorkProfile(testHandle, true);
+ assertThrows("Should not be able to set an illegal preference",
+ IllegalArgumentException.class,
+ () -> mCm.setProfileNetworkPreference(testHandle,
+ PROFILE_NETWORK_PREFERENCE_ENTERPRISE + 1, null, null));
+ }
+
+ /**
+ * Make sure requests for per-profile default networking for a non-work profile are
+ * rejected
+ */
+ @Test
+ public void testProfileNetworkPrefWrongProfile() throws Exception {
+ final UserHandle testHandle = UserHandle.of(TEST_WORK_PROFILE_USER_ID);
+ mServiceContext.setWorkProfile(testHandle, false);
+ assertThrows("Should not be able to set a user pref for a non-work profile",
+ IllegalArgumentException.class , () ->
+ mCm.setProfileNetworkPreference(testHandle,
+ PROFILE_NETWORK_PREFERENCE_ENTERPRISE, null, null));
+ }
}
diff --git a/tests/net/java/com/android/server/IpSecServiceTest.java b/tests/net/java/com/android/server/IpSecServiceTest.java
index f97eabf..6232423 100644
--- a/tests/net/java/com/android/server/IpSecServiceTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceTest.java
@@ -35,6 +35,7 @@
import static org.mockito.Mockito.when;
import android.content.Context;
+import android.net.ConnectivityManager;
import android.net.INetd;
import android.net.IpSecAlgorithm;
import android.net.IpSecConfig;
@@ -47,6 +48,7 @@
import android.system.ErrnoException;
import android.system.Os;
import android.system.StructStat;
+import android.util.Range;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -647,9 +649,9 @@
@Test
public void testReserveNetId() {
- int start = mIpSecService.TUN_INTF_NETID_START;
- for (int i = 0; i < mIpSecService.TUN_INTF_NETID_RANGE; i++) {
- assertEquals(start + i, mIpSecService.reserveNetId());
+ final Range<Integer> netIdRange = ConnectivityManager.getIpSecNetIdRange();
+ for (int netId = netIdRange.getLower(); netId <= netIdRange.getUpper(); netId++) {
+ assertEquals(netId, mIpSecService.reserveNetId());
}
// Check that resource exhaustion triggers an exception
@@ -661,7 +663,7 @@
// Now release one and try again
int releasedNetId =
- mIpSecService.TUN_INTF_NETID_START + mIpSecService.TUN_INTF_NETID_RANGE / 2;
+ netIdRange.getLower() + (netIdRange.getUpper() - netIdRange.getLower()) / 2;
mIpSecService.releaseNetId(releasedNetId);
assertEquals(releasedNetId, mIpSecService.reserveNetId());
}
diff --git a/tests/net/java/com/android/server/LegacyTypeTrackerTest.kt b/tests/net/java/com/android/server/LegacyTypeTrackerTest.kt
index a10a3c8..5ec1119 100644
--- a/tests/net/java/com/android/server/LegacyTypeTrackerTest.kt
+++ b/tests/net/java/com/android/server/LegacyTypeTrackerTest.kt
@@ -21,13 +21,29 @@
package com.android.server
+import android.content.Context
+import android.content.pm.PackageManager
+import android.content.pm.PackageManager.FEATURE_WIFI
+import android.content.pm.PackageManager.FEATURE_WIFI_DIRECT
import android.net.ConnectivityManager.TYPE_ETHERNET
import android.net.ConnectivityManager.TYPE_MOBILE
+import android.net.ConnectivityManager.TYPE_MOBILE_CBS
+import android.net.ConnectivityManager.TYPE_MOBILE_DUN
+import android.net.ConnectivityManager.TYPE_MOBILE_EMERGENCY
+import android.net.ConnectivityManager.TYPE_MOBILE_FOTA
+import android.net.ConnectivityManager.TYPE_MOBILE_HIPRI
+import android.net.ConnectivityManager.TYPE_MOBILE_IA
+import android.net.ConnectivityManager.TYPE_MOBILE_IMS
+import android.net.ConnectivityManager.TYPE_MOBILE_MMS
import android.net.ConnectivityManager.TYPE_MOBILE_SUPL
+import android.net.ConnectivityManager.TYPE_VPN
import android.net.ConnectivityManager.TYPE_WIFI
+import android.net.ConnectivityManager.TYPE_WIFI_P2P
import android.net.ConnectivityManager.TYPE_WIMAX
+import android.net.EthernetManager
import android.net.NetworkInfo.DetailedState.CONNECTED
import android.net.NetworkInfo.DetailedState.DISCONNECTED
+import android.telephony.TelephonyManager
import androidx.test.filters.SmallTest
import androidx.test.runner.AndroidJUnit4
import com.android.server.ConnectivityService.LegacyTypeTracker
@@ -36,7 +52,6 @@
import org.junit.Assert.assertNull
import org.junit.Assert.assertSame
import org.junit.Assert.assertTrue
-import org.junit.Assert.fail
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.any
@@ -52,88 +67,130 @@
@RunWith(AndroidJUnit4::class)
@SmallTest
class LegacyTypeTrackerTest {
- private val supportedTypes = arrayOf(TYPE_MOBILE, TYPE_WIFI, TYPE_ETHERNET, TYPE_MOBILE_SUPL)
+ private val supportedTypes = arrayOf(TYPE_WIFI, TYPE_WIFI_P2P, TYPE_ETHERNET, TYPE_MOBILE,
+ TYPE_MOBILE_SUPL, TYPE_MOBILE_MMS, TYPE_MOBILE_SUPL, TYPE_MOBILE_DUN, TYPE_MOBILE_HIPRI,
+ TYPE_MOBILE_FOTA, TYPE_MOBILE_IMS, TYPE_MOBILE_CBS, TYPE_MOBILE_IA,
+ TYPE_MOBILE_EMERGENCY, TYPE_VPN)
private val mMockService = mock(ConnectivityService::class.java).apply {
doReturn(false).`when`(this).isDefaultNetwork(any())
}
- private val mTracker = LegacyTypeTracker(mMockService).apply {
- supportedTypes.forEach {
- addSupportedType(it)
- }
+ private val mPm = mock(PackageManager::class.java)
+ private val mContext = mock(Context::class.java).apply {
+ doReturn(true).`when`(mPm).hasSystemFeature(FEATURE_WIFI)
+ doReturn(true).`when`(mPm).hasSystemFeature(FEATURE_WIFI_DIRECT)
+ doReturn(mPm).`when`(this).packageManager
+ doReturn(mock(EthernetManager::class.java)).`when`(this).getSystemService(
+ Context.ETHERNET_SERVICE)
+ }
+ private val mTm = mock(TelephonyManager::class.java).apply {
+ doReturn(true).`when`(this).isDataCapable
+ }
+
+ private fun makeTracker() = LegacyTypeTracker(mMockService).apply {
+ loadSupportedTypes(mContext, mTm)
}
@Test
fun testSupportedTypes() {
- try {
- mTracker.addSupportedType(supportedTypes[0])
- fail("Expected IllegalStateException")
- } catch (expected: IllegalStateException) {}
+ val tracker = makeTracker()
supportedTypes.forEach {
- assertTrue(mTracker.isTypeSupported(it))
+ assertTrue(tracker.isTypeSupported(it))
}
- assertFalse(mTracker.isTypeSupported(UNSUPPORTED_TYPE))
+ assertFalse(tracker.isTypeSupported(UNSUPPORTED_TYPE))
+ }
+
+ @Test
+ fun testSupportedTypes_NoEthernet() {
+ doReturn(null).`when`(mContext).getSystemService(Context.ETHERNET_SERVICE)
+ assertFalse(makeTracker().isTypeSupported(TYPE_ETHERNET))
+ }
+
+ @Test
+ fun testSupportedTypes_NoTelephony() {
+ doReturn(false).`when`(mTm).isDataCapable
+ val tracker = makeTracker()
+ val nonMobileTypes = arrayOf(TYPE_WIFI, TYPE_WIFI_P2P, TYPE_ETHERNET, TYPE_VPN)
+ nonMobileTypes.forEach {
+ assertTrue(tracker.isTypeSupported(it))
+ }
+ supportedTypes.toSet().minus(nonMobileTypes).forEach {
+ assertFalse(tracker.isTypeSupported(it))
+ }
+ }
+
+ @Test
+ fun testSupportedTypes_NoWifiDirect() {
+ doReturn(false).`when`(mPm).hasSystemFeature(FEATURE_WIFI_DIRECT)
+ val tracker = makeTracker()
+ assertFalse(tracker.isTypeSupported(TYPE_WIFI_P2P))
+ supportedTypes.toSet().minus(TYPE_WIFI_P2P).forEach {
+ assertTrue(tracker.isTypeSupported(it))
+ }
}
@Test
fun testSupl() {
+ val tracker = makeTracker()
val mobileNai = mock(NetworkAgentInfo::class.java)
- mTracker.add(TYPE_MOBILE, mobileNai)
+ tracker.add(TYPE_MOBILE, mobileNai)
verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, CONNECTED, TYPE_MOBILE)
reset(mMockService)
- mTracker.add(TYPE_MOBILE_SUPL, mobileNai)
+ tracker.add(TYPE_MOBILE_SUPL, mobileNai)
verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, CONNECTED, TYPE_MOBILE_SUPL)
reset(mMockService)
- mTracker.remove(TYPE_MOBILE_SUPL, mobileNai, false /* wasDefault */)
+ tracker.remove(TYPE_MOBILE_SUPL, mobileNai, false /* wasDefault */)
verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, DISCONNECTED, TYPE_MOBILE_SUPL)
reset(mMockService)
- mTracker.add(TYPE_MOBILE_SUPL, mobileNai)
+ tracker.add(TYPE_MOBILE_SUPL, mobileNai)
verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, CONNECTED, TYPE_MOBILE_SUPL)
reset(mMockService)
- mTracker.remove(mobileNai, false)
+ tracker.remove(mobileNai, false)
verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, DISCONNECTED, TYPE_MOBILE_SUPL)
verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, DISCONNECTED, TYPE_MOBILE)
}
@Test
fun testAddNetwork() {
+ val tracker = makeTracker()
val mobileNai = mock(NetworkAgentInfo::class.java)
val wifiNai = mock(NetworkAgentInfo::class.java)
- mTracker.add(TYPE_MOBILE, mobileNai)
- mTracker.add(TYPE_WIFI, wifiNai)
- assertSame(mTracker.getNetworkForType(TYPE_MOBILE), mobileNai)
- assertSame(mTracker.getNetworkForType(TYPE_WIFI), wifiNai)
+ tracker.add(TYPE_MOBILE, mobileNai)
+ tracker.add(TYPE_WIFI, wifiNai)
+ assertSame(tracker.getNetworkForType(TYPE_MOBILE), mobileNai)
+ assertSame(tracker.getNetworkForType(TYPE_WIFI), wifiNai)
// Make sure adding a second NAI does not change the results.
val secondMobileNai = mock(NetworkAgentInfo::class.java)
- mTracker.add(TYPE_MOBILE, secondMobileNai)
- assertSame(mTracker.getNetworkForType(TYPE_MOBILE), mobileNai)
- assertSame(mTracker.getNetworkForType(TYPE_WIFI), wifiNai)
+ tracker.add(TYPE_MOBILE, secondMobileNai)
+ assertSame(tracker.getNetworkForType(TYPE_MOBILE), mobileNai)
+ assertSame(tracker.getNetworkForType(TYPE_WIFI), wifiNai)
// Make sure removing a network that wasn't added for this type is a no-op.
- mTracker.remove(TYPE_MOBILE, wifiNai, false /* wasDefault */)
- assertSame(mTracker.getNetworkForType(TYPE_MOBILE), mobileNai)
- assertSame(mTracker.getNetworkForType(TYPE_WIFI), wifiNai)
+ tracker.remove(TYPE_MOBILE, wifiNai, false /* wasDefault */)
+ assertSame(tracker.getNetworkForType(TYPE_MOBILE), mobileNai)
+ assertSame(tracker.getNetworkForType(TYPE_WIFI), wifiNai)
// Remove the top network for mobile and make sure the second one becomes the network
// of record for this type.
- mTracker.remove(TYPE_MOBILE, mobileNai, false /* wasDefault */)
- assertSame(mTracker.getNetworkForType(TYPE_MOBILE), secondMobileNai)
- assertSame(mTracker.getNetworkForType(TYPE_WIFI), wifiNai)
+ tracker.remove(TYPE_MOBILE, mobileNai, false /* wasDefault */)
+ assertSame(tracker.getNetworkForType(TYPE_MOBILE), secondMobileNai)
+ assertSame(tracker.getNetworkForType(TYPE_WIFI), wifiNai)
// Make sure adding a network for an unsupported type does not register it.
- mTracker.add(UNSUPPORTED_TYPE, mobileNai)
- assertNull(mTracker.getNetworkForType(UNSUPPORTED_TYPE))
+ tracker.add(UNSUPPORTED_TYPE, mobileNai)
+ assertNull(tracker.getNetworkForType(UNSUPPORTED_TYPE))
}
@Test
fun testBroadcastOnDisconnect() {
+ val tracker = makeTracker()
val mobileNai1 = mock(NetworkAgentInfo::class.java)
val mobileNai2 = mock(NetworkAgentInfo::class.java)
doReturn(false).`when`(mMockService).isDefaultNetwork(mobileNai1)
- mTracker.add(TYPE_MOBILE, mobileNai1)
+ tracker.add(TYPE_MOBILE, mobileNai1)
verify(mMockService).sendLegacyNetworkBroadcast(mobileNai1, CONNECTED, TYPE_MOBILE)
reset(mMockService)
doReturn(false).`when`(mMockService).isDefaultNetwork(mobileNai2)
- mTracker.add(TYPE_MOBILE, mobileNai2)
+ tracker.add(TYPE_MOBILE, mobileNai2)
verify(mMockService, never()).sendLegacyNetworkBroadcast(any(), any(), anyInt())
- mTracker.remove(TYPE_MOBILE, mobileNai1, false /* wasDefault */)
+ tracker.remove(TYPE_MOBILE, mobileNai1, false /* wasDefault */)
verify(mMockService).sendLegacyNetworkBroadcast(mobileNai1, DISCONNECTED, TYPE_MOBILE)
verify(mMockService).sendLegacyNetworkBroadcast(mobileNai2, CONNECTED, TYPE_MOBILE)
}
diff --git a/tests/net/java/com/android/server/connectivity/DnsManagerTest.java b/tests/net/java/com/android/server/connectivity/DnsManagerTest.java
index 5760211..692c50f 100644
--- a/tests/net/java/com/android/server/connectivity/DnsManagerTest.java
+++ b/tests/net/java/com/android/server/connectivity/DnsManagerTest.java
@@ -18,15 +18,15 @@
import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF;
import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
+import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_DEFAULT_MODE;
+import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE;
+import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_SPECIFIER;
import static android.net.NetworkCapabilities.MAX_TRANSPORT;
import static android.net.NetworkCapabilities.MIN_TRANSPORT;
import static android.net.NetworkCapabilities.TRANSPORT_VPN;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_FAILURE;
import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_SUCCESS;
-import static android.provider.Settings.Global.PRIVATE_DNS_DEFAULT_MODE;
-import static android.provider.Settings.Global.PRIVATE_DNS_MODE;
-import static android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER;
import static com.android.testutils.MiscAsserts.assertContainsExactly;
import static com.android.testutils.MiscAsserts.assertContainsStringsExactly;
@@ -312,14 +312,14 @@
@Test
public void testOverrideDefaultMode() throws Exception {
// Hard-coded default is opportunistic mode.
- final PrivateDnsConfig cfgAuto = DnsManager.getPrivateDnsConfig(mContentResolver);
+ final PrivateDnsConfig cfgAuto = DnsManager.getPrivateDnsConfig(mCtx);
assertTrue(cfgAuto.useTls);
assertEquals("", cfgAuto.hostname);
assertEquals(new InetAddress[0], cfgAuto.ips);
// Pretend a gservices push sets the default to "off".
Settings.Global.putString(mContentResolver, PRIVATE_DNS_DEFAULT_MODE, "off");
- final PrivateDnsConfig cfgOff = DnsManager.getPrivateDnsConfig(mContentResolver);
+ final PrivateDnsConfig cfgOff = DnsManager.getPrivateDnsConfig(mCtx);
assertFalse(cfgOff.useTls);
assertEquals("", cfgOff.hostname);
assertEquals(new InetAddress[0], cfgOff.ips);
@@ -328,7 +328,7 @@
Settings.Global.putString(
mContentResolver, PRIVATE_DNS_MODE, PRIVATE_DNS_MODE_PROVIDER_HOSTNAME);
Settings.Global.putString(mContentResolver, PRIVATE_DNS_SPECIFIER, "strictmode.com");
- final PrivateDnsConfig cfgStrict = DnsManager.getPrivateDnsConfig(mContentResolver);
+ final PrivateDnsConfig cfgStrict = DnsManager.getPrivateDnsConfig(mCtx);
assertTrue(cfgStrict.useTls);
assertEquals("strictmode.com", cfgStrict.hostname);
assertEquals(new InetAddress[0], cfgStrict.ips);
diff --git a/tests/net/java/com/android/server/connectivity/FullScoreTest.kt b/tests/net/java/com/android/server/connectivity/FullScoreTest.kt
new file mode 100644
index 0000000..eb3b4df
--- /dev/null
+++ b/tests/net/java/com/android/server/connectivity/FullScoreTest.kt
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.connectivity
+
+import android.net.NetworkAgentConfig
+import android.net.NetworkCapabilities
+import android.text.TextUtils
+import android.util.ArraySet
+import androidx.test.filters.SmallTest
+import androidx.test.runner.AndroidJUnit4
+import com.android.server.connectivity.FullScore.MAX_CS_MANAGED_POLICY
+import com.android.server.connectivity.FullScore.POLICY_ACCEPT_UNVALIDATED
+import com.android.server.connectivity.FullScore.POLICY_EVER_USER_SELECTED
+import com.android.server.connectivity.FullScore.POLICY_IS_VALIDATED
+import com.android.server.connectivity.FullScore.POLICY_IS_VPN
+import org.junit.Test
+import org.junit.runner.RunWith
+import kotlin.collections.minOfOrNull
+import kotlin.collections.maxOfOrNull
+import kotlin.reflect.full.staticProperties
+import kotlin.test.assertEquals
+import kotlin.test.assertFailsWith
+import kotlin.test.assertFalse
+import kotlin.test.assertTrue
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class FullScoreTest {
+ // Convenience methods
+ fun FullScore.withPolicies(
+ validated: Boolean = false,
+ vpn: Boolean = false,
+ onceChosen: Boolean = false,
+ acceptUnvalidated: Boolean = false
+ ): FullScore {
+ val nac = NetworkAgentConfig.Builder().apply {
+ setUnvalidatedConnectivityAcceptable(acceptUnvalidated)
+ setExplicitlySelected(onceChosen)
+ }.build()
+ val nc = NetworkCapabilities.Builder().apply {
+ if (vpn) addTransportType(NetworkCapabilities.TRANSPORT_VPN)
+ if (validated) addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
+ }.build()
+ return mixInScore(nc, nac)
+ }
+
+ @Test
+ fun testGetLegacyInt() {
+ val ns = FullScore(50, 0L /* policy */)
+ assertEquals(10, ns.legacyInt) // -40 penalty for not being validated
+ assertEquals(50, ns.legacyIntAsValidated)
+
+ val vpnNs = FullScore(101, 0L /* policy */).withPolicies(vpn = true)
+ assertEquals(101, vpnNs.legacyInt) // VPNs are not subject to unvalidation penalty
+ assertEquals(101, vpnNs.legacyIntAsValidated)
+ assertEquals(101, vpnNs.withPolicies(validated = true).legacyInt)
+ assertEquals(101, vpnNs.withPolicies(validated = true).legacyIntAsValidated)
+
+ val validatedNs = ns.withPolicies(validated = true)
+ assertEquals(50, validatedNs.legacyInt) // No penalty, this is validated
+ assertEquals(50, validatedNs.legacyIntAsValidated)
+
+ val chosenNs = ns.withPolicies(onceChosen = true)
+ assertEquals(10, chosenNs.legacyInt)
+ assertEquals(100, chosenNs.legacyIntAsValidated)
+ assertEquals(10, chosenNs.withPolicies(acceptUnvalidated = true).legacyInt)
+ assertEquals(50, chosenNs.withPolicies(acceptUnvalidated = true).legacyIntAsValidated)
+ }
+
+ @Test
+ fun testToString() {
+ val string = FullScore(10, 0L /* policy */)
+ .withPolicies(vpn = true, acceptUnvalidated = true).toString()
+ assertTrue(string.contains("Score(10"), string)
+ assertTrue(string.contains("ACCEPT_UNVALIDATED"), string)
+ assertTrue(string.contains("IS_VPN"), string)
+ assertFalse(string.contains("IS_VALIDATED"), string)
+ val foundNames = ArraySet<String>()
+ getAllPolicies().forEach {
+ val name = FullScore.policyNameOf(it.get() as Int)
+ assertFalse(TextUtils.isEmpty(name))
+ assertFalse(foundNames.contains(name))
+ foundNames.add(name)
+ }
+ assertFailsWith<IllegalArgumentException> {
+ FullScore.policyNameOf(MAX_CS_MANAGED_POLICY + 1)
+ }
+ }
+
+ fun getAllPolicies() = Regex("POLICY_.*").let { nameRegex ->
+ FullScore::class.staticProperties.filter { it.name.matches(nameRegex) }
+ }
+
+ @Test
+ fun testHasPolicy() {
+ val ns = FullScore(50, 0L /* policy */)
+ assertFalse(ns.hasPolicy(POLICY_IS_VALIDATED))
+ assertFalse(ns.hasPolicy(POLICY_IS_VPN))
+ assertFalse(ns.hasPolicy(POLICY_EVER_USER_SELECTED))
+ assertFalse(ns.hasPolicy(POLICY_ACCEPT_UNVALIDATED))
+ assertTrue(ns.withPolicies(validated = true).hasPolicy(POLICY_IS_VALIDATED))
+ assertTrue(ns.withPolicies(vpn = true).hasPolicy(POLICY_IS_VPN))
+ assertTrue(ns.withPolicies(onceChosen = true).hasPolicy(POLICY_EVER_USER_SELECTED))
+ assertTrue(ns.withPolicies(acceptUnvalidated = true).hasPolicy(POLICY_ACCEPT_UNVALIDATED))
+ }
+
+ @Test
+ fun testMinMaxPolicyConstants() {
+ val policies = getAllPolicies()
+
+ policies.forEach { policy ->
+ assertTrue(policy.get() as Int >= FullScore.MIN_CS_MANAGED_POLICY)
+ assertTrue(policy.get() as Int <= FullScore.MAX_CS_MANAGED_POLICY)
+ }
+ assertEquals(FullScore.MIN_CS_MANAGED_POLICY,
+ policies.minOfOrNull { it.get() as Int })
+ assertEquals(FullScore.MAX_CS_MANAGED_POLICY,
+ policies.maxOfOrNull { it.get() as Int })
+ }
+}
diff --git a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
index a913673..9ab60a4 100644
--- a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
@@ -40,6 +40,7 @@
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.NetworkProvider;
+import android.net.NetworkScore;
import android.os.Binder;
import android.text.format.DateUtils;
@@ -355,9 +356,10 @@
caps.addCapability(0);
caps.addTransportType(transport);
NetworkAgentInfo nai = new NetworkAgentInfo(null, new Network(netId), info,
- new LinkProperties(), caps, 50, mCtx, null, new NetworkAgentConfig() /* config */,
- mConnService, mNetd, mDnsResolver, NetworkProvider.ID_NONE, Binder.getCallingUid(),
- mQosCallbackTracker);
+ new LinkProperties(), caps, new NetworkScore.Builder().setLegacyInt(50).build(),
+ mCtx, null, new NetworkAgentConfig.Builder().build(), mConnService, mNetd,
+ mDnsResolver, NetworkProvider.ID_NONE, Binder.getCallingUid(),
+ mQosCallbackTracker, new ConnectivityService.Dependencies());
nai.everValidated = true;
return nai;
}
diff --git a/tests/net/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java b/tests/net/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java
index 950d7163..38f6d7f 100644
--- a/tests/net/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java
+++ b/tests/net/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java
@@ -46,12 +46,12 @@
import android.content.pm.ApplicationInfo;
import android.content.res.Resources;
import android.net.ConnectivityManager;
+import android.net.EthernetNetworkSpecifier;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkPolicy;
import android.net.NetworkPolicyManager;
import android.net.NetworkTemplate;
-import android.net.StringNetworkSpecifier;
import android.net.TelephonyNetworkSpecifier;
import android.os.Handler;
import android.os.UserHandle;
@@ -240,7 +240,7 @@
NetworkCapabilities capabilities = new NetworkCapabilities()
.addCapability(NET_CAPABILITY_INTERNET)
.addTransportType(TRANSPORT_CELLULAR)
- .setNetworkSpecifier(new StringNetworkSpecifier("234"));
+ .setNetworkSpecifier(new EthernetNetworkSpecifier("eth234"));
if (!roaming) {
capabilities.addCapability(NET_CAPABILITY_NOT_ROAMING);
}
diff --git a/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java b/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
index 5f56e25..9b2a638 100644
--- a/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
+++ b/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
@@ -16,11 +16,15 @@
package com.android.server.connectivity;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -34,6 +38,7 @@
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.NetworkAgentConfig;
+import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.os.Handler;
import android.os.test.TestLooper;
@@ -72,11 +77,15 @@
Handler mHandler;
NetworkAgentConfig mAgentConfig = new NetworkAgentConfig();
- Nat464Xlat makeNat464Xlat() {
- return new Nat464Xlat(mNai, mNetd, mDnsResolver) {
+ Nat464Xlat makeNat464Xlat(boolean isCellular464XlatEnabled) {
+ return new Nat464Xlat(mNai, mNetd, mDnsResolver, new ConnectivityService.Dependencies()) {
@Override protected int getNetId() {
return NETID;
}
+
+ @Override protected boolean isCellular464XlatEnabled() {
+ return isCellular464XlatEnabled;
+ }
};
}
@@ -99,6 +108,7 @@
mNai.linkProperties.setInterfaceName(BASE_IFACE);
mNai.networkInfo = new NetworkInfo(null);
mNai.networkInfo.setType(ConnectivityManager.TYPE_WIFI);
+ mNai.networkCapabilities = new NetworkCapabilities();
markNetworkConnected();
when(mNai.connService()).thenReturn(mConnectivity);
when(mNai.netAgentConfig()).thenReturn(mAgentConfig);
@@ -110,21 +120,23 @@
}
private void assertRequiresClat(boolean expected, NetworkAgentInfo nai) {
+ Nat464Xlat nat = makeNat464Xlat(true);
String msg = String.format("requiresClat expected %b for type=%d state=%s skip=%b "
+ "nat64Prefix=%s addresses=%s", expected, nai.networkInfo.getType(),
nai.networkInfo.getDetailedState(),
mAgentConfig.skip464xlat, nai.linkProperties.getNat64Prefix(),
nai.linkProperties.getLinkAddresses());
- assertEquals(msg, expected, Nat464Xlat.requiresClat(nai));
+ assertEquals(msg, expected, nat.requiresClat(nai));
}
private void assertShouldStartClat(boolean expected, NetworkAgentInfo nai) {
+ Nat464Xlat nat = makeNat464Xlat(true);
String msg = String.format("shouldStartClat expected %b for type=%d state=%s skip=%b "
+ "nat64Prefix=%s addresses=%s", expected, nai.networkInfo.getType(),
nai.networkInfo.getDetailedState(),
mAgentConfig.skip464xlat, nai.linkProperties.getNat64Prefix(),
nai.linkProperties.getLinkAddresses());
- assertEquals(msg, expected, Nat464Xlat.shouldStartClat(nai));
+ assertEquals(msg, expected, nat.shouldStartClat(nai));
}
@Test
@@ -194,7 +206,7 @@
}
private void checkNormalStartAndStop(boolean dueToDisconnect) throws Exception {
- Nat464Xlat nat = makeNat464Xlat();
+ Nat464Xlat nat = makeNat464Xlat(true);
ArgumentCaptor<LinkProperties> c = ArgumentCaptor.forClass(LinkProperties.class);
mNai.linkProperties.addLinkAddress(V6ADDR);
@@ -245,7 +257,7 @@
}
private void checkStartStopStart(boolean interfaceRemovedFirst) throws Exception {
- Nat464Xlat nat = makeNat464Xlat();
+ Nat464Xlat nat = makeNat464Xlat(true);
ArgumentCaptor<LinkProperties> c = ArgumentCaptor.forClass(LinkProperties.class);
InOrder inOrder = inOrder(mNetd, mConnectivity);
@@ -335,7 +347,7 @@
@Test
public void testClatdCrashWhileRunning() throws Exception {
- Nat464Xlat nat = makeNat464Xlat();
+ Nat464Xlat nat = makeNat464Xlat(true);
ArgumentCaptor<LinkProperties> c = ArgumentCaptor.forClass(LinkProperties.class);
nat.setNat64PrefixFromDns(new IpPrefix(NAT64_PREFIX));
@@ -372,7 +384,7 @@
}
private void checkStopBeforeClatdStarts(boolean dueToDisconnect) throws Exception {
- Nat464Xlat nat = makeNat464Xlat();
+ Nat464Xlat nat = makeNat464Xlat(true);
mNai.linkProperties.addLinkAddress(new LinkAddress("2001:db8::1/64"));
@@ -414,7 +426,7 @@
}
private void checkStopAndClatdNeverStarts(boolean dueToDisconnect) throws Exception {
- Nat464Xlat nat = makeNat464Xlat();
+ Nat464Xlat nat = makeNat464Xlat(true);
mNai.linkProperties.addLinkAddress(new LinkAddress("2001:db8::1/64"));
@@ -450,7 +462,7 @@
final IpPrefix prefixFromDns = new IpPrefix(NAT64_PREFIX);
final IpPrefix prefixFromRa = new IpPrefix(OTHER_NAT64_PREFIX);
- Nat464Xlat nat = makeNat464Xlat();
+ Nat464Xlat nat = makeNat464Xlat(true);
final LinkProperties emptyLp = new LinkProperties();
LinkProperties fixedupLp;
@@ -486,10 +498,57 @@
assertEquals(null, fixedupLp.getNat64Prefix());
}
+ private void checkClatDisabledOnCellular(boolean onCellular) throws Exception {
+ // Disable 464xlat on cellular networks.
+ Nat464Xlat nat = makeNat464Xlat(false);
+ mNai.linkProperties.addLinkAddress(V6ADDR);
+ mNai.networkCapabilities.setTransportType(TRANSPORT_CELLULAR, onCellular);
+ nat.update();
+
+ final IpPrefix nat64Prefix = new IpPrefix(NAT64_PREFIX);
+ if (onCellular) {
+ // Prefix discovery is never started.
+ verify(mDnsResolver, never()).startPrefix64Discovery(eq(NETID));
+ assertIdle(nat);
+
+ // If a NAT64 prefix comes in from an RA, clat is not started either.
+ mNai.linkProperties.setNat64Prefix(nat64Prefix);
+ nat.setNat64PrefixFromRa(nat64Prefix);
+ nat.update();
+ verify(mNetd, never()).clatdStart(anyString(), anyString());
+ assertIdle(nat);
+ } else {
+ // Prefix discovery is started.
+ verify(mDnsResolver).startPrefix64Discovery(eq(NETID));
+ assertIdle(nat);
+
+ // If a NAT64 prefix comes in from an RA, clat is started.
+ mNai.linkProperties.setNat64Prefix(nat64Prefix);
+ nat.setNat64PrefixFromRa(nat64Prefix);
+ nat.update();
+ verify(mNetd).clatdStart(BASE_IFACE, NAT64_PREFIX);
+ assertStarting(nat);
+ }
+ }
+
+ @Test
+ public void testClatDisabledOnCellular() throws Exception {
+ checkClatDisabledOnCellular(true);
+ }
+
+ @Test
+ public void testClatDisabledOnNonCellular() throws Exception {
+ checkClatDisabledOnCellular(false);
+ }
+
static void assertIdle(Nat464Xlat nat) {
assertTrue("Nat464Xlat was not IDLE", !nat.isStarted());
}
+ static void assertStarting(Nat464Xlat nat) {
+ assertTrue("Nat464Xlat was not STARTING", nat.isStarting());
+ }
+
static void assertRunning(Nat464Xlat nat) {
assertTrue("Nat464Xlat was not RUNNING", nat.isRunning());
}
diff --git a/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java b/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
index ff8c632..3adf08c 100644
--- a/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
+++ b/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
@@ -20,6 +20,7 @@
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
@@ -35,6 +36,7 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.Resources;
+import android.net.ConnectivityResources;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.os.UserHandle;
@@ -43,9 +45,10 @@
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
-import com.android.internal.R;
+import com.android.connectivity.resources.R;
import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
+import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
@@ -119,11 +122,25 @@
when(mCtx.getSystemService(eq(Context.NOTIFICATION_SERVICE)))
.thenReturn(mNotificationManager);
when(mNetworkInfo.getExtraInfo()).thenReturn(TEST_EXTRA_INFO);
+ ConnectivityResources.setResourcesContextForTest(mCtx);
when(mResources.getColor(anyInt(), any())).thenReturn(0xFF607D8B);
+ // Come up with some credible-looking transport names. The actual values do not matter.
+ String[] transportNames = new String[NetworkCapabilities.MAX_TRANSPORT + 1];
+ for (int transport = 0; transport <= NetworkCapabilities.MAX_TRANSPORT; transport++) {
+ transportNames[transport] = NetworkCapabilities.transportNameOf(transport);
+ }
+ when(mResources.getStringArray(R.array.network_switch_type_name))
+ .thenReturn(transportNames);
+
mManager = new NetworkNotificationManager(mCtx, mTelephonyManager);
}
+ @After
+ public void tearDown() {
+ ConnectivityResources.setResourcesContextForTest(null);
+ }
+
private void verifyTitleByNetwork(final int id, final NetworkAgentInfo nai, final int title) {
final String tag = NetworkNotificationManager.tagFor(id);
mManager.showNotification(id, PRIVATE_DNS_BROKEN, nai, null, null, true);
@@ -142,15 +159,15 @@
public void testTitleOfPrivateDnsBroken() {
// Test the title of mobile data.
verifyTitleByNetwork(100, mCellNai, R.string.mobile_no_internet);
- reset(mResources);
+ clearInvocations(mResources);
// Test the title of wifi.
verifyTitleByNetwork(101, mWifiNai, R.string.wifi_no_internet);
- reset(mResources);
+ clearInvocations(mResources);
// Test the title of other networks.
verifyTitleByNetwork(102, mVpnNai, R.string.other_networks_no_internet);
- reset(mResources);
+ clearInvocations(mResources);
}
@Test
diff --git a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
index e4e24b4..fec5ef3 100644
--- a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
@@ -48,18 +48,22 @@
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
-import android.content.pm.PackageManagerInternal;
import android.net.INetd;
import android.net.UidRange;
+import android.net.Uri;
import android.os.Build;
import android.os.SystemConfigManager;
import android.os.UserHandle;
@@ -70,12 +74,11 @@
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
-import com.android.server.LocalServices;
-import com.android.server.pm.PackageList;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.AdditionalAnswers;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
@@ -112,7 +115,6 @@
@Mock private Context mContext;
@Mock private PackageManager mPackageManager;
@Mock private INetd mNetdService;
- @Mock private PackageManagerInternal mMockPmi;
@Mock private UserManager mUserManager;
@Mock private PermissionMonitor.Dependencies mDeps;
@Mock private SystemConfigManager mSystemConfigManager;
@@ -131,16 +133,14 @@
when(mContext.getSystemService(Context.SYSTEM_CONFIG_SERVICE))
.thenReturn(mSystemConfigManager);
when(mSystemConfigManager.getSystemPermissionUids(anyString())).thenReturn(new int[0]);
+ final Context asUserCtx = mock(Context.class, AdditionalAnswers.delegatesTo(mContext));
+ doReturn(UserHandle.ALL).when(asUserCtx).getUser();
+ when(mContext.createContextAsUser(eq(UserHandle.ALL), anyInt())).thenReturn(asUserCtx);
mPermissionMonitor = spy(new PermissionMonitor(mContext, mNetdService, mDeps));
- LocalServices.removeServiceForTest(PackageManagerInternal.class);
- LocalServices.addService(PackageManagerInternal.class, mMockPmi);
- when(mMockPmi.getPackageList(any())).thenReturn(new PackageList(new ArrayList<String>(),
- /* observer */ null));
when(mPackageManager.getInstalledPackages(anyInt())).thenReturn(/* empty app list */ null);
mPermissionMonitor.startMonitoring();
- verify(mMockPmi).getPackageList(mPermissionMonitor);
}
private boolean hasRestrictedNetworkPermission(String partition, int targetSdkVersion, int uid,
@@ -770,4 +770,32 @@
INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS,
new int[]{ MOCK_UID2 });
}
+
+ @Test
+ public void testIntentReceiver() throws Exception {
+ final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
+ final ArgumentCaptor<BroadcastReceiver> receiverCaptor =
+ ArgumentCaptor.forClass(BroadcastReceiver.class);
+ verify(mContext, times(1)).registerReceiver(receiverCaptor.capture(), any(), any(), any());
+ final BroadcastReceiver receiver = receiverCaptor.getValue();
+
+ // Verify receiving PACKAGE_ADDED intent.
+ final Intent addedIntent = new Intent(Intent.ACTION_PACKAGE_ADDED,
+ Uri.fromParts("package", MOCK_PACKAGE1, null /* fragment */));
+ addedIntent.putExtra(Intent.EXTRA_UID, MOCK_UID1);
+ setPackagePermissions(MOCK_PACKAGE1, MOCK_UID1,
+ new String[] { INTERNET, UPDATE_DEVICE_STATS });
+ receiver.onReceive(mContext, addedIntent);
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
+ | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[] { MOCK_UID1 });
+
+ // Verify receiving PACKAGE_REMOVED intent.
+ when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(null);
+ final Intent removedIntent = new Intent(Intent.ACTION_PACKAGE_REMOVED,
+ Uri.fromParts("package", MOCK_PACKAGE1, null /* fragment */));
+ removedIntent.putExtra(Intent.EXTRA_UID, MOCK_UID1);
+ receiver.onReceive(mContext, removedIntent);
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_UNINSTALLED, new int[] { MOCK_UID1 });
+ }
+
}
diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
index b8f7fbc..6ad4900 100644
--- a/tests/net/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/net/java/com/android/server/connectivity/VpnTest.java
@@ -23,6 +23,7 @@
import static android.net.ConnectivityManager.NetworkCallback;
import static android.net.INetd.IF_STATE_DOWN;
import static android.net.INetd.IF_STATE_UP;
+import static android.os.UserHandle.PER_USER_RANGE;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
@@ -74,7 +75,6 @@
import android.net.NetworkCapabilities;
import android.net.NetworkInfo.DetailedState;
import android.net.RouteInfo;
-import android.net.UidRange;
import android.net.UidRangeParcel;
import android.net.VpnManager;
import android.net.VpnService;
@@ -181,8 +181,7 @@
mPackages.put(PKGS[i], PKG_UIDS[i]);
}
}
- private static final UidRange PRI_USER_RANGE =
- UidRange.createForUser(UserHandle.of(primaryUser.id));
+ private static final Range<Integer> PRI_USER_RANGE = uidRangeForUser(primaryUser.id);
@Mock(answer = Answers.RETURNS_DEEP_STUBS) private Context mContext;
@Mock private UserManager mUserManager;
@@ -260,6 +259,21 @@
.thenReturn(tunnelResp);
}
+ private Set<Range<Integer>> rangeSet(Range<Integer> ... ranges) {
+ final Set<Range<Integer>> range = new ArraySet<>();
+ for (Range<Integer> r : ranges) range.add(r);
+
+ return range;
+ }
+
+ private static Range<Integer> uidRangeForUser(int userId) {
+ return new Range<Integer>(userId * PER_USER_RANGE, (userId + 1) * PER_USER_RANGE - 1);
+ }
+
+ private Range<Integer> uidRange(int start, int stop) {
+ return new Range<Integer>(start, stop);
+ }
+
@Test
public void testRestrictedProfilesAreAddedToVpn() {
setMockedUsers(primaryUser, secondaryUser, restrictedProfileA, restrictedProfileB);
@@ -268,12 +282,10 @@
// Assume the user can have restricted profiles.
doReturn(true).when(mUserManager).canHaveRestrictedProfile();
- final Set<UidRange> ranges =
+ final Set<Range<Integer>> ranges =
vpn.createUserAndRestrictedProfilesRanges(primaryUser.id, null, null);
- assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] {
- PRI_USER_RANGE, UidRange.createForUser(UserHandle.of(restrictedProfileA.id))
- })), ranges);
+ assertEquals(rangeSet(PRI_USER_RANGE, uidRangeForUser(restrictedProfileA.id)), ranges);
}
@Test
@@ -281,10 +293,10 @@
setMockedUsers(primaryUser, managedProfileA);
final Vpn vpn = createVpn(primaryUser.id);
- final Set<UidRange> ranges = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
+ final Set<Range<Integer>> ranges = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
null, null);
- assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] { PRI_USER_RANGE })), ranges);
+ assertEquals(rangeSet(PRI_USER_RANGE), ranges);
}
@Test
@@ -292,35 +304,38 @@
setMockedUsers(primaryUser, restrictedProfileA, managedProfileA);
final Vpn vpn = createVpn(primaryUser.id);
- final Set<UidRange> ranges = new ArraySet<>();
+ final Set<Range<Integer>> ranges = new ArraySet<>();
vpn.addUserToRanges(ranges, primaryUser.id, null, null);
- assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] { PRI_USER_RANGE })), ranges);
+ assertEquals(rangeSet(PRI_USER_RANGE), ranges);
}
@Test
public void testUidAllowAndDenylist() throws Exception {
final Vpn vpn = createVpn(primaryUser.id);
- final UidRange user = PRI_USER_RANGE;
+ final Range<Integer> user = PRI_USER_RANGE;
+ final int userStart = user.getLower();
+ final int userStop = user.getUpper();
final String[] packages = {PKGS[0], PKGS[1], PKGS[2]};
// Allowed list
- final Set<UidRange> allow = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
- Arrays.asList(packages), null);
- assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] {
- new UidRange(user.start + PKG_UIDS[0], user.start + PKG_UIDS[0]),
- new UidRange(user.start + PKG_UIDS[1], user.start + PKG_UIDS[2])
- })), allow);
+ final Set<Range<Integer>> allow = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
+ Arrays.asList(packages), null /* disallowedApplications */);
+ assertEquals(rangeSet(
+ uidRange(userStart + PKG_UIDS[0], userStart + PKG_UIDS[0]),
+ uidRange(userStart + PKG_UIDS[1], userStart + PKG_UIDS[2])),
+ allow);
// Denied list
- final Set<UidRange> disallow = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
- null, Arrays.asList(packages));
- assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] {
- new UidRange(user.start, user.start + PKG_UIDS[0] - 1),
- new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[1] - 1),
- /* Empty range between UIDS[1] and UIDS[2], should be excluded, */
- new UidRange(user.start + PKG_UIDS[2] + 1, user.stop)
- })), disallow);
+ final Set<Range<Integer>> disallow =
+ vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
+ null /* allowedApplications */, Arrays.asList(packages));
+ assertEquals(rangeSet(
+ uidRange(userStart, userStart + PKG_UIDS[0] - 1),
+ uidRange(userStart + PKG_UIDS[0] + 1, userStart + PKG_UIDS[1] - 1),
+ /* Empty range between UIDS[1] and UIDS[2], should be excluded, */
+ uidRange(userStart + PKG_UIDS[2] + 1, userStop)),
+ disallow);
}
@Test
@@ -350,84 +365,86 @@
@Test
public void testLockdownChangingPackage() throws Exception {
final Vpn vpn = createVpn(primaryUser.id);
- final UidRange user = PRI_USER_RANGE;
-
+ final Range<Integer> user = PRI_USER_RANGE;
+ final int userStart = user.getLower();
+ final int userStop = user.getUpper();
// Set always-on without lockdown.
assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false, null));
// Set always-on with lockdown.
assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, null));
verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
- new UidRangeParcel(user.start, user.start + PKG_UIDS[1] - 1),
- new UidRangeParcel(user.start + PKG_UIDS[1] + 1, user.stop)
+ new UidRangeParcel(userStart, userStart + PKG_UIDS[1] - 1),
+ new UidRangeParcel(userStart + PKG_UIDS[1] + 1, userStop)
}));
// Switch to another app.
assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true, null));
verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] {
- new UidRangeParcel(user.start, user.start + PKG_UIDS[1] - 1),
- new UidRangeParcel(user.start + PKG_UIDS[1] + 1, user.stop)
+ new UidRangeParcel(userStart, userStart + PKG_UIDS[1] - 1),
+ new UidRangeParcel(userStart + PKG_UIDS[1] + 1, userStop)
}));
verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
- new UidRangeParcel(user.start, user.start + PKG_UIDS[3] - 1),
- new UidRangeParcel(user.start + PKG_UIDS[3] + 1, user.stop)
+ new UidRangeParcel(userStart, userStart + PKG_UIDS[3] - 1),
+ new UidRangeParcel(userStart + PKG_UIDS[3] + 1, userStop)
}));
}
@Test
public void testLockdownAllowlist() throws Exception {
final Vpn vpn = createVpn(primaryUser.id);
- final UidRange user = PRI_USER_RANGE;
-
+ final Range<Integer> user = PRI_USER_RANGE;
+ final int userStart = user.getLower();
+ final int userStop = user.getUpper();
// Set always-on with lockdown and allow app PKGS[2] from lockdown.
assertTrue(vpn.setAlwaysOnPackage(
PKGS[1], true, Collections.singletonList(PKGS[2])));
- verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
- new UidRangeParcel(user.start, user.start + PKG_UIDS[1] - 1),
- new UidRangeParcel(user.start + PKG_UIDS[2] + 1, user.stop)
+ verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
+ new UidRangeParcel(userStart, userStart + PKG_UIDS[1] - 1),
+ new UidRangeParcel(userStart + PKG_UIDS[2] + 1, userStop)
}));
// Change allowed app list to PKGS[3].
assertTrue(vpn.setAlwaysOnPackage(
PKGS[1], true, Collections.singletonList(PKGS[3])));
verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] {
- new UidRangeParcel(user.start + PKG_UIDS[2] + 1, user.stop)
+ new UidRangeParcel(userStart + PKG_UIDS[2] + 1, userStop)
}));
verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
- new UidRangeParcel(user.start + PKG_UIDS[1] + 1, user.start + PKG_UIDS[3] - 1),
- new UidRangeParcel(user.start + PKG_UIDS[3] + 1, user.stop)
+ new UidRangeParcel(userStart + PKG_UIDS[1] + 1, userStart + PKG_UIDS[3] - 1),
+ new UidRangeParcel(userStart + PKG_UIDS[3] + 1, userStop)
}));
// Change the VPN app.
assertTrue(vpn.setAlwaysOnPackage(
PKGS[0], true, Collections.singletonList(PKGS[3])));
verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] {
- new UidRangeParcel(user.start, user.start + PKG_UIDS[1] - 1),
- new UidRangeParcel(user.start + PKG_UIDS[1] + 1, user.start + PKG_UIDS[3] - 1)
+ new UidRangeParcel(userStart, userStart + PKG_UIDS[1] - 1),
+ new UidRangeParcel(userStart + PKG_UIDS[1] + 1, userStart + PKG_UIDS[3] - 1)
}));
verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
- new UidRangeParcel(user.start, user.start + PKG_UIDS[0] - 1),
- new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[3] - 1)
+ new UidRangeParcel(userStart, userStart + PKG_UIDS[0] - 1),
+ new UidRangeParcel(userStart + PKG_UIDS[0] + 1, userStart + PKG_UIDS[3] - 1)
}));
// Remove the list of allowed packages.
assertTrue(vpn.setAlwaysOnPackage(PKGS[0], true, null));
verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] {
- new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[3] - 1),
- new UidRangeParcel(user.start + PKG_UIDS[3] + 1, user.stop)
+ new UidRangeParcel(userStart + PKG_UIDS[0] + 1, userStart + PKG_UIDS[3] - 1),
+ new UidRangeParcel(userStart + PKG_UIDS[3] + 1, userStop)
}));
verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
- new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.stop),
+ new UidRangeParcel(userStart + PKG_UIDS[0] + 1, userStop),
}));
// Add the list of allowed packages.
assertTrue(vpn.setAlwaysOnPackage(
PKGS[0], true, Collections.singletonList(PKGS[1])));
verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] {
- new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.stop)
+ new UidRangeParcel(userStart + PKG_UIDS[0] + 1, userStop)
}));
verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
- new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[1] - 1),
- new UidRangeParcel(user.start + PKG_UIDS[1] + 1, user.stop)
+ new UidRangeParcel(userStart + PKG_UIDS[0] + 1, userStart + PKG_UIDS[1] - 1),
+ new UidRangeParcel(userStart + PKG_UIDS[1] + 1, userStop)
}));
// Try allowing a package with a comma, should be rejected.
@@ -439,12 +456,12 @@
assertTrue(vpn.setAlwaysOnPackage(
PKGS[0], true, Arrays.asList("com.foo.app", PKGS[2], "com.bar.app")));
verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] {
- new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[1] - 1),
- new UidRangeParcel(user.start + PKG_UIDS[1] + 1, user.stop)
+ new UidRangeParcel(userStart + PKG_UIDS[0] + 1, userStart + PKG_UIDS[1] - 1),
+ new UidRangeParcel(userStart + PKG_UIDS[1] + 1, userStop)
}));
verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
- new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[2] - 1),
- new UidRangeParcel(user.start + PKG_UIDS[2] + 1, user.stop)
+ new UidRangeParcel(userStart + PKG_UIDS[0] + 1, userStart + PKG_UIDS[2] - 1),
+ new UidRangeParcel(userStart + PKG_UIDS[2] + 1, userStop)
}));
}
@@ -452,7 +469,7 @@
public void testLockdownRuleRepeatability() throws Exception {
final Vpn vpn = createVpn(primaryUser.id);
final UidRangeParcel[] primaryUserRangeParcel = new UidRangeParcel[] {
- new UidRangeParcel(PRI_USER_RANGE.start, PRI_USER_RANGE.stop)};
+ new UidRangeParcel(PRI_USER_RANGE.getLower(), PRI_USER_RANGE.getUpper())};
// Given legacy lockdown is already enabled,
vpn.setLockdown(true);
verify(mConnectivityManager, times(1)).setRequireVpnForUids(true,
@@ -484,7 +501,7 @@
public void testLockdownRuleReversibility() throws Exception {
final Vpn vpn = createVpn(primaryUser.id);
final UidRangeParcel[] entireUser = {
- new UidRangeParcel(PRI_USER_RANGE.start, PRI_USER_RANGE.stop)
+ new UidRangeParcel(PRI_USER_RANGE.getLower(), PRI_USER_RANGE.getUpper())
};
final UidRangeParcel[] exceptPkg0 = {
new UidRangeParcel(entireUser[0].start, entireUser[0].start + PKG_UIDS[0] - 1),
@@ -1026,7 +1043,11 @@
.thenReturn(new Network[] { new Network(101) });
when(mConnectivityManager.registerNetworkAgent(any(), any(), any(), any(),
- anyInt(), any(), anyInt())).thenReturn(new Network(102));
+ any(), any(), anyInt())).thenAnswer(invocation -> {
+ // The runner has registered an agent and is now ready.
+ legacyRunnerReady.open();
+ return new Network(102);
+ });
final Vpn vpn = startLegacyVpn(createVpn(primaryUser.id), profile);
final TestDeps deps = (TestDeps) vpn.mDeps;
try {
@@ -1048,7 +1069,7 @@
ArgumentCaptor<NetworkCapabilities> ncCaptor =
ArgumentCaptor.forClass(NetworkCapabilities.class);
verify(mConnectivityManager, timeout(10_000)).registerNetworkAgent(any(), any(),
- lpCaptor.capture(), ncCaptor.capture(), anyInt(), any(), anyInt());
+ lpCaptor.capture(), ncCaptor.capture(), any(), any(), anyInt());
// In this test the expected address is always v4 so /32.
// Note that the interface needs to be specified because RouteInfo objects stored in
diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
index 9334e2c..eeeb4fb 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -89,6 +89,7 @@
import android.net.NetworkStatsHistory;
import android.net.NetworkTemplate;
import android.net.UnderlyingNetworkInfo;
+import android.net.TelephonyNetworkSpecifier;
import android.net.netstats.provider.INetworkStatsProviderCallback;
import android.os.ConditionVariable;
import android.os.Handler;
@@ -1280,6 +1281,77 @@
}
@Test
+ public void testDualVilteProviderStats() throws Exception {
+ // Pretend that network comes online.
+ expectDefaultSettings();
+ final int subId1 = 1;
+ final int subId2 = 2;
+ final NetworkStateSnapshot[] states = new NetworkStateSnapshot[]{
+ buildImsState(IMSI_1, subId1, TEST_IFACE),
+ buildImsState(IMSI_2, subId2, TEST_IFACE2)};
+ expectNetworkStatsSummary(buildEmptyStats());
+ expectNetworkStatsUidDetail(buildEmptyStats());
+
+ // Register custom provider and retrieve callback.
+ final TestableNetworkStatsProviderBinder provider =
+ new TestableNetworkStatsProviderBinder();
+ final INetworkStatsProviderCallback cb =
+ mService.registerNetworkStatsProvider("TEST", provider);
+ assertNotNull(cb);
+
+ mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
+ new UnderlyingNetworkInfo[0]);
+
+ // Verifies that one requestStatsUpdate will be called during iface update.
+ provider.expectOnRequestStatsUpdate(0 /* unused */);
+
+ // Create some initial traffic and report to the service.
+ incrementCurrentTime(HOUR_IN_MILLIS);
+ final String vtIface1 = NetworkStats.IFACE_VT + subId1;
+ final String vtIface2 = NetworkStats.IFACE_VT + subId2;
+ final NetworkStats expectedStats = new NetworkStats(0L, 1)
+ .addEntry(new NetworkStats.Entry(vtIface1, UID_RED, SET_DEFAULT,
+ TAG_NONE, METERED_YES, ROAMING_NO, DEFAULT_NETWORK_YES,
+ 128L, 2L, 128L, 2L, 1L))
+ .addEntry(new NetworkStats.Entry(vtIface2, UID_RED, SET_DEFAULT,
+ TAG_NONE, METERED_YES, ROAMING_NO, DEFAULT_NETWORK_YES,
+ 64L, 1L, 64L, 1L, 1L));
+ cb.notifyStatsUpdated(0 /* unused */, expectedStats, expectedStats);
+
+ // Make another empty mutable stats object. This is necessary since the new NetworkStats
+ // object will be used to compare with the old one in NetworkStatsRecoder, two of them
+ // cannot be the same object.
+ expectNetworkStatsUidDetail(buildEmptyStats());
+
+ forcePollAndWaitForIdle();
+
+ // Verifies that one requestStatsUpdate and setAlert will be called during polling.
+ provider.expectOnRequestStatsUpdate(0 /* unused */);
+ provider.expectOnSetAlert(MB_IN_BYTES);
+
+ // Verifies that service recorded history, does not verify uid tag part.
+ assertUidTotal(sTemplateImsi1, UID_RED, 128L, 2L, 128L, 2L, 1);
+
+ // Verifies that onStatsUpdated updates the stats accordingly.
+ NetworkStats stats = mSession.getSummaryForAllUid(
+ sTemplateImsi1, Long.MIN_VALUE, Long.MAX_VALUE, true);
+ assertEquals(1, stats.size());
+ assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
+ DEFAULT_NETWORK_YES, 128L, 2L, 128L, 2L, 1L);
+
+ stats = mSession.getSummaryForAllUid(
+ sTemplateImsi2, Long.MIN_VALUE, Long.MAX_VALUE, true);
+ assertEquals(1, stats.size());
+ assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
+ DEFAULT_NETWORK_YES, 64L, 1L, 64L, 1L, 1L);
+
+ // Verifies that unregister the callback will remove the provider from service.
+ cb.unregister();
+ forcePollAndWaitForIdle();
+ provider.assertNoCallback();
+ }
+
+ @Test
public void testStatsProviderSetAlert() throws Exception {
// Pretend that network comes online.
expectDefaultSettings();
@@ -1616,6 +1688,20 @@
TYPE_MOBILE);
}
+ private static NetworkStateSnapshot buildImsState(
+ String subscriberId, int subId, String ifaceName) {
+ final LinkProperties prop = new LinkProperties();
+ prop.setInterfaceName(ifaceName);
+ final NetworkCapabilities capabilities = new NetworkCapabilities();
+ capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, true);
+ capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, true);
+ capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_IMS, true);
+ capabilities.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
+ capabilities.setNetworkSpecifier(new TelephonyNetworkSpecifier(subId));
+ return new NetworkStateSnapshot(
+ MOBILE_NETWORK, capabilities, prop, subscriberId, TYPE_MOBILE);
+ }
+
private long getElapsedRealtime() {
return mElapsedRealtime;
}
diff --git a/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java b/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
index 5b17aad..8a0c923 100644
--- a/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
+++ b/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
@@ -109,16 +109,6 @@
}
@Test
- public void testBuilderRequiresNonEmptyUnderlyingCaps() {
- try {
- newBuilder().addExposedCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET).build();
-
- fail("Expected exception due to invalid required underlying capabilities");
- } catch (IllegalArgumentException e) {
- }
- }
-
- @Test
public void testBuilderRequiresNonNullRetryInterval() {
try {
newBuilder().setRetryInterval(null);
diff --git a/tests/vcn/java/android/net/vcn/VcnManagerTest.java b/tests/vcn/java/android/net/vcn/VcnManagerTest.java
index 7515971..516c206 100644
--- a/tests/vcn/java/android/net/vcn/VcnManagerTest.java
+++ b/tests/vcn/java/android/net/vcn/VcnManagerTest.java
@@ -204,7 +204,7 @@
new VcnStatusCallbackBinder(INLINE_EXECUTOR, mMockStatusCallback);
cbBinder.onVcnStatusChanged(VCN_STATUS_CODE_ACTIVE);
- verify(mMockStatusCallback).onVcnStatusChanged(VCN_STATUS_CODE_ACTIVE);
+ verify(mMockStatusCallback).onStatusChanged(VCN_STATUS_CODE_ACTIVE);
cbBinder.onGatewayConnectionError(
UNDERLYING_NETWORK_CAPABILITIES,
diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
index 11498de..f15d420 100644
--- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
+++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
@@ -19,6 +19,8 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
+import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS;
import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionTrackerCallback;
@@ -32,9 +34,8 @@
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyBoolean;
import static org.mockito.Mockito.argThat;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doNothing;
@@ -48,7 +49,9 @@
import android.annotation.NonNull;
import android.app.AppOpsManager;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.LinkProperties;
import android.net.NetworkCapabilities;
@@ -74,7 +77,7 @@
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
-import com.android.internal.util.LocationPermissionChecker;
+import com.android.net.module.util.LocationPermissionChecker;
import com.android.server.VcnManagementService.VcnCallback;
import com.android.server.VcnManagementService.VcnStatusCallbackInfo;
import com.android.server.vcn.TelephonySubscriptionTracker;
@@ -239,9 +242,14 @@
doReturn(Collections.singletonList(TEST_SUBSCRIPTION_INFO))
.when(mSubMgr)
.getSubscriptionsInGroup(any());
- doReturn(isPrivileged)
+ doReturn(mTelMgr)
.when(mTelMgr)
- .hasCarrierPrivileges(eq(TEST_SUBSCRIPTION_INFO.getSubscriptionId()));
+ .createForSubscriptionId(eq(TEST_SUBSCRIPTION_INFO.getSubscriptionId()));
+ doReturn(isPrivileged
+ ? CARRIER_PRIVILEGE_STATUS_HAS_ACCESS
+ : CARRIER_PRIVILEGE_STATUS_NO_ACCESS)
+ .when(mTelMgr)
+ .checkCarrierPrivilegesForPackage(eq(TEST_PACKAGE_NAME));
}
@Test
@@ -330,6 +338,13 @@
return captor.getValue();
}
+ private BroadcastReceiver getPackageChangeReceiver() {
+ final ArgumentCaptor<BroadcastReceiver> captor =
+ ArgumentCaptor.forClass(BroadcastReceiver.class);
+ verify(mMockContext).registerReceiver(captor.capture(), any(), any(), any());
+ return captor.getValue();
+ }
+
private Vcn startAndGetVcnInstance(ParcelUuid uuid) {
mVcnMgmtSvc.setVcnConfig(uuid, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
return mVcnMgmtSvc.getAllVcns().get(uuid);
@@ -392,7 +407,7 @@
mTestLooper.moveTimeForward(
VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS / 2);
mTestLooper.dispatchAll();
- mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2);
+ mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2, TEST_PACKAGE_NAME);
final Vcn newInstance = startAndGetVcnInstance(TEST_UUID_2);
// Verify that new instance was different, and the old one was torn down
@@ -406,6 +421,42 @@
}
@Test
+ public void testPackageChangeListenerRegistered() throws Exception {
+ verify(mMockContext).registerReceiver(any(BroadcastReceiver.class), argThat(filter -> {
+ return filter.hasAction(Intent.ACTION_PACKAGE_ADDED)
+ && filter.hasAction(Intent.ACTION_PACKAGE_REPLACED)
+ && filter.hasAction(Intent.ACTION_PACKAGE_REMOVED);
+ }), any(), any());
+ }
+
+ @Test
+ public void testPackageChangeListener_packageAdded() throws Exception {
+ final BroadcastReceiver receiver = getPackageChangeReceiver();
+
+ verify(mMockContext).registerReceiver(any(), argThat(filter -> {
+ return filter.hasAction(Intent.ACTION_PACKAGE_ADDED)
+ && filter.hasAction(Intent.ACTION_PACKAGE_REPLACED)
+ && filter.hasAction(Intent.ACTION_PACKAGE_REMOVED);
+ }), any(), any());
+
+ receiver.onReceive(mMockContext, new Intent(Intent.ACTION_PACKAGE_ADDED));
+ verify(mSubscriptionTracker).handleSubscriptionsChanged();
+ }
+
+ @Test
+ public void testPackageChangeListener_packageRemoved() throws Exception {
+ final BroadcastReceiver receiver = getPackageChangeReceiver();
+
+ verify(mMockContext).registerReceiver(any(), argThat(filter -> {
+ return filter.hasAction(Intent.ACTION_PACKAGE_REMOVED)
+ && filter.hasAction(Intent.ACTION_PACKAGE_REMOVED);
+ }), any(), any());
+
+ receiver.onReceive(mMockContext, new Intent(Intent.ACTION_PACKAGE_REMOVED));
+ verify(mSubscriptionTracker).handleSubscriptionsChanged();
+ }
+
+ @Test
public void testSetVcnConfigRequiresNonSystemServer() throws Exception {
doReturn(Process.SYSTEM_UID).when(mMockDeps).getBinderCallingUid();
@@ -493,7 +544,7 @@
doReturn(Process.SYSTEM_UID).when(mMockDeps).getBinderCallingUid();
try {
- mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1);
+ mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME);
fail("Expected IllegalStateException exception for system server");
} catch (IllegalStateException expected) {
}
@@ -506,7 +557,7 @@
.getBinderCallingUid();
try {
- mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1);
+ mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME);
fail("Expected security exception for non system user");
} catch (SecurityException expected) {
}
@@ -517,15 +568,24 @@
setupMockedCarrierPrivilege(false);
try {
- mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1);
+ mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME);
fail("Expected security exception for missing carrier privileges");
} catch (SecurityException expected) {
}
}
@Test
+ public void testClearVcnConfigMismatchedPackages() throws Exception {
+ try {
+ mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, "IncorrectPackage");
+ fail("Expected security exception due to mismatched packages");
+ } catch (SecurityException expected) {
+ }
+ }
+
+ @Test
public void testClearVcnConfig() throws Exception {
- mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1);
+ mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME);
assertTrue(mVcnMgmtSvc.getConfigs().isEmpty());
verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class));
}
@@ -536,7 +596,7 @@
mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_2, mMockStatusCallback, TEST_PACKAGE_NAME);
verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_ACTIVE);
- mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2);
+ mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2, TEST_PACKAGE_NAME);
verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED);
}
@@ -565,7 +625,7 @@
verify(vcnInstance).updateConfig(TEST_VCN_CONFIG);
// Verify Vcn is stopped if it was already started
- mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2);
+ mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2, TEST_PACKAGE_NAME);
verify(vcnInstance).teardownAsynchronously();
}
@@ -593,6 +653,16 @@
mVcnMgmtSvc.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
}
+ @Test(expected = SecurityException.class)
+ public void testRemoveVcnUnderlyingNetworkPolicyListenerInvalidPermission() {
+ doThrow(new SecurityException())
+ .when(mMockContext)
+ .enforceCallingOrSelfPermission(
+ eq(android.Manifest.permission.NETWORK_FACTORY), any());
+
+ mVcnMgmtSvc.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
+ }
+
@Test
public void testRemoveVcnUnderlyingNetworkPolicyListenerNeverRegistered() {
mVcnMgmtSvc.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
@@ -646,7 +716,7 @@
.setNetworkSpecifier(new TelephonyNetworkSpecifier(TEST_SUBSCRIPTION_ID));
} else if (transport == TRANSPORT_WIFI) {
WifiInfo wifiInfo = mock(WifiInfo.class);
- when(wifiInfo.makeCopy(anyBoolean())).thenReturn(wifiInfo);
+ when(wifiInfo.makeCopy(anyLong())).thenReturn(wifiInfo);
when(mMockDeps.getSubIdForWifiInfo(eq(wifiInfo))).thenReturn(TEST_SUBSCRIPTION_ID);
ncBuilder
@@ -772,7 +842,7 @@
mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
- mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2);
+ mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2, TEST_PACKAGE_NAME);
verify(mMockPolicyListener).onPolicyChanged();
}
diff --git a/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java b/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java
index 1d459a3..1ef1a61 100644
--- a/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java
+++ b/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java
@@ -194,29 +194,35 @@
}
private NetworkRequest getWifiRequest() {
- return getExpectedRequestBase()
+ return getExpectedRequestBase(true)
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.build();
}
private NetworkRequest getCellRequestForSubId(int subId) {
- return getExpectedRequestBase()
+ return getExpectedRequestBase(false)
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
.setNetworkSpecifier(new TelephonyNetworkSpecifier(subId))
.build();
}
private NetworkRequest getRouteSelectionRequest() {
- return getExpectedRequestBase().build();
+ return getExpectedRequestBase(true).build();
}
- private NetworkRequest.Builder getExpectedRequestBase() {
- return new NetworkRequest.Builder()
- .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
- .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
- .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
- .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)
- .addUnwantedCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED);
+ private NetworkRequest.Builder getExpectedRequestBase(boolean requireVcnManaged) {
+ final NetworkRequest.Builder builder =
+ new NetworkRequest.Builder()
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+ .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
+ .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
+ .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED);
+
+ if (requireVcnManaged) {
+ builder.addUnwantedCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED);
+ }
+
+ return builder;
}
@Test
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
index 4bf8491..ca6448c 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
@@ -73,7 +73,7 @@
mGatewayConnection.setUnderlyingNetwork(TEST_UNDERLYING_NETWORK_RECORD_1);
- mIkeSession = mGatewayConnection.buildIkeSession();
+ mIkeSession = mGatewayConnection.buildIkeSession(TEST_UNDERLYING_NETWORK_RECORD_1.network);
mGatewayConnection.setIkeSession(mIkeSession);
mGatewayConnection.transitionTo(mGatewayConnection.mConnectedState);
@@ -188,7 +188,7 @@
any(),
lpCaptor.capture(),
ncCaptor.capture(),
- anyInt(),
+ any(),
any(),
anyInt());
verify(mIpSecSvc)
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java
index d07d2cf..7afa449 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java
@@ -25,12 +25,15 @@
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
+import android.net.ipsec.ike.IkeSessionParams;
+
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.ArgumentCaptor;
/** Tests for VcnGatewayConnection.ConnectingState */
@RunWith(AndroidJUnit4.class)
@@ -51,7 +54,12 @@
@Test
public void testEnterStateCreatesNewIkeSession() throws Exception {
- verify(mDeps).newIkeSession(any(), any(), any(), any(), any());
+ final ArgumentCaptor<IkeSessionParams> paramsCaptor =
+ ArgumentCaptor.forClass(IkeSessionParams.class);
+ verify(mDeps).newIkeSession(any(), paramsCaptor.capture(), any(), any(), any());
+ assertEquals(
+ TEST_UNDERLYING_NETWORK_RECORD_1.network,
+ paramsCaptor.getValue().getConfiguredNetwork());
}
@Test
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java
index 661e03a..99feffd 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java
@@ -38,7 +38,8 @@
public void setUp() throws Exception {
super.setUp();
- mGatewayConnection.setIkeSession(mGatewayConnection.buildIkeSession());
+ mGatewayConnection.setIkeSession(
+ mGatewayConnection.buildIkeSession(TEST_UNDERLYING_NETWORK_RECORD_2.network));
// ensure that mGatewayConnection has an underlying Network before entering
// DisconnectingState
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java
index 748c792..d08af9d 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java
@@ -18,6 +18,7 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
@@ -87,6 +88,7 @@
private void verifyBuildNetworkCapabilitiesCommon(int transportType) {
final NetworkCapabilities underlyingCaps = new NetworkCapabilities();
underlyingCaps.addTransportType(transportType);
+ underlyingCaps.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
underlyingCaps.addCapability(NET_CAPABILITY_NOT_METERED);
underlyingCaps.addCapability(NET_CAPABILITY_NOT_ROAMING);
diff --git a/tests/vcn/java/com/android/server/vcn/VcnTest.java b/tests/vcn/java/com/android/server/vcn/VcnTest.java
index 4fa63d4..c853fc5 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnTest.java
@@ -29,6 +29,7 @@
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -139,8 +140,7 @@
mTestLooper.dispatchAll();
}
- @Test
- public void testSubscriptionSnapshotUpdatesVcnGatewayConnections() {
+ private void verifyUpdateSubscriptionSnapshotNotifiesConnectionGateways(boolean isActive) {
final NetworkRequestListener requestListener = verifyAndGetRequestListener();
startVcnGatewayWithCapabilities(requestListener, TEST_CAPS[0]);
@@ -150,14 +150,27 @@
final TelephonySubscriptionSnapshot updatedSnapshot =
mock(TelephonySubscriptionSnapshot.class);
+ mVcn.setIsActive(isActive);
+
mVcn.updateSubscriptionSnapshot(updatedSnapshot);
mTestLooper.dispatchAll();
for (final VcnGatewayConnection gateway : gatewayConnections) {
- verify(gateway).updateSubscriptionSnapshot(eq(updatedSnapshot));
+ verify(gateway, isActive ? times(1) : never())
+ .updateSubscriptionSnapshot(eq(updatedSnapshot));
}
}
+ @Test
+ public void testSubscriptionSnapshotUpdatesVcnGatewayConnections() {
+ verifyUpdateSubscriptionSnapshotNotifiesConnectionGateways(true /* isActive */);
+ }
+
+ @Test
+ public void testSubscriptionSnapshotUpdatesVcnGatewayConnectionsWhileInactive() {
+ verifyUpdateSubscriptionSnapshotNotifiesConnectionGateways(false /* isActive */);
+ }
+
private void triggerVcnRequestListeners(NetworkRequestListener requestListener) {
for (final int[] caps : TEST_CAPS) {
startVcnGatewayWithCapabilities(requestListener, caps);
@@ -187,7 +200,6 @@
NetworkRequestListener requestListener,
Set<VcnGatewayConnection> expectedGatewaysTornDown) {
assertFalse(mVcn.isActive());
- assertTrue(mVcn.getVcnGatewayConnections().isEmpty());
for (final VcnGatewayConnection gatewayConnection : expectedGatewaysTornDown) {
verify(gatewayConnection).teardownAsynchronously();
}
@@ -238,6 +250,51 @@
}
@Test
+ public void testGatewayQuitWhileInactive() {
+ final NetworkRequestListener requestListener = verifyAndGetRequestListener();
+ final Set<VcnGatewayConnection> gatewayConnections =
+ new ArraySet<>(startGatewaysAndGetGatewayConnections(requestListener));
+
+ mVcn.teardownAsynchronously();
+ mTestLooper.dispatchAll();
+
+ final VcnGatewayStatusCallback statusCallback = mGatewayStatusCallbackCaptor.getValue();
+ statusCallback.onQuit();
+ mTestLooper.dispatchAll();
+
+ // Verify that the VCN requests the networkRequests be resent
+ assertEquals(1, mVcn.getVcnGatewayConnections().size());
+ verify(mVcnNetworkProvider, never()).resendAllRequests(requestListener);
+ }
+
+ @Test
+ public void testUpdateConfigReevaluatesGatewayConnections() {
+ final NetworkRequestListener requestListener = verifyAndGetRequestListener();
+ startGatewaysAndGetGatewayConnections(requestListener);
+ assertEquals(2, mVcn.getVcnGatewayConnectionConfigMap().size());
+
+ // Create VcnConfig with only one VcnGatewayConnectionConfig so a gateway connection is torn
+ // down
+ final VcnGatewayConnectionConfig activeConfig =
+ VcnGatewayConnectionConfigTest.buildTestConfigWithExposedCaps(TEST_CAPS[0]);
+ final VcnGatewayConnectionConfig removedConfig =
+ VcnGatewayConnectionConfigTest.buildTestConfigWithExposedCaps(TEST_CAPS[1]);
+ final VcnConfig updatedConfig =
+ new VcnConfig.Builder(mContext).addGatewayConnectionConfig(activeConfig).build();
+
+ mVcn.updateConfig(updatedConfig);
+ mTestLooper.dispatchAll();
+
+ final VcnGatewayConnection activeGatewayConnection =
+ mVcn.getVcnGatewayConnectionConfigMap().get(activeConfig);
+ final VcnGatewayConnection removedGatewayConnection =
+ mVcn.getVcnGatewayConnectionConfigMap().get(removedConfig);
+ verify(activeGatewayConnection, never()).teardownAsynchronously();
+ verify(removedGatewayConnection).teardownAsynchronously();
+ verify(mVcnNetworkProvider).resendAllRequests(requestListener);
+ }
+
+ @Test
public void testUpdateConfigExitsSafeMode() {
final NetworkRequestListener requestListener = verifyAndGetRequestListener();
final Set<VcnGatewayConnection> gatewayConnections =
@@ -261,8 +318,8 @@
verify(mVcnNetworkProvider, times(2)).registerListener(eq(requestListener));
assertTrue(mVcn.isActive());
for (final int[] caps : TEST_CAPS) {
- // Expect each gateway connection created on initial startup, and again with new configs
- verify(mDeps, times(2))
+ // Expect each gateway connection created only on initial startup
+ verify(mDeps)
.newVcnGatewayConnection(
eq(mVcnContext),
eq(TEST_SUB_GROUP),
@@ -271,4 +328,14 @@
any());
}
}
+
+ @Test
+ public void testIgnoreNetworkRequestWhileInactive() {
+ mVcn.setIsActive(false /* isActive */);
+
+ final NetworkRequestListener requestListener = verifyAndGetRequestListener();
+ triggerVcnRequestListeners(requestListener);
+
+ verify(mDeps, never()).newVcnGatewayConnection(any(), any(), any(), any(), any());
+ }
}