Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8697a083 authored by Kweku Adams's avatar Kweku Adams
Browse files

Migrate to the asynchronous version of getActiveNetworkForUid.

Register a network callback to get the active network for each UID that
schedules a job with a network constraint. Using the asynchronous
version means that JS no longer has to call any synchronous network APIs.
The networking stack has a hard limit on the number of callbacks that can
be scheduled, so we try to prioritize the UIDs that we register callbacks
for based on certain characteristics.

Bug: 134978280
Bug: 165835257
Bug: 179501234
Bug: 183089482
Test: atest frameworks/base/services/tests/servicestests/src/com/android/server/job
Test: atest frameworks/base/services/tests/mockingservicestests/src/com/android/server/job
Test: atest CtsJobSchedulerTestCases
Change-Id: Ie93cd22b11cc28135a385c0cf6ad6b577b61d1b7
parent 2e998fc4
Loading
Loading
Loading
Loading
+472 −41

File changed.

Preview size limit exceeded, changes collapsed.

+90 −39
Original line number Original line Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.server.job.controllers;
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
@@ -41,10 +42,11 @@ import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verify;


import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.job.JobInfo;
import android.app.job.JobInfo;
import android.content.ComponentName;
import android.content.ComponentName;
import android.content.Context;
import android.content.Context;
@@ -53,8 +55,6 @@ import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
import android.net.ConnectivityManager.NetworkCallback;
import android.net.Network;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
import android.net.NetworkPolicyManager;
import android.net.NetworkPolicyManager;
import android.os.Build;
import android.os.Build;
import android.os.Looper;
import android.os.Looper;
@@ -136,7 +136,7 @@ public class ConnectivityControllerTest {
    }
    }


    @Test
    @Test
    public void testInsane() throws Exception {
    public void testUsable() throws Exception {
        final Network net = new Network(101);
        final Network net = new Network(101);
        final JobInfo.Builder job = createJob()
        final JobInfo.Builder job = createJob()
                .setEstimatedNetworkBytes(DataUnit.MEBIBYTES.toBytes(1),
                .setEstimatedNetworkBytes(DataUnit.MEBIBYTES.toBytes(1),
@@ -191,6 +191,30 @@ public class ConnectivityControllerTest {
                        .setLinkDownstreamBandwidthKbps(130), mConstants));
                        .setLinkDownstreamBandwidthKbps(130), mConstants));
    }
    }


    @Test
    public void testInsane() throws Exception {
        final Network net = new Network(101);
        final JobInfo.Builder job = createJob()
                .setEstimatedNetworkBytes(DataUnit.MEBIBYTES.toBytes(1),
                        DataUnit.MEBIBYTES.toBytes(1))
                .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);

        final ConnectivityController controller = new ConnectivityController(mService);
        when(mService.getMaxJobExecutionTimeMs(any())).thenReturn(10 * 60_000L);


        // Suspended networks aren't usable.
        assertFalse(controller.isSatisfied(createJobStatus(job), net,
                createCapabilities().removeCapability(NET_CAPABILITY_NOT_SUSPENDED)
                        .setLinkUpstreamBandwidthKbps(1024).setLinkDownstreamBandwidthKbps(1024),
                mConstants));

        // Not suspended networks are usable.
        assertTrue(controller.isSatisfied(createJobStatus(job), net,
                createCapabilities().setLinkUpstreamBandwidthKbps(1024)
                        .setLinkDownstreamBandwidthKbps(1024), mConstants));
    }

    @Test
    @Test
    public void testCongestion() throws Exception {
    public void testCongestion() throws Exception {
        final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
        final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
@@ -263,9 +287,17 @@ public class ConnectivityControllerTest {


    @Test
    @Test
    public void testUpdates() throws Exception {
    public void testUpdates() throws Exception {
        final ArgumentCaptor<NetworkCallback> callback = ArgumentCaptor
        final ArgumentCaptor<NetworkCallback> callbackCaptor =
                .forClass(NetworkCallback.class);
                ArgumentCaptor.forClass(NetworkCallback.class);
        doNothing().when(mConnManager).registerNetworkCallback(any(), callback.capture());
        doNothing().when(mConnManager).registerNetworkCallback(any(), callbackCaptor.capture());
        final ArgumentCaptor<NetworkCallback> redCallbackCaptor =
                ArgumentCaptor.forClass(NetworkCallback.class);
        doNothing().when(mConnManager).registerDefaultNetworkCallbackAsUid(
                eq(UID_RED), redCallbackCaptor.capture(), any());
        final ArgumentCaptor<NetworkCallback> blueCallbackCaptor =
                ArgumentCaptor.forClass(NetworkCallback.class);
        doNothing().when(mConnManager).registerDefaultNetworkCallbackAsUid(
                eq(UID_BLUE), blueCallbackCaptor.capture(), any());


        final ConnectivityController controller = new ConnectivityController(mService);
        final ConnectivityController controller = new ConnectivityController(mService);


@@ -281,15 +313,16 @@ public class ConnectivityControllerTest {
        final JobStatus blue = createJobStatus(createJob()
        final JobStatus blue = createJobStatus(createJob()
                .setEstimatedNetworkBytes(DataUnit.MEBIBYTES.toBytes(1), 0)
                .setEstimatedNetworkBytes(DataUnit.MEBIBYTES.toBytes(1), 0)
                .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY), UID_BLUE);
                .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY), UID_BLUE);
        controller.maybeStartTrackingJobLocked(red, null);
        controller.maybeStartTrackingJobLocked(blue, null);
        final NetworkCallback generalCallback = callbackCaptor.getValue();
        final NetworkCallback redCallback = redCallbackCaptor.getValue();
        final NetworkCallback blueCallback = blueCallbackCaptor.getValue();


        // Pretend we're offline when job is added
        // Pretend we're offline when job is added
        {
        {
            reset(mConnManager);
            answerNetwork(generalCallback, redCallback, null, null, null);
            answerNetwork(UID_RED, null, null);
            answerNetwork(generalCallback, blueCallback, null, null, null);
            answerNetwork(UID_BLUE, null, null);

            controller.maybeStartTrackingJobLocked(red, null);
            controller.maybeStartTrackingJobLocked(blue, null);


            assertFalse(red.isConstraintSatisfied(JobStatus.CONSTRAINT_CONNECTIVITY));
            assertFalse(red.isConstraintSatisfied(JobStatus.CONSTRAINT_CONNECTIVITY));
            assertFalse(blue.isConstraintSatisfied(JobStatus.CONSTRAINT_CONNECTIVITY));
            assertFalse(blue.isConstraintSatisfied(JobStatus.CONSTRAINT_CONNECTIVITY));
@@ -297,11 +330,10 @@ public class ConnectivityControllerTest {


        // Metered network
        // Metered network
        {
        {
            reset(mConnManager);
            answerNetwork(generalCallback, redCallback, null, meteredNet, meteredCaps);
            answerNetwork(UID_RED, meteredNet, meteredCaps);
            answerNetwork(generalCallback, blueCallback, null, meteredNet, meteredCaps);
            answerNetwork(UID_BLUE, meteredNet, meteredCaps);


            callback.getValue().onCapabilitiesChanged(meteredNet, meteredCaps);
            generalCallback.onCapabilitiesChanged(meteredNet, meteredCaps);


            assertFalse(red.isConstraintSatisfied(JobStatus.CONSTRAINT_CONNECTIVITY));
            assertFalse(red.isConstraintSatisfied(JobStatus.CONSTRAINT_CONNECTIVITY));
            assertTrue(blue.isConstraintSatisfied(JobStatus.CONSTRAINT_CONNECTIVITY));
            assertTrue(blue.isConstraintSatisfied(JobStatus.CONSTRAINT_CONNECTIVITY));
@@ -309,11 +341,10 @@ public class ConnectivityControllerTest {


        // Unmetered network background
        // Unmetered network background
        {
        {
            reset(mConnManager);
            answerNetwork(generalCallback, redCallback, meteredNet, meteredNet, meteredCaps);
            answerNetwork(UID_RED, meteredNet, meteredCaps);
            answerNetwork(generalCallback, blueCallback, meteredNet, meteredNet, meteredCaps);
            answerNetwork(UID_BLUE, meteredNet, meteredCaps);


            callback.getValue().onCapabilitiesChanged(unmeteredNet, unmeteredCaps);
            generalCallback.onCapabilitiesChanged(unmeteredNet, unmeteredCaps);


            assertFalse(red.isConstraintSatisfied(JobStatus.CONSTRAINT_CONNECTIVITY));
            assertFalse(red.isConstraintSatisfied(JobStatus.CONSTRAINT_CONNECTIVITY));
            assertTrue(blue.isConstraintSatisfied(JobStatus.CONSTRAINT_CONNECTIVITY));
            assertTrue(blue.isConstraintSatisfied(JobStatus.CONSTRAINT_CONNECTIVITY));
@@ -321,11 +352,10 @@ public class ConnectivityControllerTest {


        // Lost metered network
        // Lost metered network
        {
        {
            reset(mConnManager);
            answerNetwork(generalCallback, redCallback, meteredNet, unmeteredNet, unmeteredCaps);
            answerNetwork(UID_RED, unmeteredNet, unmeteredCaps);
            answerNetwork(generalCallback, blueCallback, meteredNet, unmeteredNet, unmeteredCaps);
            answerNetwork(UID_BLUE, unmeteredNet, unmeteredCaps);


            callback.getValue().onLost(meteredNet);
            generalCallback.onLost(meteredNet);


            assertTrue(red.isConstraintSatisfied(JobStatus.CONSTRAINT_CONNECTIVITY));
            assertTrue(red.isConstraintSatisfied(JobStatus.CONSTRAINT_CONNECTIVITY));
            assertTrue(blue.isConstraintSatisfied(JobStatus.CONSTRAINT_CONNECTIVITY));
            assertTrue(blue.isConstraintSatisfied(JobStatus.CONSTRAINT_CONNECTIVITY));
@@ -333,11 +363,10 @@ public class ConnectivityControllerTest {


        // Specific UID was blocked
        // Specific UID was blocked
        {
        {
            reset(mConnManager);
            answerNetwork(generalCallback, redCallback, unmeteredNet, null, null);
            answerNetwork(UID_RED, null, null);
            answerNetwork(generalCallback, blueCallback, unmeteredNet, unmeteredNet, unmeteredCaps);
            answerNetwork(UID_BLUE, unmeteredNet, unmeteredCaps);


            callback.getValue().onCapabilitiesChanged(unmeteredNet, unmeteredCaps);
            generalCallback.onCapabilitiesChanged(unmeteredNet, unmeteredCaps);


            assertFalse(red.isConstraintSatisfied(JobStatus.CONSTRAINT_CONNECTIVITY));
            assertFalse(red.isConstraintSatisfied(JobStatus.CONSTRAINT_CONNECTIVITY));
            assertTrue(blue.isConstraintSatisfied(JobStatus.CONSTRAINT_CONNECTIVITY));
            assertTrue(blue.isConstraintSatisfied(JobStatus.CONSTRAINT_CONNECTIVITY));
@@ -404,6 +433,8 @@ public class ConnectivityControllerTest {
        final JobStatus blue = createJobStatus(createJob()
        final JobStatus blue = createJobStatus(createJob()
                .setEstimatedNetworkBytes(DataUnit.MEBIBYTES.toBytes(1), 0)
                .setEstimatedNetworkBytes(DataUnit.MEBIBYTES.toBytes(1), 0)
                .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY), UID_BLUE);
                .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY), UID_BLUE);
        controller.maybeStartTrackingJobLocked(red, null);
        controller.maybeStartTrackingJobLocked(blue, null);


        InOrder inOrder = inOrder(mNetPolicyManagerInternal);
        InOrder inOrder = inOrder(mNetPolicyManagerInternal);


@@ -560,6 +591,18 @@ public class ConnectivityControllerTest {


    @Test
    @Test
    public void testRestrictedJobTracking() {
    public void testRestrictedJobTracking() {
        final ArgumentCaptor<NetworkCallback> callback =
                ArgumentCaptor.forClass(NetworkCallback.class);
        doNothing().when(mConnManager).registerNetworkCallback(any(), callback.capture());
        final ArgumentCaptor<NetworkCallback> redCallback =
                ArgumentCaptor.forClass(NetworkCallback.class);
        doNothing().when(mConnManager).registerDefaultNetworkCallbackAsUid(
                eq(UID_RED), redCallback.capture(), any());
        final ArgumentCaptor<NetworkCallback> blueCallback =
                ArgumentCaptor.forClass(NetworkCallback.class);
        doNothing().when(mConnManager).registerDefaultNetworkCallbackAsUid(
                eq(UID_BLUE), blueCallback.capture(), any());

        final JobStatus networked = createJobStatus(createJob()
        final JobStatus networked = createJobStatus(createJob()
                .setEstimatedNetworkBytes(DataUnit.MEBIBYTES.toBytes(1), 0)
                .setEstimatedNetworkBytes(DataUnit.MEBIBYTES.toBytes(1), 0)
                .setRequiredNetworkType(JobInfo.NETWORK_TYPE_CELLULAR), UID_RED);
                .setRequiredNetworkType(JobInfo.NETWORK_TYPE_CELLULAR), UID_RED);
@@ -570,13 +613,11 @@ public class ConnectivityControllerTest {
        final Network cellularNet = new Network(101);
        final Network cellularNet = new Network(101);
        final NetworkCapabilities cellularCaps =
        final NetworkCapabilities cellularCaps =
                createCapabilities().addTransportType(TRANSPORT_CELLULAR);
                createCapabilities().addTransportType(TRANSPORT_CELLULAR);
        reset(mConnManager);
        answerNetwork(UID_RED, cellularNet, cellularCaps);
        answerNetwork(UID_BLUE, cellularNet, cellularCaps);


        final ConnectivityController controller = new ConnectivityController(mService);
        final ConnectivityController controller = new ConnectivityController(mService);
        controller.maybeStartTrackingJobLocked(networked, null);
        controller.maybeStartTrackingJobLocked(networked, null);
        controller.maybeStartTrackingJobLocked(unnetworked, null);
        controller.maybeStartTrackingJobLocked(unnetworked, null);
        answerNetwork(callback.getValue(), redCallback.getValue(), null, cellularNet, cellularCaps);


        assertTrue(networked.isConstraintSatisfied(JobStatus.CONSTRAINT_CONNECTIVITY));
        assertTrue(networked.isConstraintSatisfied(JobStatus.CONSTRAINT_CONNECTIVITY));
        assertFalse(unnetworked.isConstraintSatisfied(JobStatus.CONSTRAINT_CONNECTIVITY));
        assertFalse(unnetworked.isConstraintSatisfied(JobStatus.CONSTRAINT_CONNECTIVITY));
@@ -600,18 +641,28 @@ public class ConnectivityControllerTest {
        assertFalse(unnetworked.isConstraintSatisfied(JobStatus.CONSTRAINT_CONNECTIVITY));
        assertFalse(unnetworked.isConstraintSatisfied(JobStatus.CONSTRAINT_CONNECTIVITY));
    }
    }


    private void answerNetwork(int uid, Network net, NetworkCapabilities caps) {
    private void answerNetwork(@NonNull NetworkCallback generalCallback,
        when(mConnManager.getActiveNetworkForUid(eq(uid), anyBoolean())).thenReturn(net);
            @Nullable NetworkCallback uidCallback, @Nullable Network lastNetwork,
        when(mConnManager.getNetworkCapabilities(eq(net))).thenReturn(caps);
            @Nullable Network net, @Nullable NetworkCapabilities caps) {
        if (net != null) {
        if (net == null) {
            final NetworkInfo ni = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, null, null);
            generalCallback.onLost(lastNetwork);
            ni.setDetailedState(DetailedState.CONNECTED, null, null);
            if (uidCallback != null) {
            when(mConnManager.getNetworkInfoForUid(eq(net), eq(uid), anyBoolean())).thenReturn(ni);
                uidCallback.onLost(lastNetwork);
            }
        } else {
            generalCallback.onAvailable(net);
            generalCallback.onCapabilitiesChanged(net, caps);
            if (uidCallback != null) {
                uidCallback.onAvailable(net);
                uidCallback.onBlockedStatusChanged(net, false);
                uidCallback.onCapabilitiesChanged(net, caps);
            }
        }
        }
    }
    }


    private static NetworkCapabilities createCapabilities() {
    private static NetworkCapabilities createCapabilities() {
        return new NetworkCapabilities().addCapability(NET_CAPABILITY_INTERNET)
        return new NetworkCapabilities().addCapability(NET_CAPABILITY_INTERNET)
                .addCapability(NET_CAPABILITY_NOT_SUSPENDED)
                .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
                .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
                .addCapability(NET_CAPABILITY_VALIDATED);
                .addCapability(NET_CAPABILITY_VALIDATED);
    }
    }