Merge changes from topics "CATEGORY_EVENT_ALWAYS_ON_STATE_CHANGED", "CATEGORY_EVENT_DEACTIVATED_BY_USER" into tm-dev

* changes:
  Send VPN manager event when VPN is deactivated
  Send VPN manager event when VPN always-on status is changed
This commit is contained in:
Lucas Lin
2022-05-25 10:20:18 +00:00
committed by Android (Google) Code Review

View File

@@ -125,6 +125,7 @@ import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.net.LegacyVpnInfo; import com.android.internal.net.LegacyVpnInfo;
import com.android.internal.net.VpnConfig; import com.android.internal.net.VpnConfig;
import com.android.internal.net.VpnProfile; import com.android.internal.net.VpnProfile;
import com.android.modules.utils.build.SdkLevel;
import com.android.net.module.util.NetdUtils; import com.android.net.module.util.NetdUtils;
import com.android.net.module.util.NetworkStackConstants; import com.android.net.module.util.NetworkStackConstants;
import com.android.server.DeviceIdleInternal; import com.android.server.DeviceIdleInternal;
@@ -213,7 +214,9 @@ public class Vpn {
private final Context mUserIdContext; private final Context mUserIdContext;
@VisibleForTesting final Dependencies mDeps; @VisibleForTesting final Dependencies mDeps;
private final NetworkInfo mNetworkInfo; private final NetworkInfo mNetworkInfo;
@GuardedBy("this")
private int mLegacyState; private int mLegacyState;
@GuardedBy("this")
@VisibleForTesting protected String mPackage; @VisibleForTesting protected String mPackage;
private int mOwnerUID; private int mOwnerUID;
private boolean mIsPackageTargetingAtLeastQ; private boolean mIsPackageTargetingAtLeastQ;
@@ -251,6 +254,7 @@ public class Vpn {
* Whether to keep the connection active after rebooting, or upgrading or reinstalling. This * Whether to keep the connection active after rebooting, or upgrading or reinstalling. This
* only applies to {@link VpnService} connections. * only applies to {@link VpnService} connections.
*/ */
@GuardedBy("this")
@VisibleForTesting protected boolean mAlwaysOn = false; @VisibleForTesting protected boolean mAlwaysOn = false;
/** /**
@@ -258,6 +262,7 @@ public class Vpn {
* apps can still bypass by choosing explicit networks. Has no effect if {@link mAlwaysOn} is * apps can still bypass by choosing explicit networks. Has no effect if {@link mAlwaysOn} is
* not set. Applies to all types of VPNs. * not set. Applies to all types of VPNs.
*/ */
@GuardedBy("this")
@VisibleForTesting protected boolean mLockdown = false; @VisibleForTesting protected boolean mLockdown = false;
/** /**
@@ -610,7 +615,7 @@ public class Vpn {
} }
/** Returns the package name that is currently prepared. */ /** Returns the package name that is currently prepared. */
public String getPackage() { public synchronized String getPackage() {
return mPackage; return mPackage;
} }
@@ -691,6 +696,36 @@ public class Vpn {
return true; return true;
} }
private boolean sendEventToVpnManagerApp(@NonNull String category, int errorClass,
int errorCode, @NonNull final String packageName, @Nullable final String sessionKey,
@NonNull final VpnProfileState profileState, @Nullable final Network underlyingNetwork,
@Nullable final NetworkCapabilities nc, @Nullable final LinkProperties lp) {
final Intent intent = new Intent(VpnManager.ACTION_VPN_MANAGER_EVENT);
intent.setPackage(packageName);
intent.addCategory(category);
intent.putExtra(VpnManager.EXTRA_VPN_PROFILE_STATE, profileState);
intent.putExtra(VpnManager.EXTRA_SESSION_KEY, sessionKey);
intent.putExtra(VpnManager.EXTRA_UNDERLYING_NETWORK, underlyingNetwork);
intent.putExtra(VpnManager.EXTRA_UNDERLYING_NETWORK_CAPABILITIES, nc);
intent.putExtra(VpnManager.EXTRA_UNDERLYING_LINK_PROPERTIES, lp);
intent.putExtra(VpnManager.EXTRA_TIMESTAMP_MILLIS, System.currentTimeMillis());
if (!VpnManager.CATEGORY_EVENT_DEACTIVATED_BY_USER.equals(category)
|| !VpnManager.CATEGORY_EVENT_ALWAYS_ON_STATE_CHANGED.equals(category)) {
intent.putExtra(VpnManager.EXTRA_ERROR_CLASS, errorClass);
intent.putExtra(VpnManager.EXTRA_ERROR_CODE, errorCode);
}
try {
return mUserIdContext.startService(intent) != null;
} catch (RuntimeException e) {
Log.e(TAG, "Service of VpnManager app " + intent + " failed to start", e);
return false;
}
}
private boolean isVpnApp(String packageName) {
return packageName != null && !VpnConfig.LEGACY_VPN.equals(packageName);
}
/** /**
* Configures an always-on VPN connection through a specific application. This connection is * Configures an always-on VPN connection through a specific application. This connection is
* automatically granted and persisted after a reboot. * automatically granted and persisted after a reboot.
@@ -713,9 +748,40 @@ public class Vpn {
boolean lockdown, boolean lockdown,
@Nullable List<String> lockdownAllowlist) { @Nullable List<String> lockdownAllowlist) {
enforceControlPermissionOrInternalCaller(); enforceControlPermissionOrInternalCaller();
// Store mPackage since it might be reset or might be replaced with the other VPN app.
final String oldPackage = mPackage;
final boolean isPackageChanged = !Objects.equals(packageName, oldPackage);
// TODO: Remove "SdkLevel.isAtLeastT()" check once VpnManagerService is decoupled from
// ConnectivityServiceTest.
// Only notify VPN apps that were already always-on, and only if the always-on provider
// changed, or the lockdown mode changed.
final boolean shouldNotifyOldPkg = isVpnApp(oldPackage) && mAlwaysOn
&& (lockdown != mLockdown || isPackageChanged);
// Also notify the new package if there was a provider change.
final boolean shouldNotifyNewPkg = isVpnApp(packageName) && isPackageChanged;
if (setAlwaysOnPackageInternal(packageName, lockdown, lockdownAllowlist)) { if (setAlwaysOnPackageInternal(packageName, lockdown, lockdownAllowlist)) {
saveAlwaysOnPackage(); saveAlwaysOnPackage();
// TODO(b/230548427): Remove SDK check once VPN related stuff are decoupled from
// ConnectivityServiceTest.
if (shouldNotifyOldPkg && SdkLevel.isAtLeastT()) {
// If both of shouldNotifyOldPkg & isPackageChanged are true, which means the
// always-on of old package is disabled or the old package is replaced with the new
// package. In this case, VpnProfileState should be disconnected.
sendEventToVpnManagerApp(VpnManager.CATEGORY_EVENT_ALWAYS_ON_STATE_CHANGED,
-1 /* errorClass */, -1 /* errorCode*/, oldPackage,
null /* sessionKey */, isPackageChanged ? makeDisconnectedVpnProfileState()
: makeVpnProfileStateLocked(),
null /* underlyingNetwork */, null /* nc */, null /* lp */);
}
// TODO(b/230548427): Remove SDK check once VPN related stuff are decoupled from
// ConnectivityServiceTest.
if (shouldNotifyNewPkg && SdkLevel.isAtLeastT()) {
sendEventToVpnManagerApp(VpnManager.CATEGORY_EVENT_ALWAYS_ON_STATE_CHANGED,
-1 /* errorClass */, -1 /* errorCode*/, packageName,
getSessionKeyLocked(), makeVpnProfileStateLocked(),
null /* underlyingNetwork */, null /* nc */, null /* lp */);
}
return true; return true;
} }
return false; return false;
@@ -1012,6 +1078,7 @@ public class Vpn {
return true; return true;
} }
@GuardedBy("this")
private boolean isCurrentPreparedPackage(String packageName) { private boolean isCurrentPreparedPackage(String packageName) {
// We can't just check that packageName matches mPackage, because if the app was uninstalled // We can't just check that packageName matches mPackage, because if the app was uninstalled
// and reinstalled it will no longer be prepared. Similarly if there is a shared UID, the // and reinstalled it will no longer be prepared. Similarly if there is a shared UID, the
@@ -1049,6 +1116,17 @@ public class Vpn {
if (!VpnConfig.LEGACY_VPN.equals(mPackage)) { if (!VpnConfig.LEGACY_VPN.equals(mPackage)) {
mAppOpsManager.finishOp( mAppOpsManager.finishOp(
AppOpsManager.OPSTR_ESTABLISH_VPN_MANAGER, mOwnerUID, mPackage, null); AppOpsManager.OPSTR_ESTABLISH_VPN_MANAGER, mOwnerUID, mPackage, null);
// The underlying network, NetworkCapabilities and LinkProperties are not
// necessary to send to VPN app since the purpose of this event is to notify
// VPN app that VPN is deactivated by the user.
// TODO(b/230548427): Remove SDK check once VPN related stuff are decoupled from
// ConnectivityServiceTest.
if (SdkLevel.isAtLeastT()) {
sendEventToVpnManagerApp(VpnManager.CATEGORY_EVENT_DEACTIVATED_BY_USER,
-1 /* errorClass */, -1 /* errorCode*/, mPackage,
getSessionKeyLocked(), makeVpnProfileStateLocked(),
null /* underlyingNetwork */, null /* nc */, null /* lp */);
}
} }
// cleanupVpnStateLocked() is called from mVpnRunner.exit() // cleanupVpnStateLocked() is called from mVpnRunner.exit()
mVpnRunner.exit(); mVpnRunner.exit();
@@ -1305,6 +1383,7 @@ public class Vpn {
return true; return true;
} }
@GuardedBy("this")
private void agentConnect() { private void agentConnect() {
LinkProperties lp = makeLinkProperties(); LinkProperties lp = makeLinkProperties();
@@ -2005,6 +2084,7 @@ public class Vpn {
return isIkev2VpnRunner() ? VpnManager.TYPE_VPN_PLATFORM : VpnManager.TYPE_VPN_LEGACY; return isIkev2VpnRunner() ? VpnManager.TYPE_VPN_PLATFORM : VpnManager.TYPE_VPN_LEGACY;
} }
@GuardedBy("this")
private void updateAlwaysOnNotification(DetailedState networkState) { private void updateAlwaysOnNotification(DetailedState networkState) {
final boolean visible = (mAlwaysOn && networkState != DetailedState.CONNECTED); final boolean visible = (mAlwaysOn && networkState != DetailedState.CONNECTED);
@@ -3593,11 +3673,19 @@ public class Vpn {
} }
} }
private VpnProfileState makeVpnProfileState() { @GuardedBy("this")
@NonNull
private VpnProfileState makeVpnProfileStateLocked() {
return new VpnProfileState(getStateFromLegacyState(mLegacyState), return new VpnProfileState(getStateFromLegacyState(mLegacyState),
isIkev2VpnRunner() ? getSessionKeyLocked() : null, mAlwaysOn, mLockdown); isIkev2VpnRunner() ? getSessionKeyLocked() : null, mAlwaysOn, mLockdown);
} }
@NonNull
private VpnProfileState makeDisconnectedVpnProfileState() {
return new VpnProfileState(VpnProfileState.STATE_DISCONNECTED, null /* sessionKey */,
false /* alwaysOn */, false /* lockdown */);
}
/** /**
* Retrieve the VpnProfileState for the profile provisioned by the given package. * Retrieve the VpnProfileState for the profile provisioned by the given package.
* *
@@ -3609,7 +3697,7 @@ public class Vpn {
@NonNull String packageName) { @NonNull String packageName) {
requireNonNull(packageName, "No package name provided"); requireNonNull(packageName, "No package name provided");
enforceNotRestrictedUser(); enforceNotRestrictedUser();
return isCurrentIkev2VpnLocked(packageName) ? makeVpnProfileState() : null; return isCurrentIkev2VpnLocked(packageName) ? makeVpnProfileStateLocked() : null;
} }
/** /**