Merge "Don't try to report non-existent stats"
diff --git a/Android.bp b/Android.bp
index c9ed7ed..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"],
}
@@ -607,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",
@@ -687,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"],
}
@@ -788,7 +787,7 @@
java_library {
name: "framework-annotations-lib",
- srcs: [ ":framework-annotations" ],
+ srcs: [":framework-annotations"],
sdk_version: "core_current",
}
@@ -1015,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 {
@@ -1176,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/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/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/core/api/current.txt b/core/api/current.txt
index 07bebbe..15dfc51 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -25723,7 +25723,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);
}
}
@@ -34219,6 +34219,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";
@@ -40662,7 +40665,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();
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 92c18c6..86f1eae 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -11745,6 +11745,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);
@@ -11759,6 +11760,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);
@@ -12052,7 +12061,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;
}
@@ -12248,7 +12257,7 @@
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 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
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 11df058..1d094c3 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -1652,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/bluetooth/le/ScanFilter.java b/core/java/android/bluetooth/le/ScanFilter.java
index 8672150..3c20dca 100644
--- a/core/java/android/bluetooth/le/ScanFilter.java
+++ b/core/java/android/bluetooth/le/ScanFilter.java
@@ -587,7 +587,7 @@
* @throws IllegalArgumentException If the {@code deviceAddress} is invalid.
*/
public Builder setDeviceAddress(String deviceAddress) {
- return setDeviceAddress(mDeviceAddress, BluetoothDevice.ADDRESS_TYPE_PUBLIC);
+ return setDeviceAddress(deviceAddress, BluetoothDevice.ADDRESS_TYPE_PUBLIC);
}
/**
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/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/VcnManager.java b/core/java/android/net/vcn/VcnManager.java
index b73fdbf..abd41da 100644
--- a/core/java/android/net/vcn/VcnManager.java
+++ b/core/java/android/net/vcn/VcnManager.java
@@ -154,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) {
@@ -439,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
@@ -476,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.
@@ -580,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/provider/Telephony.java b/core/java/android/provider/Telephony.java
index 753abea..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";
}
/**
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 0f6f15d..8db991b 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4343,6 +4343,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/symbols.xml b/core/res/res/values/symbols.xml
index ad24b79..46efd2c 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3848,6 +3848,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/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/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
index 5cb2c3b..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,
@@ -472,7 +472,7 @@
* @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;
@@ -1051,7 +1051,7 @@
*/
@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/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/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/packages/Connectivity/framework/api/current.txt b/packages/Connectivity/framework/api/current.txt
index e415e01..ad44b27 100644
--- a/packages/Connectivity/framework/api/current.txt
+++ b/packages/Connectivity/framework/api/current.txt
@@ -396,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();
diff --git a/packages/Connectivity/framework/api/module-lib-current.txt b/packages/Connectivity/framework/api/module-lib-current.txt
index aa7a0ac..1bb6a12 100644
--- a/packages/Connectivity/framework/api/module-lib-current.txt
+++ b/packages/Connectivity/framework/api/module-lib-current.txt
@@ -11,6 +11,7 @@
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, @NonNull android.os.Handler, @NonNull android.net.ConnectivityManager.NetworkCallback);
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);
@@ -30,15 +31,18 @@
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
@@ -51,7 +55,13 @@
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>>);
}
diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
index 30ccb20..b3e2286 100644
--- a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
+++ b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
@@ -3700,8 +3700,9 @@
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);
if (reqType != TRACK_DEFAULT && reqType != TRACK_SYSTEM_DEFAULT && need == null) {
@@ -3726,8 +3727,8 @@
getAttributionTag());
} else {
request = mService.requestNetwork(
- need, reqType.ordinal(), messenger, timeoutMs, binder, legacyType,
- callbackFlags, callingPackageName, getAttributionTag());
+ asUid, need, reqType.ordinal(), messenger, timeoutMs, binder,
+ legacyType, callbackFlags, callingPackageName, getAttributionTag());
}
if (request != null) {
sCallbacks.put(request, callback);
@@ -3742,6 +3743,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.
*
@@ -4227,8 +4234,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);
}
diff --git a/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl b/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl
index 3300fa8..0826922 100644
--- a/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl
+++ b/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl
@@ -142,7 +142,7 @@
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,
int callbackFlags, String callingPackageName, String callingAttributionTag);
diff --git a/packages/Connectivity/framework/src/android/net/NetworkAgentConfig.java b/packages/Connectivity/framework/src/android/net/NetworkAgentConfig.java
index 5e50a64..0bd2371 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkAgentConfig.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkAgentConfig.java
@@ -64,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.
@@ -347,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 c9c0940..881fa8c 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
@@ -639,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;
}
@@ -723,6 +735,7 @@
}
/** @hide */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public boolean hasUnwantedCapability(@NetCapability int capability) {
return isValidCapability(capability)
&& ((mUnwantedNetworkCapabilities & (1 << capability)) != 0);
@@ -736,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;
}
/**
diff --git a/packages/Connectivity/framework/src/android/net/NetworkRequest.java b/packages/Connectivity/framework/src/android/net/NetworkRequest.java
index cf131f0..bcbc04f7 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkRequest.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkRequest.java
@@ -216,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() {
@@ -305,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.
*
@@ -567,6 +594,7 @@
*
* @hide
*/
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public boolean hasUnwantedCapability(@NetCapability int capability) {
return networkCapabilities.hasUnwantedCapability(capability);
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 6fcb3f7..a0bdd7f 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1203,7 +1203,7 @@
mNetworkRanker = new NetworkRanker();
final NetworkRequest defaultInternetRequest = createDefaultRequest();
mDefaultRequest = new NetworkRequestInfo(
- defaultInternetRequest, null,
+ Process.myUid(), defaultInternetRequest, null,
new Binder(), NetworkCallback.FLAG_INCLUDE_LOCATION_INFO,
null /* attributionTags */);
mNetworkRequests.put(defaultInternetRequest, mDefaultRequest);
@@ -1410,8 +1410,7 @@
if (enable) {
handleRegisterNetworkRequest(new NetworkRequestInfo(
- networkRequest, null,
- new Binder(),
+ Process.myUid(), networkRequest, null, new Binder(),
NetworkCallback.FLAG_INCLUDE_LOCATION_INFO,
null /* attributionTags */));
} else {
@@ -1558,7 +1557,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()));
}
/**
@@ -2073,6 +2072,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);
@@ -5363,6 +5364,8 @@
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;
@@ -5370,6 +5373,13 @@
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
@@ -5397,12 +5407,12 @@
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);
@@ -5413,6 +5423,7 @@
mBinder = null;
mPid = getCallingPid();
mUid = mDeps.getCallingUid();
+ mAsUid = asUid;
mNetworkRequestCounter.incrementCountOrThrow(mUid);
/**
* Location sensitive data not included in pending intent. Only included in
@@ -5422,14 +5433,15 @@
mCallingAttributionTag = callingAttributionTag;
}
- NetworkRequestInfo(@NonNull final NetworkRequest r, @Nullable final Messenger m,
+ NetworkRequestInfo(int asUid, @NonNull final NetworkRequest r, @Nullable final Messenger m,
@Nullable final IBinder binder,
@NetworkCallback.Flag int callbackFlags,
@Nullable String callingAttributionTag) {
- this(Collections.singletonList(r), r, m, binder, callbackFlags, 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,
@NetworkCallback.Flag int callbackFlags,
@@ -5442,6 +5454,7 @@
mBinder = binder;
mPid = getCallingPid();
mUid = mDeps.getCallingUid();
+ mAsUid = asUid;
mPendingIntent = null;
mNetworkRequestCounter.incrementCountOrThrow(mUid);
mCallbackFlags = callbackFlags;
@@ -5484,18 +5497,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
@@ -5531,9 +5545,10 @@
@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)
@@ -5634,7 +5649,7 @@
}
@Override
- public NetworkRequest requestNetwork(NetworkCapabilities networkCapabilities,
+ public NetworkRequest requestNetwork(int asUid, NetworkCapabilities networkCapabilities,
int reqTypeInt, Messenger messenger, int timeoutMs, IBinder binder,
int legacyType, int callbackFlags, @NonNull String callingPackageName,
@Nullable String callingAttributionTag) {
@@ -5646,6 +5661,12 @@
}
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];
@@ -5655,10 +5676,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:
@@ -5710,7 +5731,8 @@
final NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, legacyType,
nextNetworkRequestId(), reqType);
final NetworkRequestInfo nri = getNriToRegister(
- networkRequest, messenger, binder, callbackFlags, 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
@@ -5737,25 +5759,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, callbackFlags, callingAttributionTag);
+ asUid, requests, nr, msgr, binder, callbackFlags, callingAttributionTag);
}
private void enforceNetworkRequestPermissions(NetworkCapabilities networkCapabilities,
@@ -5836,8 +5860,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));
@@ -5904,7 +5928,7 @@
NetworkRequest networkRequest = new NetworkRequest(nc, TYPE_NONE, nextNetworkRequestId(),
NetworkRequest.Type.LISTEN);
NetworkRequestInfo nri =
- new NetworkRequestInfo(networkRequest, messenger, binder, callbackFlags,
+ new NetworkRequestInfo(callingUid, networkRequest, messenger, binder, callbackFlags,
callingAttributionTag);
if (VDBG) log("listenForNetwork for " + nri);
@@ -5929,8 +5953,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));
@@ -6080,33 +6104,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;
@@ -6114,17 +6142,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 mAsUid. restrictRequestUidsForCallerAndSetRequestorInfo will
+ // 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.setSingleUid(asUid);
restrictRequestUidsForCallerAndSetRequestorInfo(
netCap, requestorUid, requestorPackageName);
return netCap;
@@ -8025,9 +8053,9 @@
final boolean metered = nai.networkCapabilities.isMetered();
boolean blocked;
- blocked = isUidBlockedByVpn(nri.mUid, mVpnBlockedUidRanges);
+ blocked = isUidBlockedByVpn(nri.mAsUid, mVpnBlockedUidRanges);
blocked |= NetworkPolicyManager.isUidBlocked(
- mUidBlockedReasons.get(nri.mUid, BLOCKED_REASON_NONE), metered);
+ mUidBlockedReasons.get(nri.mAsUid, BLOCKED_REASON_NONE), metered);
callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_AVAILABLE, blocked ? 1 : 0);
}
@@ -8055,12 +8083,12 @@
NetworkRequestInfo nri = mNetworkRequests.get(nr);
final boolean oldBlocked, newBlocked, oldVpnBlocked, newVpnBlocked;
- oldVpnBlocked = isUidBlockedByVpn(nri.mUid, oldBlockedUidRanges);
+ oldVpnBlocked = isUidBlockedByVpn(nri.mAsUid, oldBlockedUidRanges);
newVpnBlocked = (oldBlockedUidRanges != newBlockedUidRanges)
- ? isUidBlockedByVpn(nri.mUid, newBlockedUidRanges)
+ ? isUidBlockedByVpn(nri.mAsUid, newBlockedUidRanges)
: oldVpnBlocked;
- final int blockedReasons = mUidBlockedReasons.get(nri.mUid, BLOCKED_REASON_NONE);
+ final int blockedReasons = mUidBlockedReasons.get(nri.mAsUid, BLOCKED_REASON_NONE);
oldBlocked = oldVpnBlocked || NetworkPolicyManager.isUidBlocked(
blockedReasons, oldMetered);
newBlocked = newVpnBlocked || NetworkPolicyManager.isUidBlocked(
@@ -8095,7 +8123,7 @@
for (int i = 0; i < nai.numNetworkRequests(); i++) {
NetworkRequest nr = nai.requestAt(i);
NetworkRequestInfo nri = mNetworkRequests.get(nr);
- if (nri != null && nri.mUid == uid) {
+ if (nri != null && nri.mAsUid == uid) {
callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_BLK_CHANGED, arg);
}
}
@@ -8860,7 +8888,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);
@@ -9344,7 +9372,7 @@
nrs.add(createNetworkRequest(NetworkRequest.Type.REQUEST, pref.capabilities));
nrs.add(createDefaultRequest());
setNetworkRequestUids(nrs, UidRange.fromIntRanges(pref.capabilities.getUids()));
- final NetworkRequestInfo nri = new NetworkRequestInfo(nrs);
+ final NetworkRequestInfo nri = new NetworkRequestInfo(Process.myUid(), nrs);
result.add(nri);
}
return result;
@@ -9515,7 +9543,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);
}
@@ -9537,7 +9565,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) {
@@ -9547,12 +9575,12 @@
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;
}
@@ -9656,7 +9684,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/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java
index 6c18cde..642fc6b 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -349,7 +349,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 +364,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 +540,7 @@
mContext.getSystemService(AppOpsManager.class)
.checkPackage(mDeps.getBinderCallingUid(), config.getProvisioningPackageName());
- enforceCallingUserAndCarrierPrivilege(subscriptionGroup);
+ enforceCallingUserAndCarrierPrivilege(subscriptionGroup, opPkgName);
Binder.withCleanCallingIdentity(() -> {
synchronized (mLock) {
@@ -554,11 +558,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) {
@@ -821,8 +828,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/apphibernation/AppHibernationService.java b/services/core/java/com/android/server/apphibernation/AppHibernationService.java
index b3373d0..351231f 100644
--- a/services/core/java/com/android/server/apphibernation/AppHibernationService.java
+++ b/services/core/java/com/android/server/apphibernation/AppHibernationService.java
@@ -69,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;
@@ -101,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;
@@ -126,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 */);
@@ -147,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();
@@ -170,16 +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;
}
getContext().enforceCallingOrSelfPermission(
android.Manifest.permission.MANAGE_APP_HIBERNATION,
"Caller does not have MANAGE_APP_HIBERNATION permission.");
- userId = handleIncomingUser(userId, "isHibernating");
- if (!mUserManager.isUserUnlockingOrUnlocked(userId)) {
- Slog.e(TAG, "Attempt to get hibernation state of stopped or nonexistent user "
- + userId);
+ userId = handleIncomingUser(userId, methodName);
+ if (!checkUserStatesExist(userId, methodName)) {
return false;
}
synchronized (mLock) {
@@ -225,16 +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;
}
getContext().enforceCallingOrSelfPermission(
android.Manifest.permission.MANAGE_APP_HIBERNATION,
"Caller does not have MANAGE_APP_HIBERNATION permission.");
- userId = handleIncomingUser(userId, "setHibernating");
- if (!mUserManager.isUserUnlockingOrUnlocked(userId)) {
- Slog.w(TAG, "Attempt to set hibernation state for a stopped or nonexistent user "
- + userId);
+ userId = handleIncomingUser(userId, methodName);
+ if (!checkUserStatesExist(userId, methodName)) {
return;
}
synchronized (mLock) {
@@ -298,16 +301,15 @@
*/
@NonNull List<String> getHibernatingPackagesForUser(int userId) {
ArrayList<String> hibernatingPackages = new ArrayList<>();
- if (!checkHibernationEnabled("getHibernatingPackagesForUser")) {
+ 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, "getHibernatingPackagesForUser");
- if (!mUserManager.isUserUnlockingOrUnlocked(userId)) {
- Slog.w(TAG, "Attempt to get hibernating packages for a stopped or nonexistent user "
- + userId);
+ userId = handleIncomingUser(userId, methodName);
+ if (!checkUserStatesExist(userId, methodName)) {
return hibernatingPackages;
}
synchronized (mLock) {
@@ -477,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
@@ -550,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));
@@ -720,6 +741,8 @@
UserManager getUserManager();
+ Executor getBackgroundExecutor();
+
HibernationStateDiskStore<GlobalLevelState> getGlobalLevelDiskStore();
HibernationStateDiskStore<UserLevelState> getUserLevelDiskStore(int userId);
@@ -758,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 6776f49..d4eb104 100644
--- a/services/core/java/com/android/server/clipboard/ClipboardService.java
+++ b/services/core/java/com/android/server/clipboard/ClipboardService.java
@@ -106,6 +106,17 @@
return false;
}
+ private void closePipe() {
+ try {
+ final RandomAccessFile pipe = mPipe;
+ mPipe = null;
+ if (pipe != null) {
+ pipe.close();
+ }
+ } catch (IOException ignore) {
+ }
+ }
+
public HostClipboardMonitor(HostClipboardCallback cb) {
mHostClipboardCallback = cb;
}
@@ -127,10 +138,7 @@
mHostClipboardCallback.onHostClipboardUpdated(
new String(receivedData));
} catch (IOException e) {
- try {
- mPipe.close();
- } catch (IOException ee) {}
- mPipe = null;
+ closePipe();
} catch (InterruptedException e) {}
}
}
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 30e0c7e..c8f9982 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -19,10 +19,10 @@
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.os.UserHandle.PER_USER_RANGE;
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;
@@ -223,7 +223,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;
@@ -460,11 +460,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();
}
@@ -525,8 +526,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();
}
/**
@@ -1237,29 +1240,33 @@
// 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.Builder().build();
- 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,
new NetworkScore.Builder().setLegacyInt(VPN_DEFAULT_SCORE).build(),
@@ -1426,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;
@@ -1576,7 +1584,8 @@
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);
}
@@ -1605,7 +1614,8 @@
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);
}
@@ -1849,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;
@@ -1886,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;
}
/**
diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
index 6e99cba..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;
@@ -65,6 +70,22 @@
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.
@@ -86,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.
*/
@@ -199,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);
@@ -221,6 +271,11 @@
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) {
@@ -261,6 +316,7 @@
if (rebootEscrowUsers.isEmpty()) {
Slog.i(TAG, "No reboot escrow data found for users,"
+ " skipping loading escrow data");
+ clearMetricsStorage();
return;
}
@@ -284,6 +340,7 @@
}
Slog.w(TAG, "Failed to load reboot escrow data after " + attemptNumber + " attempts");
+ mLoadEscrowDataErrorCode = ERROR_RETRY_COUNT_EXHAUSTED;
onGetRebootEscrowKeyFailed(users, attemptNumber);
}
@@ -307,6 +364,17 @@
}
if (escrowKey == null) {
+ 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;
}
@@ -321,9 +389,49 @@
// Clear the old key in keystore. A new key will be generated by new RoR requests.
mKeyStoreManager.clearKeyStoreEncryptionKey();
+ if (!allUsersUnlocked && mLoadEscrowDataErrorCode == ERROR_NONE) {
+ mLoadEscrowDataErrorCode = ERROR_UNLOCK_ALL_USERS;
+ }
onEscrowRestoreComplete(allUsersUnlocked, attemptNumber + 1);
}
+ 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
@@ -331,26 +439,32 @@
long armedTimestamp = mStorage.getLong(REBOOT_ESCROW_KEY_ARMED_TIMESTAMP, -1,
USER_SYSTEM);
- mStorage.removeKey(REBOOT_ESCROW_KEY_ARMED_TIMESTAMP, USER_SYSTEM);
- int escrowDurationInSeconds = armedTimestamp != -1
- ? (int) (System.currentTimeMillis() - armedTimestamp) / 1000 : -1;
+ int escrowDurationInSeconds = -1;
+ long currentTimeStamp = mInjector.getCurrentTimeMillis();
+ if (armedTimestamp != -1 && currentTimeStamp > armedTimestamp) {
+ escrowDurationInSeconds = (int) (currentTimeStamp - armedTimestamp) / 1000;
+ }
- // TODO(b/179105110) design error code; and report the true value for other fields.
- int vbmetaDigestStatus = FrameworkStatsLog
- .REBOOT_ESCROW_RECOVERY_REPORTED__VBMETA_DIGEST_STATUS__MATCH_EXPECTED_SLOT;
+ int vbmetaDigestStatus = getVbmetaDigestStatusOnRestoreComplete();
+ if (!success && mLoadEscrowDataErrorCode == ERROR_NONE) {
+ mLoadEscrowDataErrorCode = ERROR_UNKNOWN;
+ }
- mInjector.reportMetric(success, 0 /* error code */, serviceType, attemptCount,
+ // 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);
- mStorage.removeKey(REBOOT_ESCROW_ARMED_KEY, USER_SYSTEM);
int bootCountDelta = mInjector.getBootCount() - previousBootCount;
if (success || (previousBootCount != -1 && bootCountDelta <= BOOT_COUNT_TOLERANCE)) {
reportMetricOnRestoreComplete(success, attemptCount);
}
+ clearMetricsStorage();
}
private RebootEscrowKey getAndClearRebootEscrowKey(SecretKey kk) throws IOException {
@@ -358,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;
}
@@ -463,7 +585,7 @@
return;
}
- mStorage.removeKey(REBOOT_ESCROW_ARMED_KEY, USER_SYSTEM);
+ clearMetricsStorage();
rebootEscrowProvider.clearRebootEscrowKey();
List<UserInfo> users = mUserManager.getUsers();
@@ -486,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;
@@ -505,8 +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, System.currentTimeMillis(),
+ 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/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/recoverysystem/RecoverySystemService.java b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
index 0a6772b..fe21201 100644
--- a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
+++ b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
@@ -734,7 +734,15 @@
return REBOOT_ERROR_SLOT_MISMATCH;
}
- if (!mInjector.getLockSettingsService().armRebootEscrow()) {
+ 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;
}
@@ -742,11 +750,20 @@
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 = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_OTA,
- "server_based_ror_enabled", false);
+ boolean serverBased = useServerBasedRoR();
int preparedClientCount;
synchronized (this) {
preparedClientCount = mCallerPreparedForReboot.size();
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/vcn/Vcn.java b/services/core/java/com/android/server/vcn/Vcn.java
index 3f74938..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(
@@ -318,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/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java b/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java
index 1b8ab21..2f0d71a 100644
--- a/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java
@@ -58,6 +58,7 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.Executor;
/**
* Tests for {@link com.android.server.apphibernation.AppHibernationService}
@@ -116,8 +117,8 @@
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;
}
@@ -150,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
@@ -188,8 +189,8 @@
// 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});
- mAppHibernationService.onUserUnlocking(new SystemService.TargetUser(userInfo));
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);
@@ -259,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/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 91342ce..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,6 +21,7 @@
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;
@@ -110,6 +111,10 @@
public interface MockableRebootEscrowInjected {
int getBootCount();
+ long getCurrentTimeMillis();
+
+ boolean forceServerBased();
+
void reportMetric(boolean success, int errorCode, int serviceType, int attemptCount,
int escrowDurationInSeconds, int vbmetaDigestStatus, int durationSinceBootComplete);
}
@@ -174,6 +179,9 @@
@Override
public boolean serverBasedResumeOnReboot() {
+ if (mInjected.forceServerBased()) {
+ return true;
+ }
return mServerBased;
}
@@ -205,9 +213,20 @@
}
@Override
+ 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);
}
@@ -430,16 +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(),
eq(0) /* error code */, eq(1) /* HAL based */, eq(1) /* attempt count */,
- anyInt(), anyInt(), anyInt());
+ 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
@@ -468,7 +492,7 @@
ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class);
doNothing().when(mInjected).reportMetric(metricsSuccessCaptor.capture(),
eq(0) /* error code */, eq(2) /* Server based */, eq(1) /* attempt count */,
- anyInt(), anyInt(), anyInt());
+ anyInt(), eq(0) /* vbmeta status */, anyInt());
when(mServiceConnection.unwrap(any(), anyLong()))
.thenAnswer(invocation -> invocation.getArgument(0));
@@ -479,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();
@@ -607,9 +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), eq(0) /* error code */, eq(1) /* HAL based */,
- eq(1) /* attempt count */, anyInt(), anyInt(), anyInt());
+ eq(1) /* attempt count */, anyInt(), eq(2) /* vbmeta status */, anyInt());
+ assertEquals(mStorage.getString(RebootEscrowManager.REBOOT_ESCROW_KEY_VBMETA_DIGEST,
+ "", USER_SYSTEM), "");
}
@Test
@@ -636,12 +743,17 @@
when(mInjected.getBootCount()).thenReturn(1);
ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class);
+ ArgumentCaptor<Integer> metricsErrorCodeCaptor = ArgumentCaptor.forClass(Integer.class);
+ // Return a null escrow key
doNothing().when(mInjected).reportMetric(metricsSuccessCaptor.capture(),
- anyInt() /* error code */, eq(1) /* HAL based */, eq(1) /* attempt count */,
- anyInt(), anyInt(), anyInt());
- when(mRebootEscrow.retrieveKey()).thenAnswer(invocation -> new byte[32]);
+ 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/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/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/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 bae032c..7c39cf0 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -14570,7 +14570,12 @@
* 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}).
+ * 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.
@@ -14589,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) {
diff --git a/telephony/java/android/telephony/ims/RcsContactUceCapability.java b/telephony/java/android/telephony/ims/RcsContactUceCapability.java
index 52d0f03..a133ead 100644
--- a/telephony/java/android/telephony/ims/RcsContactUceCapability.java
+++ b/telephony/java/android/telephony/ims/RcsContactUceCapability.java
@@ -29,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.
@@ -110,7 +112,6 @@
/**
* Builder to help construct {@link RcsContactUceCapability} instances when capabilities were
* queried through SIP OPTIONS.
- * @hide
*/
public static final class OptionsBuilder {
@@ -151,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;
}
@@ -220,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,
@@ -235,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());
}
@@ -245,7 +248,7 @@
out.writeInt(mCapabilityMechanism);
out.writeInt(mSourceType);
out.writeInt(mRequestResult);
- out.writeStringList(mFeatureTags);
+ out.writeStringList(new ArrayList<>(mFeatureTags));
out.writeParcelableList(mPresenceTuples, flags);
}
@@ -285,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);
}
/**
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/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/RcsCapabilityExchangeImplBase.java b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java
index 03e17fb..25b9446 100644
--- a/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java
@@ -33,6 +33,7 @@
import java.lang.annotation.RetentionPolicy;
import java.util.Collection;
import java.util.List;
+import java.util.Set;
import java.util.concurrent.Executor;
/**
@@ -433,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")
@@ -446,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 45702c31..c306c57 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -2231,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
diff --git a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
index d40b88c..1f50e31 100644
--- a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
@@ -329,7 +329,8 @@
if (isAtLeastS()) {
netCap.setSubIds(Set.of(TEST_SUBID1, TEST_SUBID2));
netCap.setUids(uids);
- } else if (isAtLeastR()) {
+ }
+ if (isAtLeastR()) {
netCap.setOwnerUid(123);
netCap.setAdministratorUids(new int[] {5, 11});
}
@@ -531,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
@@ -596,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);
diff --git a/tests/net/java/android/net/ConnectivityManagerTest.java b/tests/net/java/android/net/ConnectivityManagerTest.java
index 6fc605e..36f205b 100644
--- a/tests/net/java/android/net/ConnectivityManagerTest.java
+++ b/tests/net/java/android/net/ConnectivityManagerTest.java
@@ -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(),
- 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(),
- 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(),
- 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(), 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,34 +358,40 @@
final NetworkCallback callback = new ConnectivityManager.NetworkCallback();
manager.requestNetwork(request, callback);
- verify(mService).requestNetwork(eq(request.networkCapabilities),
+ 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(),
- anyInt(), any(), any());
+ 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(null),
+ 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);
- Handler handler = new Handler(ConnectivityThread.getInstanceLooper());
+ 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(request.networkCapabilities),
+ 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),
+ 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/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index ed9a44b..ee17d75 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -1451,6 +1451,23 @@
});
}
+ 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));
@@ -3813,8 +3830,9 @@
NetworkCapabilities networkCapabilities = new NetworkCapabilities();
networkCapabilities.addTransportType(TRANSPORT_WIFI)
.setNetworkSpecifier(new MatchAllNetworkSpecifier());
- mService.requestNetwork(networkCapabilities, NetworkRequest.Type.REQUEST.ordinal(),
- null, 0, null, ConnectivityManager.TYPE_WIFI, NetworkCallback.FLAG_NONE,
+ mService.requestNetwork(Process.INVALID_UID, networkCapabilities,
+ NetworkRequest.Type.REQUEST.ordinal(), null, 0, null,
+ ConnectivityManager.TYPE_WIFI, NetworkCallback.FLAG_NONE,
mContext.getPackageName(), getAttributionTag());
});
@@ -4043,7 +4061,7 @@
}
@Test
- public void testRegisterSystemDefaultCallbackRequiresNetworkSettings() throws Exception {
+ public void testRegisterPrivilegedDefaultCallbacksRequireNetworkSettings() throws Exception {
mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(false /* validated */);
@@ -4052,12 +4070,19 @@
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) {
@@ -7490,6 +7515,10 @@
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<>();
@@ -7509,6 +7538,7 @@
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);
@@ -7522,6 +7552,7 @@
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());
@@ -7537,6 +7568,7 @@
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
@@ -7558,6 +7590,7 @@
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);
@@ -7579,6 +7612,7 @@
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);
@@ -7591,6 +7625,7 @@
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);
@@ -7606,6 +7641,7 @@
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);
@@ -7618,6 +7654,7 @@
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);
@@ -7631,6 +7668,7 @@
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);
@@ -7642,6 +7680,7 @@
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);
@@ -7654,12 +7693,14 @@
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() {
@@ -9805,8 +9846,8 @@
for (int reqTypeInt : invalidReqTypeInts) {
assertThrows("Expect throws for invalid request type " + reqTypeInt,
IllegalArgumentException.class,
- () -> mService.requestNetwork(nc, reqTypeInt, null, 0, null,
- ConnectivityManager.TYPE_NONE, NetworkCallback.FLAG_NONE,
+ () -> mService.requestNetwork(Process.INVALID_UID, nc, reqTypeInt, null, 0,
+ null, ConnectivityManager.TYPE_NONE, NetworkCallback.FLAG_NONE,
mContext.getPackageName(), getAttributionTag())
);
}
@@ -10377,6 +10418,7 @@
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);
}
@@ -10396,7 +10438,7 @@
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);
@@ -10532,6 +10574,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);
@@ -10542,19 +10589,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
@@ -10572,6 +10622,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);
@@ -10583,15 +10638,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
@@ -10605,6 +10664,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);
@@ -10620,6 +10684,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,
@@ -10627,25 +10694,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);
}
/**
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 a9d5822..babea36 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;
@@ -238,9 +240,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
@@ -391,7 +398,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
@@ -492,7 +499,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) {
}
@@ -505,7 +512,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) {
}
@@ -516,15 +523,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));
}
@@ -535,7 +551,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);
}
@@ -564,7 +580,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();
}
@@ -781,7 +797,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/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());
+ }
}