Merge changes If2201f39,Ia1c366c5
* changes:
Stop calling Vpn#updateCapabilities in CS.
Stop accessing VPNs in checkConnectivityDiagnosticsPermissions.
diff --git a/core/java/android/net/NetworkProvider.java b/core/java/android/net/NetworkProvider.java
index d31218d..a17a498 100644
--- a/core/java/android/net/NetworkProvider.java
+++ b/core/java/android/net/NetworkProvider.java
@@ -51,13 +51,6 @@
public static final int ID_NONE = -1;
/**
- * A hardcoded ID for NetworkAgents representing VPNs. These agents are not created by any
- * provider, so they use this constant for clarity instead of NONE.
- * @hide only used by ConnectivityService.
- */
- public static final int ID_VPN = -2;
-
- /**
* The first providerId value that will be allocated.
* @hide only used by ConnectivityService.
*/
diff --git a/core/java/com/android/internal/compat/ChangeReporter.java b/core/java/com/android/internal/compat/ChangeReporter.java
index 5e886a6..60a30a0 100644
--- a/core/java/com/android/internal/compat/ChangeReporter.java
+++ b/core/java/com/android/internal/compat/ChangeReporter.java
@@ -221,7 +221,7 @@
FrameworkStatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__SOURCE__SYSTEM_SERVER;
@Retention(RetentionPolicy.SOURCE)
- @IntDef(flag = true, prefix = { "STATE_" }, value = {
+ @IntDef(prefix = { "STATE_" }, value = {
STATE_UNKNOWN_STATE,
STATE_ENABLED,
STATE_DISABLED,
@@ -231,7 +231,7 @@
}
@Retention(RetentionPolicy.SOURCE)
- @IntDef(flag = true, prefix = { "SOURCE_" }, value = {
+ @IntDef(prefix = { "SOURCE_" }, value = {
SOURCE_UNKNOWN_SOURCE,
SOURCE_APP_PROCESS,
SOURCE_SYSTEM_SERVER
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
index 5867ef6..b1b6306 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
@@ -83,8 +83,7 @@
boolean supports3DES = "true".equals(android.os.SystemProperties.get(DESEDE_SYSTEM_PROPERTY));
// java.security.KeyStore
- put("KeyStore.AndroidKeyStore", PACKAGE_NAME + ".AndroidKeyStoreSpi");
- put("Alg.Alias.KeyStore.AndroidKeyStoreLegacy", "AndroidKeyStore");
+ put("KeyStore." + providerName, PACKAGE_NAME + ".AndroidKeyStoreSpi");
// java.security.KeyPairGenerator
put("KeyPairGenerator.EC", PACKAGE_NAME + ".AndroidKeyStoreKeyPairGeneratorSpi$EC");
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index bcd722e..f056117 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -5131,7 +5131,7 @@
}
}
- private void onUserStart(int userId) {
+ private void onUserStarted(int userId) {
synchronized (mVpns) {
Vpn userVpn = mVpns.get(userId);
if (userVpn != null) {
@@ -5146,7 +5146,7 @@
}
}
- private void onUserStop(int userId) {
+ private void onUserStopped(int userId) {
synchronized (mVpns) {
Vpn userVpn = mVpns.get(userId);
if (userVpn == null) {
@@ -5257,9 +5257,9 @@
if (userId == UserHandle.USER_NULL) return;
if (Intent.ACTION_USER_STARTED.equals(action)) {
- onUserStart(userId);
+ onUserStarted(userId);
} else if (Intent.ACTION_USER_STOPPED.equals(action)) {
- onUserStop(userId);
+ onUserStopped(userId);
} else if (Intent.ACTION_USER_ADDED.equals(action)) {
onUserAdded(userId);
} else if (Intent.ACTION_USER_REMOVED.equals(action)) {
diff --git a/services/core/java/com/android/server/OWNERS b/services/core/java/com/android/server/OWNERS
index 8099f8f..3d1e709a 100644
--- a/services/core/java/com/android/server/OWNERS
+++ b/services/core/java/com/android/server/OWNERS
@@ -7,3 +7,6 @@
# Zram writeback
per-file ZramWriteback.java = minchan@google.com, rajekumar@google.com, srnvs@google.com
+
+# Userspace reboot
+per-file UserspaceRebootLogger.java = ioffe@google.com, tomcherry@google.com
diff --git a/services/core/java/com/android/server/UserspaceRebootLogger.java b/services/core/java/com/android/server/UserspaceRebootLogger.java
index 2403b63..89327b5 100644
--- a/services/core/java/com/android/server/UserspaceRebootLogger.java
+++ b/services/core/java/com/android/server/UserspaceRebootLogger.java
@@ -59,7 +59,7 @@
*/
public static void noteUserspaceRebootWasRequested() {
if (!PowerManager.isRebootingUserspaceSupportedImpl()) {
- Slog.wtf(TAG, "Userspace reboot is not supported.");
+ Slog.wtf(TAG, "noteUserspaceRebootWasRequested: Userspace reboot is not supported.");
return;
}
@@ -77,7 +77,7 @@
*/
public static void noteUserspaceRebootSuccess() {
if (!PowerManager.isRebootingUserspaceSupportedImpl()) {
- Slog.wtf(TAG, "Userspace reboot is not supported.");
+ Slog.wtf(TAG, "noteUserspaceRebootSuccess: Userspace reboot is not supported.");
return;
}
@@ -88,11 +88,11 @@
/**
* Returns {@code true} if {@code UserspaceRebootReported} atom should be logged.
*
- * <p>This call should only be made on devices supporting userspace reboot.
+ * <p>On devices that do not support userspace reboot this method will always return {@code
+ * false}.
*/
public static boolean shouldLogUserspaceRebootEvent() {
if (!PowerManager.isRebootingUserspaceSupportedImpl()) {
- Slog.wtf(TAG, "Userspace reboot is not supported.");
return false;
}
@@ -110,7 +110,7 @@
*/
public static void logEventAsync(boolean userUnlocked, Executor executor) {
if (!PowerManager.isRebootingUserspaceSupportedImpl()) {
- Slog.wtf(TAG, "Userspace reboot is not supported.");
+ Slog.wtf(TAG, "logEventAsync: Userspace reboot is not supported.");
return;
}
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 39b9294..73125c1 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -122,7 +122,6 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.math.BigInteger;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
@@ -152,36 +151,13 @@
public class Vpn {
private static final String NETWORKTYPE = "VPN";
private static final String TAG = "Vpn";
+ private static final String VPN_PROVIDER_NAME_BASE = "VpnNetworkProvider:";
private static final boolean LOGD = true;
// Length of time (in milliseconds) that an app hosting an always-on VPN is placed on
// the device idle allowlist during service launch and VPN bootstrap.
private static final long VPN_LAUNCH_IDLE_ALLOWLIST_DURATION_MS = 60 * 1000;
- // Settings for how much of the address space should be routed so that Vpn considers
- // "most" of the address space is routed. This is used to determine whether this Vpn
- // should be marked with the INTERNET capability.
- private static final long MOST_IPV4_ADDRESSES_COUNT;
- private static final BigInteger MOST_IPV6_ADDRESSES_COUNT;
- static {
- // 85% of the address space must be routed for Vpn to consider this VPN to provide
- // INTERNET access.
- final int howManyPercentIsMost = 85;
-
- final long twoPower32 = 1L << 32;
- MOST_IPV4_ADDRESSES_COUNT = twoPower32 * howManyPercentIsMost / 100;
- final BigInteger twoPower128 = BigInteger.ONE.shiftLeft(128);
- MOST_IPV6_ADDRESSES_COUNT = twoPower128
- .multiply(BigInteger.valueOf(howManyPercentIsMost))
- .divide(BigInteger.valueOf(100));
- }
- // How many routes to evaluate before bailing and declaring this Vpn should provide
- // the INTERNET capability. This is necessary because computing the address space is
- // O(n²) and this is running in the system service, so a limit is needed to alleviate
- // the risk of attack.
- // This is taken as a total of IPv4 + IPV6 routes for simplicity, but the algorithm
- // is actually O(n²)+O(n²).
- private static final int MAX_ROUTES_TO_EVALUATE = 150;
private static final String LOCKDOWN_ALLOWLIST_SETTING_NAME =
Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN_WHITELIST;
/**
@@ -198,6 +174,7 @@
// automated reconnection
private final Context mContext;
+ private final ConnectivityManager mConnectivityManager;
// The context is for specific user which is created from mUserId
private final Context mUserIdContext;
@VisibleForTesting final Dependencies mDeps;
@@ -218,6 +195,7 @@
private final INetworkManagementService mNetd;
@VisibleForTesting
protected VpnConfig mConfig;
+ private final NetworkProvider mNetworkProvider;
@VisibleForTesting
protected NetworkAgent mNetworkAgent;
private final Looper mLooper;
@@ -401,6 +379,7 @@
int userId, @NonNull KeyStore keyStore, SystemServices systemServices,
Ikev2SessionCreator ikev2SessionCreator) {
mContext = context;
+ mConnectivityManager = mContext.getSystemService(ConnectivityManager.class);
mUserIdContext = context.createContextAsUser(UserHandle.of(userId), 0 /* flags */);
mDeps = deps;
mNetd = netService;
@@ -419,6 +398,10 @@
Log.wtf(TAG, "Problem registering observer", e);
}
+ mNetworkProvider = new NetworkProvider(context, looper, VPN_PROVIDER_NAME_BASE + mUserId);
+ // This constructor is called in onUserStart and registers the provider. The provider
+ // will be unregistered in onUserStop.
+ mConnectivityManager.registerNetworkProvider(mNetworkProvider);
mLegacyState = LegacyVpnInfo.STATE_DISCONNECTED;
mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_VPN, 0 /* subtype */, NETWORKTYPE,
"" /* subtypeName */);
@@ -442,12 +425,39 @@
* Update current state, dispatching event to listeners.
*/
@VisibleForTesting
+ @GuardedBy("this")
protected void updateState(DetailedState detailedState, String reason) {
if (LOGD) Log.d(TAG, "setting state=" + detailedState + ", reason=" + reason);
mLegacyState = LegacyVpnInfo.stateFromNetworkInfo(detailedState);
mNetworkInfo.setDetailedState(detailedState, reason, null);
- if (mNetworkAgent != null) {
- mNetworkAgent.sendNetworkInfo(mNetworkInfo);
+ // TODO : only accept transitions when the agent is in the correct state (non-null for
+ // CONNECTED, DISCONNECTED and FAILED, null for CONNECTED).
+ // This will require a way for tests to pretend the VPN is connected that's not
+ // calling this method with CONNECTED.
+ // It will also require audit of where the code calls this method with DISCONNECTED
+ // with a null agent, which it was doing historically to make sure the agent is
+ // disconnected as this was a no-op if the agent was null.
+ switch (detailedState) {
+ case CONNECTED:
+ if (null != mNetworkAgent) {
+ mNetworkAgent.markConnected();
+ }
+ break;
+ case DISCONNECTED:
+ case FAILED:
+ if (null != mNetworkAgent) {
+ mNetworkAgent.unregister();
+ mNetworkAgent = null;
+ }
+ break;
+ case CONNECTING:
+ if (null != mNetworkAgent) {
+ throw new IllegalStateException("VPN can only go to CONNECTING state when"
+ + " the agent is null.");
+ }
+ break;
+ default:
+ throw new IllegalArgumentException("Illegal state argument " + detailedState);
}
updateAlwaysOnNotification(detailedState);
}
@@ -475,7 +485,7 @@
final boolean isAlwaysMetered = mIsPackageTargetingAtLeastQ && mConfig.isMetered;
applyUnderlyingCapabilities(
- mContext.getSystemService(ConnectivityManager.class),
+ mConnectivityManager,
underlyingNetworks,
mNetworkCapabilities,
isAlwaysMetered);
@@ -485,10 +495,10 @@
@VisibleForTesting
public static void applyUnderlyingCapabilities(
- ConnectivityManager cm,
- Network[] underlyingNetworks,
- NetworkCapabilities caps,
- boolean isAlwaysMetered) {
+ @NonNull final ConnectivityManager cm,
+ @Nullable final Network[] underlyingNetworks,
+ @NonNull final NetworkCapabilities caps,
+ final boolean isAlwaysMetered) {
int[] transportTypes = new int[] { NetworkCapabilities.TRANSPORT_VPN };
int downKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
int upKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
@@ -1015,7 +1025,7 @@
}
mConfig = null;
- updateState(DetailedState.IDLE, "prepare");
+ updateState(DetailedState.DISCONNECTED, "prepare");
setVpnForcedLocked(mLockdown);
} finally {
Binder.restoreCallingIdentity(token);
@@ -1251,7 +1261,7 @@
mNetworkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
mLegacyState = LegacyVpnInfo.STATE_CONNECTING;
- mNetworkInfo.setDetailedState(DetailedState.CONNECTING, null, null);
+ updateState(DetailedState.CONNECTING, "agentConnect");
NetworkAgentConfig networkAgentConfig = new NetworkAgentConfig();
networkAgentConfig.allowBypass = mConfig.allowBypass && !mLockdown;
@@ -1269,20 +1279,23 @@
mNetworkCapabilities.addCapability(NET_CAPABILITY_NOT_METERED);
}
- final long token = Binder.clearCallingIdentity();
- try {
- mNetworkAgent = new NetworkAgent(mLooper, mContext, NETWORKTYPE /* logtag */,
- mNetworkInfo, mNetworkCapabilities, lp,
- ConnectivityConstants.VPN_DEFAULT_SCORE, networkAgentConfig,
- NetworkProvider.ID_VPN) {
- @Override
- public void unwanted() {
- // We are user controlled, not driven by NetworkRequest.
- }
- };
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ mNetworkAgent = new NetworkAgent(mContext, mLooper, NETWORKTYPE /* logtag */,
+ mNetworkCapabilities, lp,
+ ConnectivityConstants.VPN_DEFAULT_SCORE, networkAgentConfig, mNetworkProvider) {
+ @Override
+ public void unwanted() {
+ // We are user controlled, not driven by NetworkRequest.
+ }
+ };
+ Binder.withCleanCallingIdentity(() -> {
+ try {
+ mNetworkAgent.register();
+ } catch (final Exception e) {
+ // If register() throws, don't keep an unregistered agent.
+ mNetworkAgent = null;
+ throw e;
+ }
+ });
mNetworkAgent.setUnderlyingNetworks((mConfig.underlyingNetworks != null)
? Arrays.asList(mConfig.underlyingNetworks) : null);
mNetworkInfo.setIsAvailable(true);
@@ -1300,19 +1313,12 @@
private void agentDisconnect(NetworkAgent networkAgent) {
if (networkAgent != null) {
- NetworkInfo networkInfo = new NetworkInfo(mNetworkInfo);
- networkInfo.setIsAvailable(false);
- networkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null);
- networkAgent.sendNetworkInfo(networkInfo);
+ networkAgent.unregister();
}
}
private void agentDisconnect() {
- if (mNetworkInfo.isConnected()) {
- mNetworkInfo.setIsAvailable(false);
- updateState(DetailedState.DISCONNECTED, "agentDisconnect");
- mNetworkAgent = null;
- }
+ updateState(DetailedState.DISCONNECTED, "agentDisconnect");
}
/**
@@ -1401,6 +1407,8 @@
&& updateLinkPropertiesInPlaceIfPossible(mNetworkAgent, oldConfig)) {
// Keep mNetworkAgent unchanged
} else {
+ // Initialize the state for a new agent, while keeping the old one connected
+ // in case this new connection fails.
mNetworkAgent = null;
updateState(DetailedState.CONNECTING, "establish");
// Set up forwarding and DNS rules.
@@ -1636,6 +1644,9 @@
// Quit any active connections
agentDisconnect();
+
+ // The provider has been registered in the constructor, which is called in onUserStart.
+ mConnectivityManager.unregisterNetworkProvider(mNetworkProvider);
}
/**
@@ -2412,7 +2423,6 @@
// When restricted to test networks, select any network with TRANSPORT_TEST. Since the
// creator of the profile and the test network creator both have MANAGE_TEST_NETWORKS,
// this is considered safe.
- final ConnectivityManager cm = ConnectivityManager.from(mContext);
final NetworkRequest req;
if (mProfile.isRestrictedToTestNetworks()) {
@@ -2431,7 +2441,7 @@
.build();
}
- cm.requestNetwork(req, mNetworkCallback);
+ mConnectivityManager.requestNetwork(req, mNetworkCallback);
}
private boolean isActiveNetwork(@Nullable Network network) {
@@ -2718,8 +2728,7 @@
resetIkeState();
- final ConnectivityManager cm = ConnectivityManager.from(mContext);
- cm.unregisterNetworkCallback(mNetworkCallback);
+ mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
mExecutor.shutdown();
}
@@ -2800,13 +2809,12 @@
mProfile = profile;
if (!TextUtils.isEmpty(mOuterInterface)) {
- final ConnectivityManager cm = ConnectivityManager.from(mContext);
- for (Network network : cm.getAllNetworks()) {
- final LinkProperties lp = cm.getLinkProperties(network);
+ for (Network network : mConnectivityManager.getAllNetworks()) {
+ final LinkProperties lp = mConnectivityManager.getLinkProperties(network);
if (lp != null && lp.getAllInterfaceNames().contains(mOuterInterface)) {
- final NetworkInfo networkInfo = cm.getNetworkInfo(network);
- if (networkInfo != null) {
- mOuterConnection.set(networkInfo.getType());
+ final NetworkInfo netInfo = mConnectivityManager.getNetworkInfo(network);
+ if (netInfo != null) {
+ mOuterConnection.set(netInfo.getType());
break;
}
}
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index cef5cb6..4563a2d 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -154,6 +154,7 @@
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
+import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -261,7 +262,13 @@
@Override
public void onStart() {
- AndroidKeyStoreProvider.install();
+ Optional<Boolean> keystore2_enabled =
+ android.sysprop.Keystore2Properties.keystore2_enabled();
+ if (keystore2_enabled.isPresent() && keystore2_enabled.get()) {
+ android.security.keystore2.AndroidKeyStoreProvider.install();
+ } else {
+ AndroidKeyStoreProvider.install();
+ }
mLockSettingsService = new LockSettingsService(getContext());
publishBinderService("lock_settings", mLockSettingsService);
}
@@ -542,7 +549,8 @@
public @NonNull ManagedProfilePasswordCache getManagedProfilePasswordCache() {
try {
- java.security.KeyStore ks = java.security.KeyStore.getInstance("AndroidKeyStore");
+ java.security.KeyStore ks = java.security.KeyStore.getInstance(
+ SyntheticPasswordCrypto.androidKeystoreProviderName());
ks.load(null);
return new ManagedProfilePasswordCache(ks, getUserManager());
} catch (Exception e) {
@@ -1284,7 +1292,8 @@
byte[] encryptedPassword = Arrays.copyOfRange(storedData, PROFILE_KEY_IV_SIZE,
storedData.length);
byte[] decryptionResult;
- java.security.KeyStore keyStore = java.security.KeyStore.getInstance("AndroidKeyStore");
+ java.security.KeyStore keyStore = java.security.KeyStore.getInstance(
+ SyntheticPasswordCrypto.androidKeystoreProviderName());
keyStore.load(null);
SecretKey decryptionKey = (SecretKey) keyStore.getKey(
LockPatternUtils.PROFILE_KEY_NAME_DECRYPT + userId, null);
@@ -1743,7 +1752,8 @@
KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES);
keyGenerator.init(new SecureRandom());
SecretKey secretKey = keyGenerator.generateKey();
- java.security.KeyStore keyStore = java.security.KeyStore.getInstance("AndroidKeyStore");
+ java.security.KeyStore keyStore = java.security.KeyStore.getInstance(
+ SyntheticPasswordCrypto.androidKeystoreProviderName());
keyStore.load(null);
try {
keyStore.setEntry(
@@ -2299,7 +2309,8 @@
private void removeKeystoreProfileKey(int targetUserId) {
Slog.i(TAG, "Remove keystore profile key for user: " + targetUserId);
try {
- java.security.KeyStore keyStore = java.security.KeyStore.getInstance("AndroidKeyStore");
+ java.security.KeyStore keyStore = java.security.KeyStore.getInstance(
+ SyntheticPasswordCrypto.androidKeystoreProviderName());
keyStore.load(null);
keyStore.deleteEntry(LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + targetUserId);
keyStore.deleteEntry(LockPatternUtils.PROFILE_KEY_NAME_DECRYPT + targetUserId);
diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordCrypto.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordCrypto.java
index 9246311..6d420a9 100644
--- a/services/core/java/com/android/server/locksettings/SyntheticPasswordCrypto.java
+++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordCrypto.java
@@ -18,6 +18,7 @@
import android.security.keystore.KeyProperties;
import android.security.keystore.KeyProtection;
+import android.security.keystore2.AndroidKeyStoreProvider;
import android.util.Slog;
import java.io.ByteArrayOutputStream;
@@ -125,7 +126,7 @@
public static byte[] decryptBlobV1(String keyAlias, byte[] blob, byte[] applicationId) {
try {
- KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
+ KeyStore keyStore = KeyStore.getInstance(androidKeystoreProviderName());
keyStore.load(null);
SecretKey decryptionKey = (SecretKey) keyStore.getKey(keyAlias, null);
@@ -140,9 +141,24 @@
}
}
+ /**
+ * TODO This function redirects keystore access to the legacy keystore during a transitional
+ * phase during which not all calling code has been adjusted to use Keystore 2.0.
+ * This can be reverted to a constant of "AndroidKeyStore" when b/171305684 is complete.
+ * The specific bug for this component is b/171305115.
+ */
+ static String androidKeystoreProviderName() {
+ if (AndroidKeyStoreProvider.isInstalled()) {
+ return "AndroidKeyStoreLegacy";
+ } else {
+ return "AndroidKeystore";
+ }
+
+ }
+
public static byte[] decryptBlob(String keyAlias, byte[] blob, byte[] applicationId) {
try {
- KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
+ KeyStore keyStore = KeyStore.getInstance(androidKeystoreProviderName());
keyStore.load(null);
SecretKey decryptionKey = (SecretKey) keyStore.getKey(keyAlias, null);
@@ -166,7 +182,7 @@
KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES);
keyGenerator.init(AES_KEY_LENGTH * 8, new SecureRandom());
SecretKey secretKey = keyGenerator.generateKey();
- KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
+ KeyStore keyStore = KeyStore.getInstance(androidKeystoreProviderName());
keyStore.load(null);
KeyProtection.Builder builder = new KeyProtection.Builder(KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
@@ -196,7 +212,7 @@
public static void destroyBlobKey(String keyAlias) {
KeyStore keyStore;
try {
- keyStore = KeyStore.getInstance("AndroidKeyStore");
+ keyStore = KeyStore.getInstance(androidKeystoreProviderName());
keyStore.load(null);
keyStore.deleteEntry(keyAlias);
Slog.i(TAG, "SP key deleted: " + keyAlias);
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorService.java b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
index c63f306..6dac6b1 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorService.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
@@ -125,7 +125,7 @@
/** Internal method for handling the auto time setting being changed. */
@VisibleForTesting
public void handleAutoTimeDetectionChanged() {
- mHandler.post(mTimeDetectorStrategy::handleAutoTimeDetectionChanged);
+ mHandler.post(mTimeDetectorStrategy::handleAutoTimeConfigChanged);
}
@Override
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
index 13f0ab6..abd4c8c 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
@@ -16,6 +16,7 @@
package com.android.server.timedetector;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.timedetector.ManualTimeSuggestion;
@@ -24,6 +25,8 @@
import android.os.TimestampedValue;
import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
/**
* The interface for the class that implements the time detection algorithm used by the
@@ -37,22 +40,41 @@
*/
public interface TimeDetectorStrategy {
- /** Process the suggested time from telephony sources. */
+ @IntDef({ ORIGIN_TELEPHONY, ORIGIN_MANUAL, ORIGIN_NETWORK })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface Origin {}
+
+ /** Used when a time value originated from a telephony signal. */
+ @Origin
+ int ORIGIN_TELEPHONY = 1;
+
+ /** Used when a time value originated from a user / manual settings. */
+ @Origin
+ int ORIGIN_MANUAL = 2;
+
+ /** Used when a time value originated from a network signal. */
+ @Origin
+ int ORIGIN_NETWORK = 3;
+
+ /** Processes the suggested time from telephony sources. */
void suggestTelephonyTime(@NonNull TelephonyTimeSuggestion timeSuggestion);
/**
- * Process the suggested manually entered time. Returns {@code false} if the suggestion was
+ * Processes the suggested manually entered time. Returns {@code false} if the suggestion was
* invalid, or the device configuration prevented the suggestion being used, {@code true} if the
* suggestion was accepted. A suggestion that is valid but does not change the time because it
* matches the current device time is considered accepted.
*/
boolean suggestManualTime(@NonNull ManualTimeSuggestion timeSuggestion);
- /** Process the suggested time from network sources. */
+ /** Processes the suggested time from network sources. */
void suggestNetworkTime(@NonNull NetworkTimeSuggestion timeSuggestion);
- /** Handle the auto-time setting being toggled on or off. */
- void handleAutoTimeDetectionChanged();
+ /**
+ * Handles the auto-time configuration changing For example, when the auto-time setting is
+ * toggled on or off.
+ */
+ void handleAutoTimeConfigChanged();
/** Dump debug information. */
void dump(@NonNull PrintWriter pw, @Nullable String[] args);
@@ -67,4 +89,38 @@
return (referenceClockMillisNow - timeValue.getReferenceTimeMillis())
+ timeValue.getValue();
}
+
+ /**
+ * Converts one of the {@code ORIGIN_} constants to a human readable string suitable for config
+ * and debug usage. Throws an {@link IllegalArgumentException} if the value is unrecognized.
+ */
+ static String originToString(@Origin int origin) {
+ switch (origin) {
+ case ORIGIN_MANUAL:
+ return "manual";
+ case ORIGIN_NETWORK:
+ return "network";
+ case ORIGIN_TELEPHONY:
+ return "telephony";
+ default:
+ throw new IllegalArgumentException("origin=" + origin);
+ }
+ }
+
+ /**
+ * Converts a human readable config string to one of the {@code ORIGIN_} constants.
+ * Throws an {@link IllegalArgumentException} if the value is unrecognized.
+ */
+ static @Origin int stringToOrigin(String originString) {
+ switch (originString) {
+ case "manual":
+ return ORIGIN_MANUAL;
+ case "network":
+ return ORIGIN_NETWORK;
+ case "telephony":
+ return ORIGIN_TELEPHONY;
+ default:
+ throw new IllegalArgumentException("originString=" + originString);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyCallbackImpl.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyCallbackImpl.java
index e06fe92..5b6de05 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyCallbackImpl.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyCallbackImpl.java
@@ -16,16 +16,21 @@
package com.android.server.timedetector;
+import static com.android.server.timedetector.TimeDetectorStrategy.stringToOrigin;
+
import android.annotation.NonNull;
import android.app.AlarmManager;
import android.content.ContentResolver;
import android.content.Context;
+import android.os.Build;
+import android.os.Environment;
import android.os.PowerManager;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.provider.Settings;
import android.util.Slog;
+import java.time.Instant;
import java.util.Objects;
/**
@@ -38,6 +43,13 @@
private static final int SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS_DEFAULT = 2 * 1000;
/**
+ * Time in the past. If automatic time suggestion is before this point, it's
+ * incorrect for sure.
+ */
+ private static final Instant TIME_LOWER_BOUND = Instant.ofEpochMilli(
+ Long.max(Environment.getRootDirectory().lastModified(), Build.TIME));
+
+ /**
* If a newly calculated system clock time and the current system clock time differs by this or
* more the system clock will actually be updated. Used to prevent the system clock being set
* for only minor differences.
@@ -48,6 +60,7 @@
@NonNull private final ContentResolver mContentResolver;
@NonNull private final PowerManager.WakeLock mWakeLock;
@NonNull private final AlarmManager mAlarmManager;
+ @NonNull private final int[] mOriginPriorities;
public TimeDetectorStrategyCallbackImpl(@NonNull Context context) {
mContext = Objects.requireNonNull(context);
@@ -62,6 +75,15 @@
mSystemClockUpdateThresholdMillis =
SystemProperties.getInt("ro.sys.time_detector_update_diff",
SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS_DEFAULT);
+
+ // TODO(b/172230856): Obtain these values from configuration.
+ String[] originStrings = { "telephony", "network" };
+ int[] origins = new int[originStrings.length];
+ for (int i = 0; i < originStrings.length; i++) {
+ int origin = stringToOrigin(originStrings[i]);
+ origins[i] = origin;
+ }
+ mOriginPriorities = origins;
}
@Override
@@ -79,6 +101,16 @@
}
@Override
+ public Instant autoTimeLowerBound() {
+ return TIME_LOWER_BOUND;
+ }
+
+ @Override
+ public int[] getAutoOriginPriorities() {
+ return mOriginPriorities;
+ }
+
+ @Override
public void acquireWakeLock() {
if (mWakeLock.isHeld()) {
Slog.wtf(TAG, "WakeLock " + mWakeLock + " already held");
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
index d447a78..36a3ddd 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
@@ -16,7 +16,8 @@
package com.android.server.timedetector;
-import android.annotation.IntDef;
+import static com.android.server.timedetector.TimeDetectorStrategy.originToString;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AlarmManager;
@@ -34,8 +35,8 @@
import com.android.server.timezonedetector.ReferenceWithHistory;
import java.io.PrintWriter;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
+import java.time.Instant;
+import java.util.Arrays;
/**
* An implementation of {@link TimeDetectorStrategy} that passes telephony and manual suggestions to
@@ -63,22 +64,6 @@
static final long MAX_UTC_TIME_AGE_MILLIS =
TELEPHONY_BUCKET_COUNT * TELEPHONY_BUCKET_SIZE_MILLIS;
- @IntDef({ ORIGIN_TELEPHONY, ORIGIN_MANUAL, ORIGIN_NETWORK })
- @Retention(RetentionPolicy.SOURCE)
- public @interface Origin {}
-
- /** Used when a time value originated from a telephony signal. */
- @Origin
- private static final int ORIGIN_TELEPHONY = 1;
-
- /** Used when a time value originated from a user / manual settings. */
- @Origin
- private static final int ORIGIN_MANUAL = 2;
-
- /** Used when a time value originated from a network signal. */
- @Origin
- private static final int ORIGIN_NETWORK = 3;
-
/**
* CLOCK_PARANOIA: The maximum difference allowed between the expected system clock time and the
* actual system clock time before a warning is logged. Used to help identify situations where
@@ -143,6 +128,21 @@
/** Returns true if automatic time detection is enabled. */
boolean isAutoTimeDetectionEnabled();
+ /**
+ * Returns a lower bound for valid automatic times. It is guaranteed to be in the past,
+ * i.e. it is unrelated to the current system clock time.
+ * It holds no other meaning; it could be related to when the device system image was built,
+ * or could be updated by a mainline module.
+ */
+ @NonNull
+ Instant autoTimeLowerBound();
+
+ /**
+ * Returns the order to look at time suggestions when automatically detecting time.
+ * See {@code #ORIGIN_} constants
+ */
+ @Origin int[] getAutoOriginPriorities();
+
/** Acquire a suitable wake lock. Must be followed by {@link #releaseWakeLock()} */
void acquireWakeLock();
@@ -177,7 +177,7 @@
@Override
public synchronized void suggestNetworkTime(@NonNull NetworkTimeSuggestion timeSuggestion) {
- if (!validateSuggestionTime(timeSuggestion.getUtcTime(), timeSuggestion)) {
+ if (!validateAutoSuggestionTime(timeSuggestion.getUtcTime(), timeSuggestion)) {
return;
}
@@ -211,9 +211,12 @@
return;
}
- // Perform validation / input filtering and record the validated suggestion against the
- // slotIndex.
- if (!validateAndStoreTelephonySuggestion(timeSuggestion)) {
+ if (!validateAutoSuggestionTime(timeSuggestion.getUtcTime(), timeSuggestion)) {
+ return;
+ }
+
+ // Perform input filtering and record the validated suggestion against the slotIndex.
+ if (!storeTelephonySuggestion(timeSuggestion)) {
return;
}
@@ -224,12 +227,12 @@
}
@Override
- public synchronized void handleAutoTimeDetectionChanged() {
+ public synchronized void handleAutoTimeConfigChanged() {
boolean enabled = mCallback.isAutoTimeDetectionEnabled();
// When automatic time detection is enabled we update the system clock instantly if we can.
// Conversely, when automatic time detection is disabled we leave the clock as it is.
if (enabled) {
- String reason = "Auto time zone detection setting enabled.";
+ String reason = "Auto time zone detection config changed.";
doAutoTimeDetection(reason);
} else {
// CLOCK_PARANOIA: We are losing "control" of the system clock so we cannot predict what
@@ -272,14 +275,9 @@
}
@GuardedBy("this")
- private boolean validateAndStoreTelephonySuggestion(
+ private boolean storeTelephonySuggestion(
@NonNull TelephonyTimeSuggestion suggestion) {
TimestampedValue<Long> newUtcTime = suggestion.getUtcTime();
- if (!validateSuggestionTime(newUtcTime, suggestion)) {
- // There's probably nothing useful we can do: elsewhere we assume that reference
- // times are in the past so just stop here.
- return false;
- }
int slotIndex = suggestion.getSlotIndex();
TelephonyTimeSuggestion previousSuggestion = mSuggestionBySlotIndex.get(slotIndex);
@@ -330,6 +328,26 @@
return true;
}
+ private boolean validateAutoSuggestionTime(
+ @NonNull TimestampedValue<Long> newUtcTime, @NonNull Object suggestion) {
+ return validateSuggestionTime(newUtcTime, suggestion)
+ && validateSuggestionAgainstLowerBound(newUtcTime, suggestion);
+ }
+
+ private boolean validateSuggestionAgainstLowerBound(
+ @NonNull TimestampedValue<Long> newUtcTime, @NonNull Object suggestion) {
+ Instant lowerBound = mCallback.autoTimeLowerBound();
+
+ // Suggestion is definitely wrong if it comes before lower time bound.
+ if (lowerBound.isAfter(Instant.ofEpochMilli(newUtcTime.getValue()))) {
+ Slog.w(LOG_TAG, "Suggestion points to time before lower bound, skipping it. "
+ + "suggestion=" + suggestion + ", lower bound=" + lowerBound);
+ return false;
+ }
+
+ return true;
+ }
+
@GuardedBy("this")
private void doAutoTimeDetection(@NonNull String detectionReason) {
if (!mCallback.isAutoTimeDetectionEnabled()) {
@@ -337,33 +355,44 @@
return;
}
- // Android devices currently prioritize any telephony over network signals. There are
- // carrier compliance tests that would need to be changed before we could ignore NITZ or
- // prefer NTP generally. This check is cheap on devices without telephony hardware.
- TelephonyTimeSuggestion bestTelephonySuggestion = findBestTelephonySuggestion();
- if (bestTelephonySuggestion != null) {
- final TimestampedValue<Long> newUtcTime = bestTelephonySuggestion.getUtcTime();
- String cause = "Found good telephony suggestion."
- + ", bestTelephonySuggestion=" + bestTelephonySuggestion
- + ", detectionReason=" + detectionReason;
- setSystemClockIfRequired(ORIGIN_TELEPHONY, newUtcTime, cause);
- return;
- }
+ // Try the different origins one at a time.
+ int[] originPriorities = mCallback.getAutoOriginPriorities();
+ for (int origin : originPriorities) {
+ TimestampedValue<Long> newUtcTime = null;
+ String cause = null;
+ if (origin == ORIGIN_TELEPHONY) {
+ TelephonyTimeSuggestion bestTelephonySuggestion = findBestTelephonySuggestion();
+ if (bestTelephonySuggestion != null) {
+ newUtcTime = bestTelephonySuggestion.getUtcTime();
+ cause = "Found good telephony suggestion."
+ + ", bestTelephonySuggestion=" + bestTelephonySuggestion
+ + ", detectionReason=" + detectionReason;
+ }
+ } else if (origin == ORIGIN_NETWORK) {
+ NetworkTimeSuggestion networkSuggestion = findLatestValidNetworkSuggestion();
+ if (networkSuggestion != null) {
+ newUtcTime = networkSuggestion.getUtcTime();
+ cause = "Found good network suggestion."
+ + ", networkSuggestion=" + networkSuggestion
+ + ", detectionReason=" + detectionReason;
+ }
+ } else {
+ Slog.w(LOG_TAG, "Unknown or unsupported origin=" + origin
+ + " in " + Arrays.toString(originPriorities)
+ + ": Skipping");
+ }
- // There is no good telephony suggestion, try network.
- NetworkTimeSuggestion networkSuggestion = findLatestValidNetworkSuggestion();
- if (networkSuggestion != null) {
- final TimestampedValue<Long> newUtcTime = networkSuggestion.getUtcTime();
- String cause = "Found good network suggestion."
- + ", networkSuggestion=" + networkSuggestion
- + ", detectionReason=" + detectionReason;
- setSystemClockIfRequired(ORIGIN_NETWORK, newUtcTime, cause);
- return;
+ // Update the system clock if a good suggestion has been found.
+ if (newUtcTime != null) {
+ setSystemClockIfRequired(origin, newUtcTime, cause);
+ return;
+ }
}
if (DBG) {
- Slog.d(LOG_TAG, "Could not determine time: No best telephony or network suggestion."
- + " detectionReason=" + detectionReason);
+ Slog.d(LOG_TAG, "Could not determine time: No suggestion found in"
+ + " originPriorities=" + Arrays.toString(originPriorities)
+ + ", detectionReason=" + detectionReason);
}
}
@@ -448,7 +477,7 @@
// Validate first.
TimestampedValue<Long> utcTime = timeSuggestion.getUtcTime();
if (!validateSuggestionUtcTime(elapsedRealtimeMillis, utcTime)) {
- Slog.w(LOG_TAG, "Existing suggestion found to be invalid "
+ Slog.w(LOG_TAG, "Existing suggestion found to be invalid"
+ " elapsedRealtimeMillis=" + elapsedRealtimeMillis
+ ", timeSuggestion=" + timeSuggestion);
return TELEPHONY_INVALID_SCORE;
@@ -497,7 +526,7 @@
if (!mCallback.isAutoTimeDetectionEnabled()) {
if (DBG) {
Slog.d(LOG_TAG, "Auto time detection is not enabled."
- + " origin=" + origin
+ + " origin=" + originToString(origin)
+ ", time=" + time
+ ", cause=" + cause);
}
@@ -507,7 +536,7 @@
if (mCallback.isAutoTimeDetectionEnabled()) {
if (DBG) {
Slog.d(LOG_TAG, "Auto time detection is enabled."
- + " origin=" + origin
+ + " origin=" + originToString(origin)
+ ", time=" + time
+ ", cause=" + cause);
}
@@ -529,7 +558,7 @@
@GuardedBy("this")
private boolean setSystemClockUnderWakeLock(
- int origin, @NonNull TimestampedValue<Long> newTime, @NonNull Object cause) {
+ @Origin int origin, @NonNull TimestampedValue<Long> newTime, @NonNull String cause) {
long elapsedRealtimeMillis = mCallback.elapsedRealtimeMillis();
boolean isOriginAutomatic = isOriginAutomatic(origin);
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 39aa60b..0d2f57e 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -3246,7 +3246,7 @@
int numTaskContainers = display.getTaskDisplayAreaCount();
for (int tdaNdx = 0; tdaNdx < numTaskContainers; tdaNdx++) {
final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
- final int numStacks = display.getStackCount();
+ final int numStacks = taskDisplayArea.getStackCount();
for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
final ActivityStack stack = taskDisplayArea.getStackAt(stackNdx);
stack.finishVoiceTask(session);
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
index 02031bc..22addf9 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
@@ -242,7 +242,7 @@
}
@Override
- public void handleAutoTimeDetectionChanged() {
+ public void handleAutoTimeConfigChanged() {
mHandleAutoTimeDetectionChangedCalled = true;
}
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
index 1be074d..c23fb80 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
@@ -16,6 +16,9 @@
package com.android.server.timedetector;
+import static com.android.server.timedetector.TimeDetectorStrategy.ORIGIN_NETWORK;
+import static com.android.server.timedetector.TimeDetectorStrategy.ORIGIN_TELEPHONY;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
@@ -25,32 +28,39 @@
import android.app.timedetector.ManualTimeSuggestion;
import android.app.timedetector.NetworkTimeSuggestion;
import android.app.timedetector.TelephonyTimeSuggestion;
-import android.icu.util.Calendar;
-import android.icu.util.GregorianCalendar;
-import android.icu.util.TimeZone;
import android.os.TimestampedValue;
import androidx.test.runner.AndroidJUnit4;
+import com.android.server.timedetector.TimeDetectorStrategy.Origin;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.time.Duration;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
@RunWith(AndroidJUnit4.class)
public class TimeDetectorStrategyImplTest {
- private static final TimestampedValue<Long> ARBITRARY_CLOCK_INITIALIZATION_INFO =
+ private static final Instant TIME_LOWER_BOUND = createUtcTime(2009, 1, 1, 12, 0, 0);
+
+ private static final TimestampedValue<Instant> ARBITRARY_CLOCK_INITIALIZATION_INFO =
new TimestampedValue<>(
123456789L /* realtimeClockMillis */,
- createUtcTime(2008, 5, 23, 12, 0, 0));
+ createUtcTime(2010, 5, 23, 12, 0, 0));
+
+ // This is the traditional ordering for time detection on Android.
+ private static final @Origin int [] PROVIDERS_PRIORITY = { ORIGIN_TELEPHONY, ORIGIN_NETWORK };
/**
* An arbitrary time, very different from the {@link #ARBITRARY_CLOCK_INITIALIZATION_INFO}
* time. Can be used as the basis for time suggestions.
*/
- private static final long ARBITRARY_TEST_TIME_MILLIS = createUtcTime(2018, 1, 1, 12, 0, 0);
+ private static final Instant ARBITRARY_TEST_TIME = createUtcTime(2018, 1, 1, 12, 0, 0);
private static final int ARBITRARY_SLOT_INDEX = 123456;
@@ -67,10 +77,10 @@
.pokeAutoTimeDetectionEnabled(true);
int slotIndex = ARBITRARY_SLOT_INDEX;
- long testTimeMillis = ARBITRARY_TEST_TIME_MILLIS;
+ Instant testTime = ARBITRARY_TEST_TIME;
TelephonyTimeSuggestion timeSuggestion =
- mScript.generateTelephonyTimeSuggestion(slotIndex, testTimeMillis);
+ mScript.generateTelephonyTimeSuggestion(slotIndex, testTime);
mScript.simulateTimePassing()
.simulateTelephonyTimeSuggestion(timeSuggestion);
@@ -106,9 +116,9 @@
// Send the first time signal. It should be used.
{
TelephonyTimeSuggestion timeSuggestion1 =
- mScript.generateTelephonyTimeSuggestion(slotIndex, ARBITRARY_TEST_TIME_MILLIS);
+ mScript.generateTelephonyTimeSuggestion(slotIndex, ARBITRARY_TEST_TIME);
- // Increment the the device clocks to simulate the passage of time.
+ // Increment the device clocks to simulate the passage of time.
mScript.simulateTimePassing(clockIncrementMillis);
long expectedSystemClockMillis1 =
@@ -157,13 +167,13 @@
// uses the lowest slotIndex when multiple telephony suggestions are available.
int slotIndex1 = ARBITRARY_SLOT_INDEX;
int slotIndex2 = ARBITRARY_SLOT_INDEX + 1;
- long slotIndex1TimeMillis = ARBITRARY_TEST_TIME_MILLIS;
- long slotIndex2TimeMillis = ARBITRARY_TEST_TIME_MILLIS + Duration.ofDays(1).toMillis();
+ Instant slotIndex1Time = ARBITRARY_TEST_TIME;
+ Instant slotIndex2Time = ARBITRARY_TEST_TIME.plus(Duration.ofDays(1));
// Make a suggestion with slotIndex2.
{
TelephonyTimeSuggestion slotIndex2TimeSuggestion =
- mScript.generateTelephonyTimeSuggestion(slotIndex2, slotIndex2TimeMillis);
+ mScript.generateTelephonyTimeSuggestion(slotIndex2, slotIndex2Time);
mScript.simulateTimePassing();
long expectedSystemClockMillis =
@@ -180,7 +190,7 @@
// Now make a different suggestion with slotIndex1.
{
TelephonyTimeSuggestion slotIndex1TimeSuggestion =
- mScript.generateTelephonyTimeSuggestion(slotIndex1, slotIndex1TimeMillis);
+ mScript.generateTelephonyTimeSuggestion(slotIndex1, slotIndex1Time);
mScript.simulateTimePassing();
long expectedSystemClockMillis =
@@ -198,7 +208,7 @@
// slotIndex1 suggestion will still "win".
{
TelephonyTimeSuggestion slotIndex2TimeSuggestion =
- mScript.generateTelephonyTimeSuggestion(slotIndex2, slotIndex2TimeMillis);
+ mScript.generateTelephonyTimeSuggestion(slotIndex2, slotIndex2Time);
mScript.simulateTimePassing();
mScript.simulateTelephonyTimeSuggestion(slotIndex2TimeSuggestion)
@@ -213,7 +223,7 @@
// is in an older "bucket".
{
TelephonyTimeSuggestion slotIndex2TimeSuggestion =
- mScript.generateTelephonyTimeSuggestion(slotIndex2, slotIndex2TimeMillis);
+ mScript.generateTelephonyTimeSuggestion(slotIndex2, slotIndex2Time);
mScript.simulateTimePassing();
long expectedSystemClockMillis =
@@ -232,7 +242,7 @@
int slotIndex = ARBITRARY_SLOT_INDEX;
TelephonyTimeSuggestion timeSuggestion =
- mScript.generateTelephonyTimeSuggestion(slotIndex, ARBITRARY_TEST_TIME_MILLIS);
+ mScript.generateTelephonyTimeSuggestion(slotIndex, ARBITRARY_TEST_TIME);
mScript.simulateTimePassing()
.simulateTelephonyTimeSuggestion(timeSuggestion)
.verifySystemClockWasNotSetAndResetCallTracking()
@@ -246,11 +256,11 @@
.pokeThresholds(systemClockUpdateThreshold)
.pokeAutoTimeDetectionEnabled(true);
- long testTimeMillis = ARBITRARY_TEST_TIME_MILLIS;
+ Instant testTime = ARBITRARY_TEST_TIME;
int slotIndex = ARBITRARY_SLOT_INDEX;
TelephonyTimeSuggestion timeSuggestion1 =
- mScript.generateTelephonyTimeSuggestion(slotIndex, testTimeMillis);
+ mScript.generateTelephonyTimeSuggestion(slotIndex, testTime);
TimestampedValue<Long> utcTime1 = timeSuggestion1.getUtcTime();
// Initialize the strategy / device with a time set from a telephony suggestion.
@@ -300,6 +310,23 @@
}
@Test
+ public void telephonyTimeSuggestion_ignoredWhenReferencedTimeIsInThePast() {
+ mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
+ .pokeAutoTimeDetectionEnabled(true);
+
+ int slotIndex = ARBITRARY_SLOT_INDEX;
+ Instant suggestedTime = TIME_LOWER_BOUND.minus(Duration.ofDays(1));
+
+ TelephonyTimeSuggestion timeSuggestion =
+ mScript.generateTelephonyTimeSuggestion(
+ slotIndex, suggestedTime);
+
+ mScript.simulateTelephonyTimeSuggestion(timeSuggestion)
+ .verifySystemClockWasNotSetAndResetCallTracking()
+ .assertLatestTelephonySuggestion(slotIndex, null);
+ }
+
+ @Test
public void testSuggestTelephonyTime_timeDetectionToggled() {
final int clockIncrementMillis = 100;
final int systemClockUpdateThreshold = 2000;
@@ -308,9 +335,9 @@
.pokeAutoTimeDetectionEnabled(false);
int slotIndex = ARBITRARY_SLOT_INDEX;
- long testTimeMillis = ARBITRARY_TEST_TIME_MILLIS;
+ Instant testTime = ARBITRARY_TEST_TIME;
TelephonyTimeSuggestion timeSuggestion1 =
- mScript.generateTelephonyTimeSuggestion(slotIndex, testTimeMillis);
+ mScript.generateTelephonyTimeSuggestion(slotIndex, testTime);
TimestampedValue<Long> utcTime1 = timeSuggestion1.getUtcTime();
// Simulate time passing.
@@ -366,9 +393,9 @@
.pokeAutoTimeDetectionEnabled(true);
int slotIndex = ARBITRARY_SLOT_INDEX;
- long testTimeMillis = ARBITRARY_TEST_TIME_MILLIS;
+ Instant testTime = ARBITRARY_TEST_TIME;
TelephonyTimeSuggestion telephonySuggestion =
- mScript.generateTelephonyTimeSuggestion(slotIndex, testTimeMillis);
+ mScript.generateTelephonyTimeSuggestion(slotIndex, testTime);
mScript.simulateTimePassing();
@@ -397,7 +424,7 @@
.pokeAutoTimeDetectionEnabled(false);
ManualTimeSuggestion timeSuggestion =
- mScript.generateManualTimeSuggestion(ARBITRARY_TEST_TIME_MILLIS);
+ mScript.generateManualTimeSuggestion(ARBITRARY_TEST_TIME);
mScript.simulateTimePassing();
@@ -416,9 +443,9 @@
int slotIndex = ARBITRARY_SLOT_INDEX;
// Simulate a telephony suggestion.
- long testTimeMillis = ARBITRARY_TEST_TIME_MILLIS;
+ Instant testTime = ARBITRARY_TEST_TIME;
TelephonyTimeSuggestion telephonyTimeSuggestion =
- mScript.generateTelephonyTimeSuggestion(slotIndex, testTimeMillis);
+ mScript.generateTelephonyTimeSuggestion(slotIndex, testTime);
// Simulate the passage of time.
mScript.simulateTimePassing();
@@ -441,9 +468,9 @@
mScript.simulateTimePassing();
// Simulate a manual suggestion 1 day different from the auto suggestion.
- long manualTimeMillis = testTimeMillis + Duration.ofDays(1).toMillis();
+ Instant manualTime = testTime.plus(Duration.ofDays(1));
ManualTimeSuggestion manualTimeSuggestion =
- mScript.generateManualTimeSuggestion(manualTimeMillis);
+ mScript.generateManualTimeSuggestion(manualTime);
mScript.simulateTimePassing();
long expectedManualClockMillis =
@@ -469,16 +496,13 @@
.assertLatestTelephonySuggestion(slotIndex, telephonyTimeSuggestion);
}
- /**
- * Manual suggestions should be ignored if auto time is enabled.
- */
@Test
- public void testSuggestManualTime_autoTimeEnabled() {
+ public void manualTimeSuggestion_isIgnored_whenAutoTimeEnabled() {
mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
.pokeAutoTimeDetectionEnabled(true);
ManualTimeSuggestion timeSuggestion =
- mScript.generateManualTimeSuggestion(ARBITRARY_TEST_TIME_MILLIS);
+ mScript.generateManualTimeSuggestion(ARBITRARY_TEST_TIME);
mScript.simulateTimePassing()
.simulateManualTimeSuggestion(timeSuggestion, false /* expectedResult */)
@@ -486,12 +510,25 @@
}
@Test
+ public void manualTimeSuggestion_ignoresTimeLowerBound() {
+ mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
+ .pokeAutoTimeDetectionEnabled(false);
+ Instant suggestedTime = TIME_LOWER_BOUND.minus(Duration.ofDays(1));
+
+ ManualTimeSuggestion timeSuggestion =
+ mScript.generateManualTimeSuggestion(suggestedTime);
+
+ mScript.simulateManualTimeSuggestion(timeSuggestion, true /* expectedResult */)
+ .verifySystemClockWasSetAndResetCallTracking(suggestedTime.toEpochMilli());
+ }
+
+ @Test
public void testSuggestNetworkTime_autoTimeEnabled() {
mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
.pokeAutoTimeDetectionEnabled(true);
NetworkTimeSuggestion timeSuggestion =
- mScript.generateNetworkTimeSuggestion(ARBITRARY_TEST_TIME_MILLIS);
+ mScript.generateNetworkTimeSuggestion(ARBITRARY_TEST_TIME);
mScript.simulateTimePassing();
@@ -507,7 +544,7 @@
.pokeAutoTimeDetectionEnabled(false);
NetworkTimeSuggestion timeSuggestion =
- mScript.generateNetworkTimeSuggestion(ARBITRARY_TEST_TIME_MILLIS);
+ mScript.generateNetworkTimeSuggestion(ARBITRARY_TEST_TIME);
mScript.simulateTimePassing()
.simulateNetworkTimeSuggestion(timeSuggestion)
@@ -520,16 +557,16 @@
.pokeAutoTimeDetectionEnabled(true);
// Three obviously different times that could not be mistaken for each other.
- long networkTimeMillis1 = ARBITRARY_TEST_TIME_MILLIS;
- long networkTimeMillis2 = ARBITRARY_TEST_TIME_MILLIS + Duration.ofDays(30).toMillis();
- long telephonyTimeMillis = ARBITRARY_TEST_TIME_MILLIS + Duration.ofDays(60).toMillis();
+ Instant networkTime1 = ARBITRARY_TEST_TIME;
+ Instant networkTime2 = ARBITRARY_TEST_TIME.plus(Duration.ofDays(30));
+ Instant telephonyTime = ARBITRARY_TEST_TIME.plus(Duration.ofDays(60));
// A small increment used to simulate the passage of time, but not enough to interfere with
// macro-level time changes associated with suggestion age.
final long smallTimeIncrementMillis = 101;
// A network suggestion is made. It should be used because there is no telephony suggestion.
NetworkTimeSuggestion networkTimeSuggestion1 =
- mScript.generateNetworkTimeSuggestion(networkTimeMillis1);
+ mScript.generateNetworkTimeSuggestion(networkTime1);
mScript.simulateTimePassing(smallTimeIncrementMillis)
.simulateNetworkTimeSuggestion(networkTimeSuggestion1)
.verifySystemClockWasSetAndResetCallTracking(
@@ -548,7 +585,7 @@
// Now a telephony suggestion is made. Telephony suggestions are prioritized over network
// suggestions so it should "win".
TelephonyTimeSuggestion telephonyTimeSuggestion =
- mScript.generateTelephonyTimeSuggestion(ARBITRARY_SLOT_INDEX, telephonyTimeMillis);
+ mScript.generateTelephonyTimeSuggestion(ARBITRARY_SLOT_INDEX, telephonyTime);
mScript.simulateTimePassing(smallTimeIncrementMillis)
.simulateTelephonyTimeSuggestion(telephonyTimeSuggestion)
.verifySystemClockWasSetAndResetCallTracking(
@@ -568,7 +605,7 @@
// Now another network suggestion is made. Telephony suggestions are prioritized over
// network suggestions so the latest telephony suggestion should still "win".
NetworkTimeSuggestion networkTimeSuggestion2 =
- mScript.generateNetworkTimeSuggestion(networkTimeMillis2);
+ mScript.generateNetworkTimeSuggestion(networkTime2);
mScript.simulateTimePassing(smallTimeIncrementMillis)
.simulateNetworkTimeSuggestion(networkTimeSuggestion2)
.verifySystemClockWasNotSetAndResetCallTracking();
@@ -612,6 +649,87 @@
assertNull(mScript.peekBestTelephonySuggestion());
}
+ @Test
+ public void networkTimeSuggestion_ignoredWhenReferencedTimeIsInThePast() {
+ mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
+ .pokeAutoTimeDetectionEnabled(true);
+
+ Instant suggestedTime = TIME_LOWER_BOUND.minus(Duration.ofDays(1));
+ NetworkTimeSuggestion timeSuggestion = mScript
+ .generateNetworkTimeSuggestion(suggestedTime);
+
+ mScript.simulateNetworkTimeSuggestion(timeSuggestion)
+ .verifySystemClockWasNotSetAndResetCallTracking()
+ .assertLatestNetworkSuggestion(null);
+ }
+
+ @Test
+ public void whenAllTimeSuggestionsAreAvailable_higherPriorityWins_lowerPriorityComesFirst() {
+ mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
+ .pokeAutoTimeDetectionEnabled(true);
+
+ Instant networkTime = ARBITRARY_TEST_TIME;
+ Instant telephonyTime = ARBITRARY_TEST_TIME.plus(Duration.ofDays(30));
+
+ NetworkTimeSuggestion networkTimeSuggestion =
+ mScript.generateNetworkTimeSuggestion(networkTime);
+ TelephonyTimeSuggestion telephonyTimeSuggestion =
+ mScript.generateTelephonyTimeSuggestion(ARBITRARY_SLOT_INDEX, telephonyTime);
+
+ mScript.simulateNetworkTimeSuggestion(networkTimeSuggestion)
+ .simulateTelephonyTimeSuggestion(telephonyTimeSuggestion)
+ .assertLatestNetworkSuggestion(networkTimeSuggestion)
+ .assertLatestTelephonySuggestion(ARBITRARY_SLOT_INDEX, telephonyTimeSuggestion)
+ .verifySystemClockWasSetAndResetCallTracking(telephonyTime.toEpochMilli());
+ }
+
+ @Test
+ public void whenAllTimeSuggestionsAreAvailable_higherPriorityWins_higherPriorityComesFirst() {
+ mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
+ .pokeAutoTimeDetectionEnabled(true);
+
+ Instant networkTime = ARBITRARY_TEST_TIME;
+ Instant telephonyTime = ARBITRARY_TEST_TIME.plus(Duration.ofDays(30));
+
+ NetworkTimeSuggestion networkTimeSuggestion =
+ mScript.generateNetworkTimeSuggestion(networkTime);
+ TelephonyTimeSuggestion telephonyTimeSuggestion =
+ mScript.generateTelephonyTimeSuggestion(ARBITRARY_SLOT_INDEX, telephonyTime);
+
+ mScript.simulateTelephonyTimeSuggestion(telephonyTimeSuggestion)
+ .simulateNetworkTimeSuggestion(networkTimeSuggestion)
+ .assertLatestNetworkSuggestion(networkTimeSuggestion)
+ .assertLatestTelephonySuggestion(ARBITRARY_SLOT_INDEX, telephonyTimeSuggestion)
+ .verifySystemClockWasSetAndResetCallTracking(telephonyTime.toEpochMilli());
+ }
+
+ @Test
+ public void whenHighestPrioritySuggestionIsNotAvailable_fallbacksToNext() {
+ mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
+ .pokeAutoTimeDetectionEnabled(true);
+
+ NetworkTimeSuggestion timeSuggestion =
+ mScript.generateNetworkTimeSuggestion(ARBITRARY_TEST_TIME);
+
+ mScript.simulateNetworkTimeSuggestion(timeSuggestion)
+ .assertLatestNetworkSuggestion(timeSuggestion)
+ .verifySystemClockWasSetAndResetCallTracking(ARBITRARY_TEST_TIME.toEpochMilli());
+ }
+
+ @Test
+ public void suggestionsFromSourceNotListedInPrioritiesList_areIgnored() {
+ mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
+ .pokeAutoTimeDetectionEnabled(true)
+ .pokeAutoOriginPriorities(new int[]{ORIGIN_TELEPHONY});
+
+ NetworkTimeSuggestion timeSuggestion = mScript.generateNetworkTimeSuggestion(
+ ARBITRARY_TEST_TIME);
+
+ mScript.simulateNetworkTimeSuggestion(timeSuggestion)
+ .assertLatestNetworkSuggestion(timeSuggestion)
+ .verifySystemClockWasNotSetAndResetCallTracking();
+ }
+
/**
* A fake implementation of TimeDetectorStrategy.Callback. Besides tracking changes and behaving
* like the real thing should, it also asserts preconditions.
@@ -622,6 +740,7 @@
private long mElapsedRealtimeMillis;
private long mSystemClockMillis;
private int mSystemClockUpdateThresholdMillis = 2000;
+ private int[] mAutoOriginPriorities = PROVIDERS_PRIORITY;
// Tracking operations.
private boolean mSystemClockWasSet;
@@ -637,6 +756,16 @@
}
@Override
+ public Instant autoTimeLowerBound() {
+ return TIME_LOWER_BOUND;
+ }
+
+ @Override
+ public int[] getAutoOriginPriorities() {
+ return mAutoOriginPriorities;
+ }
+
+ @Override
public void acquireWakeLock() {
if (mWakeLockAcquired) {
fail("Wake lock already acquired");
@@ -685,6 +814,10 @@
mAutoTimeDetectionEnabled = enabled;
}
+ void pokeAutoOriginPriorities(@Origin int[] autoOriginPriorities) {
+ mAutoOriginPriorities = autoOriginPriorities;
+ }
+
long peekElapsedRealtimeMillis() {
return mElapsedRealtimeMillis;
}
@@ -703,7 +836,10 @@
}
void verifySystemClockNotSet() {
- assertFalse(mSystemClockWasSet);
+ assertFalse(
+ String.format("System clock was manipulated and set to %s(=%s)",
+ Instant.ofEpochMilli(mSystemClockMillis), mSystemClockMillis),
+ mSystemClockWasSet);
}
void verifySystemClockWasSet(long expectedSystemClockMillis) {
@@ -739,9 +875,9 @@
return this;
}
- Script pokeFakeClocks(TimestampedValue<Long> timeInfo) {
+ Script pokeFakeClocks(TimestampedValue<Instant> timeInfo) {
mFakeCallback.pokeElapsedRealtimeMillis(timeInfo.getReferenceTimeMillis());
- mFakeCallback.pokeSystemClockMillis(timeInfo.getValue());
+ mFakeCallback.pokeSystemClockMillis(timeInfo.getValue().toEpochMilli());
return this;
}
@@ -750,6 +886,11 @@
return this;
}
+ Script pokeAutoOriginPriorities(@Origin int[] autoOriginPriorites) {
+ mFakeCallback.pokeAutoOriginPriorities(autoOriginPriorites);
+ return this;
+ }
+
long peekElapsedRealtimeMillis() {
return mFakeCallback.peekElapsedRealtimeMillis();
}
@@ -765,7 +906,13 @@
Script simulateManualTimeSuggestion(
ManualTimeSuggestion timeSuggestion, boolean expectedResult) {
- assertEquals(expectedResult, mTimeDetectorStrategy.suggestManualTime(timeSuggestion));
+ String errorMessage = expectedResult
+ ? "Manual time suggestion was ignored, but expected to be accepted."
+ : "Manual time suggestion was accepted, but expected to be ignored.";
+ assertEquals(
+ errorMessage,
+ expectedResult,
+ mTimeDetectorStrategy.suggestManualTime(timeSuggestion));
return this;
}
@@ -776,7 +923,7 @@
Script simulateAutoTimeDetectionToggle() {
mFakeCallback.simulateAutoTimeZoneDetectionToggle();
- mTimeDetectorStrategy.handleAutoTimeDetectionChanged();
+ mTimeDetectorStrategy.handleAutoTimeConfigChanged();
return this;
}
@@ -808,7 +955,10 @@
* White box test info: Asserts the latest suggestion for the slotIndex is as expected.
*/
Script assertLatestTelephonySuggestion(int slotIndex, TelephonyTimeSuggestion expected) {
- assertEquals(expected, mTimeDetectorStrategy.getLatestTelephonySuggestion(slotIndex));
+ assertEquals(
+ "Expected to see " + expected + " at slotIndex=" + slotIndex + ", but got "
+ + mTimeDetectorStrategy.getLatestTelephonySuggestion(slotIndex),
+ expected, mTimeDetectorStrategy.getLatestTelephonySuggestion(slotIndex));
return this;
}
@@ -840,9 +990,11 @@
* Generates a ManualTimeSuggestion using the current elapsed realtime clock for the
* reference time.
*/
- ManualTimeSuggestion generateManualTimeSuggestion(long timeMillis) {
+ ManualTimeSuggestion generateManualTimeSuggestion(Instant suggestedTime) {
TimestampedValue<Long> utcTime =
- new TimestampedValue<>(mFakeCallback.peekElapsedRealtimeMillis(), timeMillis);
+ new TimestampedValue<>(
+ mFakeCallback.peekElapsedRealtimeMillis(),
+ suggestedTime.toEpochMilli());
return new ManualTimeSuggestion(utcTime);
}
@@ -850,21 +1002,33 @@
* Generates a {@link TelephonyTimeSuggestion} using the current elapsed realtime clock for
* the reference time.
*/
- TelephonyTimeSuggestion generateTelephonyTimeSuggestion(int slotIndex, Long timeMillis) {
- TimestampedValue<Long> time = null;
- if (timeMillis != null) {
- time = new TimestampedValue<>(peekElapsedRealtimeMillis(), timeMillis);
- }
+ TelephonyTimeSuggestion generateTelephonyTimeSuggestion(int slotIndex, long timeMillis) {
+ TimestampedValue<Long> time =
+ new TimestampedValue<>(peekElapsedRealtimeMillis(), timeMillis);
return createTelephonyTimeSuggestion(slotIndex, time);
}
/**
+ * Generates a {@link TelephonyTimeSuggestion} using the current elapsed realtime clock for
+ * the reference time.
+ */
+ TelephonyTimeSuggestion generateTelephonyTimeSuggestion(
+ int slotIndex, Instant suggestedTime) {
+ if (suggestedTime == null) {
+ return createTelephonyTimeSuggestion(slotIndex, null);
+ }
+ return generateTelephonyTimeSuggestion(slotIndex, suggestedTime.toEpochMilli());
+ }
+
+ /**
* Generates a NetworkTimeSuggestion using the current elapsed realtime clock for the
* reference time.
*/
- NetworkTimeSuggestion generateNetworkTimeSuggestion(long timeMillis) {
+ NetworkTimeSuggestion generateNetworkTimeSuggestion(Instant suggestedTime) {
TimestampedValue<Long> utcTime =
- new TimestampedValue<>(mFakeCallback.peekElapsedRealtimeMillis(), timeMillis);
+ new TimestampedValue<>(
+ mFakeCallback.peekElapsedRealtimeMillis(),
+ suggestedTime.toEpochMilli());
return new NetworkTimeSuggestion(utcTime);
}
@@ -884,11 +1048,9 @@
.build();
}
- private static long createUtcTime(int year, int monthInYear, int day, int hourOfDay, int minute,
- int second) {
- Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("Etc/UTC"));
- cal.clear();
- cal.set(year, monthInYear - 1, day, hourOfDay, minute, second);
- return cal.getTimeInMillis();
+ private static Instant createUtcTime(int year, int monthInYear, int day, int hourOfDay,
+ int minute, int second) {
+ return LocalDateTime.of(year, monthInYear, day, hourOfDay, minute, second)
+ .toInstant(ZoneOffset.UTC);
}
}
diff --git a/tests/net/common/java/android/net/OemNetworkPreferencesTest.java b/tests/net/common/java/android/net/OemNetworkPreferencesTest.java
index b77ed6a..c9161b6 100644
--- a/tests/net/common/java/android/net/OemNetworkPreferencesTest.java
+++ b/tests/net/common/java/android/net/OemNetworkPreferencesTest.java
@@ -22,11 +22,14 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import android.os.Build;
import android.util.SparseArray;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,6 +37,7 @@
import java.util.ArrayList;
import java.util.List;
+@IgnoreUpTo(Build.VERSION_CODES.R)
@RunWith(AndroidJUnit4.class)
@SmallTest
public class OemNetworkPreferencesTest {
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index c54190a..c917e66 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -1091,6 +1091,10 @@
mMockNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN, lp,
mNetworkCapabilities);
mMockNetworkAgent.waitForIdle(TIMEOUT_MS);
+ verify(mNetworkManagementService, times(1))
+ .addVpnUidRanges(eq(mMockVpn.getNetId()), eq(uids.toArray(new UidRange[0])));
+ verify(mNetworkManagementService, never())
+ .removeVpnUidRanges(eq(mMockVpn.getNetId()), any());
mAgentRegistered = true;
mNetworkCapabilities.set(mMockNetworkAgent.getNetworkCapabilities());
mNetworkAgent = mMockNetworkAgent.getNetworkAgent();
@@ -6902,8 +6906,8 @@
final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER));
mMockVpn.establish(lp, VPN_UID, vpnRange);
- // Connected VPN should have interface rules set up. There are two expected invocations,
- // one during VPN uid update, one during VPN LinkProperties update
+ // A connected VPN should have interface rules set up. There are two expected invocations,
+ // one during the VPN initial connection, one during the VPN LinkProperties update.
ArgumentCaptor<int[]> uidCaptor = ArgumentCaptor.forClass(int[].class);
verify(mMockNetd, times(2)).firewallAddUidInterfaceRules(eq("tun0"), uidCaptor.capture());
assertContainsExactly(uidCaptor.getAllValues().get(0), APP1_UID, APP2_UID);
diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
index a553b58..e1e0efa 100644
--- a/tests/net/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/net/java/com/android/server/connectivity/VpnTest.java
@@ -41,6 +41,7 @@
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doAnswer;
@@ -86,10 +87,10 @@
import android.os.Bundle;
import android.os.ConditionVariable;
import android.os.INetworkManagementService;
-import android.os.Looper;
import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
+import android.os.test.TestLooper;
import android.provider.Settings;
import android.security.Credentials;
import android.security.KeyStore;
@@ -100,6 +101,7 @@
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.R;
+import com.android.internal.net.LegacyVpnInfo;
import com.android.internal.net.VpnConfig;
import com.android.internal.net.VpnProfile;
import com.android.server.IpSecService;
@@ -223,6 +225,8 @@
.thenReturn(mNotificationManager);
when(mContext.getSystemService(eq(Context.CONNECTIVITY_SERVICE)))
.thenReturn(mConnectivityManager);
+ when(mContext.getSystemServiceName(eq(ConnectivityManager.class)))
+ .thenReturn(Context.CONNECTIVITY_SERVICE);
when(mContext.getSystemService(eq(Context.IPSEC_SERVICE))).thenReturn(mIpSecManager);
when(mContext.getString(R.string.config_customVpnAlwaysOnDisconnectedDialogComponent))
.thenReturn(Resources.getSystem().getString(
@@ -589,7 +593,7 @@
}
@Test
- public void testNotificationShownForAlwaysOnApp() {
+ public void testNotificationShownForAlwaysOnApp() throws Exception {
final UserHandle userHandle = UserHandle.of(primaryUser.id);
final Vpn vpn = createVpn(primaryUser.id);
setMockedUsers(primaryUser);
@@ -619,7 +623,6 @@
@Test
public void testCapabilities() {
- final Vpn vpn = createVpn(primaryUser.id);
setMockedUsers(primaryUser);
final Network mobile = new Network(1);
@@ -1037,7 +1040,7 @@
when(exception.getErrorType())
.thenReturn(IkeProtocolException.ERROR_TYPE_AUTHENTICATION_FAILED);
- final Vpn vpn = startLegacyVpn(mVpnProfile);
+ final Vpn vpn = startLegacyVpn(createVpn(primaryUser.id), (mVpnProfile));
final NetworkCallback cb = triggerOnAvailableAndGetCallback();
// Wait for createIkeSession() to be called before proceeding in order to ensure consistent
@@ -1048,20 +1051,20 @@
ikeCb.onClosedExceptionally(exception);
verify(mConnectivityManager, timeout(TEST_TIMEOUT_MS)).unregisterNetworkCallback(eq(cb));
- assertEquals(DetailedState.FAILED, vpn.getNetworkInfo().getDetailedState());
+ assertEquals(LegacyVpnInfo.STATE_FAILED, vpn.getLegacyVpnInfo().state);
}
@Test
public void testStartPlatformVpnIllegalArgumentExceptionInSetup() throws Exception {
when(mIkev2SessionCreator.createIkeSession(any(), any(), any(), any(), any(), any()))
.thenThrow(new IllegalArgumentException());
- final Vpn vpn = startLegacyVpn(mVpnProfile);
+ final Vpn vpn = startLegacyVpn(createVpn(primaryUser.id), mVpnProfile);
final NetworkCallback cb = triggerOnAvailableAndGetCallback();
// Wait for createIkeSession() to be called before proceeding in order to ensure consistent
// state
verify(mConnectivityManager, timeout(TEST_TIMEOUT_MS)).unregisterNetworkCallback(eq(cb));
- assertEquals(DetailedState.FAILED, vpn.getNetworkInfo().getDetailedState());
+ assertEquals(LegacyVpnInfo.STATE_FAILED, vpn.getLegacyVpnInfo().state);
}
private void setAndVerifyAlwaysOnPackage(Vpn vpn, int uid, boolean lockdownEnabled) {
@@ -1100,8 +1103,7 @@
// a subsequent CL.
}
- public Vpn startLegacyVpn(final VpnProfile vpnProfile) throws Exception {
- final Vpn vpn = createVpn(primaryUser.id);
+ private Vpn startLegacyVpn(final Vpn vpn, final VpnProfile vpnProfile) throws Exception {
setMockedUsers(primaryUser);
// Dummy egress interface
@@ -1118,7 +1120,7 @@
@Test
public void testStartPlatformVpn() throws Exception {
- startLegacyVpn(mVpnProfile);
+ startLegacyVpn(createVpn(primaryUser.id), mVpnProfile);
// TODO: Test the Ikev2VpnRunner started up properly. Relies on utility methods added in
// a subsequent patch.
}
@@ -1153,7 +1155,7 @@
legacyRunnerReady.open();
return new Network(102);
});
- final Vpn vpn = startLegacyVpn(profile);
+ final Vpn vpn = startLegacyVpn(createVpn(primaryUser.id), profile);
final TestDeps deps = (TestDeps) vpn.mDeps;
try {
// udppsk and 1701 are the values for TYPE_L2TP_IPSEC_PSK
@@ -1287,8 +1289,13 @@
doReturn(UserHandle.of(userId)).when(asUserContext).getUser();
when(mContext.createContextAsUser(eq(UserHandle.of(userId)), anyInt()))
.thenReturn(asUserContext);
- return new Vpn(Looper.myLooper(), mContext, new TestDeps(), mNetService,
+ final TestLooper testLooper = new TestLooper();
+ final Vpn vpn = new Vpn(testLooper.getLooper(), mContext, new TestDeps(), mNetService,
userId, mKeyStore, mSystemServices, mIkev2SessionCreator);
+ verify(mConnectivityManager, times(1)).registerNetworkProvider(argThat(
+ provider -> provider.getName().contains("VpnNetworkProvider")
+ ));
+ return vpn;
}
private static void assertBlocked(Vpn vpn, int... uids) {