Merge "Optionally have ConnectivityService kill sockets for frozen apps" am: 2d626e5632
Original change: https://android-review.googlesource.com/c/platform/packages/modules/Connectivity/+/2578597 Change-Id: I8d4bc9e0a16a7154edef691976570856821a2d2f Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
package com.android.server;
|
||||
|
||||
import static android.Manifest.permission.RECEIVE_DATA_ACTIVITY_CHANGE;
|
||||
import static android.app.ActivityManager.UidFrozenStateChangedCallback.UID_FROZEN_STATE_FROZEN;
|
||||
import static android.content.pm.PackageManager.FEATURE_BLUETOOTH;
|
||||
import static android.content.pm.PackageManager.FEATURE_WATCH;
|
||||
import static android.content.pm.PackageManager.FEATURE_WIFI;
|
||||
@@ -110,6 +111,8 @@ import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.ActivityManager.UidFrozenStateChangedCallback;
|
||||
import android.app.AppOpsManager;
|
||||
import android.app.BroadcastOptions;
|
||||
import android.app.PendingIntent;
|
||||
@@ -786,6 +789,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
*/
|
||||
private static final int EVENT_SET_LOW_TCP_POLLING_UNTIL = 60;
|
||||
|
||||
/**
|
||||
* Event to inform the ConnectivityService handler when a uid has been frozen or unfrozen.
|
||||
*/
|
||||
private static final int EVENT_UID_FROZEN_STATE_CHANGED = 61;
|
||||
|
||||
/**
|
||||
* Argument for {@link #EVENT_PROVISIONING_NOTIFICATION} to indicate that the notification
|
||||
* should be shown.
|
||||
@@ -1691,6 +1699,32 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
} else {
|
||||
mCdmps = null;
|
||||
}
|
||||
|
||||
if (SdkLevel.isAtLeastU()
|
||||
&& mDeps.isFeatureEnabled(context, KEY_DESTROY_FROZEN_SOCKETS_VERSION)) {
|
||||
final UidFrozenStateChangedCallback frozenStateChangedCallback =
|
||||
new UidFrozenStateChangedCallback() {
|
||||
@Override
|
||||
public void onUidFrozenStateChanged(int[] uids, int[] frozenStates) {
|
||||
if (uids.length != frozenStates.length) {
|
||||
Log.wtf(TAG, "uids has length " + uids.length
|
||||
+ " but frozenStates has length " + frozenStates.length);
|
||||
return;
|
||||
}
|
||||
|
||||
final UidFrozenStateChangedArgs args =
|
||||
new UidFrozenStateChangedArgs(uids, frozenStates);
|
||||
|
||||
mHandler.sendMessage(
|
||||
mHandler.obtainMessage(EVENT_UID_FROZEN_STATE_CHANGED, args));
|
||||
}
|
||||
};
|
||||
|
||||
final ActivityManager activityManager =
|
||||
mContext.getSystemService(ActivityManager.class);
|
||||
activityManager.registerUidFrozenStateChangedCallback(
|
||||
(Runnable r) -> r.run(), frozenStateChangedCallback);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2859,6 +2893,39 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
setUidBlockedReasons(uid, blockedReasons);
|
||||
}
|
||||
|
||||
static final class UidFrozenStateChangedArgs {
|
||||
final int[] mUids;
|
||||
final int[] mFrozenStates;
|
||||
|
||||
UidFrozenStateChangedArgs(int[] uids, int[] frozenStates) {
|
||||
mUids = uids;
|
||||
mFrozenStates = frozenStates;
|
||||
}
|
||||
}
|
||||
|
||||
private void handleFrozenUids(int[] uids, int[] frozenStates) {
|
||||
final ArraySet<Range<Integer>> ranges = new ArraySet<>();
|
||||
|
||||
for (int i = 0; i < uids.length; i++) {
|
||||
if (frozenStates[i] == UID_FROZEN_STATE_FROZEN) {
|
||||
Integer uidAsInteger = Integer.valueOf(uids[i]);
|
||||
ranges.add(new Range(uidAsInteger, uidAsInteger));
|
||||
}
|
||||
}
|
||||
|
||||
if (!ranges.isEmpty()) {
|
||||
final Set<Integer> exemptUids = new ArraySet<>();
|
||||
try {
|
||||
mDeps.destroyLiveTcpSockets(ranges, exemptUids);
|
||||
} catch (Exception e) {
|
||||
loge("Exception in socket destroy: " + e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static final String KEY_DESTROY_FROZEN_SOCKETS_VERSION = "destroy_frozen_sockets_version";
|
||||
|
||||
private void enforceInternetPermission() {
|
||||
mContext.enforceCallingOrSelfPermission(
|
||||
android.Manifest.permission.INTERNET,
|
||||
@@ -5722,6 +5789,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
mKeepaliveTracker.handleSetTestLowTcpPollingTimer(time);
|
||||
break;
|
||||
}
|
||||
case EVENT_UID_FROZEN_STATE_CHANGED:
|
||||
UidFrozenStateChangedArgs args = (UidFrozenStateChangedArgs) msg.obj;
|
||||
handleFrozenUids(args.mUids, args.mFrozenStates);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,8 @@ import static android.Manifest.permission.NETWORK_SETTINGS;
|
||||
import static android.Manifest.permission.NETWORK_SETUP_WIZARD;
|
||||
import static android.Manifest.permission.NETWORK_STACK;
|
||||
import static android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD;
|
||||
import static android.app.ActivityManager.UidFrozenStateChangedCallback.UID_FROZEN_STATE_FROZEN;
|
||||
import static android.app.ActivityManager.UidFrozenStateChangedCallback.UID_FROZEN_STATE_UNFROZEN;
|
||||
import static android.app.PendingIntent.FLAG_IMMUTABLE;
|
||||
import static android.content.Intent.ACTION_PACKAGE_ADDED;
|
||||
import static android.content.Intent.ACTION_PACKAGE_REMOVED;
|
||||
@@ -148,6 +150,7 @@ import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.VALID
|
||||
import static android.os.Process.INVALID_UID;
|
||||
import static android.system.OsConstants.IPPROTO_TCP;
|
||||
|
||||
import static com.android.server.ConnectivityService.KEY_DESTROY_FROZEN_SOCKETS_VERSION;
|
||||
import static com.android.server.ConnectivityService.MAX_NETWORK_REQUESTS_PER_SYSTEM_UID;
|
||||
import static com.android.server.ConnectivityService.PREFERENCE_ORDER_MOBILE_DATA_PREFERERRED;
|
||||
import static com.android.server.ConnectivityService.PREFERENCE_ORDER_OEM;
|
||||
@@ -224,6 +227,8 @@ import static java.util.Arrays.asList;
|
||||
import android.Manifest;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.ActivityManager.UidFrozenStateChangedCallback;
|
||||
import android.app.AlarmManager;
|
||||
import android.app.AppOpsManager;
|
||||
import android.app.BroadcastOptions;
|
||||
@@ -609,6 +614,7 @@ public class ConnectivityServiceTest {
|
||||
@Mock CarrierPrivilegeAuthenticator mCarrierPrivilegeAuthenticator;
|
||||
@Mock TetheringManager mTetheringManager;
|
||||
@Mock BroadcastOptionsShim mBroadcastOptionsShim;
|
||||
@Mock ActivityManager mActivityManager;
|
||||
|
||||
// BatteryStatsManager is final and cannot be mocked with regular mockito, so just mock the
|
||||
// underlying binder calls.
|
||||
@@ -732,6 +738,7 @@ public class ConnectivityServiceTest {
|
||||
if (Context.BATTERY_STATS_SERVICE.equals(name)) return mBatteryStatsManager;
|
||||
if (Context.PAC_PROXY_SERVICE.equals(name)) return mPacProxyManager;
|
||||
if (Context.TETHERING_SERVICE.equals(name)) return mTetheringManager;
|
||||
if (Context.ACTIVITY_SERVICE.equals(name)) return mActivityManager;
|
||||
return super.getSystemService(name);
|
||||
}
|
||||
|
||||
@@ -2081,6 +2088,8 @@ public class ConnectivityServiceTest {
|
||||
switch (name) {
|
||||
case ConnectivityFlags.NO_REMATCH_ALL_REQUESTS_ON_REGISTER:
|
||||
return true;
|
||||
case KEY_DESTROY_FROZEN_SOCKETS_VERSION:
|
||||
return true;
|
||||
default:
|
||||
return super.isFeatureEnabled(context, name);
|
||||
}
|
||||
@@ -17833,4 +17842,35 @@ public class ConnectivityServiceTest {
|
||||
verify(mMockNetd, never()).wakeupAddInterface(eq(ethernetIface), anyString(), anyInt(),
|
||||
anyInt());
|
||||
}
|
||||
|
||||
private static final int TEST_FROZEN_UID = 1000;
|
||||
private static final int TEST_UNFROZEN_UID = 2000;
|
||||
|
||||
/**
|
||||
* Send a UidFrozenStateChanged message to ConnectivityService. Verify that only the frozen UID
|
||||
* gets passed to socketDestroy().
|
||||
*/
|
||||
@Test
|
||||
@IgnoreUpTo(Build.VERSION_CODES.TIRAMISU)
|
||||
public void testFrozenUidSocketDestroy() throws Exception {
|
||||
ArgumentCaptor<UidFrozenStateChangedCallback> callbackArg =
|
||||
ArgumentCaptor.forClass(UidFrozenStateChangedCallback.class);
|
||||
|
||||
verify(mActivityManager).registerUidFrozenStateChangedCallback(any(),
|
||||
callbackArg.capture());
|
||||
|
||||
final int[] uids = {TEST_FROZEN_UID, TEST_UNFROZEN_UID};
|
||||
final int[] frozenStates = {UID_FROZEN_STATE_FROZEN, UID_FROZEN_STATE_UNFROZEN};
|
||||
|
||||
callbackArg.getValue().onUidFrozenStateChanged(uids, frozenStates);
|
||||
|
||||
waitForIdle();
|
||||
|
||||
final Set<Integer> exemptUids = new ArraySet();
|
||||
final UidRange frozenUidRange = new UidRange(TEST_FROZEN_UID, TEST_FROZEN_UID);
|
||||
final Set<UidRange> ranges = Collections.singleton(frozenUidRange);
|
||||
|
||||
verify(mDeps).destroyLiveTcpSockets(eq(UidRange.toIntRanges(ranges)),
|
||||
eq(exemptUids));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user