Merge changes I3242ad0e,I5daced20,Iefd284ae am: f1d78f17c2
Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1580104 MUST ONLY BE SUBMITTED BY AUTOMERGER Change-Id: Ibc653e7fbd0969eede95a194e2a47cd7c7d79dad
This commit is contained in:
@@ -18,6 +18,7 @@ package android.net.vcn;
|
|||||||
|
|
||||||
import android.net.LinkProperties;
|
import android.net.LinkProperties;
|
||||||
import android.net.NetworkCapabilities;
|
import android.net.NetworkCapabilities;
|
||||||
|
import android.net.vcn.IVcnStatusCallback;
|
||||||
import android.net.vcn.IVcnUnderlyingNetworkPolicyListener;
|
import android.net.vcn.IVcnUnderlyingNetworkPolicyListener;
|
||||||
import android.net.vcn.VcnConfig;
|
import android.net.vcn.VcnConfig;
|
||||||
import android.net.vcn.VcnUnderlyingNetworkPolicy;
|
import android.net.vcn.VcnUnderlyingNetworkPolicy;
|
||||||
@@ -33,4 +34,7 @@ interface IVcnManagementService {
|
|||||||
void addVcnUnderlyingNetworkPolicyListener(in IVcnUnderlyingNetworkPolicyListener listener);
|
void addVcnUnderlyingNetworkPolicyListener(in IVcnUnderlyingNetworkPolicyListener listener);
|
||||||
void removeVcnUnderlyingNetworkPolicyListener(in IVcnUnderlyingNetworkPolicyListener listener);
|
void removeVcnUnderlyingNetworkPolicyListener(in IVcnUnderlyingNetworkPolicyListener listener);
|
||||||
VcnUnderlyingNetworkPolicy getUnderlyingNetworkPolicy(in NetworkCapabilities nc, in LinkProperties lp);
|
VcnUnderlyingNetworkPolicy getUnderlyingNetworkPolicy(in NetworkCapabilities nc, in LinkProperties lp);
|
||||||
|
|
||||||
|
void registerVcnStatusCallback(in ParcelUuid subscriptionGroup, in IVcnStatusCallback callback, in String opPkgName);
|
||||||
|
void unregisterVcnStatusCallback(in IVcnStatusCallback callback);
|
||||||
}
|
}
|
||||||
|
|||||||
22
core/java/android/net/vcn/IVcnStatusCallback.aidl
Normal file
22
core/java/android/net/vcn/IVcnStatusCallback.aidl
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021, The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package android.net.vcn;
|
||||||
|
|
||||||
|
/** @hide */
|
||||||
|
interface IVcnStatusCallback {
|
||||||
|
void onEnteredSafeMode();
|
||||||
|
}
|
||||||
@@ -23,6 +23,7 @@ import android.annotation.SystemService;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.net.LinkProperties;
|
import android.net.LinkProperties;
|
||||||
import android.net.NetworkCapabilities;
|
import android.net.NetworkCapabilities;
|
||||||
|
import android.os.Binder;
|
||||||
import android.os.ParcelUuid;
|
import android.os.ParcelUuid;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.os.ServiceSpecificException;
|
import android.os.ServiceSpecificException;
|
||||||
@@ -261,6 +262,100 @@ public class VcnManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: make VcnStatusCallback @SystemApi
|
||||||
|
/**
|
||||||
|
* VcnStatusCallback is the interface for Carrier apps to receive updates for their VCNs.
|
||||||
|
*
|
||||||
|
* <p>VcnStatusCallbacks may be registered before {@link VcnConfig}s are provided for a
|
||||||
|
* subscription group.
|
||||||
|
*
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public abstract static class VcnStatusCallback {
|
||||||
|
private VcnStatusCallbackBinder mCbBinder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoked when the VCN for this Callback's subscription group enters safe mode.
|
||||||
|
*
|
||||||
|
* <p>A VCN will be put into safe mode if any of the gateway connections were unable to
|
||||||
|
* establish a connection within a system-determined timeout (while underlying networks were
|
||||||
|
* available).
|
||||||
|
*
|
||||||
|
* <p>A VCN-configuring app may opt to exit safe mode by (re)setting the VCN configuration
|
||||||
|
* via {@link #setVcnConfig(ParcelUuid, VcnConfig)}.
|
||||||
|
*/
|
||||||
|
public abstract void onEnteredSafeMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers the given callback to receive status updates for the specified subscription.
|
||||||
|
*
|
||||||
|
* <p>Callbacks can be registered for a subscription before {@link VcnConfig}s are set for it.
|
||||||
|
*
|
||||||
|
* <p>A {@link VcnStatusCallback} may only be registered for one subscription at a time. {@link
|
||||||
|
* VcnStatusCallback}s may be reused once unregistered.
|
||||||
|
*
|
||||||
|
* <p>A {@link VcnStatusCallback} will only be invoked if the registering package has carrier
|
||||||
|
* privileges for the specified subscription at the time of invocation.
|
||||||
|
*
|
||||||
|
* @param subscriptionGroup The subscription group to match for callbacks
|
||||||
|
* @param executor The {@link Executor} to be used for invoking callbacks
|
||||||
|
* @param callback The VcnStatusCallback to be registered
|
||||||
|
* @throws IllegalStateException if callback is currently registered with VcnManager
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public void registerVcnStatusCallback(
|
||||||
|
@NonNull ParcelUuid subscriptionGroup,
|
||||||
|
@NonNull Executor executor,
|
||||||
|
@NonNull VcnStatusCallback callback) {
|
||||||
|
requireNonNull(subscriptionGroup, "subscriptionGroup must not be null");
|
||||||
|
requireNonNull(executor, "executor must not be null");
|
||||||
|
requireNonNull(callback, "callback must not be null");
|
||||||
|
|
||||||
|
synchronized (callback) {
|
||||||
|
if (callback.mCbBinder != null) {
|
||||||
|
throw new IllegalStateException("callback is already registered with VcnManager");
|
||||||
|
}
|
||||||
|
callback.mCbBinder = new VcnStatusCallbackBinder(executor, callback);
|
||||||
|
|
||||||
|
try {
|
||||||
|
mService.registerVcnStatusCallback(
|
||||||
|
subscriptionGroup, callback.mCbBinder, mContext.getOpPackageName());
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
callback.mCbBinder = null;
|
||||||
|
throw e.rethrowFromSystemServer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unregisters the given callback.
|
||||||
|
*
|
||||||
|
* <p>Once unregistered, the callback will stop receiving status updates for the subscription it
|
||||||
|
* was registered with.
|
||||||
|
*
|
||||||
|
* @param callback The callback to be unregistered
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public void unregisterVcnStatusCallback(@NonNull VcnStatusCallback callback) {
|
||||||
|
requireNonNull(callback, "callback must not be null");
|
||||||
|
|
||||||
|
synchronized (callback) {
|
||||||
|
if (callback.mCbBinder == null) {
|
||||||
|
// no Binder attached to this callback, so it's not currently registered
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
mService.unregisterVcnStatusCallback(callback.mCbBinder);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
throw e.rethrowFromSystemServer();
|
||||||
|
} finally {
|
||||||
|
callback.mCbBinder = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Binder wrapper for added VcnUnderlyingNetworkPolicyListeners to receive signals from System
|
* Binder wrapper for added VcnUnderlyingNetworkPolicyListeners to receive signals from System
|
||||||
* Server.
|
* Server.
|
||||||
@@ -280,7 +375,30 @@ public class VcnManager {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPolicyChanged() {
|
public void onPolicyChanged() {
|
||||||
mExecutor.execute(() -> mListener.onPolicyChanged());
|
Binder.withCleanCallingIdentity(
|
||||||
|
() -> mExecutor.execute(() -> mListener.onPolicyChanged()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Binder wrapper for VcnStatusCallbacks to receive signals from VcnManagementService.
|
||||||
|
*
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
private class VcnStatusCallbackBinder extends IVcnStatusCallback.Stub {
|
||||||
|
@NonNull private final Executor mExecutor;
|
||||||
|
@NonNull private final VcnStatusCallback mCallback;
|
||||||
|
|
||||||
|
private VcnStatusCallbackBinder(
|
||||||
|
@NonNull Executor executor, @NonNull VcnStatusCallback callback) {
|
||||||
|
mExecutor = executor;
|
||||||
|
mCallback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEnteredSafeMode() {
|
||||||
|
Binder.withCleanCallingIdentity(
|
||||||
|
() -> mExecutor.execute(() -> mCallback.onEnteredSafeMode()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubsc
|
|||||||
import static java.util.Objects.requireNonNull;
|
import static java.util.Objects.requireNonNull;
|
||||||
|
|
||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
|
import android.annotation.Nullable;
|
||||||
import android.app.AppOpsManager;
|
import android.app.AppOpsManager;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.net.ConnectivityManager;
|
import android.net.ConnectivityManager;
|
||||||
@@ -29,6 +30,7 @@ import android.net.LinkProperties;
|
|||||||
import android.net.NetworkCapabilities;
|
import android.net.NetworkCapabilities;
|
||||||
import android.net.TelephonyNetworkSpecifier;
|
import android.net.TelephonyNetworkSpecifier;
|
||||||
import android.net.vcn.IVcnManagementService;
|
import android.net.vcn.IVcnManagementService;
|
||||||
|
import android.net.vcn.IVcnStatusCallback;
|
||||||
import android.net.vcn.IVcnUnderlyingNetworkPolicyListener;
|
import android.net.vcn.IVcnUnderlyingNetworkPolicyListener;
|
||||||
import android.net.vcn.VcnConfig;
|
import android.net.vcn.VcnConfig;
|
||||||
import android.net.vcn.VcnUnderlyingNetworkPolicy;
|
import android.net.vcn.VcnUnderlyingNetworkPolicy;
|
||||||
@@ -54,6 +56,7 @@ import android.util.Slog;
|
|||||||
import com.android.internal.annotations.GuardedBy;
|
import com.android.internal.annotations.GuardedBy;
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
import com.android.internal.annotations.VisibleForTesting.Visibility;
|
import com.android.internal.annotations.VisibleForTesting.Visibility;
|
||||||
|
import com.android.internal.util.LocationPermissionChecker;
|
||||||
import com.android.server.vcn.TelephonySubscriptionTracker;
|
import com.android.server.vcn.TelephonySubscriptionTracker;
|
||||||
import com.android.server.vcn.Vcn;
|
import com.android.server.vcn.Vcn;
|
||||||
import com.android.server.vcn.VcnContext;
|
import com.android.server.vcn.VcnContext;
|
||||||
@@ -124,6 +127,7 @@ import java.util.concurrent.TimeUnit;
|
|||||||
*
|
*
|
||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
|
// TODO(b/180451994): ensure all incoming + outgoing calls have a cleared calling identity
|
||||||
public class VcnManagementService extends IVcnManagementService.Stub {
|
public class VcnManagementService extends IVcnManagementService.Stub {
|
||||||
@NonNull private static final String TAG = VcnManagementService.class.getSimpleName();
|
@NonNull private static final String TAG = VcnManagementService.class.getSimpleName();
|
||||||
|
|
||||||
@@ -147,6 +151,9 @@ public class VcnManagementService extends IVcnManagementService.Stub {
|
|||||||
@NonNull private final TelephonySubscriptionTracker mTelephonySubscriptionTracker;
|
@NonNull private final TelephonySubscriptionTracker mTelephonySubscriptionTracker;
|
||||||
@NonNull private final VcnContext mVcnContext;
|
@NonNull private final VcnContext mVcnContext;
|
||||||
|
|
||||||
|
/** Can only be assigned when {@link #systemReady()} is called, since it uses AppOpsManager. */
|
||||||
|
@Nullable private LocationPermissionChecker mLocationPermissionChecker;
|
||||||
|
|
||||||
@GuardedBy("mLock")
|
@GuardedBy("mLock")
|
||||||
@NonNull
|
@NonNull
|
||||||
private final Map<ParcelUuid, VcnConfig> mConfigs = new ArrayMap<>();
|
private final Map<ParcelUuid, VcnConfig> mConfigs = new ArrayMap<>();
|
||||||
@@ -169,6 +176,10 @@ public class VcnManagementService extends IVcnManagementService.Stub {
|
|||||||
private final Map<IBinder, PolicyListenerBinderDeath> mRegisteredPolicyListeners =
|
private final Map<IBinder, PolicyListenerBinderDeath> mRegisteredPolicyListeners =
|
||||||
new ArrayMap<>();
|
new ArrayMap<>();
|
||||||
|
|
||||||
|
@GuardedBy("mLock")
|
||||||
|
@NonNull
|
||||||
|
private final Map<IBinder, VcnStatusCallbackInfo> mRegisteredStatusCallbacks = new ArrayMap<>();
|
||||||
|
|
||||||
@VisibleForTesting(visibility = Visibility.PRIVATE)
|
@VisibleForTesting(visibility = Visibility.PRIVATE)
|
||||||
VcnManagementService(@NonNull Context context, @NonNull Dependencies deps) {
|
VcnManagementService(@NonNull Context context, @NonNull Dependencies deps) {
|
||||||
mContext = requireNonNull(context, "Missing context");
|
mContext = requireNonNull(context, "Missing context");
|
||||||
@@ -293,8 +304,8 @@ public class VcnManagementService extends IVcnManagementService.Stub {
|
|||||||
@NonNull ParcelUuid subscriptionGroup,
|
@NonNull ParcelUuid subscriptionGroup,
|
||||||
@NonNull VcnConfig config,
|
@NonNull VcnConfig config,
|
||||||
@NonNull TelephonySubscriptionSnapshot snapshot,
|
@NonNull TelephonySubscriptionSnapshot snapshot,
|
||||||
@NonNull VcnSafemodeCallback safemodeCallback) {
|
@NonNull VcnSafeModeCallback safeModeCallback) {
|
||||||
return new Vcn(vcnContext, subscriptionGroup, config, snapshot, safemodeCallback);
|
return new Vcn(vcnContext, subscriptionGroup, config, snapshot, safeModeCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the subId indicated by the given {@link WifiInfo}. */
|
/** Gets the subId indicated by the given {@link WifiInfo}. */
|
||||||
@@ -302,6 +313,11 @@ public class VcnManagementService extends IVcnManagementService.Stub {
|
|||||||
// TODO(b/178501049): use the subId indicated by WifiInfo#getSubscriptionId
|
// TODO(b/178501049): use the subId indicated by WifiInfo#getSubscriptionId
|
||||||
return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
|
return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Creates a new LocationPermissionChecker for the provided Context. */
|
||||||
|
public LocationPermissionChecker newLocationPermissionChecker(@NonNull Context context) {
|
||||||
|
return new LocationPermissionChecker(context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Notifies the VcnManagementService that external dependencies can be set up. */
|
/** Notifies the VcnManagementService that external dependencies can be set up. */
|
||||||
@@ -309,6 +325,7 @@ public class VcnManagementService extends IVcnManagementService.Stub {
|
|||||||
mContext.getSystemService(ConnectivityManager.class)
|
mContext.getSystemService(ConnectivityManager.class)
|
||||||
.registerNetworkProvider(mNetworkProvider);
|
.registerNetworkProvider(mNetworkProvider);
|
||||||
mTelephonySubscriptionTracker.register();
|
mTelephonySubscriptionTracker.register();
|
||||||
|
mLocationPermissionChecker = mDeps.newLocationPermissionChecker(mVcnContext.getContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void enforcePrimaryUser() {
|
private void enforcePrimaryUser() {
|
||||||
@@ -440,12 +457,12 @@ public class VcnManagementService extends IVcnManagementService.Stub {
|
|||||||
// TODO(b/176939047): Support multiple VCNs active at the same time, or limit to one active
|
// TODO(b/176939047): Support multiple VCNs active at the same time, or limit to one active
|
||||||
// VCN.
|
// VCN.
|
||||||
|
|
||||||
final VcnSafemodeCallbackImpl safemodeCallback =
|
final VcnSafeModeCallbackImpl safeModeCallback =
|
||||||
new VcnSafemodeCallbackImpl(subscriptionGroup);
|
new VcnSafeModeCallbackImpl(subscriptionGroup);
|
||||||
|
|
||||||
final Vcn newInstance =
|
final Vcn newInstance =
|
||||||
mDeps.newVcn(
|
mDeps.newVcn(
|
||||||
mVcnContext, subscriptionGroup, config, mLastSnapshot, safemodeCallback);
|
mVcnContext, subscriptionGroup, config, mLastSnapshot, safeModeCallback);
|
||||||
mVcns.put(subscriptionGroup, newInstance);
|
mVcns.put(subscriptionGroup, newInstance);
|
||||||
|
|
||||||
// Now that a new VCN has started, notify all registered listeners to refresh their
|
// Now that a new VCN has started, notify all registered listeners to refresh their
|
||||||
@@ -551,6 +568,14 @@ public class VcnManagementService extends IVcnManagementService.Stub {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Get current VcnStatusCallbacks for testing purposes. */
|
||||||
|
@VisibleForTesting(visibility = Visibility.PRIVATE)
|
||||||
|
public Map<IBinder, VcnStatusCallbackInfo> getAllStatusCallbacks() {
|
||||||
|
synchronized (mLock) {
|
||||||
|
return Collections.unmodifiableMap(mRegisteredStatusCallbacks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Binder death recipient used to remove a registered policy listener. */
|
/** Binder death recipient used to remove a registered policy listener. */
|
||||||
private class PolicyListenerBinderDeath implements Binder.DeathRecipient {
|
private class PolicyListenerBinderDeath implements Binder.DeathRecipient {
|
||||||
@NonNull private final IVcnUnderlyingNetworkPolicyListener mListener;
|
@NonNull private final IVcnUnderlyingNetworkPolicyListener mListener;
|
||||||
@@ -672,22 +697,109 @@ public class VcnManagementService extends IVcnManagementService.Stub {
|
|||||||
return new VcnUnderlyingNetworkPolicy(false /* isTearDownRequested */, networkCapabilities);
|
return new VcnUnderlyingNetworkPolicy(false /* isTearDownRequested */, networkCapabilities);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Callback for signalling when a Vcn has entered Safemode. */
|
/** Binder death recipient used to remove registered VcnStatusCallbacks. */
|
||||||
public interface VcnSafemodeCallback {
|
@VisibleForTesting(visibility = Visibility.PRIVATE)
|
||||||
/** Called by a Vcn to signal that it has entered Safemode. */
|
class VcnStatusCallbackInfo implements Binder.DeathRecipient {
|
||||||
void onEnteredSafemode();
|
@NonNull final ParcelUuid mSubGroup;
|
||||||
|
@NonNull final IVcnStatusCallback mCallback;
|
||||||
|
@NonNull final String mPkgName;
|
||||||
|
final int mUid;
|
||||||
|
|
||||||
|
private VcnStatusCallbackInfo(
|
||||||
|
@NonNull ParcelUuid subGroup,
|
||||||
|
@NonNull IVcnStatusCallback callback,
|
||||||
|
@NonNull String pkgName,
|
||||||
|
int uid) {
|
||||||
|
mSubGroup = subGroup;
|
||||||
|
mCallback = callback;
|
||||||
|
mPkgName = pkgName;
|
||||||
|
mUid = uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void binderDied() {
|
||||||
|
Log.e(TAG, "app died without unregistering VcnStatusCallback");
|
||||||
|
unregisterVcnStatusCallback(mCallback);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** VcnSafemodeCallback is used by Vcns to notify VcnManagementService on entering Safemode. */
|
/** Registers the provided callback for receiving VCN status updates. */
|
||||||
private class VcnSafemodeCallbackImpl implements VcnSafemodeCallback {
|
@Override
|
||||||
|
public void registerVcnStatusCallback(
|
||||||
|
@NonNull ParcelUuid subGroup,
|
||||||
|
@NonNull IVcnStatusCallback callback,
|
||||||
|
@NonNull String opPkgName) {
|
||||||
|
final int callingUid = mDeps.getBinderCallingUid();
|
||||||
|
final long identity = Binder.clearCallingIdentity();
|
||||||
|
try {
|
||||||
|
requireNonNull(subGroup, "subGroup must not be null");
|
||||||
|
requireNonNull(callback, "callback must not be null");
|
||||||
|
requireNonNull(opPkgName, "opPkgName must not be null");
|
||||||
|
|
||||||
|
mContext.getSystemService(AppOpsManager.class).checkPackage(callingUid, opPkgName);
|
||||||
|
|
||||||
|
final IBinder cbBinder = callback.asBinder();
|
||||||
|
final VcnStatusCallbackInfo cbInfo =
|
||||||
|
new VcnStatusCallbackInfo(
|
||||||
|
subGroup, callback, opPkgName, mDeps.getBinderCallingUid());
|
||||||
|
|
||||||
|
try {
|
||||||
|
cbBinder.linkToDeath(cbInfo, 0 /* flags */);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
// Remote binder already died - don't add to mRegisteredStatusCallbacks and exit
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized (mLock) {
|
||||||
|
if (mRegisteredStatusCallbacks.containsKey(cbBinder)) {
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"Attempting to register a callback that is already in use");
|
||||||
|
}
|
||||||
|
|
||||||
|
mRegisteredStatusCallbacks.put(cbBinder, cbInfo);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
Binder.restoreCallingIdentity(identity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Unregisters the provided callback from receiving future VCN status updates. */
|
||||||
|
@Override
|
||||||
|
public void unregisterVcnStatusCallback(@NonNull IVcnStatusCallback callback) {
|
||||||
|
final long identity = Binder.clearCallingIdentity();
|
||||||
|
try {
|
||||||
|
requireNonNull(callback, "callback must not be null");
|
||||||
|
|
||||||
|
final IBinder cbBinder = callback.asBinder();
|
||||||
|
synchronized (mLock) {
|
||||||
|
VcnStatusCallbackInfo cbInfo = mRegisteredStatusCallbacks.remove(cbBinder);
|
||||||
|
|
||||||
|
if (cbInfo != null) {
|
||||||
|
cbBinder.unlinkToDeath(cbInfo, 0 /* flags */);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
Binder.restoreCallingIdentity(identity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(b/180452282): Make name more generic and implement directly with VcnManagementService
|
||||||
|
/** Callback for signalling when a Vcn has entered safe mode. */
|
||||||
|
public interface VcnSafeModeCallback {
|
||||||
|
/** Called by a Vcn to signal that it has entered safe mode. */
|
||||||
|
void onEnteredSafeMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** VcnSafeModeCallback is used by Vcns to notify VcnManagementService on entering safe mode. */
|
||||||
|
private class VcnSafeModeCallbackImpl implements VcnSafeModeCallback {
|
||||||
@NonNull private final ParcelUuid mSubGroup;
|
@NonNull private final ParcelUuid mSubGroup;
|
||||||
|
|
||||||
private VcnSafemodeCallbackImpl(@NonNull final ParcelUuid subGroup) {
|
private VcnSafeModeCallbackImpl(@NonNull final ParcelUuid subGroup) {
|
||||||
mSubGroup = Objects.requireNonNull(subGroup, "Missing subGroup");
|
mSubGroup = Objects.requireNonNull(subGroup, "Missing subGroup");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEnteredSafemode() {
|
public void onEnteredSafeMode() {
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
// Ignore if this subscription group doesn't exist anymore
|
// Ignore if this subscription group doesn't exist anymore
|
||||||
if (!mVcns.containsKey(mSubGroup)) {
|
if (!mVcns.containsKey(mSubGroup)) {
|
||||||
@@ -695,6 +807,27 @@ public class VcnManagementService extends IVcnManagementService.Stub {
|
|||||||
}
|
}
|
||||||
|
|
||||||
notifyAllPolicyListenersLocked();
|
notifyAllPolicyListenersLocked();
|
||||||
|
|
||||||
|
// Notify all registered StatusCallbacks for this subGroup
|
||||||
|
for (VcnStatusCallbackInfo cbInfo : mRegisteredStatusCallbacks.values()) {
|
||||||
|
if (!mSubGroup.equals(cbInfo.mSubGroup)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!mLastSnapshot.packageHasPermissionsForSubscriptionGroup(
|
||||||
|
mSubGroup, cbInfo.mPkgName)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mLocationPermissionChecker.checkLocationPermission(
|
||||||
|
cbInfo.mPkgName,
|
||||||
|
"VcnStatusCallback" /* featureId */,
|
||||||
|
cbInfo.mUid,
|
||||||
|
null /* message */)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Binder.withCleanCallingIdentity(() -> cbInfo.mCallback.onEnteredSafeMode());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ import android.util.Slog;
|
|||||||
|
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
import com.android.internal.annotations.VisibleForTesting.Visibility;
|
import com.android.internal.annotations.VisibleForTesting.Visibility;
|
||||||
import com.android.server.VcnManagementService.VcnSafemodeCallback;
|
import com.android.server.VcnManagementService.VcnSafeModeCallback;
|
||||||
import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
|
import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@@ -86,18 +86,18 @@ public class Vcn extends Handler {
|
|||||||
private static final int MSG_CMD_TEARDOWN = MSG_CMD_BASE;
|
private static final int MSG_CMD_TEARDOWN = MSG_CMD_BASE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Causes this VCN to immediately enter Safemode.
|
* Causes this VCN to immediately enter safe mode.
|
||||||
*
|
*
|
||||||
* <p>Upon entering Safemode, the VCN will unregister its RequestListener, tear down all of its
|
* <p>Upon entering safe mode, the VCN will unregister its RequestListener, tear down all of its
|
||||||
* VcnGatewayConnections, and notify VcnManagementService that it is in Safemode.
|
* VcnGatewayConnections, and notify VcnManagementService that it is in safe mode.
|
||||||
*/
|
*/
|
||||||
private static final int MSG_CMD_ENTER_SAFEMODE = MSG_CMD_BASE + 1;
|
private static final int MSG_CMD_ENTER_SAFE_MODE = MSG_CMD_BASE + 1;
|
||||||
|
|
||||||
@NonNull private final VcnContext mVcnContext;
|
@NonNull private final VcnContext mVcnContext;
|
||||||
@NonNull private final ParcelUuid mSubscriptionGroup;
|
@NonNull private final ParcelUuid mSubscriptionGroup;
|
||||||
@NonNull private final Dependencies mDeps;
|
@NonNull private final Dependencies mDeps;
|
||||||
@NonNull private final VcnNetworkRequestListener mRequestListener;
|
@NonNull private final VcnNetworkRequestListener mRequestListener;
|
||||||
@NonNull private final VcnSafemodeCallback mVcnSafemodeCallback;
|
@NonNull private final VcnSafeModeCallback mVcnSafeModeCallback;
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private final Map<VcnGatewayConnectionConfig, VcnGatewayConnection> mVcnGatewayConnections =
|
private final Map<VcnGatewayConnectionConfig, VcnGatewayConnection> mVcnGatewayConnections =
|
||||||
@@ -125,13 +125,13 @@ public class Vcn extends Handler {
|
|||||||
@NonNull ParcelUuid subscriptionGroup,
|
@NonNull ParcelUuid subscriptionGroup,
|
||||||
@NonNull VcnConfig config,
|
@NonNull VcnConfig config,
|
||||||
@NonNull TelephonySubscriptionSnapshot snapshot,
|
@NonNull TelephonySubscriptionSnapshot snapshot,
|
||||||
@NonNull VcnSafemodeCallback vcnSafemodeCallback) {
|
@NonNull VcnSafeModeCallback vcnSafeModeCallback) {
|
||||||
this(
|
this(
|
||||||
vcnContext,
|
vcnContext,
|
||||||
subscriptionGroup,
|
subscriptionGroup,
|
||||||
config,
|
config,
|
||||||
snapshot,
|
snapshot,
|
||||||
vcnSafemodeCallback,
|
vcnSafeModeCallback,
|
||||||
new Dependencies());
|
new Dependencies());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,13 +141,13 @@ public class Vcn extends Handler {
|
|||||||
@NonNull ParcelUuid subscriptionGroup,
|
@NonNull ParcelUuid subscriptionGroup,
|
||||||
@NonNull VcnConfig config,
|
@NonNull VcnConfig config,
|
||||||
@NonNull TelephonySubscriptionSnapshot snapshot,
|
@NonNull TelephonySubscriptionSnapshot snapshot,
|
||||||
@NonNull VcnSafemodeCallback vcnSafemodeCallback,
|
@NonNull VcnSafeModeCallback vcnSafeModeCallback,
|
||||||
@NonNull Dependencies deps) {
|
@NonNull Dependencies deps) {
|
||||||
super(Objects.requireNonNull(vcnContext, "Missing vcnContext").getLooper());
|
super(Objects.requireNonNull(vcnContext, "Missing vcnContext").getLooper());
|
||||||
mVcnContext = vcnContext;
|
mVcnContext = vcnContext;
|
||||||
mSubscriptionGroup = Objects.requireNonNull(subscriptionGroup, "Missing subscriptionGroup");
|
mSubscriptionGroup = Objects.requireNonNull(subscriptionGroup, "Missing subscriptionGroup");
|
||||||
mVcnSafemodeCallback =
|
mVcnSafeModeCallback =
|
||||||
Objects.requireNonNull(vcnSafemodeCallback, "Missing vcnSafemodeCallback");
|
Objects.requireNonNull(vcnSafeModeCallback, "Missing vcnSafeModeCallback");
|
||||||
mDeps = Objects.requireNonNull(deps, "Missing deps");
|
mDeps = Objects.requireNonNull(deps, "Missing deps");
|
||||||
mRequestListener = new VcnNetworkRequestListener();
|
mRequestListener = new VcnNetworkRequestListener();
|
||||||
|
|
||||||
@@ -216,8 +216,8 @@ public class Vcn extends Handler {
|
|||||||
case MSG_CMD_TEARDOWN:
|
case MSG_CMD_TEARDOWN:
|
||||||
handleTeardown();
|
handleTeardown();
|
||||||
break;
|
break;
|
||||||
case MSG_CMD_ENTER_SAFEMODE:
|
case MSG_CMD_ENTER_SAFE_MODE:
|
||||||
handleEnterSafemode();
|
handleEnterSafeMode();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
Slog.wtf(getLogTag(), "Unknown msg.what: " + msg.what);
|
Slog.wtf(getLogTag(), "Unknown msg.what: " + msg.what);
|
||||||
@@ -243,10 +243,10 @@ public class Vcn extends Handler {
|
|||||||
mIsActive.set(false);
|
mIsActive.set(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleEnterSafemode() {
|
private void handleEnterSafeMode() {
|
||||||
handleTeardown();
|
handleTeardown();
|
||||||
|
|
||||||
mVcnSafemodeCallback.onEnteredSafemode();
|
mVcnSafeModeCallback.onEnteredSafeMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleNetworkRequested(
|
private void handleNetworkRequested(
|
||||||
@@ -335,14 +335,14 @@ public class Vcn extends Handler {
|
|||||||
/** Callback used for passing status signals from a VcnGatewayConnection to its managing Vcn. */
|
/** Callback used for passing status signals from a VcnGatewayConnection to its managing Vcn. */
|
||||||
@VisibleForTesting(visibility = Visibility.PACKAGE)
|
@VisibleForTesting(visibility = Visibility.PACKAGE)
|
||||||
public interface VcnGatewayStatusCallback {
|
public interface VcnGatewayStatusCallback {
|
||||||
/** Called by a VcnGatewayConnection to indicate that it has entered Safemode. */
|
/** Called by a VcnGatewayConnection to indicate that it has entered safe mode. */
|
||||||
void onEnteredSafemode();
|
void onEnteredSafeMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
private class VcnGatewayStatusCallbackImpl implements VcnGatewayStatusCallback {
|
private class VcnGatewayStatusCallbackImpl implements VcnGatewayStatusCallback {
|
||||||
@Override
|
@Override
|
||||||
public void onEnteredSafemode() {
|
public void onEnteredSafeMode() {
|
||||||
sendMessage(obtainMessage(MSG_CMD_ENTER_SAFEMODE));
|
sendMessage(obtainMessage(MSG_CMD_ENTER_SAFE_MODE));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -418,13 +418,13 @@ public class VcnGatewayConnection extends StateMachine {
|
|||||||
private static final int EVENT_SUBSCRIPTIONS_CHANGED = 9;
|
private static final int EVENT_SUBSCRIPTIONS_CHANGED = 9;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sent when this VcnGatewayConnection has entered Safemode.
|
* Sent when this VcnGatewayConnection has entered safe mode.
|
||||||
*
|
*
|
||||||
* <p>A VcnGatewayConnection enters Safemode when it takes over {@link
|
* <p>A VcnGatewayConnection enters safe mode when it takes over {@link
|
||||||
* #SAFEMODE_TIMEOUT_SECONDS} to enter {@link ConnectedState}.
|
* #SAFEMODE_TIMEOUT_SECONDS} to enter {@link ConnectedState}.
|
||||||
*
|
*
|
||||||
* <p>When a VcnGatewayConnection enters safe mode, it will fire {@link
|
* <p>When a VcnGatewayConnection enters safe mode, it will fire {@link
|
||||||
* VcnGatewayStatusCallback#onEnteredSafemode()} to notify its Vcn. The Vcn will then shut down
|
* VcnGatewayStatusCallback#onEnteredSafeMode()} to notify its Vcn. The Vcn will then shut down
|
||||||
* its VcnGatewayConnectin(s).
|
* its VcnGatewayConnectin(s).
|
||||||
*
|
*
|
||||||
* <p>Relevant in DisconnectingState, ConnectingState, ConnectedState (if the Vcn Network is not
|
* <p>Relevant in DisconnectingState, ConnectingState, ConnectedState (if the Vcn Network is not
|
||||||
@@ -432,7 +432,7 @@ public class VcnGatewayConnection extends StateMachine {
|
|||||||
*
|
*
|
||||||
* @param arg1 The "all" token; this signal is always honored.
|
* @param arg1 The "all" token; this signal is always honored.
|
||||||
*/
|
*/
|
||||||
private static final int EVENT_SAFEMODE_TIMEOUT_EXCEEDED = 10;
|
private static final int EVENT_SAFE_MODE_TIMEOUT_EXCEEDED = 10;
|
||||||
|
|
||||||
@VisibleForTesting(visibility = Visibility.PRIVATE)
|
@VisibleForTesting(visibility = Visibility.PRIVATE)
|
||||||
@NonNull
|
@NonNull
|
||||||
@@ -551,7 +551,7 @@ public class VcnGatewayConnection extends StateMachine {
|
|||||||
@Nullable private WakeupMessage mTeardownTimeoutAlarm;
|
@Nullable private WakeupMessage mTeardownTimeoutAlarm;
|
||||||
@Nullable private WakeupMessage mDisconnectRequestAlarm;
|
@Nullable private WakeupMessage mDisconnectRequestAlarm;
|
||||||
@Nullable private WakeupMessage mRetryTimeoutAlarm;
|
@Nullable private WakeupMessage mRetryTimeoutAlarm;
|
||||||
@Nullable private WakeupMessage mSafemodeTimeoutAlarm;
|
@Nullable private WakeupMessage mSafeModeTimeoutAlarm;
|
||||||
|
|
||||||
public VcnGatewayConnection(
|
public VcnGatewayConnection(
|
||||||
@NonNull VcnContext vcnContext,
|
@NonNull VcnContext vcnContext,
|
||||||
@@ -638,7 +638,7 @@ public class VcnGatewayConnection extends StateMachine {
|
|||||||
cancelTeardownTimeoutAlarm();
|
cancelTeardownTimeoutAlarm();
|
||||||
cancelDisconnectRequestAlarm();
|
cancelDisconnectRequestAlarm();
|
||||||
cancelRetryTimeoutAlarm();
|
cancelRetryTimeoutAlarm();
|
||||||
cancelSafemodeAlarm();
|
cancelSafeModeAlarm();
|
||||||
|
|
||||||
mUnderlyingNetworkTracker.teardown();
|
mUnderlyingNetworkTracker.teardown();
|
||||||
}
|
}
|
||||||
@@ -928,27 +928,27 @@ public class VcnGatewayConnection extends StateMachine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting(visibility = Visibility.PRIVATE)
|
@VisibleForTesting(visibility = Visibility.PRIVATE)
|
||||||
void setSafemodeAlarm() {
|
void setSafeModeAlarm() {
|
||||||
// Only schedule a NEW alarm if none is already set.
|
// Only schedule a NEW alarm if none is already set.
|
||||||
if (mSafemodeTimeoutAlarm != null) {
|
if (mSafeModeTimeoutAlarm != null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final Message delayedMessage = obtainMessage(EVENT_SAFEMODE_TIMEOUT_EXCEEDED, TOKEN_ALL);
|
final Message delayedMessage = obtainMessage(EVENT_SAFE_MODE_TIMEOUT_EXCEEDED, TOKEN_ALL);
|
||||||
mSafemodeTimeoutAlarm =
|
mSafeModeTimeoutAlarm =
|
||||||
createScheduledAlarm(
|
createScheduledAlarm(
|
||||||
SAFEMODE_TIMEOUT_ALARM,
|
SAFEMODE_TIMEOUT_ALARM,
|
||||||
delayedMessage,
|
delayedMessage,
|
||||||
TimeUnit.SECONDS.toMillis(SAFEMODE_TIMEOUT_SECONDS));
|
TimeUnit.SECONDS.toMillis(SAFEMODE_TIMEOUT_SECONDS));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void cancelSafemodeAlarm() {
|
private void cancelSafeModeAlarm() {
|
||||||
if (mSafemodeTimeoutAlarm != null) {
|
if (mSafeModeTimeoutAlarm != null) {
|
||||||
mSafemodeTimeoutAlarm.cancel();
|
mSafeModeTimeoutAlarm.cancel();
|
||||||
mSafemodeTimeoutAlarm = null;
|
mSafeModeTimeoutAlarm = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
removeEqualMessages(EVENT_SAFEMODE_TIMEOUT_EXCEEDED);
|
removeEqualMessages(EVENT_SAFE_MODE_TIMEOUT_EXCEEDED);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sessionLost(int token, @Nullable Exception exception) {
|
private void sessionLost(int token, @Nullable Exception exception) {
|
||||||
@@ -1125,7 +1125,7 @@ public class VcnGatewayConnection extends StateMachine {
|
|||||||
Slog.wtf(TAG, "Active IKE Session or NetworkAgent in DisconnectedState");
|
Slog.wtf(TAG, "Active IKE Session or NetworkAgent in DisconnectedState");
|
||||||
}
|
}
|
||||||
|
|
||||||
cancelSafemodeAlarm();
|
cancelSafeModeAlarm();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -1153,7 +1153,7 @@ public class VcnGatewayConnection extends StateMachine {
|
|||||||
@Override
|
@Override
|
||||||
protected void exitState() {
|
protected void exitState() {
|
||||||
// Safe to blindly set up, as it is cancelled and cleared on entering this state
|
// Safe to blindly set up, as it is cancelled and cleared on entering this state
|
||||||
setSafemodeAlarm();
|
setSafeModeAlarm();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1245,9 +1245,9 @@ public class VcnGatewayConnection extends StateMachine {
|
|||||||
transitionTo(mDisconnectedState);
|
transitionTo(mDisconnectedState);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case EVENT_SAFEMODE_TIMEOUT_EXCEEDED:
|
case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED:
|
||||||
mGatewayStatusCallback.onEnteredSafemode();
|
mGatewayStatusCallback.onEnteredSafeMode();
|
||||||
mSafemodeTimeoutAlarm = null;
|
mSafeModeTimeoutAlarm = null;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
logUnhandledMessage(msg);
|
logUnhandledMessage(msg);
|
||||||
@@ -1331,9 +1331,9 @@ public class VcnGatewayConnection extends StateMachine {
|
|||||||
case EVENT_DISCONNECT_REQUESTED:
|
case EVENT_DISCONNECT_REQUESTED:
|
||||||
handleDisconnectRequested(((EventDisconnectRequestedInfo) msg.obj).reason);
|
handleDisconnectRequested(((EventDisconnectRequestedInfo) msg.obj).reason);
|
||||||
break;
|
break;
|
||||||
case EVENT_SAFEMODE_TIMEOUT_EXCEEDED:
|
case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED:
|
||||||
mGatewayStatusCallback.onEnteredSafemode();
|
mGatewayStatusCallback.onEnteredSafeMode();
|
||||||
mSafemodeTimeoutAlarm = null;
|
mSafeModeTimeoutAlarm = null;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
logUnhandledMessage(msg);
|
logUnhandledMessage(msg);
|
||||||
@@ -1399,7 +1399,7 @@ public class VcnGatewayConnection extends StateMachine {
|
|||||||
|
|
||||||
// Validated connection, clear failed attempt counter
|
// Validated connection, clear failed attempt counter
|
||||||
mFailedAttempts = 0;
|
mFailedAttempts = 0;
|
||||||
cancelSafemodeAlarm();
|
cancelSafeModeAlarm();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void applyTransform(
|
protected void applyTransform(
|
||||||
@@ -1517,9 +1517,9 @@ public class VcnGatewayConnection extends StateMachine {
|
|||||||
case EVENT_DISCONNECT_REQUESTED:
|
case EVENT_DISCONNECT_REQUESTED:
|
||||||
handleDisconnectRequested(((EventDisconnectRequestedInfo) msg.obj).reason);
|
handleDisconnectRequested(((EventDisconnectRequestedInfo) msg.obj).reason);
|
||||||
break;
|
break;
|
||||||
case EVENT_SAFEMODE_TIMEOUT_EXCEEDED:
|
case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED:
|
||||||
mGatewayStatusCallback.onEnteredSafemode();
|
mGatewayStatusCallback.onEnteredSafeMode();
|
||||||
mSafemodeTimeoutAlarm = null;
|
mSafeModeTimeoutAlarm = null;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
logUnhandledMessage(msg);
|
logUnhandledMessage(msg);
|
||||||
@@ -1575,7 +1575,7 @@ public class VcnGatewayConnection extends StateMachine {
|
|||||||
protected void exitState() {
|
protected void exitState() {
|
||||||
// Attempt to set the safe mode alarm - this requires the Vcn Network being validated
|
// Attempt to set the safe mode alarm - this requires the Vcn Network being validated
|
||||||
// while in ConnectedState (which cancels the previous alarm)
|
// while in ConnectedState (which cancels the previous alarm)
|
||||||
setSafemodeAlarm();
|
setSafeModeAlarm();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1623,9 +1623,9 @@ public class VcnGatewayConnection extends StateMachine {
|
|||||||
case EVENT_DISCONNECT_REQUESTED:
|
case EVENT_DISCONNECT_REQUESTED:
|
||||||
handleDisconnectRequested(((EventDisconnectRequestedInfo) msg.obj).reason);
|
handleDisconnectRequested(((EventDisconnectRequestedInfo) msg.obj).reason);
|
||||||
break;
|
break;
|
||||||
case EVENT_SAFEMODE_TIMEOUT_EXCEEDED:
|
case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED:
|
||||||
mGatewayStatusCallback.onEnteredSafemode();
|
mGatewayStatusCallback.onEnteredSafeMode();
|
||||||
mSafemodeTimeoutAlarm = null;
|
mSafeModeTimeoutAlarm = null;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
logUnhandledMessage(msg);
|
logUnhandledMessage(msg);
|
||||||
|
|||||||
@@ -26,24 +26,30 @@ import static org.mockito.Mockito.any;
|
|||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.never;
|
import static org.mockito.Mockito.never;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.net.LinkProperties;
|
import android.net.LinkProperties;
|
||||||
import android.net.NetworkCapabilities;
|
import android.net.NetworkCapabilities;
|
||||||
|
import android.net.vcn.VcnManager.VcnStatusCallback;
|
||||||
import android.net.vcn.VcnManager.VcnUnderlyingNetworkPolicyListener;
|
import android.net.vcn.VcnManager.VcnUnderlyingNetworkPolicyListener;
|
||||||
|
import android.os.ParcelUuid;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mockito.ArgumentCaptor;
|
import org.mockito.ArgumentCaptor;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
public class VcnManagerTest {
|
public class VcnManagerTest {
|
||||||
|
private static final ParcelUuid SUB_GROUP = new ParcelUuid(new UUID(0, 0));
|
||||||
private static final Executor INLINE_EXECUTOR = Runnable::run;
|
private static final Executor INLINE_EXECUTOR = Runnable::run;
|
||||||
|
|
||||||
private IVcnManagementService mMockVcnManagementService;
|
private IVcnManagementService mMockVcnManagementService;
|
||||||
private VcnUnderlyingNetworkPolicyListener mMockPolicyListener;
|
private VcnUnderlyingNetworkPolicyListener mMockPolicyListener;
|
||||||
|
private VcnStatusCallback mMockStatusCallback;
|
||||||
|
|
||||||
private Context mContext;
|
private Context mContext;
|
||||||
private VcnManager mVcnManager;
|
private VcnManager mVcnManager;
|
||||||
@@ -52,6 +58,7 @@ public class VcnManagerTest {
|
|||||||
public void setUp() {
|
public void setUp() {
|
||||||
mMockVcnManagementService = mock(IVcnManagementService.class);
|
mMockVcnManagementService = mock(IVcnManagementService.class);
|
||||||
mMockPolicyListener = mock(VcnUnderlyingNetworkPolicyListener.class);
|
mMockPolicyListener = mock(VcnUnderlyingNetworkPolicyListener.class);
|
||||||
|
mMockStatusCallback = mock(VcnStatusCallback.class);
|
||||||
|
|
||||||
mContext = getContext();
|
mContext = getContext();
|
||||||
mVcnManager = new VcnManager(mContext, mMockVcnManagementService);
|
mVcnManager = new VcnManager(mContext, mMockVcnManagementService);
|
||||||
@@ -132,4 +139,60 @@ public class VcnManagerTest {
|
|||||||
public void testGetUnderlyingNetworkPolicyNullLinkProperties() throws Exception {
|
public void testGetUnderlyingNetworkPolicyNullLinkProperties() throws Exception {
|
||||||
mVcnManager.getUnderlyingNetworkPolicy(new NetworkCapabilities(), null);
|
mVcnManager.getUnderlyingNetworkPolicy(new NetworkCapabilities(), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRegisterVcnStatusCallback() throws Exception {
|
||||||
|
mVcnManager.registerVcnStatusCallback(SUB_GROUP, INLINE_EXECUTOR, mMockStatusCallback);
|
||||||
|
|
||||||
|
ArgumentCaptor<IVcnStatusCallback> captor =
|
||||||
|
ArgumentCaptor.forClass(IVcnStatusCallback.class);
|
||||||
|
verify(mMockVcnManagementService)
|
||||||
|
.registerVcnStatusCallback(eq(SUB_GROUP), captor.capture(), any());
|
||||||
|
|
||||||
|
IVcnStatusCallback callbackWrapper = captor.getValue();
|
||||||
|
callbackWrapper.onEnteredSafeMode();
|
||||||
|
verify(mMockStatusCallback).onEnteredSafeMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalStateException.class)
|
||||||
|
public void testRegisterVcnStatusCallbackAlreadyRegistered() throws Exception {
|
||||||
|
mVcnManager.registerVcnStatusCallback(SUB_GROUP, INLINE_EXECUTOR, mMockStatusCallback);
|
||||||
|
mVcnManager.registerVcnStatusCallback(SUB_GROUP, INLINE_EXECUTOR, mMockStatusCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = NullPointerException.class)
|
||||||
|
public void testRegisterVcnStatusCallbackNullSubscriptionGroup() throws Exception {
|
||||||
|
mVcnManager.registerVcnStatusCallback(null, INLINE_EXECUTOR, mMockStatusCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = NullPointerException.class)
|
||||||
|
public void testRegisterVcnStatusCallbackNullExecutor() throws Exception {
|
||||||
|
mVcnManager.registerVcnStatusCallback(SUB_GROUP, null, mMockStatusCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = NullPointerException.class)
|
||||||
|
public void testRegisterVcnStatusCallbackNullCallback() throws Exception {
|
||||||
|
mVcnManager.registerVcnStatusCallback(SUB_GROUP, INLINE_EXECUTOR, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUnregisterVcnStatusCallback() throws Exception {
|
||||||
|
mVcnManager.registerVcnStatusCallback(SUB_GROUP, INLINE_EXECUTOR, mMockStatusCallback);
|
||||||
|
|
||||||
|
mVcnManager.unregisterVcnStatusCallback(mMockStatusCallback);
|
||||||
|
|
||||||
|
verify(mMockVcnManagementService).unregisterVcnStatusCallback(any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUnregisterUnknownVcnStatusCallback() throws Exception {
|
||||||
|
mVcnManager.unregisterVcnStatusCallback(mMockStatusCallback);
|
||||||
|
|
||||||
|
verifyNoMoreInteractions(mMockVcnManagementService);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = NullPointerException.class)
|
||||||
|
public void testUnregisterNullVcnStatusCallback() throws Exception {
|
||||||
|
mVcnManager.unregisterVcnStatusCallback(null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import static com.android.server.vcn.VcnTestUtils.setupSystemService;
|
|||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
import static org.junit.Assert.assertNull;
|
import static org.junit.Assert.assertNull;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
@@ -42,9 +43,11 @@ import static org.mockito.Mockito.doThrow;
|
|||||||
import static org.mockito.Mockito.eq;
|
import static org.mockito.Mockito.eq;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.never;
|
import static org.mockito.Mockito.never;
|
||||||
|
import static org.mockito.Mockito.times;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.annotation.NonNull;
|
||||||
import android.app.AppOpsManager;
|
import android.app.AppOpsManager;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.net.ConnectivityManager;
|
import android.net.ConnectivityManager;
|
||||||
@@ -52,6 +55,7 @@ import android.net.LinkProperties;
|
|||||||
import android.net.NetworkCapabilities;
|
import android.net.NetworkCapabilities;
|
||||||
import android.net.NetworkCapabilities.Transport;
|
import android.net.NetworkCapabilities.Transport;
|
||||||
import android.net.TelephonyNetworkSpecifier;
|
import android.net.TelephonyNetworkSpecifier;
|
||||||
|
import android.net.vcn.IVcnStatusCallback;
|
||||||
import android.net.vcn.IVcnUnderlyingNetworkPolicyListener;
|
import android.net.vcn.IVcnUnderlyingNetworkPolicyListener;
|
||||||
import android.net.vcn.VcnConfig;
|
import android.net.vcn.VcnConfig;
|
||||||
import android.net.vcn.VcnConfigTest;
|
import android.net.vcn.VcnConfigTest;
|
||||||
@@ -70,7 +74,9 @@ import android.telephony.TelephonyManager;
|
|||||||
import androidx.test.filters.SmallTest;
|
import androidx.test.filters.SmallTest;
|
||||||
import androidx.test.runner.AndroidJUnit4;
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
import com.android.server.VcnManagementService.VcnSafemodeCallback;
|
import com.android.internal.util.LocationPermissionChecker;
|
||||||
|
import com.android.server.VcnManagementService.VcnSafeModeCallback;
|
||||||
|
import com.android.server.VcnManagementService.VcnStatusCallbackInfo;
|
||||||
import com.android.server.vcn.TelephonySubscriptionTracker;
|
import com.android.server.vcn.TelephonySubscriptionTracker;
|
||||||
import com.android.server.vcn.Vcn;
|
import com.android.server.vcn.Vcn;
|
||||||
import com.android.server.vcn.VcnContext;
|
import com.android.server.vcn.VcnContext;
|
||||||
@@ -147,14 +153,17 @@ public class VcnManagementServiceTest {
|
|||||||
mock(PersistableBundleUtils.LockingReadWriteHelper.class);
|
mock(PersistableBundleUtils.LockingReadWriteHelper.class);
|
||||||
private final TelephonySubscriptionTracker mSubscriptionTracker =
|
private final TelephonySubscriptionTracker mSubscriptionTracker =
|
||||||
mock(TelephonySubscriptionTracker.class);
|
mock(TelephonySubscriptionTracker.class);
|
||||||
|
private final LocationPermissionChecker mLocationPermissionChecker =
|
||||||
|
mock(LocationPermissionChecker.class);
|
||||||
|
|
||||||
private final ArgumentCaptor<VcnSafemodeCallback> mSafemodeCallbackCaptor =
|
private final ArgumentCaptor<VcnSafeModeCallback> mSafeModeCallbackCaptor =
|
||||||
ArgumentCaptor.forClass(VcnSafemodeCallback.class);
|
ArgumentCaptor.forClass(VcnSafeModeCallback.class);
|
||||||
|
|
||||||
private final VcnManagementService mVcnMgmtSvc;
|
private final VcnManagementService mVcnMgmtSvc;
|
||||||
|
|
||||||
private final IVcnUnderlyingNetworkPolicyListener mMockPolicyListener =
|
private final IVcnUnderlyingNetworkPolicyListener mMockPolicyListener =
|
||||||
mock(IVcnUnderlyingNetworkPolicyListener.class);
|
mock(IVcnUnderlyingNetworkPolicyListener.class);
|
||||||
|
private final IVcnStatusCallback mMockStatusCallback = mock(IVcnStatusCallback.class);
|
||||||
private final IBinder mMockIBinder = mock(IBinder.class);
|
private final IBinder mMockIBinder = mock(IBinder.class);
|
||||||
|
|
||||||
public VcnManagementServiceTest() throws Exception {
|
public VcnManagementServiceTest() throws Exception {
|
||||||
@@ -171,6 +180,7 @@ public class VcnManagementServiceTest {
|
|||||||
|
|
||||||
doReturn(TEST_PACKAGE_NAME).when(mMockContext).getOpPackageName();
|
doReturn(TEST_PACKAGE_NAME).when(mMockContext).getOpPackageName();
|
||||||
|
|
||||||
|
doReturn(mMockContext).when(mVcnContext).getContext();
|
||||||
doReturn(mTestLooper.getLooper()).when(mMockDeps).getLooper();
|
doReturn(mTestLooper.getLooper()).when(mMockDeps).getLooper();
|
||||||
doReturn(TEST_UID).when(mMockDeps).getBinderCallingUid();
|
doReturn(TEST_UID).when(mMockDeps).getBinderCallingUid();
|
||||||
doReturn(mVcnContext)
|
doReturn(mVcnContext)
|
||||||
@@ -188,6 +198,9 @@ public class VcnManagementServiceTest {
|
|||||||
doReturn(mConfigReadWriteHelper)
|
doReturn(mConfigReadWriteHelper)
|
||||||
.when(mMockDeps)
|
.when(mMockDeps)
|
||||||
.newPersistableBundleLockingReadWriteHelper(any());
|
.newPersistableBundleLockingReadWriteHelper(any());
|
||||||
|
doReturn(mLocationPermissionChecker)
|
||||||
|
.when(mMockDeps)
|
||||||
|
.newLocationPermissionChecker(eq(mMockContext));
|
||||||
|
|
||||||
// Setup VCN instance generation
|
// Setup VCN instance generation
|
||||||
doAnswer((invocation) -> {
|
doAnswer((invocation) -> {
|
||||||
@@ -206,6 +219,7 @@ public class VcnManagementServiceTest {
|
|||||||
mVcnMgmtSvc = new VcnManagementService(mMockContext, mMockDeps);
|
mVcnMgmtSvc = new VcnManagementService(mMockContext, mMockDeps);
|
||||||
|
|
||||||
doReturn(mMockIBinder).when(mMockPolicyListener).asBinder();
|
doReturn(mMockIBinder).when(mMockPolicyListener).asBinder();
|
||||||
|
doReturn(mMockIBinder).when(mMockStatusCallback).asBinder();
|
||||||
|
|
||||||
// Make sure the profiles are loaded.
|
// Make sure the profiles are loaded.
|
||||||
mTestLooper.dispatchAll();
|
mTestLooper.dispatchAll();
|
||||||
@@ -707,24 +721,138 @@ public class VcnManagementServiceTest {
|
|||||||
verify(mMockPolicyListener).onPolicyChanged();
|
verify(mMockPolicyListener).onPolicyChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
private void verifyVcnSafeModeCallback(
|
||||||
public void testVcnSafemodeCallbackOnEnteredSafemode() throws Exception {
|
@NonNull ParcelUuid subGroup, @NonNull TelephonySubscriptionSnapshot snapshot)
|
||||||
TelephonySubscriptionSnapshot snapshot =
|
throws Exception {
|
||||||
triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_1));
|
|
||||||
verify(mMockDeps)
|
verify(mMockDeps)
|
||||||
.newVcn(
|
.newVcn(
|
||||||
eq(mVcnContext),
|
eq(mVcnContext),
|
||||||
eq(TEST_UUID_1),
|
eq(subGroup),
|
||||||
eq(TEST_VCN_CONFIG),
|
eq(TEST_VCN_CONFIG),
|
||||||
eq(snapshot),
|
eq(snapshot),
|
||||||
mSafemodeCallbackCaptor.capture());
|
mSafeModeCallbackCaptor.capture());
|
||||||
|
|
||||||
mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
|
mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
|
||||||
|
|
||||||
VcnSafemodeCallback safemodeCallback = mSafemodeCallbackCaptor.getValue();
|
VcnSafeModeCallback safeModeCallback = mSafeModeCallbackCaptor.getValue();
|
||||||
safemodeCallback.onEnteredSafemode();
|
safeModeCallback.onEnteredSafeMode();
|
||||||
|
|
||||||
assertFalse(mVcnMgmtSvc.getAllVcns().get(TEST_UUID_1).isActive());
|
|
||||||
verify(mMockPolicyListener).onPolicyChanged();
|
verify(mMockPolicyListener).onPolicyChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testVcnSafeModeCallbackOnEnteredSafeMode() throws Exception {
|
||||||
|
TelephonySubscriptionSnapshot snapshot =
|
||||||
|
triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_1));
|
||||||
|
|
||||||
|
verifyVcnSafeModeCallback(TEST_UUID_1, snapshot);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void triggerVcnStatusCallbackOnEnteredSafeMode(
|
||||||
|
@NonNull ParcelUuid subGroup,
|
||||||
|
@NonNull String pkgName,
|
||||||
|
int uid,
|
||||||
|
boolean hasPermissionsforSubGroup,
|
||||||
|
boolean hasLocationPermission)
|
||||||
|
throws Exception {
|
||||||
|
TelephonySubscriptionSnapshot snapshot =
|
||||||
|
triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(subGroup));
|
||||||
|
|
||||||
|
doReturn(hasPermissionsforSubGroup)
|
||||||
|
.when(snapshot)
|
||||||
|
.packageHasPermissionsForSubscriptionGroup(eq(subGroup), eq(pkgName));
|
||||||
|
|
||||||
|
doReturn(hasLocationPermission)
|
||||||
|
.when(mLocationPermissionChecker)
|
||||||
|
.checkLocationPermission(eq(pkgName), any(), eq(uid), any());
|
||||||
|
|
||||||
|
mVcnMgmtSvc.registerVcnStatusCallback(subGroup, mMockStatusCallback, pkgName);
|
||||||
|
|
||||||
|
// Trigger systemReady() to set up LocationPermissionChecker
|
||||||
|
mVcnMgmtSvc.systemReady();
|
||||||
|
|
||||||
|
verifyVcnSafeModeCallback(subGroup, snapshot);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testVcnStatusCallbackOnEnteredSafeModeWithCarrierPrivileges() throws Exception {
|
||||||
|
triggerVcnStatusCallbackOnEnteredSafeMode(
|
||||||
|
TEST_UUID_1,
|
||||||
|
TEST_PACKAGE_NAME,
|
||||||
|
TEST_UID,
|
||||||
|
true /* hasPermissionsforSubGroup */,
|
||||||
|
true /* hasLocationPermission */);
|
||||||
|
|
||||||
|
verify(mMockStatusCallback, times(1)).onEnteredSafeMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testVcnStatusCallbackOnEnteredSafeModeWithoutCarrierPrivileges() throws Exception {
|
||||||
|
triggerVcnStatusCallbackOnEnteredSafeMode(
|
||||||
|
TEST_UUID_1,
|
||||||
|
TEST_PACKAGE_NAME,
|
||||||
|
TEST_UID,
|
||||||
|
false /* hasPermissionsforSubGroup */,
|
||||||
|
true /* hasLocationPermission */);
|
||||||
|
|
||||||
|
verify(mMockStatusCallback, never()).onEnteredSafeMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testVcnStatusCallbackOnEnteredSafeModeWithoutLocationPermission() throws Exception {
|
||||||
|
triggerVcnStatusCallbackOnEnteredSafeMode(
|
||||||
|
TEST_UUID_1,
|
||||||
|
TEST_PACKAGE_NAME,
|
||||||
|
TEST_UID,
|
||||||
|
true /* hasPermissionsforSubGroup */,
|
||||||
|
false /* hasLocationPermission */);
|
||||||
|
|
||||||
|
verify(mMockStatusCallback, never()).onEnteredSafeMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRegisterVcnStatusCallback() throws Exception {
|
||||||
|
mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_1, mMockStatusCallback, TEST_PACKAGE_NAME);
|
||||||
|
|
||||||
|
Map<IBinder, VcnStatusCallbackInfo> callbacks = mVcnMgmtSvc.getAllStatusCallbacks();
|
||||||
|
VcnStatusCallbackInfo cbInfo = callbacks.get(mMockIBinder);
|
||||||
|
|
||||||
|
assertNotNull(cbInfo);
|
||||||
|
assertEquals(TEST_UUID_1, cbInfo.mSubGroup);
|
||||||
|
assertEquals(mMockStatusCallback, cbInfo.mCallback);
|
||||||
|
assertEquals(TEST_PACKAGE_NAME, cbInfo.mPkgName);
|
||||||
|
assertEquals(TEST_UID, cbInfo.mUid);
|
||||||
|
verify(mMockIBinder).linkToDeath(eq(cbInfo), anyInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalStateException.class)
|
||||||
|
public void testRegisterVcnStatusCallbackDuplicate() {
|
||||||
|
mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_1, mMockStatusCallback, TEST_PACKAGE_NAME);
|
||||||
|
mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_1, mMockStatusCallback, TEST_PACKAGE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUnregisterVcnStatusCallback() {
|
||||||
|
mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_1, mMockStatusCallback, TEST_PACKAGE_NAME);
|
||||||
|
Map<IBinder, VcnStatusCallbackInfo> callbacks = mVcnMgmtSvc.getAllStatusCallbacks();
|
||||||
|
VcnStatusCallbackInfo cbInfo = callbacks.get(mMockIBinder);
|
||||||
|
|
||||||
|
mVcnMgmtSvc.unregisterVcnStatusCallback(mMockStatusCallback);
|
||||||
|
assertTrue(mVcnMgmtSvc.getAllStatusCallbacks().isEmpty());
|
||||||
|
verify(mMockIBinder).unlinkToDeath(eq(cbInfo), anyInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = SecurityException.class)
|
||||||
|
public void testRegisterVcnStatusCallbackInvalidPackage() {
|
||||||
|
doThrow(new SecurityException()).when(mAppOpsMgr).checkPackage(TEST_UID, TEST_PACKAGE_NAME);
|
||||||
|
|
||||||
|
mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_1, mMockStatusCallback, TEST_PACKAGE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUnregisterVcnStatusCallbackNeverRegistered() {
|
||||||
|
mVcnMgmtSvc.unregisterVcnStatusCallback(mMockStatusCallback);
|
||||||
|
|
||||||
|
assertTrue(mVcnMgmtSvc.getAllStatusCallbacks().isEmpty());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,8 +75,8 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEnterStateDoesNotCancelSafemodeAlarm() {
|
public void testEnterStateDoesNotCancelSafeModeAlarm() {
|
||||||
verifySafemodeTimeoutAlarmAndGetCallback(false /* expectCanceled */);
|
verifySafeModeTimeoutAlarmAndGetCallback(false /* expectCanceled */);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -144,7 +144,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection
|
|||||||
@Test
|
@Test
|
||||||
public void testChildOpenedRegistersNetwork() throws Exception {
|
public void testChildOpenedRegistersNetwork() throws Exception {
|
||||||
// Verify scheduled but not canceled when entering ConnectedState
|
// Verify scheduled but not canceled when entering ConnectedState
|
||||||
verifySafemodeTimeoutAlarmAndGetCallback(false /* expectCanceled */);
|
verifySafeModeTimeoutAlarmAndGetCallback(false /* expectCanceled */);
|
||||||
|
|
||||||
final VcnChildSessionConfiguration mMockChildSessionConfig =
|
final VcnChildSessionConfiguration mMockChildSessionConfig =
|
||||||
mock(VcnChildSessionConfiguration.class);
|
mock(VcnChildSessionConfiguration.class);
|
||||||
@@ -188,17 +188,17 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection
|
|||||||
assertTrue(nc.hasCapability(cap));
|
assertTrue(nc.hasCapability(cap));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now that Vcn Network is up, notify it as validated and verify the Safemode alarm is
|
// Now that Vcn Network is up, notify it as validated and verify the SafeMode alarm is
|
||||||
// canceled
|
// canceled
|
||||||
mGatewayConnection.mNetworkAgent.onValidationStatus(
|
mGatewayConnection.mNetworkAgent.onValidationStatus(
|
||||||
NetworkAgent.VALIDATION_STATUS_VALID, null /* redirectUri */);
|
NetworkAgent.VALIDATION_STATUS_VALID, null /* redirectUri */);
|
||||||
verify(mSafemodeTimeoutAlarm).cancel();
|
verify(mSafeModeTimeoutAlarm).cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testChildSessionClosedTriggersDisconnect() throws Exception {
|
public void testChildSessionClosedTriggersDisconnect() throws Exception {
|
||||||
// Verify scheduled but not canceled when entering ConnectedState
|
// Verify scheduled but not canceled when entering ConnectedState
|
||||||
verifySafemodeTimeoutAlarmAndGetCallback(false /* expectCanceled */);
|
verifySafeModeTimeoutAlarmAndGetCallback(false /* expectCanceled */);
|
||||||
|
|
||||||
getChildSessionCallback().onClosed();
|
getChildSessionCallback().onClosed();
|
||||||
mTestLooper.dispatchAll();
|
mTestLooper.dispatchAll();
|
||||||
@@ -206,14 +206,14 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection
|
|||||||
assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
|
assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
|
||||||
verifyTeardownTimeoutAlarmAndGetCallback(false /* expectCanceled */);
|
verifyTeardownTimeoutAlarmAndGetCallback(false /* expectCanceled */);
|
||||||
|
|
||||||
// Since network never validated, verify mSafemodeTimeoutAlarm not canceled
|
// Since network never validated, verify mSafeModeTimeoutAlarm not canceled
|
||||||
verifyNoMoreInteractions(mSafemodeTimeoutAlarm);
|
verifyNoMoreInteractions(mSafeModeTimeoutAlarm);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIkeSessionClosedTriggersDisconnect() throws Exception {
|
public void testIkeSessionClosedTriggersDisconnect() throws Exception {
|
||||||
// Verify scheduled but not canceled when entering ConnectedState
|
// Verify scheduled but not canceled when entering ConnectedState
|
||||||
verifySafemodeTimeoutAlarmAndGetCallback(false /* expectCanceled */);
|
verifySafeModeTimeoutAlarmAndGetCallback(false /* expectCanceled */);
|
||||||
|
|
||||||
getIkeSessionCallback().onClosed();
|
getIkeSessionCallback().onClosed();
|
||||||
mTestLooper.dispatchAll();
|
mTestLooper.dispatchAll();
|
||||||
@@ -221,7 +221,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection
|
|||||||
assertEquals(mGatewayConnection.mRetryTimeoutState, mGatewayConnection.getCurrentState());
|
assertEquals(mGatewayConnection.mRetryTimeoutState, mGatewayConnection.getCurrentState());
|
||||||
verify(mIkeSession).close();
|
verify(mIkeSession).close();
|
||||||
|
|
||||||
// Since network never validated, verify mSafemodeTimeoutAlarm not canceled
|
// Since network never validated, verify mSafeModeTimeoutAlarm not canceled
|
||||||
verifyNoMoreInteractions(mSafemodeTimeoutAlarm);
|
verifyNoMoreInteractions(mSafeModeTimeoutAlarm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ public class VcnGatewayConnectionConnectingStateTest extends VcnGatewayConnectio
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSafemodeTimeoutNotifiesCallback() {
|
public void testSafeModeTimeoutNotifiesCallback() {
|
||||||
verifySafemodeTimeoutNotifiesCallback(mGatewayConnection.mConnectingState);
|
verifySafeModeTimeoutNotifiesCallback(mGatewayConnection.mConnectingState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ public class VcnGatewayConnectionDisconnectedStateTest extends VcnGatewayConnect
|
|||||||
mTestLooper.dispatchAll();
|
mTestLooper.dispatchAll();
|
||||||
|
|
||||||
assertEquals(mGatewayConnection.mConnectingState, mGatewayConnection.getCurrentState());
|
assertEquals(mGatewayConnection.mConnectingState, mGatewayConnection.getCurrentState());
|
||||||
verifySafemodeTimeoutAlarmAndGetCallback(false /* expectCanceled */);
|
verifySafeModeTimeoutAlarmAndGetCallback(false /* expectCanceled */);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -100,6 +100,6 @@ public class VcnGatewayConnectionDisconnectedStateTest extends VcnGatewayConnect
|
|||||||
|
|
||||||
assertNull(mGatewayConnection.getCurrentState());
|
assertNull(mGatewayConnection.getCurrentState());
|
||||||
verify(mIpSecSvc).deleteTunnelInterface(eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), any());
|
verify(mIpSecSvc).deleteTunnelInterface(eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), any());
|
||||||
verifySafemodeTimeoutAlarmAndGetCallback(true /* expectCanceled */);
|
verifySafeModeTimeoutAlarmAndGetCallback(true /* expectCanceled */);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ public class VcnGatewayConnectionDisconnectingStateTest extends VcnGatewayConnec
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSafemodeTimeoutNotifiesCallback() {
|
public void testSafeModeTimeoutNotifiesCallback() {
|
||||||
verifySafemodeTimeoutNotifiesCallback(mGatewayConnection.mDisconnectingState);
|
verifySafeModeTimeoutNotifiesCallback(mGatewayConnection.mDisconnectingState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ public class VcnGatewayConnectionRetryTimeoutStateTest extends VcnGatewayConnect
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSafemodeTimeoutNotifiesCallback() {
|
public void testSafeModeTimeoutNotifiesCallback() {
|
||||||
verifySafemodeTimeoutNotifiesCallback(mGatewayConnection.mRetryTimeoutState);
|
verifySafeModeTimeoutNotifiesCallback(mGatewayConnection.mRetryTimeoutState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ public class VcnGatewayConnectionTestBase {
|
|||||||
@NonNull protected final WakeupMessage mTeardownTimeoutAlarm;
|
@NonNull protected final WakeupMessage mTeardownTimeoutAlarm;
|
||||||
@NonNull protected final WakeupMessage mDisconnectRequestAlarm;
|
@NonNull protected final WakeupMessage mDisconnectRequestAlarm;
|
||||||
@NonNull protected final WakeupMessage mRetryTimeoutAlarm;
|
@NonNull protected final WakeupMessage mRetryTimeoutAlarm;
|
||||||
@NonNull protected final WakeupMessage mSafemodeTimeoutAlarm;
|
@NonNull protected final WakeupMessage mSafeModeTimeoutAlarm;
|
||||||
|
|
||||||
@NonNull protected final IpSecService mIpSecSvc;
|
@NonNull protected final IpSecService mIpSecSvc;
|
||||||
@NonNull protected final ConnectivityManager mConnMgr;
|
@NonNull protected final ConnectivityManager mConnMgr;
|
||||||
@@ -131,7 +131,7 @@ public class VcnGatewayConnectionTestBase {
|
|||||||
mTeardownTimeoutAlarm = mock(WakeupMessage.class);
|
mTeardownTimeoutAlarm = mock(WakeupMessage.class);
|
||||||
mDisconnectRequestAlarm = mock(WakeupMessage.class);
|
mDisconnectRequestAlarm = mock(WakeupMessage.class);
|
||||||
mRetryTimeoutAlarm = mock(WakeupMessage.class);
|
mRetryTimeoutAlarm = mock(WakeupMessage.class);
|
||||||
mSafemodeTimeoutAlarm = mock(WakeupMessage.class);
|
mSafeModeTimeoutAlarm = mock(WakeupMessage.class);
|
||||||
|
|
||||||
mIpSecSvc = mock(IpSecService.class);
|
mIpSecSvc = mock(IpSecService.class);
|
||||||
setupIpSecManager(mContext, mIpSecSvc);
|
setupIpSecManager(mContext, mIpSecSvc);
|
||||||
@@ -154,7 +154,7 @@ public class VcnGatewayConnectionTestBase {
|
|||||||
setUpWakeupMessage(mTeardownTimeoutAlarm, VcnGatewayConnection.TEARDOWN_TIMEOUT_ALARM);
|
setUpWakeupMessage(mTeardownTimeoutAlarm, VcnGatewayConnection.TEARDOWN_TIMEOUT_ALARM);
|
||||||
setUpWakeupMessage(mDisconnectRequestAlarm, VcnGatewayConnection.DISCONNECT_REQUEST_ALARM);
|
setUpWakeupMessage(mDisconnectRequestAlarm, VcnGatewayConnection.DISCONNECT_REQUEST_ALARM);
|
||||||
setUpWakeupMessage(mRetryTimeoutAlarm, VcnGatewayConnection.RETRY_TIMEOUT_ALARM);
|
setUpWakeupMessage(mRetryTimeoutAlarm, VcnGatewayConnection.RETRY_TIMEOUT_ALARM);
|
||||||
setUpWakeupMessage(mSafemodeTimeoutAlarm, VcnGatewayConnection.SAFEMODE_TIMEOUT_ALARM);
|
setUpWakeupMessage(mSafeModeTimeoutAlarm, VcnGatewayConnection.SAFEMODE_TIMEOUT_ALARM);
|
||||||
|
|
||||||
doReturn(ELAPSED_REAL_TIME).when(mDeps).getElapsedRealTime();
|
doReturn(ELAPSED_REAL_TIME).when(mDeps).getElapsedRealTime();
|
||||||
}
|
}
|
||||||
@@ -259,23 +259,23 @@ public class VcnGatewayConnectionTestBase {
|
|||||||
expectCanceled);
|
expectCanceled);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Runnable verifySafemodeTimeoutAlarmAndGetCallback(boolean expectCanceled) {
|
protected Runnable verifySafeModeTimeoutAlarmAndGetCallback(boolean expectCanceled) {
|
||||||
return verifyWakeupMessageSetUpAndGetCallback(
|
return verifyWakeupMessageSetUpAndGetCallback(
|
||||||
VcnGatewayConnection.SAFEMODE_TIMEOUT_ALARM,
|
VcnGatewayConnection.SAFEMODE_TIMEOUT_ALARM,
|
||||||
mSafemodeTimeoutAlarm,
|
mSafeModeTimeoutAlarm,
|
||||||
TimeUnit.SECONDS.toMillis(VcnGatewayConnection.SAFEMODE_TIMEOUT_SECONDS),
|
TimeUnit.SECONDS.toMillis(VcnGatewayConnection.SAFEMODE_TIMEOUT_SECONDS),
|
||||||
expectCanceled);
|
expectCanceled);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void verifySafemodeTimeoutNotifiesCallback(@NonNull State expectedState) {
|
protected void verifySafeModeTimeoutNotifiesCallback(@NonNull State expectedState) {
|
||||||
// Safemode timer starts when VcnGatewayConnection exits DisconnectedState (the initial
|
// SafeMode timer starts when VcnGatewayConnection exits DisconnectedState (the initial
|
||||||
// state)
|
// state)
|
||||||
final Runnable delayedEvent =
|
final Runnable delayedEvent =
|
||||||
verifySafemodeTimeoutAlarmAndGetCallback(false /* expectCanceled */);
|
verifySafeModeTimeoutAlarmAndGetCallback(false /* expectCanceled */);
|
||||||
delayedEvent.run();
|
delayedEvent.run();
|
||||||
mTestLooper.dispatchAll();
|
mTestLooper.dispatchAll();
|
||||||
|
|
||||||
verify(mGatewayStatusCallback).onEnteredSafemode();
|
verify(mGatewayStatusCallback).onEnteredSafeMode();
|
||||||
assertEquals(expectedState, mGatewayConnection.getCurrentState());
|
assertEquals(expectedState, mGatewayConnection.getCurrentState());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ import android.net.vcn.VcnGatewayConnectionConfigTest;
|
|||||||
import android.os.ParcelUuid;
|
import android.os.ParcelUuid;
|
||||||
import android.os.test.TestLooper;
|
import android.os.test.TestLooper;
|
||||||
|
|
||||||
import com.android.server.VcnManagementService.VcnSafemodeCallback;
|
import com.android.server.VcnManagementService.VcnSafeModeCallback;
|
||||||
import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
|
import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
|
||||||
import com.android.server.vcn.Vcn.VcnGatewayStatusCallback;
|
import com.android.server.vcn.Vcn.VcnGatewayStatusCallback;
|
||||||
import com.android.server.vcn.VcnNetworkProvider.NetworkRequestListener;
|
import com.android.server.vcn.VcnNetworkProvider.NetworkRequestListener;
|
||||||
@@ -56,7 +56,7 @@ public class VcnTest {
|
|||||||
private VcnContext mVcnContext;
|
private VcnContext mVcnContext;
|
||||||
private TelephonySubscriptionSnapshot mSubscriptionSnapshot;
|
private TelephonySubscriptionSnapshot mSubscriptionSnapshot;
|
||||||
private VcnNetworkProvider mVcnNetworkProvider;
|
private VcnNetworkProvider mVcnNetworkProvider;
|
||||||
private VcnSafemodeCallback mVcnSafemodeCallback;
|
private VcnSafeModeCallback mVcnSafeModeCallback;
|
||||||
private Vcn.Dependencies mDeps;
|
private Vcn.Dependencies mDeps;
|
||||||
|
|
||||||
private ArgumentCaptor<VcnGatewayStatusCallback> mGatewayStatusCallbackCaptor;
|
private ArgumentCaptor<VcnGatewayStatusCallback> mGatewayStatusCallbackCaptor;
|
||||||
@@ -72,7 +72,7 @@ public class VcnTest {
|
|||||||
mVcnContext = mock(VcnContext.class);
|
mVcnContext = mock(VcnContext.class);
|
||||||
mSubscriptionSnapshot = mock(TelephonySubscriptionSnapshot.class);
|
mSubscriptionSnapshot = mock(TelephonySubscriptionSnapshot.class);
|
||||||
mVcnNetworkProvider = mock(VcnNetworkProvider.class);
|
mVcnNetworkProvider = mock(VcnNetworkProvider.class);
|
||||||
mVcnSafemodeCallback = mock(VcnSafemodeCallback.class);
|
mVcnSafeModeCallback = mock(VcnSafeModeCallback.class);
|
||||||
mDeps = mock(Vcn.Dependencies.class);
|
mDeps = mock(Vcn.Dependencies.class);
|
||||||
|
|
||||||
mTestLooper = new TestLooper();
|
mTestLooper = new TestLooper();
|
||||||
@@ -104,7 +104,7 @@ public class VcnTest {
|
|||||||
TEST_SUB_GROUP,
|
TEST_SUB_GROUP,
|
||||||
mConfig,
|
mConfig,
|
||||||
mSubscriptionSnapshot,
|
mSubscriptionSnapshot,
|
||||||
mVcnSafemodeCallback,
|
mVcnSafeModeCallback,
|
||||||
mDeps);
|
mDeps);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,7 +148,7 @@ public class VcnTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGatewayEnteringSafemodeNotifiesVcn() {
|
public void testGatewayEnteringSafeModeNotifiesVcn() {
|
||||||
final NetworkRequestListener requestListener = verifyAndGetRequestListener();
|
final NetworkRequestListener requestListener = verifyAndGetRequestListener();
|
||||||
for (final int capability : VcnGatewayConnectionConfigTest.EXPOSED_CAPS) {
|
for (final int capability : VcnGatewayConnectionConfigTest.EXPOSED_CAPS) {
|
||||||
startVcnGatewayWithCapabilities(requestListener, capability);
|
startVcnGatewayWithCapabilities(requestListener, capability);
|
||||||
@@ -168,16 +168,17 @@ public class VcnTest {
|
|||||||
any(),
|
any(),
|
||||||
mGatewayStatusCallbackCaptor.capture());
|
mGatewayStatusCallbackCaptor.capture());
|
||||||
|
|
||||||
// Doesn't matter which callback this gets - any Gateway entering Safemode should shut down
|
// Doesn't matter which callback this gets - any Gateway entering safe mode should shut down
|
||||||
// all Gateways
|
// all Gateways
|
||||||
final VcnGatewayStatusCallback statusCallback = mGatewayStatusCallbackCaptor.getValue();
|
final VcnGatewayStatusCallback statusCallback = mGatewayStatusCallbackCaptor.getValue();
|
||||||
statusCallback.onEnteredSafemode();
|
statusCallback.onEnteredSafeMode();
|
||||||
mTestLooper.dispatchAll();
|
mTestLooper.dispatchAll();
|
||||||
|
|
||||||
|
assertFalse(mVcn.isActive());
|
||||||
for (final VcnGatewayConnection gatewayConnection : gatewayConnections) {
|
for (final VcnGatewayConnection gatewayConnection : gatewayConnections) {
|
||||||
verify(gatewayConnection).teardownAsynchronously();
|
verify(gatewayConnection).teardownAsynchronously();
|
||||||
}
|
}
|
||||||
verify(mVcnNetworkProvider).unregisterListener(requestListener);
|
verify(mVcnNetworkProvider).unregisterListener(requestListener);
|
||||||
verify(mVcnSafemodeCallback).onEnteredSafemode();
|
verify(mVcnSafeModeCallback).onEnteredSafeMode();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user