1531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti/*
2531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti * Copyright (C) 2016 The Android Open Source Project
3531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti *
4531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti * Licensed under the Apache License, Version 2.0 (the "License");
5531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti * you may not use this file except in compliance with the License.
6531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti * You may obtain a copy of the License at
7531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti *
8531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti *      http://www.apache.org/licenses/LICENSE-2.0
9531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti *
10531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti * Unless required by applicable law or agreed to in writing, software
11531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti * distributed under the License is distributed on an "AS IS" BASIS,
12531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti * See the License for the specific language governing permissions and
14531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti * limitations under the License.
15531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti */
16531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti
17531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colittipackage com.android.server.net;
18531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti
19531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colittiimport android.content.Context;
20531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colittiimport android.net.ConnectivityManager;
21531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colittiimport android.net.ConnectivityManager.NetworkCallback;
22531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colittiimport android.net.Network;
23531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colittiimport android.net.NetworkRequest;
24531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colittiimport android.util.Log;
25531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti
26531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colittiimport com.android.internal.annotations.GuardedBy;
27531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colittiimport com.android.internal.annotations.VisibleForTesting;
28531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti
29531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti/**
30531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti * A class that pins a process to the first network that satisfies a particular NetworkRequest.
31531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti *
32531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti * We use this to maintain compatibility with pre-M apps that call WifiManager.enableNetwork()
33531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti * to connect to a Wi-Fi network that has no Internet access, and then assume that they will be
34531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti * able to use that network because it's the system default.
35531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti *
36531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti * In order to maintain compatibility with apps that call setProcessDefaultNetwork themselves,
37531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti * we try not to set the default network unless they have already done so, and we try not to
38531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti * clear the default network unless we set it ourselves.
39531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti *
40531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti * This should maintain behaviour that's compatible with L, which would pin the whole system to
41531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti * any wifi network that was created via enableNetwork(..., true) until that network
42531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti * disconnected.
43531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti *
44531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti * Note that while this hack allows network traffic to flow, it is quite limited. For example:
45531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti *
46531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti * 1. setProcessDefaultNetwork only affects this process, so:
47531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti *    - Any subprocesses spawned by this process will not be pinned to Wi-Fi.
48531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti *    - If this app relies on any other apps on the device also being on Wi-Fi, that won't work
49531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti *      either, because other apps on the device will not be pinned.
50531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti * 2. The behaviour of other APIs is not modified. For example:
51531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti *    - getActiveNetworkInfo will return the system default network, not Wi-Fi.
52531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti *    - There will be no CONNECTIVITY_ACTION broadcasts about TYPE_WIFI.
53531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti *    - getProcessDefaultNetwork will not return null, so if any apps are relying on that, they
54531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti *      will be surprised as well.
55531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti *
56531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti * This class is a per-process singleton because the process default network is a per-process
57531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti * singleton.
58531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti *
59531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti */
60531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colittipublic class NetworkPinner extends NetworkCallback {
61531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti
62531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti    private static final String TAG = NetworkPinner.class.getSimpleName();
63531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti
64531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti    @VisibleForTesting
65531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti    protected static final Object sLock = new Object();
66531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti
67531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti    @GuardedBy("sLock")
68531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti    private static ConnectivityManager sCM;
69531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti    @GuardedBy("sLock")
70531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti    private static Callback sCallback;
71531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti    @VisibleForTesting
72531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti    @GuardedBy("sLock")
73531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti    protected static Network sNetwork;
74531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti
75531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti    private static void maybeInitConnectivityManager(Context context) {
76531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti        // TODO: what happens if an app calls a WifiManager API before ConnectivityManager is
77531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti        // registered? Can we fix this by starting ConnectivityService before WifiService?
78531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti        if (sCM == null) {
79531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti            // Getting a ConnectivityManager does not leak the calling context, because it stores
80531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti            // the application context and not the calling context.
81531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti            sCM = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
82531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti            if (sCM == null) {
83531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti                throw new IllegalStateException("Bad luck, ConnectivityService not started.");
84531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti            }
85531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti        }
86531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti    }
87531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti
88531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti    private static class Callback extends NetworkCallback {
89531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti        @Override
90531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti        public void onAvailable(Network network) {
91531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti            synchronized(sLock) {
92531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti                if (this != sCallback) return;
93531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti
94531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti                if (sCM.getBoundNetworkForProcess() == null && sNetwork == null) {
95531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti                    sCM.bindProcessToNetwork(network);
96531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti                    sNetwork = network;
97531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti                    Log.d(TAG, "Wifi alternate reality enabled on network " + network);
98531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti                }
99531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti                sLock.notify();
100531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti            }
101531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti        }
102531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti
103531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti        @Override
104531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti        public void onLost(Network network) {
105531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti            synchronized (sLock) {
106531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti                if (this != sCallback) return;
107531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti
108531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti                if (network.equals(sNetwork) && network.equals(sCM.getBoundNetworkForProcess())) {
109531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti                    unpin();
110531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti                    Log.d(TAG, "Wifi alternate reality disabled on network " + network);
111531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti                }
112531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti                sLock.notify();
113531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti            }
114531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti        }
115531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti    }
116531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti
117531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti    public static void pin(Context context, NetworkRequest request) {
118531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti        synchronized (sLock) {
119531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti            if (sCallback == null) {
120531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti                maybeInitConnectivityManager(context);
121531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti                sCallback = new Callback();
122531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti                try {
123531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti                    sCM.registerNetworkCallback(request, sCallback);
124531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti                } catch (SecurityException e) {
125531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti                    Log.d(TAG, "Failed to register network callback", e);
126531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti                    sCallback = null;
127531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti                }
128531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti            }
129531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti        }
130531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti    }
131531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti
132531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti    public static void unpin() {
133531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti        synchronized (sLock) {
134531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti            if (sCallback != null) {
135531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti                try {
136531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti                    sCM.bindProcessToNetwork(null);
137531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti                    sCM.unregisterNetworkCallback(sCallback);
138531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti                } catch (SecurityException e) {
139531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti                    Log.d(TAG, "Failed to unregister network callback", e);
140531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti                }
141531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti                sCallback = null;
142531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti                sNetwork = null;
143531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti            }
144531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti        }
145531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti    }
146531a34430072b9296aaeb47d9e7d04326a93fee4Lorenzo Colitti}
147