Merge "NetworkCapabilities: Hide copy constructor"
diff --git a/Android.bp b/Android.bp
index 856e11ec..0b0a9b7 100644
--- a/Android.bp
+++ b/Android.bp
@@ -296,8 +296,6 @@
":framework-connectivity-sources",
"core/java/**/*.logtags",
],
- // See comment on framework-atb-backward-compatibility module below
- exclude_srcs: ["core/java/android/content/pm/AndroidTestBaseUpdater.java"],
aidl: {
generate_get_transaction_name: true,
},
@@ -378,20 +376,6 @@
src: ":framework-minus-apex",
}
-// A temporary build target that is conditionally included on the bootclasspath if
-// android.test.base library has been removed and which provides support for
-// maintaining backwards compatibility for APKs that target pre-P and depend on
-// android.test.base classes. This is used iff REMOVE_ATB_FROM_BCP=true is
-// specified on the build command line.
-java_library {
- name: "framework-atb-backward-compatibility",
- installable: true,
- libs: ["app-compat-annotations"],
- srcs: [
- "core/java/android/content/pm/AndroidTestBaseUpdater.java",
- ],
-}
-
genrule {
name: "statslog-framework-java-gen",
tools: ["stats-log-api-gen"],
@@ -872,38 +856,6 @@
},
}
-// TODO(b/77285514): remove this once the last few hidl interfaces have been
-// updated to use hwbinder.stubs.
-java_library {
- name: "hwbinder",
- sdk_version: "core_platform",
-
- srcs: [
- "core/java/android/os/HidlSupport.java",
- "core/java/android/annotation/IntDef.java",
- "core/java/android/annotation/IntRange.java",
- "core/java/android/annotation/NonNull.java",
- "core/java/android/annotation/Nullable.java",
- "core/java/android/annotation/SystemApi.java",
- "core/java/android/annotation/TestApi.java",
- "core/java/android/os/HidlMemory.java",
- "core/java/android/os/HwBinder.java",
- "core/java/android/os/HwBlob.java",
- "core/java/android/os/HwParcel.java",
- "core/java/android/os/IHwBinder.java",
- "core/java/android/os/IHwInterface.java",
- "core/java/android/os/DeadObjectException.java",
- "core/java/android/os/DeadSystemException.java",
- "core/java/android/os/NativeHandle.java",
- "core/java/android/os/RemoteException.java",
- "core/java/android/util/AndroidException.java",
- ],
- libs: ["unsupportedappusage"],
-
- dxflags: ["--core-library"],
- installable: false,
-}
-
python_defaults {
name: "base_default",
version: {
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index 3b7a617..fe8b9d6 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -23,6 +23,7 @@
package android.content {
public abstract class Context {
+ field public static final String PAC_PROXY_SERVICE = "pac_proxy";
field public static final String TEST_NETWORK_SERVICE = "test_network";
}
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 3f11b72..e6624cd 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -11988,7 +11988,7 @@
method @NonNull public byte[] getEncodedMessage();
method @NonNull public String getHeaderSection();
method @NonNull public String getStartLine();
- method @Nullable public String getViaBranchParameter();
+ method @NonNull public String getViaBranchParameter();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.SipMessage> CREATOR;
}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index fe9ed27..4293ab0 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -4026,6 +4026,7 @@
* @see android.net.PacProxyManager
* @hide
*/
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final String PAC_PROXY_SERVICE = "pac_proxy";
/**
diff --git a/core/java/android/net/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl
index 171c6a2..f50aa99 100644
--- a/core/java/android/net/INetworkPolicyManager.aidl
+++ b/core/java/android/net/INetworkPolicyManager.aidl
@@ -78,5 +78,4 @@
boolean isUidNetworkingBlocked(int uid, boolean meteredNetwork);
boolean isUidRestrictedOnMeteredNetworks(int uid);
- boolean checkUidNetworkingBlocked(int uid, int uidRules, boolean isNetworkMetered, boolean isBackgroundRestricted);
}
diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java
index b037261..1eef7d9 100644
--- a/core/java/android/net/NetworkIdentity.java
+++ b/core/java/android/net/NetworkIdentity.java
@@ -198,15 +198,11 @@
final int oemManaged = getOemBitfield(snapshot.networkCapabilities);
if (legacyType == TYPE_WIFI) {
- if (snapshot.networkCapabilities.getSsid() != null) {
- networkId = snapshot.networkCapabilities.getSsid();
- if (networkId == null) {
- // TODO: Figure out if this code path never runs. If so, remove them.
- final WifiManager wifi = (WifiManager) context.getSystemService(
- Context.WIFI_SERVICE);
- final WifiInfo info = wifi.getConnectionInfo();
- networkId = info != null ? info.getSSID() : null;
- }
+ networkId = snapshot.networkCapabilities.getSsid();
+ if (networkId == null) {
+ final WifiManager wifi = context.getSystemService(WifiManager.class);
+ final WifiInfo info = wifi.getConnectionInfo();
+ networkId = info != null ? info.getSSID() : null;
}
}
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index 68606ec..da3febd 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -564,31 +564,6 @@
}
/**
- * Figure out if networking is blocked for a given set of conditions.
- *
- * This is used by ConnectivityService via passing stale copies of conditions, so it must not
- * take any locks.
- *
- * @param uid The target uid.
- * @param uidRules The uid rules which are obtained from NetworkPolicyManagerService.
- * @param isNetworkMetered True if the network is metered.
- * @param isBackgroundRestricted True if data saver is enabled.
- *
- * @return true if networking is blocked for the UID under the specified conditions.
- *
- * @hide
- */
- public boolean checkUidNetworkingBlocked(int uid, int uidRules,
- boolean isNetworkMetered, boolean isBackgroundRestricted) {
- try {
- return mService.checkUidNetworkingBlocked(uid, uidRules, isNetworkMetered,
- isBackgroundRestricted);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
* Check that the given uid is restricted from doing networking on metered networks.
*
* @param uid The target uid.
diff --git a/core/java/android/util/TimeUtils.java b/core/java/android/util/TimeUtils.java
index cd6585c..5fd0c33 100644
--- a/core/java/android/util/TimeUtils.java
+++ b/core/java/android/util/TimeUtils.java
@@ -30,6 +30,7 @@
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
+import java.time.Instant;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Calendar;
@@ -43,11 +44,39 @@
public class TimeUtils {
/** @hide */ public TimeUtils() {}
/** {@hide} */
- private static SimpleDateFormat sLoggingFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ private static final SimpleDateFormat sLoggingFormat =
+ new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
/** @hide */
public static final SimpleDateFormat sDumpDateFormat =
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
+
+ /**
+ * This timestamp is used in TimeUtils methods and by the SettingsUI to filter time zones
+ * to only "effective" ones in a country. It is compared against the notUsedAfter metadata that
+ * Android records for some time zones.
+ *
+ * <p>What is notUsedAfter?</p>
+ * Android chooses to avoid making users choose between functionally identical time zones at the
+ * expense of not being able to represent local times in the past.
+ *
+ * notUsedAfter exists because some time zones can "merge" with other time zones after a given
+ * point in time (i.e. they change to have identical transitions, offsets, display names, etc.).
+ * From the notUsedAfter time, the zone will express the same local time as the one it merged
+ * with.
+ *
+ * <p>Why hardcoded?</p>
+ * Rather than using System.currentTimeMillis(), a timestamp known to be in the recent past is
+ * used to ensure consistent behavior across devices and time, and avoid assumptions that the
+ * system clock on a device is currently set correctly. The fixed value should be updated
+ * occasionally, but it doesn't have to be very often as effective time zones for a country
+ * don't change very often.
+ *
+ * @hide
+ */
+ public static final Instant MIN_USE_DATE_OF_TIMEZONE =
+ Instant.ofEpochMilli(1546300800000L); // 1/1/2019 00:00 UTC
+
/**
* Tries to return a time zone that would have had the specified offset
* and DST value at the specified moment in the specified country.
@@ -109,7 +138,7 @@
List<String> timeZoneIds = new ArrayList<>();
for (TimeZoneMapping timeZoneMapping : countryTimeZones.getTimeZoneMappings()) {
- if (timeZoneMapping.isShownInPicker()) {
+ if (timeZoneMapping.isShownInPickerAt(MIN_USE_DATE_OF_TIMEZONE)) {
timeZoneIds.add(timeZoneMapping.getTimeZoneId());
}
}
diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp
index 510578e..5045e3b 100644
--- a/core/tests/coretests/Android.bp
+++ b/core/tests/coretests/Android.bp
@@ -61,7 +61,6 @@
"org.apache.http.legacy",
"android.test.base",
"android.test.mock",
- "framework-atb-backward-compatibility",
"framework",
"ext",
"framework-res",
diff --git a/core/tests/coretests/src/android/window/OWNERS b/core/tests/coretests/src/android/window/OWNERS
new file mode 100644
index 0000000..6c80cf9
--- /dev/null
+++ b/core/tests/coretests/src/android/window/OWNERS
@@ -0,0 +1,2 @@
+include /services/core/java/com/android/server/wm/OWNERS
+charlesccchen@google.com
diff --git a/graphics/java/android/graphics/RecordingCanvas.java b/graphics/java/android/graphics/RecordingCanvas.java
index c0e0a24..4a24b42 100644
--- a/graphics/java/android/graphics/RecordingCanvas.java
+++ b/graphics/java/android/graphics/RecordingCanvas.java
@@ -21,6 +21,7 @@
import android.util.Pools.SynchronizedPool;
import android.view.DisplayListCanvas;
import android.view.TextureLayer;
+import android.os.SystemProperties;
import dalvik.annotation.optimization.CriticalNative;
import dalvik.annotation.optimization.FastNative;
@@ -41,7 +42,14 @@
private static final int POOL_LIMIT = 25;
/** @hide */
- public static final int MAX_BITMAP_SIZE = 100 * 1024 * 1024; // 100 MB
+ private static int getPanelFrameSize() {
+ final int DefaultSize = 100 * 1024 * 1024; // 100 MB;
+ return Math.max(SystemProperties.getInt("ro.hwui.max_texture_allocation_size", DefaultSize),
+ DefaultSize);
+ }
+
+ /** @hide */
+ public static final int MAX_BITMAP_SIZE = getPanelFrameSize();
private static final SynchronizedPool<RecordingCanvas> sPool =
new SynchronizedPool<>(POOL_LIMIT);
diff --git a/keystore/java/android/security/keystore/AttestationUtils.java b/keystore/java/android/security/keystore/AttestationUtils.java
index 1eb8541..be865a0 100644
--- a/keystore/java/android/security/keystore/AttestationUtils.java
+++ b/keystore/java/android/security/keystore/AttestationUtils.java
@@ -36,9 +36,11 @@
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.SecureRandom;
+import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.spec.ECGenParameterSpec;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Random;
import java.util.Set;
@@ -281,8 +283,9 @@
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
+ Certificate[] certs = keyStore.getCertificateChain(keystoreAlias);
X509Certificate[] certificateChain =
- (X509Certificate[]) keyStore.getCertificateChain(keystoreAlias);
+ Arrays.copyOf(certs, certs.length, X509Certificate[].class);
keyStore.deleteEntry(keystoreAlias);
diff --git a/native/android/OWNERS b/native/android/OWNERS
index 6f7def8..02dfd39 100644
--- a/native/android/OWNERS
+++ b/native/android/OWNERS
@@ -1,3 +1,5 @@
+jreck@google.com
+
per-file libandroid_net.map.txt, net.c = set noparent
per-file libandroid_net.map.txt, net.c = codewiz@google.com, jchalard@google.com, junyulai@google.com
per-file libandroid_net.map.txt, net.c = lorenzo@google.com, reminv@google.com, satk@google.com
@@ -6,3 +8,9 @@
per-file native_window_jni.cpp = file:/services/core/java/com/android/server/wm/OWNERS
per-file native_activity.cpp = file:/services/core/java/com/android/server/wm/OWNERS
per-file surface_control.cpp = file:/services/core/java/com/android/server/wm/OWNERS
+
+per-file choreographer.cpp = file:/graphics/java/android/graphics/OWNERS
+per-file hardware_buffer_jni.cpp = file:/graphics/java/android/graphics/OWNERS
+per-file native_window_jni.cpp = file:/graphics/java/android/graphics/OWNERS
+per-file surface_control.cpp = file:/graphics/java/android/graphics/OWNERS
+per-file surface_texture.cpp = file:/graphics/java/android/graphics/OWNERS
diff --git a/packages/Connectivity/framework/aidl-export/android/net/IpPrefix.aidl b/packages/Connectivity/framework/aidl-export/android/net/IpPrefix.aidl
index 0d70f2a..3495efc 100644
--- a/packages/Connectivity/framework/aidl-export/android/net/IpPrefix.aidl
+++ b/packages/Connectivity/framework/aidl-export/android/net/IpPrefix.aidl
@@ -18,5 +18,5 @@
package android.net;
// @JavaOnlyStableParcelable only affects the parcelable when built as stable aidl (aidl_interface
-// build rule). IpPrefix is also used in cpp but only as non-stable aidl.
-@JavaOnlyStableParcelable parcelable IpPrefix cpp_header "binder/IpPrefix.h";
+// build rule).
+@JavaOnlyStableParcelable parcelable IpPrefix;
diff --git a/packages/Connectivity/framework/api/module-lib-current.txt b/packages/Connectivity/framework/api/module-lib-current.txt
index 82d5d6e..f95d377 100644
--- a/packages/Connectivity/framework/api/module-lib-current.txt
+++ b/packages/Connectivity/framework/api/module-lib-current.txt
@@ -175,10 +175,12 @@
}
public final class VpnTransportInfo implements android.os.Parcelable android.net.TransportInfo {
- ctor public VpnTransportInfo(int);
+ ctor public VpnTransportInfo(int, @Nullable String);
method public int describeContents();
+ method @NonNull public android.net.VpnTransportInfo makeCopy(long);
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.net.VpnTransportInfo> CREATOR;
+ field @Nullable public final String sessionId;
field public final int type;
}
diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
index c6f4e0b..92ed7fc 100644
--- a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
+++ b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
@@ -3140,18 +3140,27 @@
}
/**
- * Set a network-independent global http proxy. This is not normally what you want
- * for typical HTTP proxies - they are general network dependent. However if you're
- * doing something unusual like general internal filtering this may be useful. On
- * a private network where the proxy is not accessible, you may break HTTP using this.
+ * Set a network-independent global HTTP proxy.
*
- * @param p A {@link ProxyInfo} object defining the new global
- * HTTP proxy. A {@code null} value will clear the global HTTP proxy.
+ * This sets an HTTP proxy that applies to all networks and overrides any network-specific
+ * proxy. If set, HTTP libraries that are proxy-aware will use this global proxy when
+ * accessing any network, regardless of what the settings for that network are.
+ *
+ * Note that HTTP proxies are by nature typically network-dependent, and setting a global
+ * proxy is likely to break networking on multiple networks. This method is only meant
+ * for device policy clients looking to do general internal filtering or similar use cases.
+ *
+ * {@see #getGlobalProxy}
+ * {@see LinkProperties#getHttpProxy}
+ *
+ * @param p A {@link ProxyInfo} object defining the new global HTTP proxy. Calling this
+ * method with a {@code null} value will clear the global HTTP proxy.
* @hide
*/
+ // Used by Device Policy Manager to set the global proxy.
@SystemApi(client = MODULE_LIBRARIES)
@RequiresPermission(android.Manifest.permission.NETWORK_STACK)
- public void setGlobalProxy(@Nullable ProxyInfo p) {
+ public void setGlobalProxy(@Nullable final ProxyInfo p) {
try {
mService.setGlobalProxy(p);
} catch (RemoteException e) {
diff --git a/packages/Connectivity/framework/src/android/net/DnsResolver.java b/packages/Connectivity/framework/src/android/net/DnsResolver.java
index 3f7660f..dac88ad 100644
--- a/packages/Connectivity/framework/src/android/net/DnsResolver.java
+++ b/packages/Connectivity/framework/src/android/net/DnsResolver.java
@@ -500,7 +500,7 @@
try {
resp = resNetworkResult(fd); // Closes fd, marks it invalid.
} catch (ErrnoException e) {
- Log.e(TAG, "resNetworkResult:" + e.toString());
+ Log.w(TAG, "resNetworkResult:" + e.toString());
exception = e;
}
}
diff --git a/packages/Connectivity/framework/src/android/net/VpnTransportInfo.java b/packages/Connectivity/framework/src/android/net/VpnTransportInfo.java
index cd8f4c0..ba83a44 100644
--- a/packages/Connectivity/framework/src/android/net/VpnTransportInfo.java
+++ b/packages/Connectivity/framework/src/android/net/VpnTransportInfo.java
@@ -17,11 +17,14 @@
package android.net;
import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
+import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
+import android.text.TextUtils;
import java.util.Objects;
@@ -38,8 +41,26 @@
/** Type of this VPN. */
public final int type;
- public VpnTransportInfo(int type) {
+ @Nullable
+ public final String sessionId;
+
+ @Override
+ public long getApplicableRedactions() {
+ return REDACT_FOR_NETWORK_SETTINGS;
+ }
+
+ /**
+ * Create a copy of a {@link VpnTransportInfo} with the sessionId redacted if necessary.
+ */
+ @NonNull
+ public VpnTransportInfo makeCopy(long redactions) {
+ return new VpnTransportInfo(type,
+ ((redactions & REDACT_FOR_NETWORK_SETTINGS) != 0) ? null : sessionId);
+ }
+
+ public VpnTransportInfo(int type, @Nullable String sessionId) {
this.type = type;
+ this.sessionId = sessionId;
}
@Override
@@ -47,17 +68,17 @@
if (!(o instanceof VpnTransportInfo)) return false;
VpnTransportInfo that = (VpnTransportInfo) o;
- return this.type == that.type;
+ return (this.type == that.type) && TextUtils.equals(this.sessionId, that.sessionId);
}
@Override
public int hashCode() {
- return Objects.hash(type);
+ return Objects.hash(type, sessionId);
}
@Override
public String toString() {
- return String.format("VpnTransportInfo{type=%d}", type);
+ return String.format("VpnTransportInfo{type=%d, sessionId=%s}", type, sessionId);
}
@Override
@@ -68,12 +89,13 @@
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeInt(type);
+ dest.writeString(sessionId);
}
public static final @NonNull Creator<VpnTransportInfo> CREATOR =
new Creator<VpnTransportInfo>() {
public VpnTransportInfo createFromParcel(Parcel in) {
- return new VpnTransportInfo(in.readInt());
+ return new VpnTransportInfo(in.readInt(), in.readString());
}
public VpnTransportInfo[] newArray(int size) {
return new VpnTransportInfo[size];
diff --git a/packages/WAPPushManager/AndroidManifest.xml b/packages/WAPPushManager/AndroidManifest.xml
index a75fb2d..15f01e6 100644
--- a/packages/WAPPushManager/AndroidManifest.xml
+++ b/packages/WAPPushManager/AndroidManifest.xml
@@ -27,7 +27,8 @@
<original-package android:name="com.android.smspush" />
<application
- android:allowClearUserData="false">
+ android:allowClearUserData="false"
+ android:directBootAware="true">
<service android:name=".WapPushManager"
android:permission="com.android.smspush.WAPPUSH_MANAGER_BIND"
android:exported="true">
diff --git a/packages/WAPPushManager/src/com/android/smspush/WapPushManager.java b/packages/WAPPushManager/src/com/android/smspush/WapPushManager.java
index dc2707b..951e64f 100755
--- a/packages/WAPPushManager/src/com/android/smspush/WapPushManager.java
+++ b/packages/WAPPushManager/src/com/android/smspush/WapPushManager.java
@@ -26,17 +26,21 @@
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.database.Cursor;
-import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
import android.os.Build;
import android.os.IBinder;
import android.os.PowerManager;
import android.os.RemoteException;
+import android.os.UserManager;
import android.util.Log;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.IWapPushManager;
import com.android.internal.telephony.WapPushManagerParams;
+import java.io.File;
+
/**
* The WapPushManager service is implemented to process incoming
* WAP Push messages and to maintain the Receiver Application/Application
@@ -67,8 +71,13 @@
/**
* Inner class that deals with application ID table
*/
- private class WapPushManDBHelper extends SQLiteOpenHelper {
- WapPushManDBHelper(Context context) {
+ @VisibleForTesting
+ public static class WapPushManDBHelper extends SQLiteOpenHelper {
+ /**
+ * Constructor
+ */
+ @VisibleForTesting
+ public WapPushManDBHelper(Context context) {
super(context, DATABASE_NAME, null, WAP_PUSH_MANAGER_VERSION);
if (LOCAL_LOGV) Log.v(LOG_TAG, "helper instance created.");
}
@@ -269,10 +278,6 @@
int app_type, boolean need_signature, boolean further_processing) {
WapPushManDBHelper dbh = getDatabase(mContext);
SQLiteDatabase db = dbh.getWritableDatabase();
- WapPushManDBHelper.queryData lastapp = dbh.queryLastApp(db, x_app_id, content_type);
- boolean ret = false;
- boolean insert = false;
- int sq = 0;
if (!appTypeCheck(app_type)) {
Log.w(LOG_TAG, "invalid app_type " + app_type + ". app_type must be "
@@ -280,34 +285,8 @@
+ WapPushManagerParams.APP_TYPE_SERVICE);
return false;
}
-
- if (lastapp == null) {
- insert = true;
- sq = 0;
- } else if (!lastapp.packageName.equals(package_name) ||
- !lastapp.className.equals(class_name)) {
- insert = true;
- sq = lastapp.installOrder + 1;
- }
-
- if (insert) {
- ContentValues values = new ContentValues();
-
- values.put("x_wap_application", x_app_id);
- values.put("content_type", content_type);
- values.put("package_name", package_name);
- values.put("class_name", class_name);
- values.put("app_type", app_type);
- values.put("need_signature", need_signature ? 1 : 0);
- values.put("further_processing", further_processing ? 1 : 0);
- values.put("install_order", sq);
- db.insert(APPID_TABLE_NAME, null, values);
- if (LOCAL_LOGV) Log.v(LOG_TAG, "add:" + x_app_id + ":" + content_type
- + " " + package_name + "." + class_name
- + ", newsq:" + sq);
- ret = true;
- }
-
+ boolean ret = insertPackage(dbh, db, x_app_id, content_type, package_name, class_name,
+ app_type, need_signature, further_processing);
db.close();
return ret;
@@ -404,11 +383,91 @@
protected WapPushManDBHelper getDatabase(Context context) {
if (mDbHelper == null) {
if (LOCAL_LOGV) Log.v(LOG_TAG, "create new db inst.");
- mDbHelper = new WapPushManDBHelper(context);
+ mDbHelper = new WapPushManDBHelper(context.createDeviceProtectedStorageContext());
}
+ // Migrate existing legacy database into the device encrypted storage.
+ migrateWapPushManDBIfNeeded(context);
return mDbHelper;
}
+ /**
+ * Inserts a package information into a database
+ */
+ @VisibleForTesting
+ public boolean insertPackage(WapPushManDBHelper dbh, SQLiteDatabase db, String appId,
+ String contentType, String packageName, String className, int appType,
+ boolean needSignature, boolean furtherProcessing) {
+
+ WapPushManDBHelper.queryData lastapp = dbh.queryLastApp(db, appId, contentType);
+ boolean insert = false;
+ int sq = 0;
+
+ if (lastapp == null) {
+ insert = true;
+ sq = 0;
+ } else if (!lastapp.packageName.equals(packageName)
+ || !lastapp.className.equals(className)) {
+ insert = true;
+ sq = lastapp.installOrder + 1;
+ }
+
+ if (insert) {
+ ContentValues values = new ContentValues();
+
+ values.put("x_wap_application", appId);
+ values.put("content_type", contentType);
+ values.put("package_name", packageName);
+ values.put("class_name", className);
+ values.put("app_type", appType);
+ values.put("need_signature", needSignature ? 1 : 0);
+ values.put("further_processing", furtherProcessing ? 1 : 0);
+ values.put("install_order", sq);
+ db.insert(APPID_TABLE_NAME, null, values);
+ if (LOCAL_LOGV) {
+ Log.v(LOG_TAG, "add:" + appId + ":" + contentType + " " + packageName
+ + "." + className + ", newsq:" + sq);
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Migrates a legacy database into the device encrypted storage
+ */
+ private void migrateWapPushManDBIfNeeded(Context context) {
+ UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
+ File file = context.getDatabasePath(DATABASE_NAME);
+ if (!userManager.isUserUnlocked() || !file.exists()) {
+ // Check if the device is unlocked because a legacy database can't access during
+ // DirectBoot.
+ return;
+ }
+
+ // Migration steps below:
+ // 1. Merge the package info to legacy database if there is any package info which is
+ // registered during DirectBoot.
+ // 2. Move the data base to the device encryped storage.
+ WapPushManDBHelper legacyDbHelper = new WapPushManDBHelper(context);
+ SQLiteDatabase legacyDb = legacyDbHelper.getWritableDatabase();
+ SQLiteDatabase db = mDbHelper.getWritableDatabase();
+ Cursor cur = db.query(APPID_TABLE_NAME, null, null, null, null, null, null);
+ while (cur.moveToNext()) {
+ insertPackage(legacyDbHelper, legacyDb,
+ cur.getString(cur.getColumnIndex("x_wap_application")),
+ cur.getString(cur.getColumnIndex("content_type")),
+ cur.getString(cur.getColumnIndex("package_name")),
+ cur.getString(cur.getColumnIndex("class_name")),
+ cur.getInt(cur.getColumnIndex("app_type")),
+ cur.getInt(cur.getColumnIndex("need_signature")) == 1,
+ cur.getInt(cur.getColumnIndex("further_processing")) == 1);
+ }
+ cur.close();
+ legacyDb.close();
+ db.close();
+ context.createDeviceProtectedStorageContext().moveDatabaseFrom(context, DATABASE_NAME);
+ Log.i(LOG_TAG, "Migrated the legacy database.");
+ }
/**
* This method is used for testing
diff --git a/packages/WAPPushManager/tests/src/com/android/smspush/unitTests/WapPushTest.java b/packages/WAPPushManager/tests/src/com/android/smspush/unitTests/WapPushTest.java
index f7afc57..b9dac4e 100644
--- a/packages/WAPPushManager/tests/src/com/android/smspush/unitTests/WapPushTest.java
+++ b/packages/WAPPushManager/tests/src/com/android/smspush/unitTests/WapPushTest.java
@@ -21,6 +21,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.database.sqlite.SQLiteDatabase;
import android.os.IBinder;
import android.os.RemoteException;
import android.provider.Telephony.Sms.Intents;
@@ -33,7 +34,9 @@
import com.android.internal.telephony.uicc.IccUtils;
import com.android.internal.util.HexDump;
import com.android.smspush.WapPushManager;
+import com.android.smspush.WapPushManager.WapPushManDBHelper;
+import java.io.File;
import java.util.Random;
/**
@@ -467,8 +470,9 @@
try {
super.setUp();
// get verifier
- getContext().bindService(new Intent(IDataVerify.class.getName()),
- mConn, Context.BIND_AUTO_CREATE);
+ Intent intent = new Intent(IDataVerify.class.getName());
+ intent.setPackage("com.android.smspush.unitTests");
+ getContext().bindService(intent, mConn, Context.BIND_AUTO_CREATE);
} catch (Exception e) {
Log.w(LOG_TAG, "super exception");
}
@@ -552,15 +556,15 @@
}
/**
- * Add sqlite injection test
+ * Sqlite injection test
*/
- public void testAddPackage0() {
+ public void testSqliteInjection() {
String inject = "' union select 0,'com.android.settings','com.android.settings.Settings',0,0,0--";
- // insert new data
+ // update data
IWapPushManager iwapman = getInterface();
try {
- assertFalse(iwapman.addPackage(
+ assertFalse(iwapman.updatePackage(
inject,
Integer.toString(mContentTypeValue),
mPackageName, mClassName,
@@ -2528,4 +2532,45 @@
mMessageBody = originalMessageBody;
}
+ /**
+ * DataBase migration test.
+ */
+ public void testDataBaseMigration() {
+ IWapPushManager iwapman = getInterface();
+ WapPushManager wpman = getService();
+ Context context = getContext();
+
+ addPackageToLegacyDB(mAppIdValue, mContentTypeValue, mPackageName, mClassName,
+ WapPushManagerParams.APP_TYPE_SERVICE, true, true);
+ addPackageToLegacyDB(mAppIdValue + 10, mContentTypeValue, mPackageName, mClassName,
+ WapPushManagerParams.APP_TYPE_SERVICE, true, true);
+
+ File oldDbFile = context.getDatabasePath("wappush.db");
+ assertTrue(oldDbFile.exists());
+ assertTrue(wpman.verifyData(Integer.toString(mAppIdValue),
+ Integer.toString(mContentTypeValue),
+ mPackageName, mClassName,
+ WapPushManagerParams.APP_TYPE_SERVICE, true, true));
+ assertFalse(oldDbFile.exists());
+
+ // Clean up DB
+ try {
+ iwapman.deletePackage(Integer.toString(mAppIdValue),
+ Integer.toString(mContentTypeValue), mPackageName, mClassName);
+ iwapman.deletePackage(Integer.toString(mAppIdValue + 10),
+ Integer.toString(mContentTypeValue), mPackageName, mClassName);
+ } catch (RemoteException e) {
+ assertTrue(false);
+ }
+ }
+
+ private void addPackageToLegacyDB(int appId, int contextType, String packagename,
+ String classnName, int appType, boolean signature, boolean furtherProcessing) {
+ WapPushManager wpman = getService();
+ WapPushManDBHelper dbh = new WapPushManDBHelper(getContext());
+ SQLiteDatabase db = dbh.getWritableDatabase();
+
+ wpman.insertPackage(dbh, db, Integer.toString(appId), Integer.toString(contextType),
+ packagename, classnName, appType, signature, furtherProcessing);
+ }
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index c997e2a..629006a 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1281,14 +1281,22 @@
mPermissionMonitor = new PermissionMonitor(mContext, mNetd);
+ mUserAllContext = mContext.createContextAsUser(UserHandle.ALL, 0 /* flags */);
// Listen for user add/removes to inform PermissionMonitor.
// Should run on mHandler to avoid any races.
- IntentFilter intentFilter = new IntentFilter();
- intentFilter.addAction(Intent.ACTION_USER_ADDED);
- intentFilter.addAction(Intent.ACTION_USER_REMOVED);
+ final IntentFilter userIntentFilter = new IntentFilter();
+ userIntentFilter.addAction(Intent.ACTION_USER_ADDED);
+ userIntentFilter.addAction(Intent.ACTION_USER_REMOVED);
+ mUserAllContext.registerReceiver(mUserIntentReceiver, userIntentFilter,
+ null /* broadcastPermission */, mHandler);
- mUserAllContext = mContext.createContextAsUser(UserHandle.ALL, 0 /* flags */);
- mUserAllContext.registerReceiver(mIntentReceiver, intentFilter,
+ // Listen to package add/removes for netd
+ final IntentFilter packageIntentFilter = new IntentFilter();
+ packageIntentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
+ packageIntentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ packageIntentFilter.addAction(Intent.ACTION_PACKAGE_REPLACED);
+ packageIntentFilter.addDataScheme("package");
+ mUserAllContext.registerReceiver(mPackageIntentReceiver, packageIntentFilter,
null /* broadcastPermission */, mHandler);
mNetworkActivityTracker = new LegacyNetworkActivityTracker(mContext, mHandler, mNetd);
@@ -4958,7 +4966,7 @@
}
@Override
- public void setGlobalProxy(final ProxyInfo proxyProperties) {
+ public void setGlobalProxy(@Nullable final ProxyInfo proxyProperties) {
PermissionUtils.enforceNetworkStackPermission(mContext);
mProxyTracker.setGlobalProxy(proxyProperties);
}
@@ -5303,14 +5311,14 @@
}
}
- private void onUserAdded(UserHandle user) {
+ private void onUserAdded(@NonNull final UserHandle user) {
mPermissionMonitor.onUserAdded(user);
if (mOemNetworkPreferences.getNetworkPreferences().size() > 0) {
handleSetOemNetworkPreference(mOemNetworkPreferences, null);
}
}
- private void onUserRemoved(UserHandle user) {
+ private void onUserRemoved(@NonNull final UserHandle user) {
mPermissionMonitor.onUserRemoved(user);
// If there was a network preference for this user, remove it.
handleSetProfileNetworkPreference(new ProfileNetworkPreferences.Preference(user, null),
@@ -5320,7 +5328,18 @@
}
}
- private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
+ private void onPackageChanged(@NonNull final String packageName) {
+ // This is necessary in case a package is added or removed, but also when it's replaced to
+ // run as a new UID by its manifest rules. Also, if a separate package shares the same UID
+ // as one in the preferences, then it should follow the same routing as that other package,
+ // which means updating the rules is never to be needed in this case (whether it joins or
+ // leaves a UID with a preference).
+ if (isMappedInOemNetworkPreference(packageName)) {
+ handleSetOemNetworkPreference(mOemNetworkPreferences, null);
+ }
+ }
+
+ private final BroadcastReceiver mUserIntentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
ensureRunningOnConnectivityServiceThread();
@@ -5343,6 +5362,22 @@
}
};
+ private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ ensureRunningOnConnectivityServiceThread();
+ switch (intent.getAction()) {
+ case Intent.ACTION_PACKAGE_ADDED:
+ case Intent.ACTION_PACKAGE_REMOVED:
+ case Intent.ACTION_PACKAGE_REPLACED:
+ onPackageChanged(intent.getData().getSchemeSpecificPart());
+ break;
+ default:
+ Log.wtf(TAG, "received unexpected intent: " + intent.getAction());
+ }
+ }
+ };
+
private final HashMap<Messenger, NetworkProviderInfo> mNetworkProviderInfos = new HashMap<>();
private final HashMap<NetworkRequest, NetworkRequestInfo> mNetworkRequests = new HashMap<>();
@@ -6166,6 +6201,15 @@
@NonNull
private ProfileNetworkPreferences mProfileNetworkPreferences = new ProfileNetworkPreferences();
+ /**
+ * Determine whether a given package has a mapping in the current OemNetworkPreferences.
+ * @param packageName the package name to check existence of a mapping for.
+ * @return true if a mapping exists, false otherwise
+ */
+ private boolean isMappedInOemNetworkPreference(@NonNull final String packageName) {
+ return mOemNetworkPreferences.getNetworkPreferences().containsKey(packageName);
+ }
+
// The always-on request for an Internet-capable network that apps without a specific default
// fall back to.
@VisibleForTesting
@@ -6186,7 +6230,7 @@
* @return the NetworkRequestInfo tracking the given uid.
*/
@NonNull
- private NetworkRequestInfo getDefaultRequestTrackingUid(@NonNull final int uid) {
+ private NetworkRequestInfo getDefaultRequestTrackingUid(final int uid) {
for (final NetworkRequestInfo nri : mDefaultNetworkRequests) {
if (nri == mDefaultRequest) {
continue;
@@ -6633,7 +6677,7 @@
mDeps.reportNetworkInterfaceForTransports(mContext, iface,
caps.getTransportTypes());
} catch (Exception e) {
- loge("Exception adding interface: " + e);
+ logw("Exception adding interface: " + e);
}
}
}
@@ -9593,7 +9637,6 @@
new OemNetworkRequestFactory().createNrisFromOemNetworkPreferences(preference);
replaceDefaultNetworkRequestsForPreference(nris);
mOemNetworkPreferences = preference;
- // TODO http://b/176496396 persist data to shared preferences.
if (null != listener) {
try {
@@ -9750,7 +9793,6 @@
// packages are sent on a network preference as the system will watch for
// package installations associated with this network preference and update
// accordingly. This is done so as to minimize race conditions on app install.
- // TODO b/177092163 add app install watching.
continue;
}
}
diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java
index 4fd9373..f7ae58c 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -16,6 +16,8 @@
package com.android.server;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE;
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_INACTIVE;
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED;
@@ -35,7 +37,9 @@
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.LinkProperties;
+import android.net.Network;
import android.net.NetworkCapabilities;
+import android.net.NetworkRequest;
import android.net.vcn.IVcnManagementService;
import android.net.vcn.IVcnStatusCallback;
import android.net.vcn.IVcnUnderlyingNetworkPolicyListener;
@@ -161,6 +165,9 @@
@NonNull private final VcnContext mVcnContext;
@NonNull private final BroadcastReceiver mPkgChangeReceiver;
+ @NonNull
+ private final TrackingNetworkCallback mTrackingNetworkCallback = new TrackingNetworkCallback();
+
/** Can only be assigned when {@link #systemReady()} is called, since it uses AppOpsManager. */
@Nullable private LocationPermissionChecker mLocationPermissionChecker;
@@ -357,6 +364,10 @@
public void systemReady() {
mContext.getSystemService(ConnectivityManager.class)
.registerNetworkProvider(mNetworkProvider);
+ mContext.getSystemService(ConnectivityManager.class)
+ .registerNetworkCallback(
+ new NetworkRequest.Builder().clearCapabilities().build(),
+ mTrackingNetworkCallback);
mTelephonySubscriptionTracker.register();
mLocationPermissionChecker = mDeps.newLocationPermissionChecker(mVcnContext.getContext());
}
@@ -531,16 +542,7 @@
if (mVcns.containsKey(subscriptionGroup)) {
final Vcn vcn = mVcns.get(subscriptionGroup);
- final int status = vcn.getStatus();
vcn.updateConfig(config);
-
- // TODO(b/183174340): Remove this once opportunistic-safe-mode is supported
- // Only notify VcnStatusCallbacks if this VCN was previously in Safe Mode
- if (status == VCN_STATUS_CODE_SAFE_MODE) {
- // TODO(b/181789060): invoke asynchronously after Vcn notifies through VcnCallback
- notifyAllPermissionedStatusCallbacksLocked(
- subscriptionGroup, VCN_STATUS_CODE_ACTIVE);
- }
} else {
startVcnLocked(subscriptionGroup, config);
}
@@ -792,8 +794,9 @@
NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
}
+ final NetworkCapabilities result = ncBuilder.build();
return new VcnUnderlyingNetworkPolicy(
- false /* isTearDownRequested */, ncBuilder.build());
+ mTrackingNetworkCallback.requiresRestartForCarrierWifi(result), result);
});
}
@@ -929,8 +932,8 @@
// TODO(b/180452282): Make name more generic and implement directly with VcnManagementService
/** Callback for Vcn signals sent up to VcnManagementService. */
public interface VcnCallback {
- /** Called by a Vcn to signal that it has entered safe mode. */
- void onEnteredSafeMode();
+ /** Called by a Vcn to signal that its safe mode status has changed. */
+ void onSafeModeStatusChanged(boolean isInSafeMode);
/** Called by a Vcn to signal that an error occurred. */
void onGatewayConnectionError(
@@ -940,6 +943,49 @@
@Nullable String exceptionMessage);
}
+ /**
+ * TrackingNetworkCallback tracks all active networks
+ *
+ * <p>This is used to ensure that no underlying networks have immutable capabilities changed
+ * without requiring a Network restart.
+ */
+ private class TrackingNetworkCallback extends ConnectivityManager.NetworkCallback {
+ private final Map<Network, NetworkCapabilities> mCaps = new ArrayMap<>();
+
+ @Override
+ public void onCapabilitiesChanged(Network network, NetworkCapabilities caps) {
+ synchronized (mCaps) {
+ mCaps.put(network, caps);
+ }
+ }
+
+ @Override
+ public void onLost(Network network) {
+ synchronized (mCaps) {
+ mCaps.remove(network);
+ }
+ }
+
+ private boolean requiresRestartForCarrierWifi(NetworkCapabilities caps) {
+ if (!caps.hasTransport(TRANSPORT_WIFI) || caps.getSubIds() == null) {
+ return false;
+ }
+
+ synchronized (mCaps) {
+ for (NetworkCapabilities existing : mCaps.values()) {
+ if (existing.hasTransport(TRANSPORT_WIFI)
+ && caps.getSubIds().equals(existing.getSubIds())) {
+ // Restart if any immutable capabilities have changed
+ return existing.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)
+ != caps.hasCapability(NET_CAPABILITY_NOT_RESTRICTED);
+ }
+ }
+ }
+
+ return false;
+ }
+ }
+
/** VcnCallbackImpl for Vcn signals sent up to VcnManagementService. */
private class VcnCallbackImpl implements VcnCallback {
@NonNull private final ParcelUuid mSubGroup;
@@ -949,15 +995,18 @@
}
@Override
- public void onEnteredSafeMode() {
+ public void onSafeModeStatusChanged(boolean isInSafeMode) {
synchronized (mLock) {
// Ignore if this subscription group doesn't exist anymore
if (!mVcns.containsKey(mSubGroup)) {
return;
}
+ final int status =
+ isInSafeMode ? VCN_STATUS_CODE_SAFE_MODE : VCN_STATUS_CODE_ACTIVE;
+
notifyAllPolicyListenersLocked();
- notifyAllPermissionedStatusCallbacksLocked(mSubGroup, VCN_STATUS_CODE_SAFE_MODE);
+ notifyAllPermissionedStatusCallbacksLocked(mSubGroup, status);
}
}
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 57c25f6..0a76bdc 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -462,7 +462,7 @@
.addTransportType(NetworkCapabilities.TRANSPORT_VPN)
.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)
- .setTransportInfo(new VpnTransportInfo(VpnManager.TYPE_VPN_NONE))
+ .setTransportInfo(new VpnTransportInfo(VpnManager.TYPE_VPN_NONE, null))
.build();
loadAlwaysOnPackage();
@@ -526,7 +526,7 @@
private void resetNetworkCapabilities() {
mNetworkCapabilities = new NetworkCapabilities.Builder(mNetworkCapabilities)
.setUids(null)
- .setTransportInfo(new VpnTransportInfo(VpnManager.TYPE_VPN_NONE))
+ .setTransportInfo(new VpnTransportInfo(VpnManager.TYPE_VPN_NONE, null))
.build();
}
@@ -1256,7 +1256,7 @@
capsBuilder.setUids(createUserAndRestrictedProfilesRanges(mUserId,
mConfig.allowedApplications, mConfig.disallowedApplications));
- capsBuilder.setTransportInfo(new VpnTransportInfo(getActiveVpnType()));
+ capsBuilder.setTransportInfo(new VpnTransportInfo(getActiveVpnType(), mConfig.session));
// Only apps targeting Q and above can explicitly declare themselves as metered.
// These VPNs are assumed metered unless they state otherwise.
diff --git a/services/core/java/com/android/server/net/IpConfigStore.java b/services/core/java/com/android/server/net/IpConfigStore.java
index cc3a002..df1eb6d 100644
--- a/services/core/java/com/android/server/net/IpConfigStore.java
+++ b/services/core/java/com/android/server/net/IpConfigStore.java
@@ -22,7 +22,6 @@
import android.net.IpConfiguration.ProxySettings;
import android.net.LinkAddress;
import android.net.ProxyInfo;
-import android.net.RouteInfo;
import android.net.StaticIpConfiguration;
import android.net.Uri;
import android.util.ArrayMap;
@@ -42,6 +41,8 @@
import java.io.InputStream;
import java.net.Inet4Address;
import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.List;
public class IpConfigStore {
private static final String TAG = "IpConfigStore";
@@ -83,25 +84,25 @@
boolean written = false;
try {
- switch (config.ipAssignment) {
+ switch (config.getIpAssignment()) {
case STATIC:
out.writeUTF(IP_ASSIGNMENT_KEY);
- out.writeUTF(config.ipAssignment.toString());
- StaticIpConfiguration staticIpConfiguration = config.staticIpConfiguration;
+ out.writeUTF(config.getIpAssignment().toString());
+ StaticIpConfiguration staticIpConfiguration = config.getStaticIpConfiguration();
if (staticIpConfiguration != null) {
- if (staticIpConfiguration.ipAddress != null) {
- LinkAddress ipAddress = staticIpConfiguration.ipAddress;
+ if (staticIpConfiguration.getIpAddress() != null) {
+ LinkAddress ipAddress = staticIpConfiguration.getIpAddress();
out.writeUTF(LINK_ADDRESS_KEY);
out.writeUTF(ipAddress.getAddress().getHostAddress());
out.writeInt(ipAddress.getPrefixLength());
}
- if (staticIpConfiguration.gateway != null) {
+ if (staticIpConfiguration.getGateway() != null) {
out.writeUTF(GATEWAY_KEY);
out.writeInt(0); // Default route.
out.writeInt(1); // Have a gateway.
- out.writeUTF(staticIpConfiguration.gateway.getHostAddress());
+ out.writeUTF(staticIpConfiguration.getGateway().getHostAddress());
}
- for (InetAddress inetAddr : staticIpConfiguration.dnsServers) {
+ for (InetAddress inetAddr : staticIpConfiguration.getDnsServers()) {
out.writeUTF(DNS_KEY);
out.writeUTF(inetAddr.getHostAddress());
}
@@ -110,7 +111,7 @@
break;
case DHCP:
out.writeUTF(IP_ASSIGNMENT_KEY);
- out.writeUTF(config.ipAssignment.toString());
+ out.writeUTF(config.getIpAssignment().toString());
written = true;
break;
case UNASSIGNED:
@@ -121,13 +122,13 @@
break;
}
- switch (config.proxySettings) {
+ switch (config.getProxySettings()) {
case STATIC:
- ProxyInfo proxyProperties = config.httpProxy;
+ ProxyInfo proxyProperties = config.getHttpProxy();
String exclusionList = ProxyUtils.exclusionListAsString(
proxyProperties.getExclusionList());
out.writeUTF(PROXY_SETTINGS_KEY);
- out.writeUTF(config.proxySettings.toString());
+ out.writeUTF(config.getProxySettings().toString());
out.writeUTF(PROXY_HOST_KEY);
out.writeUTF(proxyProperties.getHost());
out.writeUTF(PROXY_PORT_KEY);
@@ -139,16 +140,16 @@
written = true;
break;
case PAC:
- ProxyInfo proxyPacProperties = config.httpProxy;
+ ProxyInfo proxyPacProperties = config.getHttpProxy();
out.writeUTF(PROXY_SETTINGS_KEY);
- out.writeUTF(config.proxySettings.toString());
+ out.writeUTF(config.getProxySettings().toString());
out.writeUTF(PROXY_PAC_FILE);
out.writeUTF(proxyPacProperties.getPacFileUrl().toString());
written = true;
break;
case NONE:
out.writeUTF(PROXY_SETTINGS_KEY);
- out.writeUTF(config.proxySettings.toString());
+ out.writeUTF(config.getProxySettings().toString());
written = true;
break;
case UNASSIGNED:
@@ -267,11 +268,14 @@
IpAssignment ipAssignment = IpAssignment.DHCP;
ProxySettings proxySettings = ProxySettings.NONE;
StaticIpConfiguration staticIpConfiguration = new StaticIpConfiguration();
+ LinkAddress linkAddress = null;
+ InetAddress gatewayAddress = null;
String proxyHost = null;
String pacFileUrl = null;
int proxyPort = -1;
String exclusionList = null;
String key;
+ final List<InetAddress> dnsServers = new ArrayList<>();
do {
key = in.readUTF();
@@ -286,15 +290,15 @@
} else if (key.equals(IP_ASSIGNMENT_KEY)) {
ipAssignment = IpAssignment.valueOf(in.readUTF());
} else if (key.equals(LINK_ADDRESS_KEY)) {
- LinkAddress linkAddr =
+ LinkAddress parsedLinkAddress =
new LinkAddress(
InetAddresses.parseNumericAddress(in.readUTF()),
in.readInt());
- if (linkAddr.getAddress() instanceof Inet4Address &&
- staticIpConfiguration.ipAddress == null) {
- staticIpConfiguration.ipAddress = linkAddr;
+ if (parsedLinkAddress.getAddress() instanceof Inet4Address
+ && linkAddress == null) {
+ linkAddress = parsedLinkAddress;
} else {
- loge("Non-IPv4 or duplicate address: " + linkAddr);
+ loge("Non-IPv4 or duplicate address: " + parsedLinkAddress);
}
} else if (key.equals(GATEWAY_KEY)) {
LinkAddress dest = null;
@@ -302,8 +306,8 @@
if (version == 1) {
// only supported default gateways - leave the dest/prefix empty
gateway = InetAddresses.parseNumericAddress(in.readUTF());
- if (staticIpConfiguration.gateway == null) {
- staticIpConfiguration.gateway = gateway;
+ if (gatewayAddress == null) {
+ gatewayAddress = gateway;
} else {
loge("Duplicate gateway: " + gateway.getHostAddress());
}
@@ -317,17 +321,18 @@
if (in.readInt() == 1) {
gateway = InetAddresses.parseNumericAddress(in.readUTF());
}
- RouteInfo route = new RouteInfo(dest, gateway);
- if (route.isIPv4Default() &&
- staticIpConfiguration.gateway == null) {
- staticIpConfiguration.gateway = gateway;
+ // If the destination is a default IPv4 route, use the gateway
+ // address unless already set.
+ if (dest.getAddress() instanceof Inet4Address
+ && dest.getPrefixLength() == 0 && gatewayAddress == null) {
+ gatewayAddress = gateway;
} else {
- loge("Non-IPv4 default or duplicate route: " + route);
+ loge("Non-IPv4 default or duplicate route: "
+ + dest.getAddress());
}
}
} else if (key.equals(DNS_KEY)) {
- staticIpConfiguration.dnsServers.add(
- InetAddresses.parseNumericAddress(in.readUTF()));
+ dnsServers.add(InetAddresses.parseNumericAddress(in.readUTF()));
} else if (key.equals(PROXY_SETTINGS_KEY)) {
proxySettings = ProxySettings.valueOf(in.readUTF());
} else if (key.equals(PROXY_HOST_KEY)) {
@@ -348,25 +353,31 @@
}
} while (true);
+ staticIpConfiguration = new StaticIpConfiguration.Builder()
+ .setIpAddress(linkAddress)
+ .setGateway(gatewayAddress)
+ .setDnsServers(dnsServers)
+ .build();
+
if (uniqueToken != null) {
IpConfiguration config = new IpConfiguration();
networks.put(uniqueToken, config);
switch (ipAssignment) {
case STATIC:
- config.staticIpConfiguration = staticIpConfiguration;
- config.ipAssignment = ipAssignment;
+ config.setStaticIpConfiguration(staticIpConfiguration);
+ config.setIpAssignment(ipAssignment);
break;
case DHCP:
- config.ipAssignment = ipAssignment;
+ config.setIpAssignment(ipAssignment);
break;
case UNASSIGNED:
loge("BUG: Found UNASSIGNED IP on file, use DHCP");
- config.ipAssignment = IpAssignment.DHCP;
+ config.setIpAssignment(IpAssignment.DHCP);
break;
default:
loge("Ignore invalid ip assignment while reading.");
- config.ipAssignment = IpAssignment.UNASSIGNED;
+ config.setIpAssignment(IpAssignment.UNASSIGNED);
break;
}
@@ -374,25 +385,25 @@
case STATIC:
ProxyInfo proxyInfo = ProxyInfo.buildDirectProxy(proxyHost, proxyPort,
ProxyUtils.exclusionStringAsList(exclusionList));
- config.proxySettings = proxySettings;
- config.httpProxy = proxyInfo;
+ config.setProxySettings(proxySettings);
+ config.setHttpProxy(proxyInfo);
break;
case PAC:
ProxyInfo proxyPacProperties =
ProxyInfo.buildPacProxy(Uri.parse(pacFileUrl));
- config.proxySettings = proxySettings;
- config.httpProxy = proxyPacProperties;
+ config.setProxySettings(proxySettings);
+ config.setHttpProxy(proxyPacProperties);
break;
case NONE:
- config.proxySettings = proxySettings;
+ config.setProxySettings(proxySettings);
break;
case UNASSIGNED:
loge("BUG: Found UNASSIGNED proxy on file, use NONE");
- config.proxySettings = ProxySettings.NONE;
+ config.setProxySettings(ProxySettings.NONE);
break;
default:
loge("Ignore invalid proxy settings while reading");
- config.proxySettings = ProxySettings.UNASSIGNED;
+ config.setProxySettings(ProxySettings.UNASSIGNED);
break;
}
} else {
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index c127858..290307b 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -5581,17 +5581,6 @@
}
@Override
- public boolean checkUidNetworkingBlocked(int uid, int uidRules,
- boolean isNetworkMetered, boolean isBackgroundRestricted) {
- mContext.enforceCallingOrSelfPermission(OBSERVE_NETWORK_POLICY, TAG);
- // Log of invoking this function is disabled because it will be called very frequently. And
- // metrics are unlikely needed on this method because the callers are external and this
- // method doesn't take any locks or perform expensive operations.
- return isUidNetworkingBlockedInternal(uid, uidRules, isNetworkMetered,
- isBackgroundRestricted, null);
- }
-
- @Override
public boolean isUidRestrictedOnMeteredNetworks(int uid) {
mContext.enforceCallingOrSelfPermission(OBSERVE_NETWORK_POLICY, TAG);
final int uidRules;
diff --git a/services/core/java/com/android/server/vcn/Vcn.java b/services/core/java/com/android/server/vcn/Vcn.java
index 546893588..ae806aa 100644
--- a/services/core/java/com/android/server/vcn/Vcn.java
+++ b/services/core/java/com/android/server/vcn/Vcn.java
@@ -17,6 +17,7 @@
package com.android.server.vcn;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE;
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_INACTIVE;
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE;
@@ -96,17 +97,21 @@
*/
private static final int MSG_EVENT_GATEWAY_CONNECTION_QUIT = MSG_EVENT_BASE + 3;
+ /**
+ * Triggers reevaluation of safe mode conditions.
+ *
+ * <p>Upon entering safe mode, the VCN will only provide gateway connections opportunistically,
+ * leaving the underlying networks marked as NOT_VCN_MANAGED.
+ *
+ * <p>Any VcnGatewayConnection in safe mode will result in the entire Vcn instance being put
+ * into safe mode. Upon receiving this message, the Vcn MUST query all VcnGatewayConnections to
+ * determine if any are in safe mode.
+ */
+ private static final int MSG_EVENT_SAFE_MODE_STATE_CHANGED = MSG_EVENT_BASE + 4;
+
/** Triggers an immediate teardown of the entire Vcn, including GatewayConnections. */
private static final int MSG_CMD_TEARDOWN = MSG_CMD_BASE;
- /**
- * Causes this VCN to immediately enter safe mode.
- *
- * <p>Upon entering safe mode, the VCN will unregister its RequestListener, tear down all of its
- * VcnGatewayConnections, and notify VcnManagementService that it is in safe mode.
- */
- private static final int MSG_CMD_ENTER_SAFE_MODE = MSG_CMD_BASE + 1;
-
@NonNull private final VcnContext mVcnContext;
@NonNull private final ParcelUuid mSubscriptionGroup;
@NonNull private final Dependencies mDeps;
@@ -233,6 +238,11 @@
@Override
public void handleMessage(@NonNull Message msg) {
+ if (mCurrentStatus != VCN_STATUS_CODE_ACTIVE
+ && mCurrentStatus != VCN_STATUS_CODE_SAFE_MODE) {
+ return;
+ }
+
switch (msg.what) {
case MSG_EVENT_CONFIG_UPDATED:
handleConfigUpdated((VcnConfig) msg.obj);
@@ -246,12 +256,12 @@
case MSG_EVENT_GATEWAY_CONNECTION_QUIT:
handleGatewayConnectionQuit((VcnGatewayConnectionConfig) msg.obj);
break;
+ case MSG_EVENT_SAFE_MODE_STATE_CHANGED:
+ handleSafeModeStatusChanged();
+ break;
case MSG_CMD_TEARDOWN:
handleTeardown();
break;
- case MSG_CMD_ENTER_SAFE_MODE:
- handleEnterSafeMode();
- break;
default:
Slog.wtf(getLogTag(), "Unknown msg.what: " + msg.what);
}
@@ -263,40 +273,28 @@
mConfig = config;
- // TODO(b/183174340): Remove this once opportunistic safe mode is supported.
- if (mCurrentStatus == VCN_STATUS_CODE_ACTIVE) {
- // 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();
+ // 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();
- // 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();
- }
+ // 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 (mCurrentStatus == VCN_STATUS_CODE_SAFE_MODE) {
- // 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);
- } else {
- // Ignored; VCN was not active; config updates ignored.
- return;
}
- mCurrentStatus = VCN_STATUS_CODE_ACTIVE;
+
+ // Trigger a re-evaluation of all NetworkRequests (to make sure any that can be
+ // satisfied start a new GatewayConnection)
+ mVcnContext.getVcnNetworkProvider().resendAllRequests(mRequestListener);
}
private void handleTeardown() {
@@ -309,21 +307,27 @@
mCurrentStatus = VCN_STATUS_CODE_INACTIVE;
}
- private void handleEnterSafeMode() {
- // TODO(b/183174340): Remove this once opportunistic-safe-mode is supported
- handleTeardown();
+ private void handleSafeModeStatusChanged() {
+ boolean hasSafeModeGatewayConnection = false;
- mCurrentStatus = VCN_STATUS_CODE_SAFE_MODE;
- mVcnCallback.onEnteredSafeMode();
+ // If any VcnGatewayConnection is in safe mode, mark the entire VCN as being in safe mode
+ for (VcnGatewayConnection gatewayConnection : mVcnGatewayConnections.values()) {
+ if (gatewayConnection.isInSafeMode()) {
+ hasSafeModeGatewayConnection = true;
+ break;
+ }
+ }
+
+ final int oldStatus = mCurrentStatus;
+ mCurrentStatus =
+ hasSafeModeGatewayConnection ? VCN_STATUS_CODE_SAFE_MODE : VCN_STATUS_CODE_ACTIVE;
+ if (oldStatus != mCurrentStatus) {
+ mVcnCallback.onSafeModeStatusChanged(hasSafeModeGatewayConnection);
+ }
}
private void handleNetworkRequested(
@NonNull NetworkRequest request, int score, int providerId) {
- if (mCurrentStatus != VCN_STATUS_CODE_ACTIVE) {
- Slog.v(getLogTag(), "Received NetworkRequest while inactive. Ignore for now");
- return;
- }
-
if (score > getNetworkScore()) {
if (VDBG) {
Slog.v(
@@ -376,25 +380,23 @@
mVcnGatewayConnections.remove(config);
// Trigger a re-evaluation of all NetworkRequests (to make sure any that can be satisfied
- // start a new GatewayConnection), but only if the Vcn is still alive
- if (mCurrentStatus == VCN_STATUS_CODE_ACTIVE) {
- mVcnContext.getVcnNetworkProvider().resendAllRequests(mRequestListener);
- }
+ // start a new GatewayConnection). VCN is always alive here, courtesy of the liveness check
+ // in handleMessage()
+ mVcnContext.getVcnNetworkProvider().resendAllRequests(mRequestListener);
}
private void handleSubscriptionsChanged(@NonNull TelephonySubscriptionSnapshot snapshot) {
mLastSnapshot = snapshot;
- if (mCurrentStatus == VCN_STATUS_CODE_ACTIVE) {
- for (VcnGatewayConnection gatewayConnection : mVcnGatewayConnections.values()) {
- gatewayConnection.updateSubscriptionSnapshot(mLastSnapshot);
- }
+ for (VcnGatewayConnection gatewayConnection : mVcnGatewayConnections.values()) {
+ gatewayConnection.updateSubscriptionSnapshot(mLastSnapshot);
}
}
private boolean isRequestSatisfiedByGatewayConnectionConfig(
@NonNull NetworkRequest request, @NonNull VcnGatewayConnectionConfig config) {
final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder();
+ builder.addTransportType(TRANSPORT_CELLULAR);
builder.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
for (int cap : config.getAllExposedCapabilities()) {
builder.addCapability(cap);
@@ -418,8 +420,8 @@
/** Callback used for passing status signals from a VcnGatewayConnection to its managing Vcn. */
@VisibleForTesting(visibility = Visibility.PACKAGE)
public interface VcnGatewayStatusCallback {
- /** Called by a VcnGatewayConnection to indicate that it has entered safe mode. */
- void onEnteredSafeMode();
+ /** Called by a VcnGatewayConnection to indicate that it's safe mode status has changed. */
+ void onSafeModeStatusChanged();
/** Callback by a VcnGatewayConnection to indicate that an error occurred. */
void onGatewayConnectionError(
@@ -445,8 +447,8 @@
}
@Override
- public void onEnteredSafeMode() {
- sendMessage(obtainMessage(MSG_CMD_ENTER_SAFE_MODE));
+ public void onSafeModeStatusChanged() {
+ sendMessage(obtainMessage(MSG_EVENT_SAFE_MODE_STATE_CHANGED));
}
@Override
diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
index 2ba8edd..20c08eb 100644
--- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
+++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
@@ -32,6 +32,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
+import android.net.ConnectivityManager;
import android.net.InetAddresses;
import android.net.IpPrefix;
import android.net.IpSecManager;
@@ -44,6 +45,7 @@
import android.net.NetworkAgent;
import android.net.NetworkAgentConfig;
import android.net.NetworkCapabilities;
+import android.net.NetworkProvider;
import android.net.RouteInfo;
import android.net.TelephonyNetworkSpecifier;
import android.net.Uri;
@@ -92,6 +94,7 @@
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
/**
* A single VCN Gateway Connection, providing a single public-facing VCN network.
@@ -504,6 +507,15 @@
private boolean mIsQuitting = false;
/**
+ * Whether the VcnGatewayConnection is in safe mode.
+ *
+ * <p>Upon hitting the safe mode timeout, this will be set to {@code true}. In safe mode, this
+ * VcnGatewayConnection will continue attempting to connect, and if a successful connection is
+ * made, safe mode will be exited.
+ */
+ private boolean mIsInSafeMode = false;
+
+ /**
* The token used by the primary/current/active session.
*
* <p>This token MUST be updated when a new stateful/async session becomes the
@@ -562,8 +574,7 @@
* <p>Set in Connected state, always @NonNull in Connected, Migrating states, @Nullable
* otherwise.
*/
- @VisibleForTesting(visibility = Visibility.PRIVATE)
- NetworkAgent mNetworkAgent;
+ private NetworkAgent mNetworkAgent;
@Nullable private WakeupMessage mTeardownTimeoutAlarm;
@Nullable private WakeupMessage mDisconnectRequestAlarm;
@@ -628,6 +639,14 @@
start();
}
+ /** Queries whether this VcnGatewayConnection is in safe mode. */
+ public boolean isInSafeMode() {
+ // Accessing internal state; must only be done on looper thread.
+ mVcnContext.ensureRunningOnLooperThread();
+
+ return mIsInSafeMode;
+ }
+
/**
* Asynchronously tears down this GatewayConnection, and any resources used.
*
@@ -1162,6 +1181,15 @@
}
}
+ protected void handleSafeModeTimeoutExceeded() {
+ mSafeModeTimeoutAlarm = null;
+
+ // Connectivity for this GatewayConnection is broken; tear down the Network.
+ teardownNetwork();
+ mIsInSafeMode = true;
+ mGatewayStatusCallback.onSafeModeStatusChanged();
+ }
+
protected void logUnexpectedEvent(int what) {
Slog.d(TAG, String.format(
"Unexpected event code %d in state %s", what, this.getClass().getSimpleName()));
@@ -1315,8 +1343,7 @@
}
break;
case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED:
- mGatewayStatusCallback.onEnteredSafeMode();
- mSafeModeTimeoutAlarm = null;
+ handleSafeModeTimeoutExceeded();
break;
default:
logUnhandledMessage(msg);
@@ -1401,8 +1428,7 @@
handleDisconnectRequested((EventDisconnectRequestedInfo) msg.obj);
break;
case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED:
- mGatewayStatusCallback.onEnteredSafeMode();
- mSafeModeTimeoutAlarm = null;
+ handleSafeModeTimeoutExceeded();
break;
default:
logUnhandledMessage(msg);
@@ -1432,30 +1458,35 @@
buildNetworkCapabilities(mConnectionConfig, mUnderlying);
final LinkProperties lp =
buildConnectedLinkProperties(mConnectionConfig, tunnelIface, childConfig);
+ final NetworkAgentConfig nac =
+ new NetworkAgentConfig.Builder()
+ .setLegacyType(ConnectivityManager.TYPE_MOBILE)
+ .build();
final NetworkAgent agent =
- new NetworkAgent(
- mVcnContext.getContext(),
- mVcnContext.getLooper(),
+ mDeps.newNetworkAgent(
+ mVcnContext,
TAG,
caps,
lp,
Vcn.getNetworkScore(),
- new NetworkAgentConfig.Builder().build(),
- mVcnContext.getVcnNetworkProvider()) {
- @Override
- public void onNetworkUnwanted() {
- Slog.d(TAG, "NetworkAgent was unwanted");
- teardownAsynchronously();
- }
-
- @Override
- public void onValidationStatus(int status, @Nullable Uri redirectUri) {
- if (status == NetworkAgent.VALIDATION_STATUS_VALID) {
- clearFailedAttemptCounterAndSafeModeAlarm();
- }
- }
- };
+ nac,
+ mVcnContext.getVcnNetworkProvider(),
+ () -> {
+ Slog.d(TAG, "NetworkAgent was unwanted");
+ // If network agent has already been torn down, skip sending the
+ // disconnect. Unwanted() is always called, even when networkAgents
+ // are unregistered in teardownNetwork(), so prevent duplicate
+ // notifications.
+ if (mNetworkAgent != null) {
+ teardownAsynchronously();
+ }
+ } /* networkUnwantedCallback */,
+ (status) -> {
+ if (status == NetworkAgent.VALIDATION_STATUS_VALID) {
+ clearFailedAttemptCounterAndSafeModeAlarm();
+ }
+ } /* validationStatusCallback */);
agent.register();
agent.markConnected();
@@ -1469,6 +1500,11 @@
// Validated connection, clear failed attempt counter
mFailedAttempts = 0;
cancelSafeModeAlarm();
+
+ if (mIsInSafeMode) {
+ mIsInSafeMode = false;
+ mGatewayStatusCallback.onSafeModeStatusChanged();
+ }
}
protected void applyTransform(
@@ -1491,13 +1527,6 @@
protected void setupInterface(
int token,
@NonNull IpSecTunnelInterface tunnelIface,
- @NonNull VcnChildSessionConfiguration childConfig) {
- setupInterface(token, tunnelIface, childConfig, null);
- }
-
- protected void setupInterface(
- int token,
- @NonNull IpSecTunnelInterface tunnelIface,
@NonNull VcnChildSessionConfiguration childConfig,
@Nullable VcnChildSessionConfiguration oldChildConfig) {
try {
@@ -1579,16 +1608,17 @@
transformCreatedInfo.direction);
break;
case EVENT_SETUP_COMPLETED:
+ final VcnChildSessionConfiguration oldChildConfig = mChildConfig;
mChildConfig = ((EventSetupCompletedInfo) msg.obj).childSessionConfig;
- setupInterfaceAndNetworkAgent(mCurrentToken, mTunnelIface, mChildConfig);
+ setupInterfaceAndNetworkAgent(
+ mCurrentToken, mTunnelIface, mChildConfig, oldChildConfig);
break;
case EVENT_DISCONNECT_REQUESTED:
handleDisconnectRequested((EventDisconnectRequestedInfo) msg.obj);
break;
case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED:
- mGatewayStatusCallback.onEnteredSafeMode();
- mSafeModeTimeoutAlarm = null;
+ handleSafeModeTimeoutExceeded();
break;
default:
logUnhandledMessage(msg);
@@ -1626,8 +1656,9 @@
protected void setupInterfaceAndNetworkAgent(
int token,
@NonNull IpSecTunnelInterface tunnelIface,
- @NonNull VcnChildSessionConfiguration childConfig) {
- setupInterface(token, tunnelIface, childConfig);
+ @NonNull VcnChildSessionConfiguration childConfig,
+ @NonNull VcnChildSessionConfiguration oldChildConfig) {
+ setupInterface(token, tunnelIface, childConfig, oldChildConfig);
if (mNetworkAgent == null) {
mNetworkAgent = buildNetworkAgent(tunnelIface, childConfig);
@@ -1692,8 +1723,7 @@
handleDisconnectRequested((EventDisconnectRequestedInfo) msg.obj);
break;
case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED:
- mGatewayStatusCallback.onEnteredSafeMode();
- mSafeModeTimeoutAlarm = null;
+ handleSafeModeTimeoutExceeded();
break;
default:
logUnhandledMessage(msg);
@@ -1935,6 +1965,16 @@
}
@VisibleForTesting(visibility = Visibility.PRIVATE)
+ NetworkAgent getNetworkAgent() {
+ return mNetworkAgent;
+ }
+
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ void setNetworkAgent(@Nullable NetworkAgent networkAgent) {
+ mNetworkAgent = networkAgent;
+ }
+
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
void sendDisconnectRequestedAndAcquireWakelock(String reason, boolean shouldQuit) {
sendMessageAndAcquireWakeLock(
EVENT_DISCONNECT_REQUESTED,
@@ -2018,6 +2058,38 @@
return new WakeupMessage(vcnContext.getContext(), handler, tag, runnable);
}
+ /** Builds a new NetworkAgent. */
+ public NetworkAgent newNetworkAgent(
+ @NonNull VcnContext vcnContext,
+ @NonNull String tag,
+ @NonNull NetworkCapabilities caps,
+ @NonNull LinkProperties lp,
+ @NonNull int score,
+ @NonNull NetworkAgentConfig nac,
+ @NonNull NetworkProvider provider,
+ @NonNull Runnable networkUnwantedCallback,
+ @NonNull Consumer<Integer> validationStatusCallback) {
+ return new NetworkAgent(
+ vcnContext.getContext(),
+ vcnContext.getLooper(),
+ tag,
+ caps,
+ lp,
+ score,
+ nac,
+ provider) {
+ @Override
+ public void onNetworkUnwanted() {
+ networkUnwantedCallback.run();
+ }
+
+ @Override
+ public void onValidationStatus(int status, @Nullable Uri redirectUri) {
+ validationStatusCallback.accept(status);
+ }
+ };
+ }
+
/** Gets the elapsed real time since boot, in millis. */
public long getElapsedRealTime() {
return SystemClock.elapsedRealtime();
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
index 100d3ea..f5876fa 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
@@ -33,12 +33,6 @@
import static android.net.NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND;
import static android.net.NetworkPolicyManager.POLICY_NONE;
import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
-import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
-import static android.net.NetworkPolicyManager.RULE_ALLOW_METERED;
-import static android.net.NetworkPolicyManager.RULE_NONE;
-import static android.net.NetworkPolicyManager.RULE_REJECT_ALL;
-import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
-import static android.net.NetworkPolicyManager.RULE_TEMPORARY_ALLOW_METERED;
import static android.net.NetworkPolicyManager.uidPoliciesToString;
import static android.net.NetworkPolicyManager.uidRulesToString;
import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
@@ -49,7 +43,6 @@
import static android.net.NetworkTemplate.buildTemplateMobileAll;
import static android.net.NetworkTemplate.buildTemplateWifi;
import static android.net.TrafficStats.MB_IN_BYTES;
-import static android.os.Process.SYSTEM_UID;
import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED;
import static android.telephony.CarrierConfigManager.DATA_CYCLE_THRESHOLD_DISABLED;
import static android.telephony.CarrierConfigManager.DATA_CYCLE_USE_PLATFORM_DEFAULT;
@@ -141,7 +134,6 @@
import android.util.ArrayMap;
import android.util.DataUnit;
import android.util.Log;
-import android.util.Pair;
import android.util.Range;
import android.util.RecurrenceRule;
@@ -1844,68 +1836,6 @@
reset(mStatsService);
}
- /**
- * Exhaustively test checkUidNetworkingBlocked to output the expected results based on external
- * conditions.
- */
- @Test
- public void testCheckUidNetworkingBlocked() {
- final ArrayList<Pair<Boolean, Integer>> expectedBlockedStates = new ArrayList<>();
-
- // Metered network. Data saver on.
- expectedBlockedStates.add(new Pair<>(true, RULE_NONE));
- expectedBlockedStates.add(new Pair<>(false, RULE_ALLOW_METERED));
- expectedBlockedStates.add(new Pair<>(false, RULE_TEMPORARY_ALLOW_METERED));
- expectedBlockedStates.add(new Pair<>(true, RULE_REJECT_METERED));
- expectedBlockedStates.add(new Pair<>(true, RULE_ALLOW_ALL));
- expectedBlockedStates.add(new Pair<>(true, RULE_REJECT_ALL));
- verifyNetworkBlockedState(
- true /* metered */, true /* backgroundRestricted */, expectedBlockedStates);
- expectedBlockedStates.clear();
-
- // Metered network. Data saver off.
- expectedBlockedStates.add(new Pair<>(false, RULE_NONE));
- expectedBlockedStates.add(new Pair<>(false, RULE_ALLOW_METERED));
- expectedBlockedStates.add(new Pair<>(false, RULE_TEMPORARY_ALLOW_METERED));
- expectedBlockedStates.add(new Pair<>(true, RULE_REJECT_METERED));
- expectedBlockedStates.add(new Pair<>(false, RULE_ALLOW_ALL));
- expectedBlockedStates.add(new Pair<>(true, RULE_REJECT_ALL));
- verifyNetworkBlockedState(
- true /* metered */, false /* backgroundRestricted */, expectedBlockedStates);
- expectedBlockedStates.clear();
-
- // Non-metered network. Data saver on.
- expectedBlockedStates.add(new Pair<>(false, RULE_NONE));
- expectedBlockedStates.add(new Pair<>(false, RULE_ALLOW_METERED));
- expectedBlockedStates.add(new Pair<>(false, RULE_TEMPORARY_ALLOW_METERED));
- expectedBlockedStates.add(new Pair<>(false, RULE_REJECT_METERED));
- expectedBlockedStates.add(new Pair<>(false, RULE_ALLOW_ALL));
- expectedBlockedStates.add(new Pair<>(true, RULE_REJECT_ALL));
- verifyNetworkBlockedState(
- false /* metered */, true /* backgroundRestricted */, expectedBlockedStates);
-
- // Non-metered network. Data saver off. The result is the same as previous case since
- // the network is blocked only for RULE_REJECT_ALL regardless of data saver.
- verifyNetworkBlockedState(
- false /* metered */, false /* backgroundRestricted */, expectedBlockedStates);
- expectedBlockedStates.clear();
- }
-
- private void verifyNetworkBlockedState(boolean metered, boolean backgroundRestricted,
- ArrayList<Pair<Boolean, Integer>> expectedBlockedStateForRules) {
-
- for (Pair<Boolean, Integer> pair : expectedBlockedStateForRules) {
- final boolean expectedResult = pair.first;
- final int rule = pair.second;
- assertEquals(formatBlockedStateError(UID_A, rule, metered, backgroundRestricted),
- expectedResult, mService.checkUidNetworkingBlocked(UID_A, rule,
- metered, backgroundRestricted));
- assertFalse(formatBlockedStateError(SYSTEM_UID, rule, metered, backgroundRestricted),
- mService.checkUidNetworkingBlocked(SYSTEM_UID, rule, metered,
- backgroundRestricted));
- }
- }
-
private void enableRestrictedMode(boolean enable) throws Exception {
mService.mRestrictedNetworkingMode = enable;
mService.updateRestrictedModeAllowlistUL();
diff --git a/telephony/java/android/telephony/ims/SipMessage.java b/telephony/java/android/telephony/ims/SipMessage.java
index ad6d73c..b529563 100644
--- a/telephony/java/android/telephony/ims/SipMessage.java
+++ b/telephony/java/android/telephony/ims/SipMessage.java
@@ -24,6 +24,7 @@
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
+import android.text.TextUtils;
import com.android.internal.telephony.SipMessageParsingUtils;
@@ -60,14 +61,19 @@
*/
public SipMessage(@NonNull String startLine, @NonNull String headerSection,
@NonNull byte[] content) {
- if (startLine == null || headerSection == null || content == null) {
- throw new IllegalArgumentException("One or more null parameters entered");
- }
+ Objects.requireNonNull(startLine, "Required parameter is null: startLine");
+ Objects.requireNonNull(headerSection, "Required parameter is null: headerSection");
+ Objects.requireNonNull(content, "Required parameter is null: content");
+
mStartLine = startLine;
mHeaderSection = headerSection;
mContent = content;
mViaBranchParam = SipMessageParsingUtils.getTransactionId(mHeaderSection);
+ if (TextUtils.isEmpty(mViaBranchParam)) {
+ throw new IllegalArgumentException("header section MUST contain a branch parameter "
+ + "inside of the Via header.");
+ }
mCallIdParam = SipMessageParsingUtils.getCallId(mHeaderSection);
}
@@ -107,11 +113,9 @@
/**
* @return the branch parameter enclosed in the Via header key's value. See RFC 3261 section
- * 20.42 for more information on the Via header. If {@code null}, then there was either no
- * Via parameter found in this SIP message's headers or no branch parameter found in the
- * Via header.
+ * 20.42 for more information on the Via header.
*/
- public @Nullable String getViaBranchParameter() {
+ public @NonNull String getViaBranchParameter() {
return mViaBranchParam;
}
diff --git a/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java b/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java
index 739946b..5c9ec53 100644
--- a/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java
+++ b/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java
@@ -28,8 +28,6 @@
import android.telephony.ims.SipDelegateManager;
import android.telephony.ims.SipMessage;
import android.telephony.ims.stub.SipDelegate;
-import android.text.TextUtils;
-import android.util.Log;
import java.util.ArrayList;
import java.util.Set;
@@ -187,11 +185,6 @@
private void notifyLocalMessageFailedToBeReceived(SipMessage m, int reason) {
String transactionId = m.getViaBranchParameter();
- if (TextUtils.isEmpty(transactionId)) {
- Log.w(LOG_TAG, "failure to parse SipMessage.");
- throw new IllegalArgumentException("Malformed SipMessage, can not determine "
- + "transaction ID.");
- }
SipDelegate d = mDelegate;
if (d != null) {
mExecutor.execute(() -> d.notifyMessageReceiveError(transactionId, reason));
diff --git a/telephony/java/android/telephony/ims/aidl/SipDelegateConnectionAidlWrapper.java b/telephony/java/android/telephony/ims/aidl/SipDelegateConnectionAidlWrapper.java
index 3cd2726..ad02fe5 100644
--- a/telephony/java/android/telephony/ims/aidl/SipDelegateConnectionAidlWrapper.java
+++ b/telephony/java/android/telephony/ims/aidl/SipDelegateConnectionAidlWrapper.java
@@ -28,7 +28,6 @@
import android.telephony.ims.stub.DelegateConnectionMessageCallback;
import android.telephony.ims.stub.DelegateConnectionStateCallback;
import android.telephony.ims.stub.SipDelegate;
-import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log;
@@ -267,12 +266,6 @@
private void notifyLocalMessageFailedToSend(SipMessage m, int reason) {
String transactionId = m.getViaBranchParameter();
- if (TextUtils.isEmpty(transactionId)) {
- Log.w(LOG_TAG, "sendMessage detected a malformed SipMessage and can not get a "
- + "transaction ID.");
- throw new IllegalArgumentException("Could not send SipMessage due to malformed header");
- }
- mExecutor.execute(() ->
- mMessageCallback.onMessageSendFailure(transactionId, reason));
+ mExecutor.execute(() -> mMessageCallback.onMessageSendFailure(transactionId, reason));
}
}
diff --git a/tests/SilkFX/OWNERS b/tests/SilkFX/OWNERS
new file mode 100644
index 0000000..c88a9f8
--- /dev/null
+++ b/tests/SilkFX/OWNERS
@@ -0,0 +1 @@
+include /libs/hwui/OWNERS
diff --git a/tests/net/java/android/net/VpnTransportInfoTest.java b/tests/net/java/android/net/VpnTransportInfoTest.java
index b7a42ec..fee65f0 100644
--- a/tests/net/java/android/net/VpnTransportInfoTest.java
+++ b/tests/net/java/android/net/VpnTransportInfoTest.java
@@ -16,6 +16,9 @@
package android.net;
+import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS;
+import static android.net.NetworkCapabilities.REDACT_NONE;
+
import static com.android.testutils.ParcelUtils.assertParcelSane;
import static org.junit.Assert.assertEquals;
@@ -33,23 +36,33 @@
@Test
public void testParceling() {
- VpnTransportInfo v = new VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM);
- assertParcelSane(v, 1 /* fieldCount */);
+ VpnTransportInfo v = new VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM, "12345");
+ assertParcelSane(v, 2 /* fieldCount */);
}
@Test
public void testEqualsAndHashCode() {
- VpnTransportInfo v1 = new VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM);
- VpnTransportInfo v2 = new VpnTransportInfo(VpnManager.TYPE_VPN_SERVICE);
- VpnTransportInfo v3 = new VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM);
- VpnTransportInfo v4 = new VpnTransportInfo(VpnManager.TYPE_VPN_LEGACY);
- VpnTransportInfo v5 = new VpnTransportInfo(VpnManager.TYPE_VPN_OEM);
+ String session1 = "12345";
+ String session2 = "6789";
+ VpnTransportInfo v11 = new VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM, session1);
+ VpnTransportInfo v12 = new VpnTransportInfo(VpnManager.TYPE_VPN_SERVICE, session1);
+ VpnTransportInfo v13 = new VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM, session1);
+ VpnTransportInfo v14 = new VpnTransportInfo(VpnManager.TYPE_VPN_LEGACY, session1);
+ VpnTransportInfo v15 = new VpnTransportInfo(VpnManager.TYPE_VPN_OEM, session1);
+ VpnTransportInfo v21 = new VpnTransportInfo(VpnManager.TYPE_VPN_LEGACY, session2);
- assertNotEquals(v1, v2);
- assertNotEquals(v3, v4);
- assertNotEquals(v4, v5);
+ VpnTransportInfo v31 = v11.makeCopy(REDACT_FOR_NETWORK_SETTINGS);
+ VpnTransportInfo v32 = v13.makeCopy(REDACT_FOR_NETWORK_SETTINGS);
- assertEquals(v1, v3);
- assertEquals(v1.hashCode(), v3.hashCode());
+ assertNotEquals(v11, v12);
+ assertNotEquals(v13, v14);
+ assertNotEquals(v14, v15);
+ assertNotEquals(v14, v21);
+
+ assertEquals(v11, v13);
+ assertEquals(v31, v32);
+ assertEquals(v11.hashCode(), v13.hashCode());
+ assertEquals(REDACT_FOR_NETWORK_SETTINGS, v32.getApplicableRedactions());
+ assertEquals(session1, v15.makeCopy(REDACT_NONE).sessionId);
}
-}
\ No newline at end of file
+}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 2ed11e0..270941f 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -21,6 +21,9 @@
import static android.Manifest.permission.NETWORK_FACTORY;
import static android.Manifest.permission.NETWORK_SETTINGS;
import static android.app.PendingIntent.FLAG_IMMUTABLE;
+import static android.content.Intent.ACTION_PACKAGE_ADDED;
+import static android.content.Intent.ACTION_PACKAGE_REMOVED;
+import static android.content.Intent.ACTION_PACKAGE_REPLACED;
import static android.content.Intent.ACTION_USER_ADDED;
import static android.content.Intent.ACTION_USER_REMOVED;
import static android.content.Intent.ACTION_USER_UNLOCKED;
@@ -1230,10 +1233,12 @@
if (mAgentRegistered) throw new IllegalStateException("already registered");
updateState(NetworkInfo.DetailedState.CONNECTING, "registerAgent");
mConfig = new VpnConfig();
+ mConfig.session = "MySession12345";
setUids(uids);
if (!isAlwaysMetered) mNetworkCapabilities.addCapability(NET_CAPABILITY_NOT_METERED);
mInterface = VPN_IFNAME;
- mNetworkCapabilities.setTransportInfo(new VpnTransportInfo(getActiveVpnType()));
+ mNetworkCapabilities.setTransportInfo(new VpnTransportInfo(getActiveVpnType(),
+ mConfig.session));
mMockNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN, lp,
mNetworkCapabilities);
mMockNetworkAgent.waitForIdle(TIMEOUT_MS);
@@ -2793,10 +2798,14 @@
}
private void grantUsingBackgroundNetworksPermissionForUid(final int uid) throws Exception {
- final String myPackageName = mContext.getPackageName();
- when(mPackageManager.getPackageInfo(eq(myPackageName), eq(GET_PERMISSIONS)))
+ grantUsingBackgroundNetworksPermissionForUid(uid, mContext.getPackageName());
+ }
+
+ private void grantUsingBackgroundNetworksPermissionForUid(
+ final int uid, final String packageName) throws Exception {
+ when(mPackageManager.getPackageInfo(eq(packageName), eq(GET_PERMISSIONS)))
.thenReturn(buildPackageInfo(true, uid));
- mService.mPermissionMonitor.onPackageAdded(myPackageName, uid);
+ mService.mPermissionMonitor.onPackageAdded(packageName, uid);
}
@Test
@@ -10255,6 +10264,12 @@
.thenReturn(applicationInfo);
}
+ private void mockGetApplicationInfoThrowsNameNotFound(@NonNull final String packageName)
+ throws Exception {
+ when(mPackageManager.getApplicationInfo(eq(packageName), anyInt()))
+ .thenThrow(new PackageManager.NameNotFoundException(packageName));
+ }
+
private void mockHasSystemFeature(@NonNull final String featureName,
@NonNull final boolean hasFeature) {
when(mPackageManager.hasSystemFeature(eq(featureName)))
@@ -10711,15 +10726,23 @@
@NonNull final UidRangeParcel[] uidRanges,
@NonNull final String testPackageName)
throws Exception {
- mockHasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, true);
-
// These tests work off a single UID therefore using 'start' is valid.
mockGetApplicationInfo(testPackageName, uidRanges[0].start);
+ setOemNetworkPreference(networkPrefToSetup, testPackageName);
+ }
+
+ private void setOemNetworkPreference(final int networkPrefToSetup,
+ @NonNull final String... testPackageNames)
+ throws Exception {
+ mockHasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, true);
+
// Build OemNetworkPreferences object
- final OemNetworkPreferences pref = new OemNetworkPreferences.Builder()
- .addNetworkPreference(testPackageName, networkPrefToSetup)
- .build();
+ final OemNetworkPreferences.Builder builder = new OemNetworkPreferences.Builder();
+ for (final String packageName : testPackageNames) {
+ builder.addNetworkPreference(packageName, networkPrefToSetup);
+ }
+ final OemNetworkPreferences pref = builder.build();
// Act on ConnectivityService.setOemNetworkPreference()
final TestOemListenerCallback oemPrefListener = new TestOemListenerCallback();
@@ -11318,8 +11341,7 @@
// Arrange PackageManager mocks
final int secondUserTestPackageUid = UserHandle.getUid(secondUser, TEST_PACKAGE_UID);
final UidRangeParcel[] uidRangesSingleUser =
- toUidRangeStableParcels(
- uidRangesForUids(TEST_PACKAGE_UID));
+ toUidRangeStableParcels(uidRangesForUids(TEST_PACKAGE_UID));
final UidRangeParcel[] uidRangesBothUsers =
toUidRangeStableParcels(
uidRangesForUids(TEST_PACKAGE_UID, secondUserTestPackageUid));
@@ -11366,6 +11388,84 @@
false /* shouldDestroyNetwork */);
}
+ @Test
+ public void testMultilayerForPackageChangesEvaluatesCorrectly()
+ throws Exception {
+ @OemNetworkPreferences.OemNetworkPreference final int networkPref =
+ OEM_NETWORK_PREFERENCE_OEM_PAID;
+ final String packageScheme = "package:";
+
+ // Arrange PackageManager mocks
+ final String packageToInstall = "package.to.install";
+ final int packageToInstallUid = 81387;
+ final UidRangeParcel[] uidRangesSinglePackage =
+ toUidRangeStableParcels(uidRangesForUids(TEST_PACKAGE_UID));
+ mockGetApplicationInfo(TEST_PACKAGE_NAME, TEST_PACKAGE_UID);
+ mockGetApplicationInfoThrowsNameNotFound(packageToInstall);
+ setOemNetworkPreference(networkPref, TEST_PACKAGE_NAME, packageToInstall);
+ grantUsingBackgroundNetworksPermissionForUid(Binder.getCallingUid(), packageToInstall);
+
+ // Verify the starting state. No networks should be connected.
+ verifySetOemNetworkPreferenceForPreference(uidRangesSinglePackage,
+ OEM_PREF_ANY_NET_ID, 0 /* times */,
+ OEM_PREF_ANY_NET_ID, 0 /* times */,
+ false /* shouldDestroyNetwork */);
+
+ // Test that we correctly add the expected values for installed packages.
+ setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true);
+ verifySetOemNetworkPreferenceForPreference(uidRangesSinglePackage,
+ mCellNetworkAgent.getNetwork().netId, 1 /* times */,
+ OEM_PREF_ANY_NET_ID, 0 /* times */,
+ false /* shouldDestroyNetwork */);
+
+ // Set the system to recognize the package to be installed
+ mockGetApplicationInfo(packageToInstall, packageToInstallUid);
+ final UidRangeParcel[] uidRangesAllPackages =
+ toUidRangeStableParcels(uidRangesForUids(TEST_PACKAGE_UID, packageToInstallUid));
+
+ // Send a broadcast indicating a package was installed.
+ final Intent addedIntent = new Intent(ACTION_PACKAGE_ADDED);
+ addedIntent.setData(Uri.parse(packageScheme + packageToInstall));
+ processBroadcast(addedIntent);
+
+ // Test the single package is removed and the combined packages are added.
+ verifySetOemNetworkPreferenceForPreference(uidRangesAllPackages, uidRangesSinglePackage,
+ mCellNetworkAgent.getNetwork().netId, 1 /* times */,
+ mCellNetworkAgent.getNetwork().netId, 1 /* times */,
+ false /* shouldDestroyNetwork */);
+
+ // Set the system to no longer recognize the package to be installed
+ mockGetApplicationInfoThrowsNameNotFound(packageToInstall);
+
+ // Send a broadcast indicating a package was removed.
+ final Intent removedIntent = new Intent(ACTION_PACKAGE_REMOVED);
+ removedIntent.setData(Uri.parse(packageScheme + packageToInstall));
+ processBroadcast(removedIntent);
+
+ // Test the combined packages are removed and the single package is added.
+ verifySetOemNetworkPreferenceForPreference(uidRangesSinglePackage, uidRangesAllPackages,
+ mCellNetworkAgent.getNetwork().netId, 1 /* times */,
+ mCellNetworkAgent.getNetwork().netId, 1 /* times */,
+ false /* shouldDestroyNetwork */);
+
+ // Set the system to change the installed package's uid
+ final int replacedTestPackageUid = TEST_PACKAGE_UID + 1;
+ mockGetApplicationInfo(TEST_PACKAGE_NAME, replacedTestPackageUid);
+ final UidRangeParcel[] uidRangesReplacedPackage =
+ toUidRangeStableParcels(uidRangesForUids(replacedTestPackageUid));
+
+ // Send a broadcast indicating a package was replaced.
+ final Intent replacedIntent = new Intent(ACTION_PACKAGE_REPLACED);
+ replacedIntent.setData(Uri.parse(packageScheme + TEST_PACKAGE_NAME));
+ processBroadcast(replacedIntent);
+
+ // Test the original uid is removed and is replaced with the new uid.
+ verifySetOemNetworkPreferenceForPreference(uidRangesReplacedPackage, uidRangesSinglePackage,
+ mCellNetworkAgent.getNetwork().netId, 1 /* times */,
+ mCellNetworkAgent.getNetwork().netId, 1 /* times */,
+ false /* shouldDestroyNetwork */);
+ }
+
/**
* Test network priority for preference OEM_NETWORK_PREFERENCE_OEM_PAID in the following order:
* NET_CAPABILITY_NOT_METERED -> NET_CAPABILITY_OEM_PAID -> fallback
diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
index 4ad7136..43e6676 100644
--- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
+++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
@@ -16,6 +16,8 @@
package com.android.server;
+import static android.net.ConnectivityManager.NetworkCallback;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
@@ -55,8 +57,10 @@
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.LinkProperties;
+import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkCapabilities.Transport;
+import android.net.NetworkRequest;
import android.net.TelephonyNetworkSpecifier;
import android.net.vcn.IVcnStatusCallback;
import android.net.vcn.IVcnUnderlyingNetworkPolicyListener;
@@ -258,6 +262,10 @@
verify(mConnMgr).registerNetworkProvider(any(VcnNetworkProvider.class));
verify(mSubscriptionTracker).register();
+ verify(mConnMgr)
+ .registerNetworkCallback(
+ eq(new NetworkRequest.Builder().clearCapabilities().build()),
+ any(NetworkCallback.class));
}
@Test
@@ -529,17 +537,6 @@
}
@Test
- public void testSetVcnConfigInSafeModeNotifiesStatusCallback() throws Exception {
- setupSubscriptionAndStartVcn(TEST_SUBSCRIPTION_ID, TEST_UUID_2, false /* isActive */);
- mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_2, mMockStatusCallback, TEST_PACKAGE_NAME);
- verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_SAFE_MODE);
-
- mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
-
- verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_ACTIVE);
- }
-
- @Test
public void testClearVcnConfigRequiresNonSystemServer() throws Exception {
doReturn(Process.SYSTEM_UID).when(mMockDeps).getBinderCallingUid();
@@ -706,10 +703,8 @@
.checkLocationPermission(eq(TEST_PACKAGE_NAME), any(), eq(TEST_UID), any());
}
- private VcnUnderlyingNetworkPolicy startVcnAndGetPolicyForTransport(
- int subId, ParcelUuid subGrp, boolean isVcnActive, int transport) {
- setupSubscriptionAndStartVcn(subId, subGrp, isVcnActive);
-
+ private NetworkCapabilities.Builder getNetworkCapabilitiesBuilderForTransport(
+ int subId, int transport) {
final NetworkCapabilities.Builder ncBuilder =
new NetworkCapabilities.Builder()
.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
@@ -718,7 +713,16 @@
ncBuilder.setSubIds(Collections.singleton(subId));
}
- return mVcnMgmtSvc.getUnderlyingNetworkPolicy(ncBuilder.build(), new LinkProperties());
+ return ncBuilder;
+ }
+
+ private VcnUnderlyingNetworkPolicy startVcnAndGetPolicyForTransport(
+ int subId, ParcelUuid subGrp, boolean isVcnActive, int transport) {
+ setupSubscriptionAndStartVcn(subId, subGrp, isVcnActive);
+
+ return mVcnMgmtSvc.getUnderlyingNetworkPolicy(
+ getNetworkCapabilitiesBuilderForTransport(subId, transport).build(),
+ new LinkProperties());
}
@Test
@@ -780,6 +784,53 @@
true /* isRestricted */);
}
+ private void setupTrackedCarrierWifiNetwork(NetworkCapabilities caps) {
+ mVcnMgmtSvc.systemReady();
+
+ final ArgumentCaptor<NetworkCallback> captor =
+ ArgumentCaptor.forClass(NetworkCallback.class);
+ verify(mConnMgr)
+ .registerNetworkCallback(
+ eq(new NetworkRequest.Builder().clearCapabilities().build()),
+ captor.capture());
+ captor.getValue().onCapabilitiesChanged(new Network(0), caps);
+ }
+
+ @Test
+ public void testGetUnderlyingNetworkPolicyVcnWifi_unrestrictingExistingNetworkRequiresRestart()
+ throws Exception {
+ final NetworkCapabilities existingNetworkCaps =
+ getNetworkCapabilitiesBuilderForTransport(TEST_SUBSCRIPTION_ID, TRANSPORT_WIFI)
+ .removeCapability(NET_CAPABILITY_NOT_RESTRICTED)
+ .build();
+ setupTrackedCarrierWifiNetwork(existingNetworkCaps);
+
+ // Trigger test without VCN instance alive; expect restart due to change of NOT_RESTRICTED
+ // immutable capability
+ final VcnUnderlyingNetworkPolicy policy =
+ mVcnMgmtSvc.getUnderlyingNetworkPolicy(
+ getNetworkCapabilitiesBuilderForTransport(
+ TEST_SUBSCRIPTION_ID, TRANSPORT_WIFI)
+ .build(),
+ new LinkProperties());
+ assertTrue(policy.isTeardownRequested());
+ }
+
+ @Test
+ public void testGetUnderlyingNetworkPolicyVcnWifi_restrictingExistingNetworkRequiresRestart()
+ throws Exception {
+ final NetworkCapabilities existingNetworkCaps =
+ getNetworkCapabilitiesBuilderForTransport(TEST_SUBSCRIPTION_ID, TRANSPORT_WIFI)
+ .build();
+ setupTrackedCarrierWifiNetwork(existingNetworkCaps);
+
+ final VcnUnderlyingNetworkPolicy policy =
+ startVcnAndGetPolicyForTransport(
+ TEST_SUBSCRIPTION_ID, TEST_UUID_2, false /* isActive */, TRANSPORT_WIFI);
+
+ assertTrue(policy.isTeardownRequested());
+ }
+
@Test
public void testGetUnderlyingNetworkPolicyNonVcnNetwork() throws Exception {
setupSubscriptionAndStartVcn(TEST_SUBSCRIPTION_ID, TEST_UUID_1, true /* isActive */);
@@ -840,7 +891,9 @@
}
private void triggerVcnSafeMode(
- @NonNull ParcelUuid subGroup, @NonNull TelephonySubscriptionSnapshot snapshot)
+ @NonNull ParcelUuid subGroup,
+ @NonNull TelephonySubscriptionSnapshot snapshot,
+ boolean isInSafeMode)
throws Exception {
verify(mMockDeps)
.newVcn(
@@ -851,22 +904,32 @@
mVcnCallbackCaptor.capture());
VcnCallback vcnCallback = mVcnCallbackCaptor.getValue();
- vcnCallback.onEnteredSafeMode();
+ vcnCallback.onSafeModeStatusChanged(isInSafeMode);
}
- @Test
- public void testVcnEnteringSafeModeNotifiesPolicyListeners() throws Exception {
+ private void verifyVcnSafeModeChangesNotifiesPolicyListeners(boolean enterSafeMode)
+ throws Exception {
TelephonySubscriptionSnapshot snapshot =
triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_1));
mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
- triggerVcnSafeMode(TEST_UUID_1, snapshot);
+ triggerVcnSafeMode(TEST_UUID_1, snapshot, enterSafeMode);
verify(mMockPolicyListener).onPolicyChanged();
}
- private void triggerVcnStatusCallbackOnEnteredSafeMode(
+ @Test
+ public void testVcnEnteringSafeModeNotifiesPolicyListeners() throws Exception {
+ verifyVcnSafeModeChangesNotifiesPolicyListeners(true /* enterSafeMode */);
+ }
+
+ @Test
+ public void testVcnExitingSafeModeNotifiesPolicyListeners() throws Exception {
+ verifyVcnSafeModeChangesNotifiesPolicyListeners(false /* enterSafeMode */);
+ }
+
+ private void triggerVcnStatusCallbackOnSafeModeStatusChanged(
@NonNull ParcelUuid subGroup,
@NonNull String pkgName,
int uid,
@@ -889,12 +952,13 @@
mVcnMgmtSvc.registerVcnStatusCallback(subGroup, mMockStatusCallback, pkgName);
- triggerVcnSafeMode(subGroup, snapshot);
+ triggerVcnSafeMode(subGroup, snapshot, true /* enterSafeMode */);
}
@Test
- public void testVcnStatusCallbackOnEnteredSafeModeWithCarrierPrivileges() throws Exception {
- triggerVcnStatusCallbackOnEnteredSafeMode(
+ public void testVcnStatusCallbackOnSafeModeStatusChangedWithCarrierPrivileges()
+ throws Exception {
+ triggerVcnStatusCallbackOnSafeModeStatusChanged(
TEST_UUID_1,
TEST_PACKAGE_NAME,
TEST_UID,
@@ -905,8 +969,9 @@
}
@Test
- public void testVcnStatusCallbackOnEnteredSafeModeWithoutCarrierPrivileges() throws Exception {
- triggerVcnStatusCallbackOnEnteredSafeMode(
+ public void testVcnStatusCallbackOnSafeModeStatusChangedWithoutCarrierPrivileges()
+ throws Exception {
+ triggerVcnStatusCallbackOnSafeModeStatusChanged(
TEST_UUID_1,
TEST_PACKAGE_NAME,
TEST_UID,
@@ -918,8 +983,9 @@
}
@Test
- public void testVcnStatusCallbackOnEnteredSafeModeWithoutLocationPermission() throws Exception {
- triggerVcnStatusCallbackOnEnteredSafeMode(
+ public void testVcnStatusCallbackOnSafeModeStatusChangedWithoutLocationPermission()
+ throws Exception {
+ triggerVcnStatusCallbackOnSafeModeStatusChanged(
TEST_UUID_1,
TEST_PACKAGE_NAME,
TEST_UID,
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
index 2fadd44..34c0018 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
@@ -32,6 +32,7 @@
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.argThat;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
@@ -40,6 +41,8 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
+import android.net.ConnectivityManager;
+import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.NetworkAgent;
import android.net.NetworkCapabilities;
@@ -58,19 +61,29 @@
import org.mockito.ArgumentCaptor;
import java.io.IOException;
+import java.net.InetAddress;
import java.net.UnknownHostException;
+import java.util.Arrays;
import java.util.Collections;
+import java.util.List;
+import java.util.function.Consumer;
/** Tests for VcnGatewayConnection.ConnectedState */
@RunWith(AndroidJUnit4.class)
@SmallTest
public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnectionTestBase {
private VcnIkeSession mIkeSession;
+ private NetworkAgent mNetworkAgent;
@Before
public void setUp() throws Exception {
super.setUp();
+ mNetworkAgent = mock(NetworkAgent.class);
+ doReturn(mNetworkAgent)
+ .when(mDeps)
+ .newNetworkAgent(any(), any(), any(), any(), anyInt(), any(), any(), any(), any());
+
mGatewayConnection.setUnderlyingNetwork(TEST_UNDERLYING_NETWORK_RECORD_1);
mIkeSession = mGatewayConnection.buildIkeSession(TEST_UNDERLYING_NETWORK_RECORD_1.network);
@@ -159,21 +172,44 @@
assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState());
}
- @Test
- public void testChildOpenedRegistersNetwork() throws Exception {
- // Verify scheduled but not canceled when entering ConnectedState
- verifySafeModeTimeoutAlarmAndGetCallback(false /* expectCanceled */);
+ private void triggerChildOpened() {
+ triggerChildOpened(Collections.singletonList(TEST_INTERNAL_ADDR), TEST_DNS_ADDR);
+ }
+ private void triggerChildOpened(List<LinkAddress> internalAddresses, InetAddress dnsAddress) {
final VcnChildSessionConfiguration mMockChildSessionConfig =
mock(VcnChildSessionConfiguration.class);
- doReturn(Collections.singletonList(TEST_INTERNAL_ADDR))
- .when(mMockChildSessionConfig)
- .getInternalAddresses();
- doReturn(Collections.singletonList(TEST_DNS_ADDR))
+ doReturn(internalAddresses).when(mMockChildSessionConfig).getInternalAddresses();
+ doReturn(Collections.singletonList(dnsAddress))
.when(mMockChildSessionConfig)
.getInternalDnsServers();
getChildSessionCallback().onOpened(mMockChildSessionConfig);
+ }
+
+ private void triggerValidation(int status) {
+ final ArgumentCaptor<Consumer<Integer>> validationCallbackCaptor =
+ ArgumentCaptor.forClass(Consumer.class);
+ verify(mDeps)
+ .newNetworkAgent(
+ any(),
+ any(),
+ any(),
+ any(),
+ anyInt(),
+ any(),
+ any(),
+ any(),
+ validationCallbackCaptor.capture());
+
+ validationCallbackCaptor.getValue().accept(status);
+ }
+
+ @Test
+ public void testChildOpenedRegistersNetwork() throws Exception {
+ // Verify scheduled but not canceled when entering ConnectedState
+ verifySafeModeTimeoutAlarmAndGetCallback(false /* expectCanceled */);
+ triggerChildOpened();
mTestLooper.dispatchAll();
assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState());
@@ -182,15 +218,20 @@
ArgumentCaptor.forClass(LinkProperties.class);
final ArgumentCaptor<NetworkCapabilities> ncCaptor =
ArgumentCaptor.forClass(NetworkCapabilities.class);
- verify(mConnMgr)
- .registerNetworkAgent(
- any(),
- any(),
- lpCaptor.capture(),
+ verify(mDeps)
+ .newNetworkAgent(
+ eq(mVcnContext),
+ any(String.class),
ncCaptor.capture(),
+ lpCaptor.capture(),
+ anyInt(),
+ argThat(nac -> nac.getLegacyType() == ConnectivityManager.TYPE_MOBILE),
any(),
any(),
- anyInt());
+ any());
+ verify(mNetworkAgent).register();
+ verify(mNetworkAgent).markConnected();
+
verify(mIpSecSvc)
.addAddressToTunnelInterface(
eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(TEST_INTERNAL_ADDR), any());
@@ -208,9 +249,78 @@
// Now that Vcn Network is up, notify it as validated and verify the SafeMode alarm is
// canceled
- mGatewayConnection.mNetworkAgent.onValidationStatus(
- NetworkAgent.VALIDATION_STATUS_VALID, null /* redirectUri */);
+ triggerValidation(NetworkAgent.VALIDATION_STATUS_VALID);
verify(mSafeModeTimeoutAlarm).cancel();
+ assertFalse(mGatewayConnection.isInSafeMode());
+ }
+
+ @Test
+ public void testInternalAndDnsAddressesChanged() throws Exception {
+ final List<LinkAddress> startingInternalAddrs =
+ Arrays.asList(new LinkAddress[] {TEST_INTERNAL_ADDR, TEST_INTERNAL_ADDR_2});
+ triggerChildOpened(startingInternalAddrs, TEST_DNS_ADDR);
+ mTestLooper.dispatchAll();
+
+ for (LinkAddress addr : startingInternalAddrs) {
+ verify(mIpSecSvc)
+ .addAddressToTunnelInterface(
+ eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(addr), any());
+ }
+
+ verify(mDeps)
+ .newNetworkAgent(
+ any(),
+ any(),
+ any(),
+ argThat(
+ lp ->
+ startingInternalAddrs.equals(lp.getLinkAddresses())
+ && Collections.singletonList(TEST_DNS_ADDR)
+ .equals(lp.getDnsServers())),
+ anyInt(),
+ any(),
+ any(),
+ any(),
+ any());
+
+ // Trigger another connection event, and verify that the addresses change
+ final List<LinkAddress> newInternalAddrs =
+ Arrays.asList(new LinkAddress[] {TEST_INTERNAL_ADDR_2, TEST_INTERNAL_ADDR_3});
+ triggerChildOpened(newInternalAddrs, TEST_DNS_ADDR_2);
+ mTestLooper.dispatchAll();
+
+ // Verify addresses on tunnel network added/removed
+ for (LinkAddress addr : newInternalAddrs) {
+ verify(mIpSecSvc)
+ .addAddressToTunnelInterface(
+ eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(addr), any());
+ }
+ verify(mIpSecSvc)
+ .removeAddressFromTunnelInterface(
+ eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(TEST_INTERNAL_ADDR), any());
+
+ // TODO(b/184579891): Also verify link properties updated and sent when sendLinkProperties
+ // is mockable
+
+ // Verify that IpSecTunnelInterface only created once
+ verify(mIpSecSvc).createTunnelInterface(any(), any(), any(), any(), any());
+ verifyNoMoreInteractions(mIpSecSvc);
+ }
+
+ @Test
+ public void testSuccessfulConnectionExitsSafeMode() throws Exception {
+ verifySafeModeTimeoutNotifiesCallbackAndUnregistersNetworkAgent(
+ mGatewayConnection.mConnectedState);
+
+ assertTrue(mGatewayConnection.isInSafeMode());
+ assertFalse(mGatewayConnection.isQuitting());
+
+ triggerChildOpened();
+ mTestLooper.dispatchAll();
+
+ triggerValidation(NetworkAgent.VALIDATION_STATUS_VALID);
+
+ assertFalse(mGatewayConnection.isInSafeMode());
}
@Test
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java
index 7afa449..bfe8c73 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java
@@ -118,8 +118,9 @@
}
@Test
- public void testSafeModeTimeoutNotifiesCallback() {
- verifySafeModeTimeoutNotifiesCallback(mGatewayConnection.mConnectingState);
+ public void testSafeModeTimeoutNotifiesCallbackAndUnregistersNetworkAgent() {
+ verifySafeModeTimeoutNotifiesCallbackAndUnregistersNetworkAgent(
+ mGatewayConnection.mConnectingState);
}
@Test
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java
index 99feffd..9da8b45 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java
@@ -86,8 +86,9 @@
}
@Test
- public void testSafeModeTimeoutNotifiesCallback() {
- verifySafeModeTimeoutNotifiesCallback(mGatewayConnection.mDisconnectingState);
+ public void testSafeModeTimeoutNotifiesCallbackAndUnregistersNetworkAgent() {
+ verifySafeModeTimeoutNotifiesCallbackAndUnregistersNetworkAgent(
+ mGatewayConnection.mDisconnectingState);
}
@Test
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java
index 85a0277..6dbf7d5 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java
@@ -96,8 +96,9 @@
}
@Test
- public void testSafeModeTimeoutNotifiesCallback() {
- verifySafeModeTimeoutNotifiesCallback(mGatewayConnection.mRetryTimeoutState);
+ public void testSafeModeTimeoutNotifiesCallbackAndUnregistersNetworkAgent() {
+ verifySafeModeTimeoutNotifiesCallbackAndUnregistersNetworkAgent(
+ mGatewayConnection.mRetryTimeoutState);
}
@Test
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
index a660735..c5ed8f6 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
@@ -21,6 +21,8 @@
import static com.android.server.vcn.VcnTestUtils.setupIpSecManager;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.atLeastOnce;
@@ -42,6 +44,7 @@
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.Network;
+import android.net.NetworkAgent;
import android.net.NetworkCapabilities;
import android.net.ipsec.ike.ChildSessionCallback;
import android.net.ipsec.ike.IkeSessionCallback;
@@ -71,8 +74,14 @@
protected static final ParcelUuid TEST_SUB_GRP = new ParcelUuid(UUID.randomUUID());
protected static final InetAddress TEST_DNS_ADDR =
InetAddresses.parseNumericAddress("2001:DB8:0:1::");
+ protected static final InetAddress TEST_DNS_ADDR_2 =
+ InetAddresses.parseNumericAddress("2001:DB8:0:2::");
protected static final LinkAddress TEST_INTERNAL_ADDR =
- new LinkAddress(InetAddresses.parseNumericAddress("2001:DB8:0:2::"), 64);
+ new LinkAddress(InetAddresses.parseNumericAddress("2001:DB8:1:1::"), 64);
+ protected static final LinkAddress TEST_INTERNAL_ADDR_2 =
+ new LinkAddress(InetAddresses.parseNumericAddress("2001:DB8:1:2::"), 64);
+ protected static final LinkAddress TEST_INTERNAL_ADDR_3 =
+ new LinkAddress(InetAddresses.parseNumericAddress("2001:DB8:1:3::"), 64);
protected static final int TEST_IPSEC_SPI_VALUE = 0x1234;
protected static final int TEST_IPSEC_SPI_RESOURCE_ID = 1;
@@ -267,7 +276,12 @@
expectCanceled);
}
- protected void verifySafeModeTimeoutNotifiesCallback(@NonNull State expectedState) {
+ protected void verifySafeModeTimeoutNotifiesCallbackAndUnregistersNetworkAgent(
+ @NonNull State expectedState) {
+ // Set a NetworkAgent, and expect it to be unregistered and cleared
+ final NetworkAgent mockNetworkAgent = mock(NetworkAgent.class);
+ mGatewayConnection.setNetworkAgent(mockNetworkAgent);
+
// SafeMode timer starts when VcnGatewayConnection exits DisconnectedState (the initial
// state)
final Runnable delayedEvent =
@@ -275,7 +289,11 @@
delayedEvent.run();
mTestLooper.dispatchAll();
- verify(mGatewayStatusCallback).onEnteredSafeMode();
+ verify(mGatewayStatusCallback).onSafeModeStatusChanged();
assertEquals(expectedState, mGatewayConnection.getCurrentState());
+ assertTrue(mGatewayConnection.isInSafeMode());
+
+ verify(mockNetworkAgent).unregister();
+ assertNull(mGatewayConnection.getNetworkAgent());
}
}
diff --git a/tests/vcn/java/com/android/server/vcn/VcnTest.java b/tests/vcn/java/com/android/server/vcn/VcnTest.java
index 540be38..90eb75e 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnTest.java
@@ -19,14 +19,13 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE;
-import static android.net.vcn.VcnManager.VCN_STATUS_CODE_INACTIVE;
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.argThat;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
@@ -54,7 +53,6 @@
import org.mockito.ArgumentCaptor;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.UUID;
@@ -136,6 +134,7 @@
private void startVcnGatewayWithCapabilities(
NetworkRequestListener requestListener, int... netCapabilities) {
final NetworkRequest.Builder requestBuilder = new NetworkRequest.Builder();
+ requestBuilder.addTransportType(TRANSPORT_CELLULAR);
for (final int netCapability : netCapabilities) {
requestBuilder.addCapability(netCapability);
}
@@ -160,8 +159,7 @@
mTestLooper.dispatchAll();
for (final VcnGatewayConnection gateway : gatewayConnections) {
- verify(gateway, status == VCN_STATUS_CODE_ACTIVE ? times(1) : never())
- .updateSubscriptionSnapshot(eq(updatedSnapshot));
+ verify(gateway).updateSubscriptionSnapshot(eq(updatedSnapshot));
}
}
@@ -202,32 +200,53 @@
private void verifySafeMode(
NetworkRequestListener requestListener,
- Set<VcnGatewayConnection> expectedGatewaysTornDown) {
- assertEquals(VCN_STATUS_CODE_SAFE_MODE, mVcn.getStatus());
- for (final VcnGatewayConnection gatewayConnection : expectedGatewaysTornDown) {
- verify(gatewayConnection).teardownAsynchronously();
+ Set<VcnGatewayConnection> activeGateways,
+ boolean expectInSafeMode) {
+ for (VcnGatewayConnection gatewayConnection : activeGateways) {
+ verify(gatewayConnection, never()).teardownAsynchronously();
}
- verify(mVcnNetworkProvider).unregisterListener(requestListener);
- verify(mVcnCallback).onEnteredSafeMode();
+
+ assertEquals(
+ expectInSafeMode ? VCN_STATUS_CODE_SAFE_MODE : VCN_STATUS_CODE_ACTIVE,
+ mVcn.getStatus());
+ verify(mVcnCallback).onSafeModeStatusChanged(expectInSafeMode);
}
@Test
- public void testGatewayEnteringSafeModeNotifiesVcn() {
+ public void testGatewayEnteringAndExitingSafeModeNotifiesVcn() {
final NetworkRequestListener requestListener = verifyAndGetRequestListener();
final Set<VcnGatewayConnection> gatewayConnections =
startGatewaysAndGetGatewayConnections(requestListener);
- // Doesn't matter which callback this gets - any Gateway entering Safemode should shut down
- // all Gateways
+ // Doesn't matter which callback this gets, or which VCN is in safe mode - any Gateway
+ // entering Safemode should trigger safe mode
final VcnGatewayStatusCallback statusCallback = mGatewayStatusCallbackCaptor.getValue();
- statusCallback.onEnteredSafeMode();
+ final VcnGatewayConnection gatewayConnection = gatewayConnections.iterator().next();
+
+ doReturn(true).when(gatewayConnection).isInSafeMode();
+ statusCallback.onSafeModeStatusChanged();
mTestLooper.dispatchAll();
- verifySafeMode(requestListener, gatewayConnections);
+ verifySafeMode(requestListener, gatewayConnections, true /* expectInSafeMode */);
+
+ // Verify that when all GatewayConnections exit safe mode, the VCN also exits safe mode
+ doReturn(false).when(gatewayConnection).isInSafeMode();
+ statusCallback.onSafeModeStatusChanged();
+ mTestLooper.dispatchAll();
+
+ verifySafeMode(requestListener, gatewayConnections, false /* expectInSafeMode */);
+
+ // Re-trigger, verify safe mode callback does not get fired again for identical state
+ statusCallback.onSafeModeStatusChanged();
+ mTestLooper.dispatchAll();
+
+ // Expect only once still; from above.
+ verify(mVcnCallback).onSafeModeStatusChanged(false);
}
- @Test
- public void testGatewayQuit() {
+ private void verifyGatewayQuit(int status) {
+ mVcn.setStatus(status);
+
final NetworkRequestListener requestListener = verifyAndGetRequestListener();
final Set<VcnGatewayConnection> gatewayConnections =
new ArraySet<>(startGatewaysAndGetGatewayConnections(requestListener));
@@ -240,7 +259,7 @@
assertEquals(1, mVcn.getVcnGatewayConnections().size());
verify(mVcnNetworkProvider).resendAllRequests(requestListener);
- // Verify that the VcnGatewayConnection is restarted
+ // Verify that the VcnGatewayConnection is restarted if a request exists for it
triggerVcnRequestListeners(requestListener);
mTestLooper.dispatchAll();
assertEquals(2, mVcn.getVcnGatewayConnections().size());
@@ -254,21 +273,13 @@
}
@Test
- public void testGatewayQuitWhileInactive() {
- final NetworkRequestListener requestListener = verifyAndGetRequestListener();
- final Set<VcnGatewayConnection> gatewayConnections =
- new ArraySet<>(startGatewaysAndGetGatewayConnections(requestListener));
+ public void testGatewayQuitReevaluatesRequests() {
+ verifyGatewayQuit(VCN_STATUS_CODE_ACTIVE);
+ }
- 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 testGatewayQuitReevaluatesRequestsInSafeMode() {
+ verifyGatewayQuit(VCN_STATUS_CODE_SAFE_MODE);
}
@Test
@@ -298,49 +309,4 @@
verify(removedGatewayConnection).teardownAsynchronously();
verify(mVcnNetworkProvider).resendAllRequests(requestListener);
}
-
- @Test
- public void testUpdateConfigExitsSafeMode() {
- final NetworkRequestListener requestListener = verifyAndGetRequestListener();
- final Set<VcnGatewayConnection> gatewayConnections =
- new ArraySet<>(startGatewaysAndGetGatewayConnections(requestListener));
-
- final VcnGatewayStatusCallback statusCallback = mGatewayStatusCallbackCaptor.getValue();
- statusCallback.onEnteredSafeMode();
- mTestLooper.dispatchAll();
- verifySafeMode(requestListener, gatewayConnections);
-
- doAnswer(invocation -> {
- final NetworkRequestListener listener = invocation.getArgument(0);
- triggerVcnRequestListeners(listener);
- return null;
- }).when(mVcnNetworkProvider).registerListener(eq(requestListener));
-
- mVcn.updateConfig(mConfig);
- mTestLooper.dispatchAll();
-
- // Registered on start, then re-registered with new configs
- verify(mVcnNetworkProvider, times(2)).registerListener(eq(requestListener));
- assertEquals(VCN_STATUS_CODE_ACTIVE, mVcn.getStatus());
- for (final int[] caps : TEST_CAPS) {
- // Expect each gateway connection created only on initial startup
- verify(mDeps)
- .newVcnGatewayConnection(
- eq(mVcnContext),
- eq(TEST_SUB_GROUP),
- eq(mSubscriptionSnapshot),
- argThat(config -> Arrays.equals(caps, config.getExposedCapabilities())),
- any());
- }
- }
-
- @Test
- public void testIgnoreNetworkRequestWhileInactive() {
- mVcn.setStatus(VCN_STATUS_CODE_INACTIVE);
-
- final NetworkRequestListener requestListener = verifyAndGetRequestListener();
- triggerVcnRequestListeners(requestListener);
-
- verify(mDeps, never()).newVcnGatewayConnection(any(), any(), any(), any(), any());
- }
}